on xenial help sign in
merged with unified-stage
commit8a50eb43246bc19c372864f95dca1e55757d6d13 authorNick Dedekind <nick.dedekind@canonical.com> dateTue 4 Oct 2016, 14:22 (10 years ago) parent3a39491431096e
91 files changed+4212−2249
debian/changelog+5−3 debian/unity8.install+1−1 plugins/Ubuntu/Gestures/TouchGate.cpp+4−1 plugins/WindowManager/TopLevelSurfaceList.cpp−5 qml/CMakeLists.txt+1−1 qml/Components/EdgeBarrier.qml+2 qml/Components/FloatingFlickable.qml+3 qml/Greeter/LoginAreaContainer.qml+1−1 qml/Notifications/Notification.qml+1−1 qml/Rotation/RotationStates.qml−6 qml/Shell.qml+52−165 qml/Stages/AbstractStage.qml → qml/Stage/AbstractStage.qml qml/Stages/ApplicationWindow.qml → qml/Stage/ApplicationWindow.qml+13−37 qml/Stage/DecoratedWindow.qml+249 qml/Stages/DesktopSpread.qml → qml/Stage/DesktopSpread.qml qml/Stages/DesktopSpreadDelegate.qml → qml/Stage/DesktopSpreadDelegate.qml qml/Stages/FakeMaximizeDelegate.qml → qml/Stage/FakeMaximizeDelegate.qml qml/Stages/MainViewStyle.qml → qml/Stage/MainViewStyle.qml qml/Stages/MoveHandler.qml → qml/Stage/MoveHandler.qml+2−2 qml/Stages/OrientationChangeAnimation.qml → qml/Stage/OrientationChangeAnimation.qml qml/Stages/PhoneStage.qml → qml/Stage/PhoneStage.qml qml/Stages/PromptSurfaceAnimations.qml → qml/Stage/PromptSurfaceAnimations.qml+2−3 qml/Stages/ResizeGrip.qml → qml/Stage/ResizeGrip.qml qml/Stages/SideStage.qml → qml/Stage/SideStage.qml qml/Stages/Splash.qml → qml/Stage/Splash.qml qml/Stage/Spread/BezierCurve.qml+45 qml/Stage/Spread/KeySpline.js+66 qml/Stage/Spread/MathUtils.js+95 qml/Stage/Spread/OpacityMask.qml+82 qml/Stage/Spread/Spread.qml+162 qml/Stage/Spread/SpreadDelegateInputArea.qml+183 qml/Stage/Spread/SpreadMaths.qml+78 qml/Stage/Spread/StagedRightEdgeMaths.qml+174 qml/Stage/Spread/WindowedRightEdgeMaths.qml+81 qml/Stage/Spread/cubic-bezier.js+39 qml/Stages/SpreadDelegate.qml → qml/Stage/SpreadDelegate.qml qml/Stages/SpreadMaths.qml → qml/Stage/SpreadMaths.qml qml/Stage/Stage.qml+1874 qml/Stage/StageMaths.qml+79 qml/Stages/StagedFullscreenPolicy.qml → qml/Stage/StagedFullscreenPolicy.qml qml/Stages/SurfaceContainer.qml → qml/Stage/SurfaceContainer.qml+5−52 qml/Stages/TabletSideStageTouchGesture.qml → qml/Stage/TabletSideStageTouchGesture.qml qml/Stages/TabletStage.qml → qml/Stage/TabletStage.qml qml/Stages/TopLevelSurfaceRepeater.qml → qml/Stage/TopLevelSurfaceRepeater.qml+9 qml/Stages/TransformedSpreadDelegate.qml → qml/Stage/TransformedSpreadDelegate.qml qml/Stages/TransformedTabletSpreadDelegate.qml → qml/Stage/TransformedTabletSpreadDelegate.qml qml/Stages/WindowControlsOverlay.qml → qml/Stage/WindowControlsOverlay.qml qml/Stages/WindowDecoration.qml → qml/Stage/WindowDecoration.qml+1−1 qml/Stage/WindowInfoItem.qml+53 qml/Stages/WindowResizeArea.qml → qml/Stage/WindowResizeArea.qml+32−31 qml/Stages/WindowedFullscreenPolicy.qml → qml/Stage/WindowedFullscreenPolicy.qml qml/Stages/graphics/PageHeaderBaseDividerBottom@18.png → qml/Stage/graphics/PageHeaderBaseDividerBottom@18.png qml/Stages/graphics/PageHeaderBaseDividerLight@18.png → qml/Stage/graphics/PageHeaderBaseDividerLight@18.png qml/Stages/graphics/PageHeaderBaseDividerLight@18.sci → qml/Stage/graphics/PageHeaderBaseDividerLight@18.sci qml/Stages/graphics/arrows-centre.png → qml/Stage/graphics/arrows-centre.png qml/Stages/graphics/arrows.png → qml/Stage/graphics/arrows.png qml/Stages/graphics/sidestage_drag.svg → qml/Stage/graphics/sidestage_drag.svg qml/Stages/graphics/sidestage_handle@20.png → qml/Stage/graphics/sidestage_handle@20.png qml/Stages/graphics/sidestage_handle@20.sci → qml/Stage/graphics/sidestage_handle@20.sci qml/Stages/graphics/sidestage_open.svg → qml/Stage/graphics/sidestage_open.svg qml/Stages/graphics/window-close.svg → qml/Stage/graphics/window-close.svg qml/Stages/DecoratedWindow.qml−157 qml/Stages/DesktopStage.qml−825 qml/Tutorial/TutorialRight.qml+1−1 qml/Stages/graphics/dropshadow2gu@30.png → qml/graphics/dropshadow2gu@30.png qml/Stages/graphics/dropshadow2gu@30.sci → qml/graphics/dropshadow2gu@30.sci tests/graphics/applicationIcons/dash.png → tests/graphics/applicationIcons/dash@18.png tests/mocks/Unity/Application/ApplicationInfo.cpp+2−2 tests/mocks/Unity/Application/ApplicationManager.cpp+2 tests/mocks/Unity/Application/MirSurface.cpp+1 tests/mocks/Unity/Application/MirSurfaceItem.cpp+13 tests/mocks/Unity/Application/MirSurfaceListModel.cpp−1 tests/mocks/Unity/Application/VirtualKeyboard.cpp+9−7 tests/mocks/Unity/Application/resources/MirSurfaceItem.qml+2−5 tests/qmltests/CMakeLists.txt+8−8 tests/qmltests/Stages/ApplicationCheckBox.qml → tests/qmltests/Stage/ApplicationCheckBox.qml tests/qmltests/Stages/SizeHintField.qml → tests/qmltests/Stage/SizeHintField.qml tests/qmltests/Stages/SurfaceManagerControls.qml → tests/qmltests/Stage/SurfaceManagerControls.qml tests/qmltests/Stages/SurfaceManagerField.qml → tests/qmltests/Stage/SurfaceManagerField.qml tests/qmltests/Stages/tst_ApplicationWindow.qml → tests/qmltests/Stage/tst_ApplicationWindow.qml+1−1 tests/qmltests/Stage/tst_DecoratedWindow.qml+232 tests/qmltests/Stages/tst_DesktopStage.qml → tests/qmltests/Stage/tst_DesktopStage.qml+29−71 tests/qmltests/Stages/tst_PhoneStage.qml → tests/qmltests/Stage/tst_PhoneStage.qml+144−211 tests/qmltests/Stages/tst_Splash.qml → tests/qmltests/Stage/tst_Splash.qml+1−1 tests/qmltests/Stages/tst_SpreadDelegate.qml → tests/qmltests/Stage/tst_SpreadDelegate.qml tests/qmltests/Stages/tst_SurfaceContainer.qml → tests/qmltests/Stage/tst_SurfaceContainer.qml+2−2 tests/qmltests/Stages/tst_TabletStage.qml → tests/qmltests/Stage/tst_TabletStage.qml+102−239 tests/qmltests/Stages/tst_WindowResizeArea.qml → tests/qmltests/Stage/tst_WindowResizeArea.qml+40−36 tests/qmltests/tst_OrientedShell.qml+38−198 tests/qmltests/tst_Shell.qml+182−163 tests/qmltests/tst_ShellWithPin.qml+9−11
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
22
33 [ Albert Astals Cid ]
44 * LVWPH: update clipItem height when list height changes (LP:
@@ -46,12 +46,14 @@ unity8 (8.14+16.10.20160922-0ubuntu1) yakkety; urgency=medium
4646 the greeter.
4747
4848 [ Lukáš Tinkl ]
49− * Implement edge maximizing (aka window snapping) (LP: #1602628)
5049 * On the PC platform (as opposed to running on $devices), use the
5150 "mute" action instead of silent mode
5251 * Respect Fitt's law wrt the window control buttons in panel (LP:
5352 #1611959)
5453 * 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
5557
5658 [ Marco Trevisan (Treviño) ]
5759 * Indicators, mocks: add fake indicators menuitem to populate mocks
@@ -73,7 +75,7 @@ unity8 (8.14+16.10.20160922-0ubuntu1) yakkety; urgency=medium
7375 * Update look of infographic a bit
7476 * Make infographic bubbles white even on the default wallpaper.
7577
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
7779
7880unity8 (8.14+16.10.20160831.3-0ubuntu1) yakkety; urgency=medium
7981
debian/unity8.install+1−1
@@ -16,7 +16,7 @@ usr/share/unity8/DeviceConfiguration.qml
1616usr/share/unity8/OrientedShell.qml
1717usr/share/unity8/DisabledScreenNotice.qml
1818usr/share/unity8/Shell.qml
19−usr/share/unity8/Stages
19+usr/share/unity8/Stage
2020usr/share/unity8/Tutorial
2121usr/share/unity8/Wizard
2222usr/share/url-dispatcher/urls/unity8-dash.url-dispatcher
plugins/Ubuntu/Gestures/TouchGate.cpp+4−1
@@ -61,7 +61,10 @@ void TouchGate::touchEvent(QTouchEvent *event)
6161 const QTouchEvent::TouchPoint &touchPoint = touchPoints[i];
6262
6363 if (touchPoint.state() == Qt::TouchPointPressed) {
64− Q_ASSERT(!m_touchInfoMap.contains(touchPoint.id()));
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.
67+// Q_ASSERT(!m_touchInfoMap.contains(touchPoint.id()));
6568 m_touchInfoMap[touchPoint.id()].ownership = OwnershipRequested;
6669 m_touchInfoMap[touchPoint.id()].ended = false;
6770 TouchRegistry::instance()->requestTouchOwnership(touchPoint.id(), this);
plugins/WindowManager/TopLevelSurfaceList.cpp−5
@@ -133,11 +133,6 @@ void TopLevelSurfaceList::appendSurfaceHelper(MirSurfaceInterface *surface, Appl
133133
134134void TopLevelSurfaceList::connectSurface(MirSurfaceInterface *surface)
135135{
136− connect(surface, &MirSurfaceInterface::focusedChanged, this, [this, surface](bool focused){
137− if (focused) {
138− this->raise(surface);
139− }
140− });
141136 connect(surface, &MirSurfaceInterface::liveChanged, this, [this, surface](bool live){
142137 if (!live) {
143138 onSurfaceDied(surface);
qml/CMakeLists.txt+1−1
@@ -12,7 +12,7 @@ set(QML_DIRS
1212 Launcher
1313 Notifications
1414 Panel
15− Stages
15+ Stage
1616 Rotation
1717 Tutorial
1818 Wizard
qml/Components/EdgeBarrier.qml+2
@@ -29,6 +29,8 @@ Item {
2929 // Supported values are: Qt.LeftEdge, Qt.RightEdge
3030 property int edge: Qt.LeftEdge
3131
32+ readonly property alias progress: controller.progress
33+
3234 property Item target: parent
3335 function push(amount) { controller.push(amount); }
3436 signal passed()
qml/Components/FloatingFlickable.qml+3
@@ -35,6 +35,9 @@ Item {
3535 property alias contentX: flickable.contentX
3636 property alias contentY: flickable.contentY
3737 property alias direction: swipeArea.direction
38+ property alias leftMargin: flickable.leftMargin
39+ property alias rightMargin: flickable.rightMargin
40+ property alias dragging: flickable.dragging
3841
3942 MouseEventGenerator {
4043 id: mouseEventGenerator
qml/Greeter/LoginAreaContainer.qml+1−1
@@ -26,7 +26,7 @@ Item {
2626 rightMargin: -units.gu(1.5)
2727 bottomMargin: -units.gu(1.5)
2828 }
29− source: "../Stages/graphics/dropshadow2gu.sci"
29+ source: "../graphics/dropshadow2gu.sci"
3030 opacity: 0.35
3131 }
3232
qml/Notifications/Notification.qml+1−1
@@ -143,7 +143,7 @@ StyledItem {
143143 fill: contents
144144 margins: shapedBack.visible ? -units.gu(1) : -units.gu(1.5)
145145 }
146− source: "../Stages/graphics/dropshadow2gu.sci"
146+ source: "../graphics/dropshadow2gu.sci"
147147 opacity: notification.opacity * 0.5
148148 enabled: !fullscreen
149149 }
qml/Rotation/RotationStates.qml−6
@@ -121,12 +121,6 @@ StateGroup {
121121 }
122122 }
123123
124− property var shellBeingResized: Binding {
125− target: root.shell
126− property: "beingResized"
127− value: d.transitioning
128− }
129−
130124 readonly property int fullAnimation: 0
131125 readonly property int indicatorsBarAnimation: 1
132126 readonly property int noAnimation: 2
qml/Shell.qml+52−165
@@ -35,7 +35,7 @@ import "Launcher"
3535import "Panel"
3636import "Components"
3737import "Notifications"
38−import "Stages"
38+import "Stage"
3939import "Tutorial"
4040import "Wizard"
4141import Unity.Notifications 1.0 as NotificationBackend
@@ -58,24 +58,22 @@ StyledItem {
5858 property real nativeWidth
5959 property real nativeHeight
6060 property alias indicatorAreaShowProgress: panel.indicatorAreaShowProgress
61− property bool beingResized
6261 property string usageScenario: "phone" // supported values: "phone", "tablet" or "desktop"
6362 property string mode: "full-greeter"
6463 property alias oskEnabled: inputMethod.enabled
6564 function updateFocusedAppOrientation() {
66− applicationsDisplayLoader.item.updateFocusedAppOrientation();
65+ stage.updateFocusedAppOrientation();
6766 }
6867 function updateFocusedAppOrientationAnimated() {
69− applicationsDisplayLoader.item.updateFocusedAppOrientationAnimated();
68+ stage.updateFocusedAppOrientationAnimated();
7069 }
7170 property bool hasMouse: false
7271
7372 // to be read from outside
74− readonly property int mainAppWindowOrientationAngle:
75− applicationsDisplayLoader.item ? applicationsDisplayLoader.item.mainAppWindowOrientationAngle : 0
73+ readonly property int mainAppWindowOrientationAngle: stage.mainAppWindowOrientationAngle
7674
7775 readonly property bool orientationChangesEnabled: panel.indicators.fullyClosed
78− && (applicationsDisplayLoader.item && applicationsDisplayLoader.item.orientationChangesEnabled)
76+ && stage.orientationChangesEnabled
7977 && (!greeter || !greeter.animating)
8078
8179 readonly property bool showingGreeter: greeter && greeter.shown
@@ -89,19 +87,13 @@ StyledItem {
8987 return Qt.PrimaryOrientation;
9088 } else if (showingGreeter || notifications.topmostIsFullscreen) {
9189 return Qt.PrimaryOrientation;
92− } else if (applicationsDisplayLoader.item) {
93− return shell.orientations.map(applicationsDisplayLoader.item.supportedOrientations);
9490 } else {
95− // we just don't care
96− return Qt.PortraitOrientation
97− | Qt.LandscapeOrientation
98− | Qt.InvertedPortraitOrientation
99− | Qt.InvertedLandscapeOrientation;
91+ return shell.orientations.map(stage.supportedOrientations);
10092 }
10193 }
10294
103− readonly property var mainApp:
104− applicationsDisplayLoader.item ? applicationsDisplayLoader.item.mainApp : null
95+ readonly property var mainApp: stage.mainApp
96+
10597 onMainAppChanged: {
10698 if (mainApp) {
10799 _onMainAppChanged(mainApp.appId);
@@ -278,154 +270,50 @@ StyledItem {
278270 applicationsModel: ApplicationManager
279271 }
280272
281− Loader {
282− id: applicationsDisplayLoader
283− objectName: "applicationsDisplayLoader"
273+ Stage {
274+ id: stage
275+ objectName: "stage"
284276 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)
285283
286− // When we have a locked app, we only want to show that one app.
287− // FIXME: do this in a less traumatic way. We currently only allow
288− // locked apps in phone mode (see FIXME in Lockscreen component in
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.
284+ applicationManager: ApplicationManager
285+ topLevelSurfaceList: topLevelSurfaceList
286+ inputMethodRect: inputMethod.visibleRect
294287
295288 property string usageScenario: shell.usageScenario === "phone" || greeter.hasLockedApp
296− ? "phone"
297− : shell.usageScenario
298− readonly property string qmlComponent: {
299− if (applicationsDisplayLoader.usageScenario === "phone") {
300− return "Stages/PhoneStage.qml";
301− } else if (applicationsDisplayLoader.usageScenario === "tablet") {
302− return "Stages/TabletStage.qml";
303− } else {
304− return "Stages/DesktopStage.qml";
305− }
306− }
307− // TODO: Ensure the current stage is destroyed before the new one gets loaded.
308− // Currently the new one will get loaded while the old is still hanging
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− }
289+ ? "phone"
290+ : shell.usageScenario
291+
292+ mode: usageScenario == "phone" ? "staged"
293+ : usageScenario == "tablet" ? "stagedWithSideStage"
294+ : "windowed"
295+
296+ shellOrientation: shell.orientation
297+ shellOrientationAngle: shell.orientationAngle
298+ orientations: shell.orientations
299+ nativeWidth: shell.nativeWidth
300+ nativeHeight: shell.nativeHeight
315301
316− property bool interactive: (!greeter || !greeter.shown)
302+ interactive: (!greeter || !greeter.shown)
317303 && panel.indicators.fullyClosed
318304 && launcher.progress == 0
319305 && !notifications.useModal
320306
321307 onInteractiveChanged: { if (interactive) { focus = true; } }
322308
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
413− }
414− Binding {
415− target: applicationsDisplayLoader.item
416− property: "applicationManager"
417− value: ApplicationManager
418− }
419− Binding {
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− }
309+ leftMargin: shell.usageScenario == "desktop" && !settings.autohideLauncher ? launcher.panelWidth: 0
310+ suspended: greeter.shown
311+ keepDashRunning: launcher.shown || launcher.dashSwipe
312+ altTabPressed: physicalKeysMapper.altTabPressed
313+ oskEnabled: shell.oskEnabled
314+
315+ // TODO: This is not implemented yet in the new stage...
316+ spreadEnabled: tutorial.spreadEnabled && (!greeter || (!greeter.hasLockedApp && !greeter.shown))
429317 }
430318 }
431319
@@ -442,6 +330,7 @@ StyledItem {
442330
443331 Loader {
444332 id: greeterLoader
333+ objectName: "greeterLoader"
445334 anchors.fill: parent
446335 anchors.topMargin: panel.panelHeight
447336 sourceComponent: shell.mode != "shell" ? integratedGreeter :
@@ -650,7 +539,7 @@ StyledItem {
650539 }
651540 onFocusChanged: {
652541 if (!focus) {
653− applicationsDisplayLoader.focus = true;
542+ stage.focus = true;
654543 }
655544 }
656545
@@ -706,12 +595,12 @@ StyledItem {
706595 delayed: dialogs.hasActiveDialog || notifications.hasNotification ||
707596 inputMethod.visible ||
708597 (launcher.shown && !launcher.lockedVisible) ||
709− panel.indicators.shown || stage.dragProgress > 0
598+ panel.indicators.shown || stage.rightEdgeDragProgress > 0
710599 usageScenario: shell.usageScenario
711600 lastInputTimestamp: inputFilter.lastInputTimestamp
712601 launcher: launcher
713602 panel: panel
714− stage: applicationsDisplayLoader.item
603+ stage: stage
715604 }
716605
717606 Wizard {
@@ -802,7 +691,7 @@ StyledItem {
802691 z: dialogs.z + 10
803692 GlobalShortcut { shortcut: Qt.Key_Print; onTriggered: itemGrabber.capture(shell) }
804693 Connections {
805− target: applicationsDisplayLoader.item
694+ target: stage
806695 ignoreUnknownSignals: true
807696 onItemSnapshotRequested: itemGrabber.capture(item)
808697 }
@@ -814,7 +703,7 @@ StyledItem {
814703 z: itemGrabber.z + 1
815704 topBoundaryOffset: panel.panelHeight
816705
817− confiningItem: applicationsDisplayLoader.item ? applicationsDisplayLoader.item.itemConfiningMouseCursor : null
706+ confiningItem: stage.itemConfiningMouseCursor
818707
819708 property bool mouseNeverMoved: true
820709 Binding {
@@ -828,10 +717,9 @@ StyledItem {
828717
829718 height: units.gu(3)
830719
831− readonly property var previewRectangle: applicationsDisplayLoader.item && applicationsDisplayLoader.item.previewRectangle &&
832− applicationsDisplayLoader.item.previewRectangle.target &&
833− applicationsDisplayLoader.item.previewRectangle.target.dragging ?
834− applicationsDisplayLoader.item.previewRectangle : null
720+ readonly property var previewRectangle: stage.previewRectangle.target &&
721+ stage.previewRectangle.target.dragging ?
722+ stage.previewRectangle : null
835723
836724 onPushedLeftBoundary: {
837725 if (buttons === Qt.NoButton) {
@@ -842,9 +730,8 @@ StyledItem {
842730 }
843731
844732 onPushedRightBoundary: {
845− if (buttons === Qt.NoButton && applicationsDisplayLoader.item
846− && applicationsDisplayLoader.item.pushRightEdge) {
847− applicationsDisplayLoader.item.pushRightEdge(amount);
733+ if (buttons === Qt.NoButton) {
734+ stage.pushRightEdge(amount);
848735 } else if (buttons === Qt.LeftButton && previewRectangle && previewRectangle.target.canBeMaximizedLeftRight) {
849736 previewRectangle.maximizeRight(amount);
850737 }
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
2020
2121FocusScope {
2222 id: root
23− implicitWidth: surfaceContainer.implicitWidth
24− implicitHeight: surfaceContainer.implicitHeight
23+ implicitWidth: requestedWidth
24+ implicitHeight: requestedHeight
2525
2626 // to be read from outside
2727 property alias interactive: surfaceContainer.interactive
@@ -29,22 +29,10 @@ FocusScope {
2929 readonly property string title: surface && surface.name !== "" ? surface.name : d.name
3030 readonly property QtObject focusedSurface: d.focusedSurface.surface
3131
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−
4332 // to be set from outside
4433 property QtObject surface
4534 property QtObject application
4635 property int surfaceOrientationAngle
47− property alias resizeSurface: surfaceContainer.resizeSurface
4836 property int requestedWidth: -1
4937 property int requestedHeight: -1
5038 property real splashRotation: 0
@@ -156,6 +144,9 @@ FocusScope {
156144 id: screenshotImage
157145 objectName: "screenshotImage"
158146 anchors.fill: parent
147+ fillMode: Image.PreserveAspectCrop
148+ horizontalAlignment: Image.AlignLeft
149+ verticalAlignment: Image.AlignTop
159150 antialiasing: !root.interactive
160151 z: 1
161152
@@ -197,6 +188,7 @@ FocusScope {
197188
198189 SurfaceContainer {
199190 id: surfaceContainer
191+ anchors.fill: parent
200192 z: splashLoader.z + 1
201193 requestedWidth: root.requestedWidth
202194 requestedHeight: root.requestedHeight
@@ -220,6 +212,8 @@ FocusScope {
220212 surface: model.surface
221213 width: root.width
222214 height: root.height
215+ requestedWidth: root.requestedWidth
216+ requestedHeight: root.requestedHeight
223217 isPromptSurface: true
224218 z: surfaceContainer.z + (promptSurfacesRepeater.count - index)
225219 property int index: model.index
@@ -239,28 +233,6 @@ FocusScope {
239233 property Item first: null
240234 }
241235
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−
264236 StateGroup {
265237 id: stateGroup
266238 objectName: "applicationWindowStateGroup"
@@ -287,6 +259,11 @@ FocusScope {
287259 (d.liveSurface ||
288260 (d.applicationState !== ApplicationInfoInterface.Running
289261 && screenshotImage.status !== Image.Ready))
262+ PropertyChanges {
263+ target: root
264+ implicitWidth: surfaceContainer.implicitWidth
265+ implicitHeight: surfaceContainer.implicitHeight
266+ }
290267 },
291268 State {
292269 name: "screenshot"
@@ -424,5 +401,4 @@ FocusScope {
424401 }
425402 ]
426403 }
427−
428404}
qml/Stage/DecoratedWindow.qmlnew file+249
@@ -0,0 +1,249 @@
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+
22+FocusScope {
23+ id: root
24+
25+ // The DecoratedWindow takes requestedWidth/requestedHeight and asks its surface to be resized to that
26+ // (minus the window decoration size in case hasDecoration and showDecoration are true)
27+ // The surface might not be able to resize to the requested values. It will return its actual size
28+ // in implicitWidth/implicitHeight.
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 maximizeButtonShown: decoration.maximizeButtonShown
36+ property alias interactive: applicationWindow.interactive
37+ readonly property alias orientationChangesEnabled: applicationWindow.orientationChangesEnabled
38+
39+ // Changing this will actually add/remove a decoration, meaning, requestedHeight will take the decoration into account.
40+ property bool hasDecoration: true
41+ // This will temporarily show/hide the decoration without actually changing the surface's dimensions
42+ property real showDecoration: 1
43+ property bool animateDecoration: false
44+ property bool showHighlight: false
45+ property int highlightSize: units.gu(1)
46+ property real shadowOpacity: 0
47+ property bool darkening: false
48+
49+ property real requestedWidth
50+ property real requestedHeight
51+ property real scaleToPreviewProgress: 0
52+ property int scaleToPreviewSize: units.gu(30)
53+
54+ property alias surfaceOrientationAngle: applicationWindow.surfaceOrientationAngle
55+ readonly property real decorationHeight: Math.min(d.visibleDecorationHeight, d.requestedDecorationHeight)
56+ readonly property bool counterRotate: surfaceOrientationAngle != 0 && surfaceOrientationAngle != 180
57+
58+ readonly property int minimumWidth: !counterRotate ? applicationWindow.minimumWidth : applicationWindow.minimumHeight
59+ readonly property int minimumHeight: decorationHeight + (!counterRotate ? applicationWindow.minimumHeight : applicationWindow.minimumWidth)
60+ readonly property int maximumWidth: !counterRotate ? applicationWindow.maximumWidth : applicationWindow.maximumHeight
61+ readonly property int maximumHeight: (root.decorationShown && applicationWindow.maximumHeight > 0 ? decoration.height : 0)
62+ + (!counterRotate ? applicationWindow.maximumHeight : applicationWindow.maximumWidth)
63+ readonly property int widthIncrement: !counterRotate ? applicationWindow.widthIncrement : applicationWindow.heightIncrement
64+ readonly property int heightIncrement: !counterRotate ? applicationWindow.heightIncrement : applicationWindow.widthIncrement
65+
66+ property alias overlayShown: decoration.overlayShown
67+ property alias stageWidth: moveHandler.stageWidth
68+ property alias stageHeight: moveHandler.stageHeight
69+ readonly property alias dragging: moveHandler.dragging
70+
71+ readonly property Item clientAreaItem: applicationWindow
72+
73+ signal closeClicked()
74+ signal maximizeClicked()
75+ signal maximizeHorizontallyClicked()
76+ signal maximizeVerticallyClicked()
77+ signal minimizeClicked()
78+ signal decorationPressed()
79+ signal decorationReleased()
80+
81+ QtObject {
82+ id: d
83+ property int requestedDecorationHeight: root.hasDecoration ? decoration.height : 0
84+ Behavior on requestedDecorationHeight { enabled: root.animateDecoration; UbuntuNumberAnimation { } }
85+
86+ property int visibleDecorationHeight: root.hasDecoration ? root.showDecoration * decoration.height : 0
87+ Behavior on visibleDecorationHeight { enabled: root.animateDecoration; UbuntuNumberAnimation { } }
88+ }
89+
90+ StateGroup {
91+ states: [
92+ State {
93+ name: "normal"; when: root.scaleToPreviewProgress <= 0 && root.application.state === ApplicationInfoInterface.Running
94+ PropertyChanges {
95+ target: root
96+ implicitWidth: counterRotate ? applicationWindow.implicitHeight : applicationWindow.implicitWidth
97+ implicitHeight: root.decorationHeight + (counterRotate ? applicationWindow.implicitWidth: applicationWindow.implicitHeight)
98+ }
99+ },
100+ State {
101+ name: "normalSuspended"; when: root.scaleToPreviewProgress <= 0 && root.application.state !== ApplicationInfoInterface.Running
102+ PropertyChanges {
103+ target: root
104+ implicitWidth: counterRotate ? applicationWindow.requestedHeight : applicationWindow.requestedWidth
105+ implicitHeight: root.decorationHeight + (counterRotate ? applicationWindow.requestedWidth: applicationWindow.requestedHeight)
106+ }
107+// PropertyChanges { target: applicationWindow; anchors.topMargin: (root.height - applicationWindow.implicitHeight) / 2 }
108+// PropertyChanges { target: dropShadow; anchors.topMargin: (root.height - applicationWindow.implicitHeight) / 2 }
109+ },
110+ State {
111+ name: "preview"; when: root.scaleToPreviewProgress > 0 && root.application.state === ApplicationInfoInterface.Running
112+ PropertyChanges {
113+ target: root
114+ implicitWidth: MathUtils.linearAnimation(0, 1, applicationWindow.oldRequestedWidth, root.scaleToPreviewSize, root.scaleToPreviewProgress)
115+ implicitHeight: MathUtils.linearAnimation(0, 1, applicationWindow.oldRequestedHeight, root.scaleToPreviewSize, root.scaleToPreviewProgress)
116+ }
117+ PropertyChanges {
118+ target: applicationWindow;
119+ requestedWidth: applicationWindow.oldRequestedWidth
120+ requestedHeight: applicationWindow.oldRequestedHeight
121+ width: MathUtils.linearAnimation(0, 1, applicationWindow.oldRequestedWidth, applicationWindow.minSize, root.scaleToPreviewProgress)
122+ height: MathUtils.linearAnimation(0, 1, applicationWindow.oldRequestedHeight, applicationWindow.minSize, root.scaleToPreviewProgress)
123+ itemScale: root.implicitWidth / width
124+ }
125+ },
126+ State {
127+ name: "previewSuspended"; when: root.scaleToPreviewProgress > 0 && root.application.state !== ApplicationInfoInterface.Running
128+ extend: "preview"
129+ PropertyChanges { target: applicationWindow;
130+ anchors.verticalCenterOffset: applicationWindow.implicitHeight < applicationWindow.height ?
131+ (root.height / applicationWindow.itemScale - applicationWindow.implicitHeight) / 2
132+ : (root.height / applicationWindow.itemScale - applicationWindow.height) / 2
133+ }
134+// PropertyChanges { target: dropShadow; anchors.topMargin: (root.height - root.implicitHeight) / 2 * (1 - root.scaleToPreviewProgress) }
135+ }
136+ ]
137+ }
138+
139+ Rectangle {
140+ id: selectionHighlight
141+ objectName: "selectionHighlight"
142+ anchors.fill: parent
143+ anchors.margins: -root.highlightSize
144+ color: "white"
145+ opacity: showHighlight ? 0.55 : 0
146+ visible: opacity > 0
147+ }
148+
149+ BorderImage {
150+ id: dropShadow
151+ anchors {
152+ left: parent.left; top: parent.top; right: parent.right
153+ margins: active ? -units.gu(2) : -units.gu(1.5)
154+ }
155+ height: Math.min(applicationWindow.implicitHeight, applicationWindow.height) * applicationWindow.itemScale
156+ + root.decorationHeight * Math.min(1, root.showDecoration) + (active ? units.gu(4) : units.gu(3))
157+ source: "../graphics/dropshadow2gu.sci"
158+ opacity: root.shadowOpacity
159+ }
160+
161+ WindowDecoration {
162+ id: decoration
163+ target: root.parent || null
164+ objectName: "appWindowDecoration"
165+ anchors { left: parent.left; top: parent.top; right: parent.right }
166+ height: units.gu(3)
167+ width: root.width
168+ title: applicationWindow.title
169+ opacity: root.hasDecoration ? Math.min(1, root.showDecoration) : 0
170+
171+ Behavior on opacity { UbuntuNumberAnimation { } }
172+
173+ onCloseClicked: root.closeClicked();
174+ onMaximizeClicked: { root.decorationPressed(); root.maximizeClicked(); }
175+ onMaximizeHorizontallyClicked: { root.decorationPressed(); root.maximizeHorizontallyClicked(); }
176+ onMaximizeVerticallyClicked: { root.decorationPressed(); root.maximizeVerticallyClicked(); }
177+ onMinimizeClicked: root.minimizeClicked();
178+ onPressed: root.decorationPressed();
179+
180+ onPressedChanged: moveHandler.handlePressedChanged(pressed, pressedButtons, mouseX, mouseY)
181+ onPositionChanged: moveHandler.handlePositionChanged(mouse)
182+ onReleased: {
183+ root.decorationReleased();
184+ moveHandler.handleReleased();
185+ }
186+ }
187+
188+ MoveHandler {
189+ id: moveHandler
190+ objectName: "moveHandler"
191+ target: root.parent
192+ buttonsWidth: decoration.buttonsWidth
193+ }
194+
195+ ApplicationWindow {
196+ id: applicationWindow
197+ objectName: "appWindow"
198+ anchors.verticalCenter: parent.verticalCenter
199+ anchors.verticalCenterOffset: (root.decorationHeight * Math.min(1, root.showDecoration)) / 2
200+ anchors.left: parent.left
201+ width: implicitWidth
202+ height: implicitHeight
203+ requestedHeight: !counterRotate ? root.requestedHeight - d.requestedDecorationHeight : root.requestedWidth
204+ requestedWidth: !counterRotate ? root.requestedWidth : root.requestedHeight - d.requestedDecorationHeight
205+ property int oldRequestedWidth: requestedWidth
206+ property int oldRequestedHeight: requestedHeight
207+ onRequestedWidthChanged: oldRequestedWidth = requestedWidth
208+ onRequestedHeightChanged: oldRequestedHeight = requestedHeight
209+ focus: true
210+
211+ property real itemScale: 1
212+ property real minSize: Math.min(root.scaleToPreviewSize, Math.min(requestedHeight, Math.min(requestedWidth, Math.min(implicitHeight, implicitWidth))))
213+
214+ transform: [
215+ Rotation {
216+ id: rotationTransform
217+ readonly property int rotationAngle: applicationWindow.application &&
218+ applicationWindow.application.rotatesWindowContents
219+ ? ((360 - applicationWindow.surfaceOrientationAngle) % 360) : 0
220+ origin.x: {
221+ if (rotationAngle == 90) return applicationWindow.height / 2;
222+ else if (rotationAngle == 270) return applicationWindow.width / 2;
223+ else if (rotationAngle == 180) return applicationWindow.width / 2;
224+ else return 0;
225+ }
226+ origin.y: {
227+ if (rotationAngle == 90) return applicationWindow.height / 2;
228+ else if (rotationAngle == 270) return applicationWindow.width / 2;
229+ else if (rotationAngle == 180) return applicationWindow.height / 2;
230+ else return 0;
231+ }
232+ angle: rotationAngle
233+ },
234+ Scale {
235+ origin.y: (applicationWindow.implicitHeight < applicationWindow.height ? applicationWindow.implicitHeight : applicationWindow.height) / 2
236+ xScale: applicationWindow.itemScale
237+ yScale: applicationWindow.itemScale
238+ }
239+ ]
240+
241+ }
242+
243+ Rectangle {
244+ anchors.fill: parent
245+ color: "black"
246+ opacity: root.darkening && !root.showHighlight ? 0.05 : 0
247+ Behavior on opacity { UbuntuNumberAnimation { duration: UbuntuAnimation.SnapDuration } }
248+ }
249+}
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 {
112112 // Use integer coordinate values to ensure that target is left in a pixel-aligned
113113 // position. Mouse movement could have subpixel precision, yielding a fractional
114114 // mouse position.
115− target.requestedX = Math.round(pos.x - priv.distanceX);
116− target.requestedY = Math.round(Math.max(pos.y - priv.distanceY, PanelState.panelHeight));
115+ target.windowedX = Math.round(pos.x - priv.distanceX);
116+ target.windowedY = Math.round(Math.max(pos.y - priv.distanceY, PanelState.panelHeight));
117117
118118 if (sensingPoints) { // edge/corner detection when dragging via the touch overlay
119119 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 {
4343 SequentialAnimation {
4444 // clip so we don't go out of parent's bounds during spread
4545 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
4747 duration: UbuntuAnimation.BriskDuration }
4848 PropertyAction { target: root.surfaceItem; property: "visible"; value: false }
4949 PropertyAction { target: container.parent; property: "clip"; value: false }
@@ -61,11 +61,10 @@ StateGroup {
6161 // clip so we don't go out of parent's bounds during spread
6262 PropertyAction { target: root.container.parent; property: "clip"; value: true }
6363 ScriptAction { script: {
64− root.surfaceItem.y = root.container.height;
6564 root.surfaceItem.visible = true;
6665 } }
6766 UbuntuNumberAnimation {
68− target: root.surfaceItem; property: "y"; to: 0
67+ target: root.surfaceItem; property: "anchors.topMargin"; from: root.container.height; to: 0
6968 duration: UbuntuAnimation.BriskDuration
7069 }
7170 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+1874
@@ -0,0 +1,1874 @@
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: "buttonsVisible"
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: "dropShadow"
342+ value: priv.focusedAppDelegate && !priv.focusedAppDelegate.maximized && priv.foregroundMaximizedAppDelegate !== null && mode == "windowed"
343+ }
344+
345+ Binding {
346+ target: PanelState
347+ property: "closeButtonShown"
348+ value: priv.focusedAppDelegate && priv.focusedAppDelegate.maximized && !priv.focusedAppDelegate.isDash
349+ }
350+
351+ Component.onDestruction: {
352+ PanelState.title = "";
353+ PanelState.buttonsVisible = false;
354+ PanelState.dropShadow = false;
355+ }
356+
357+ Instantiator {
358+ model: root.applicationManager
359+ delegate: QtObject {
360+ property var stateBinding: Binding {
361+ readonly property bool isDash: model.application ? model.application.appId == "unity8-dash" : false
362+ target: model.application
363+ property: "requestedState"
364+
365+ // TODO: figure out some lifecycle policy, like suspending minimized apps
366+ // or something if running windowed.
367+ // TODO: If the device has a dozen suspended apps because it was running
368+ // in staged mode, when it switches to Windowed mode it will suddenly
369+ // resume all those apps at once. We might want to avoid that.
370+ value: root.mode === "windowed"
371+ || (isDash && root.keepDashRunning)
372+ || (!root.suspended && model.application && priv.focusedAppDelegate &&
373+ (priv.focusedAppDelegate.appId === model.application.appId ||
374+ priv.mainStageAppId === model.application.appId ||
375+ priv.sideStageAppId === model.application.appId))
376+ ? ApplicationInfoInterface.RequestedRunning
377+ : ApplicationInfoInterface.RequestedSuspended
378+ }
379+
380+ property var lifecycleBinding: Binding {
381+ target: model.application
382+ property: "exemptFromLifecycle"
383+ value: model.application
384+ ? (!model.application.isTouchApp || isExemptFromLifecycle(model.application.appId))
385+ : false
386+ }
387+ }
388+ }
389+
390+ Binding {
391+ target: MirFocusController
392+ property: "focusedSurface"
393+ value: priv.focusedAppDelegate ? priv.focusedAppDelegate.focusedSurface : null
394+ when: !appRepeater.startingUp && root.parent
395+ }
396+
397+ states: [
398+ State {
399+ name: "spread"; when: priv.goneToSpread
400+ PropertyChanges { target: floatingFlickable; enabled: true }
401+ PropertyChanges { target: spreadItem; focus: true }
402+ PropertyChanges { target: hoverMouseArea; enabled: true }
403+ PropertyChanges { target: rightEdgeDragArea; enabled: false }
404+ PropertyChanges { target: cancelSpreadMouseArea; enabled: true }
405+ },
406+ State {
407+ name: "stagedRightEdge"; when: (rightEdgeDragArea.dragging || edgeBarrier.progress > 0) && root.mode == "staged"
408+ },
409+ State {
410+ name: "sideStagedRightEdge"; when: (rightEdgeDragArea.dragging || edgeBarrier.progress > 0) && root.mode == "stagedWithSideStage"
411+ PropertyChanges {
412+ target: sideStage
413+ opacity: priv.sideStageDelegate.x === sideStage.x ? 1 : 0
414+ visible: true
415+ }
416+ },
417+ State {
418+ name: "windowedRightEdge"; when: (rightEdgeDragArea.dragging || edgeBarrier.progress > 0) && root.mode == "windowed"
419+ },
420+ State {
421+ name: "staged"; when: root.mode === "staged"
422+ },
423+ State {
424+ name: "stagedWithSideStage"; when: root.mode === "stagedWithSideStage"
425+ PropertyChanges { target: triGestureArea; enabled: true }
426+ PropertyChanges { target: sideStage; visible: true }
427+ },
428+ State {
429+ name: "windowed"; when: root.mode === "windowed"
430+ }
431+ ]
432+ transitions: [
433+ Transition {
434+ from: "stagedRightEdge,sideStagedRightEdge,windowedRightEdge"; to: "spread"
435+ PropertyAction { target: spreadItem; property: "highlightedIndex"; value: -1 }
436+ },
437+ Transition {
438+ to: "spread"
439+ PropertyAction { target: spreadItem; property: "highlightedIndex"; value: appRepeater.count > 1 ? 1 : 0 }
440+ PropertyAction { target: floatingFlickable; property: "contentX"; value: 0 }
441+ },
442+ Transition {
443+ from: "spread"
444+ SequentialAnimation {
445+ ScriptAction {
446+ script: {
447+ var item = appRepeater.itemAt(Math.max(0, spreadItem.highlightedIndex));
448+ if (item.stage == ApplicationInfoInterface.SideStage && !sideStage.shown) {
449+ sideStage.show();
450+ }
451+ item.playFocusAnimation();
452+ }
453+ }
454+ PropertyAction { target: spreadItem; property: "highlightedIndex"; value: -1 }
455+ }
456+ },
457+ Transition {
458+ to: "stagedRightEdge"
459+ PropertyAction { target: floatingFlickable; property: "contentX"; value: 0 }
460+ },
461+ Transition {
462+ to: "stagedWithSideStage"
463+ ScriptAction { script: priv.updateMainAndSideStageIndexes(); }
464+ }
465+
466+ ]
467+
468+ MouseArea {
469+ id: cancelSpreadMouseArea
470+ anchors.fill: parent
471+ enabled: false
472+ onClicked: priv.goneToSpread = false
473+ }
474+
475+ FocusScope {
476+ id: appContainer
477+ objectName: "appContainer"
478+ anchors.fill: parent
479+ focus: true
480+
481+ Wallpaper {
482+ id: wallpaper
483+ anchors.fill: parent
484+ source: root.background
485+ // Make sure it's the lowest item. Due to the left edge drag we sometimes need
486+ // to put the dash at -1 and we don't want it behind the Wallpaper
487+ z: -2
488+ }
489+
490+ Spread {
491+ id: spreadItem
492+ objectName: "spreadItem"
493+ anchors.fill: appContainer
494+ leftMargin: root.leftMargin
495+ model: root.topLevelSurfaceList
496+ spreadFlickable: floatingFlickable
497+ z: 10
498+
499+ onLeaveSpread: {
500+ priv.goneToSpread = false;
501+ }
502+ }
503+
504+ Connections {
505+ target: root.topLevelSurfaceList
506+ onListChanged: priv.updateMainAndSideStageIndexes()
507+ }
508+
509+
510+ DropArea {
511+ objectName: "MainStageDropArea"
512+ anchors {
513+ left: parent.left
514+ top: parent.top
515+ bottom: parent.bottom
516+ }
517+ width: appContainer.width - sideStage.width
518+ enabled: sideStage.enabled
519+
520+ onDropped: {
521+ drop.source.appDelegate.saveStage(ApplicationInfoInterface.MainStage);
522+ drop.source.appDelegate.focus = true;
523+ }
524+ keys: "SideStage"
525+ }
526+
527+ SideStage {
528+ id: sideStage
529+ objectName: "sideStage"
530+ shown: false
531+ height: appContainer.height
532+ x: appContainer.width - width
533+ visible: false
534+ Behavior on opacity { UbuntuNumberAnimation {} }
535+ z: {
536+ if (!priv.mainStageItemId) return 0;
537+
538+ if (priv.sideStageItemId && priv.nextInStack > 0) {
539+
540+ // Due the order in which bindings are evaluated, this might be triggered while shuffling
541+ // the list and index doesn't yet match with itemIndex (even though itemIndex: index)
542+ // Let's walk the list and compare itemIndex to make sure we have the correct one.
543+ var nextDelegateInStack = -1;
544+ for (var i = 0; i < appRepeater.count; i++) {
545+ if (appRepeater.itemAt(i).itemIndex == priv.nextInStack) {
546+ nextDelegateInStack = appRepeater.itemAt(i);
547+ break;
548+ }
549+ }
550+
551+ if (nextDelegateInStack.stage === ApplicationInfoInterface.MainStage) {
552+ // if the next app in stack is a main stage app, put the sidestage on top of it.
553+ return 2;
554+ }
555+ return 1;
556+ }
557+
558+ return 1;
559+ }
560+
561+ onShownChanged: {
562+ if (!shown && priv.mainStageDelegate) {
563+ priv.mainStageDelegate.claimFocus();
564+ }
565+ }
566+
567+ DropArea {
568+ id: sideStageDropArea
569+ objectName: "SideStageDropArea"
570+ anchors.fill: parent
571+
572+ property bool dropAllowed: true
573+
574+ onEntered: {
575+ dropAllowed = drag.keys != "Disabled";
576+ }
577+ onExited: {
578+ dropAllowed = true;
579+ }
580+ onDropped: {
581+ if (drop.keys == "MainStage") {
582+ drop.source.appDelegate.saveStage(ApplicationInfoInterface.SideStage);
583+ drop.source.appDelegate.focus = true;
584+ }
585+ }
586+ drag {
587+ onSourceChanged: {
588+ if (!sideStageDropArea.drag.source) {
589+ dropAllowed = true;
590+ }
591+ }
592+ }
593+ }
594+ }
595+
596+ TopLevelSurfaceRepeater {
597+ id: appRepeater
598+ model: topLevelSurfaceList
599+ objectName: "appRepeater"
600+
601+ delegate: FocusScope {
602+ id: appDelegate
603+ objectName: "appDelegate_" + model.id
604+ property int itemIndex: index // We need this from outside the repeater
605+ // z might be overriden in some cases by effects, but we need z ordering
606+ // to calculate occlusion detection
607+ property int normalZ: topLevelSurfaceList.count - index
608+ onNormalZChanged: {
609+ if (visuallyMaximized) {
610+ priv.updateForegroundMaximizedApp();
611+ }
612+ }
613+ z: normalZ
614+
615+ // Normally we want x/y where we request it to be. Width/height of our delegate will
616+ // match what the actual surface size is.
617+ // Don't write to those, they will be set by states
618+ x: requestedX
619+ y: requestedY
620+ width: decoratedWindow.implicitWidth
621+ height: decoratedWindow.implicitHeight
622+
623+ // requestedX/Y/width/height is what we ask the actual surface to be.
624+ // Do not write to those, they will be set by states
625+ property real requestedX: windowedX
626+ property real requestedY: windowedY
627+ property real requestedWidth: windowedWidth
628+ property real requestedHeight: windowedHeight
629+
630+ // In those are for windowed mode. Those values basically store the window's properties
631+ // when having a floating window. If you want to move/resize a window in normal mode, this is what you want to write to.
632+ property real windowedX
633+ property real windowedY
634+ property real windowedWidth
635+ property real windowedHeight
636+
637+ // unlike windowedX/Y, this is the last known grab position before being pushed against edges/corners
638+ // when restoring, the window should return to these, not to the place where it was dropped near the edge
639+ property real restoredX
640+ property real restoredY
641+
642+ Binding {
643+ target: appDelegate
644+ property: "y"
645+ value: appDelegate.requestedY -
646+ Math.min(appDelegate.requestedY - PanelState.panelHeight,
647+ Math.max(0, priv.virtualKeyboardHeight - (appContainer.height - (appDelegate.requestedY + appDelegate.height))))
648+ when: root.oskEnabled && appDelegate.focus && (appDelegate.state == "normal" || appDelegate.state == "restored")
649+ && root.inputMethodRect.height > 0
650+
651+ }
652+
653+ Behavior on x { id: xBehavior; enabled: priv.closingIndex >= 0; UbuntuNumberAnimation { onRunningChanged: if (!running) priv.closingIndex = -1} }
654+
655+ Connections {
656+ target: root
657+ onShellOrientationAngleChanged: {
658+ // at this point decoratedWindow.surfaceOrientationAngle is the old shellOrientationAngle
659+ if (application && application.rotatesWindowContents) {
660+ if (root.state == "windowed") {
661+ var angleDiff = decoratedWindow.surfaceOrientationAngle - shellOrientationAngle;
662+ angleDiff = (360 + angleDiff) % 360;
663+ if (angleDiff === 90 || angleDiff === 270) {
664+ var aux = decoratedWindow.requestedHeight;
665+ decoratedWindow.requestedHeight = decoratedWindow.requestedWidth + decoratedWindow.decorationHeight;
666+ decoratedWindow.requestedWidth = aux - decoratedWindow.decorationHeight;
667+ }
668+ }
669+ decoratedWindow.surfaceOrientationAngle = shellOrientationAngle;
670+ } else {
671+ decoratedWindow.surfaceOrientationAngle = 0;
672+ }
673+ }
674+ }
675+ Connections {
676+ target: priv
677+ onSideStageEnabledChanged: refreshStage()
678+ }
679+
680+ readonly property alias application: decoratedWindow.application
681+ readonly property alias minimumWidth: decoratedWindow.minimumWidth
682+ readonly property alias minimumHeight: decoratedWindow.minimumHeight
683+ readonly property alias maximumWidth: decoratedWindow.maximumWidth
684+ readonly property alias maximumHeight: decoratedWindow.maximumHeight
685+ readonly property alias widthIncrement: decoratedWindow.widthIncrement
686+ readonly property alias heightIncrement: decoratedWindow.heightIncrement
687+
688+ readonly property bool maximized: windowState === WindowStateStorage.WindowStateMaximized
689+ readonly property bool maximizedLeft: windowState === WindowStateStorage.WindowStateMaximizedLeft
690+ readonly property bool maximizedRight: windowState === WindowStateStorage.WindowStateMaximizedRight
691+ readonly property bool maximizedHorizontally: windowState === WindowStateStorage.WindowStateMaximizedHorizontally
692+ readonly property bool maximizedVertically: windowState === WindowStateStorage.WindowStateMaximizedVertically
693+ readonly property bool maximizedTopLeft: windowState === WindowStateStorage.WindowStateMaximizedTopLeft
694+ readonly property bool maximizedTopRight: windowState === WindowStateStorage.WindowStateMaximizedTopRight
695+ readonly property bool maximizedBottomLeft: windowState === WindowStateStorage.WindowStateMaximizedBottomLeft
696+ readonly property bool maximizedBottomRight: windowState === WindowStateStorage.WindowStateMaximizedBottomRight
697+ readonly property bool anyMaximized: maximized || maximizedLeft || maximizedRight || maximizedHorizontally || maximizedVertically ||
698+ maximizedTopLeft || maximizedTopRight || maximizedBottomLeft || maximizedBottomRight
699+
700+ readonly property bool minimized: windowState & WindowStateStorage.WindowStateMinimized
701+ readonly property bool fullscreen: surface ? surface.state === Mir.FullscreenState : application.fullscreen
702+
703+ readonly property bool canBeMaximized: canBeMaximizedHorizontally && canBeMaximizedVertically
704+ readonly property bool canBeMaximizedLeftRight: (maximumWidth == 0 || maximumWidth >= appContainer.width/2) &&
705+ (maximumHeight == 0 || maximumHeight >= appContainer.height)
706+ readonly property bool canBeCornerMaximized: (maximumWidth == 0 || maximumWidth >= appContainer.width/2) &&
707+ (maximumHeight == 0 || maximumHeight >= appContainer.height/2)
708+ readonly property bool canBeMaximizedHorizontally: maximumWidth == 0 || maximumWidth >= appContainer.width
709+ readonly property bool canBeMaximizedVertically: maximumHeight == 0 || maximumHeight >= appContainer.height
710+ readonly property alias orientationChangesEnabled: decoratedWindow.orientationChangesEnabled
711+
712+ property int windowState: WindowStateStorage.WindowStateNormal
713+ property bool animationsEnabled: true
714+ property alias title: decoratedWindow.title
715+ readonly property string appName: model.application ? model.application.name : ""
716+ property bool visuallyMaximized: false
717+ property bool visuallyMinimized: false
718+
719+ property int stage: ApplicationInfoInterface.MainStage
720+ function saveStage(newStage) {
721+ appDelegate.stage = newStage;
722+ WindowStateStorage.saveStage(appId, newStage);
723+ priv.updateMainAndSideStageIndexes()
724+ }
725+
726+ readonly property var surface: model.surface
727+ readonly property alias resizeArea: resizeArea
728+ readonly property alias focusedSurface: decoratedWindow.focusedSurface
729+ readonly property bool dragging: touchControls.overlayShown ? touchControls.dragging : decoratedWindow.dragging
730+
731+ readonly property string appId: model.application.appId
732+ readonly property bool isDash: appId == "unity8-dash"
733+ readonly property alias clientAreaItem: decoratedWindow.clientAreaItem
734+
735+ function claimFocus() {
736+ if (root.state == "spread") {
737+ spreadItem.highlightedIndex = index
738+ priv.goneToSpread = false;
739+ }
740+ if (root.mode == "stagedWithSideStage") {
741+ if (appDelegate.stage == ApplicationInfoInterface.SideStage && !sideStage.shown) {
742+ sideStage.show();
743+ }
744+ priv.updateMainAndSideStageIndexes();
745+ }
746+
747+ if (root.mode == "windowed") {
748+ appDelegate.restore(true /* animated */, appDelegate.windowState);
749+ } else {
750+ appDelegate.focus = true;
751+ }
752+ }
753+ Connections {
754+ target: model.surface
755+ onFocusRequested: {
756+ claimFocus();
757+ }
758+ }
759+ Connections {
760+ target: model.application
761+ onFocusRequested: {
762+ if (!model.surface) {
763+ // when an app has no surfaces, we assume there's only one entry representing it:
764+ // this delegate.
765+ claimFocus();
766+ } else {
767+ // if the application has surfaces, focus request should be at surface-level.
768+ }
769+ }
770+ }
771+
772+ onFocusChanged: {
773+ if (appRepeater.startingUp)
774+ return;
775+
776+ if (focus) {
777+ topLevelSurfaceList.raiseId(model.id);
778+ priv.focusedAppDelegate = appDelegate;
779+ } else if (!focus && priv.focusedAppDelegate === appDelegate && root.state != "spread") {
780+ priv.focusedAppDelegate = null;
781+ // FIXME: No idea why the Binding{} doens't update when focusedAppDelegate turns null
782+ MirFocusController.focusedSurface = null;
783+ }
784+ }
785+ Component.onCompleted: {
786+ if (application && application.rotatesWindowContents) {
787+ decoratedWindow.surfaceOrientationAngle = shellOrientationAngle;
788+ } else {
789+ decoratedWindow.surfaceOrientationAngle = 0;
790+ }
791+
792+ // First, cascade the newly created window, relative to the currently/old focused window.
793+ windowedX = priv.focusedAppDelegate ? priv.focusedAppDelegate.windowedX + units.gu(3) : (normalZ - 1) * units.gu(3)
794+ windowedY = priv.focusedAppDelegate ? priv.focusedAppDelegate.windowedY + units.gu(3) : normalZ * units.gu(3)
795+ // Now load any saved state. This needs to happen *after* the cascading!
796+ resizeArea.loadWindowState();
797+
798+ // NB: We're differentiating if this delegate was created in response to a new entry in the model
799+ // or if the Repeater is just populating itself with delegates to match the model it received.
800+ if (!appRepeater.startingUp) {
801+ // a top level window is always the focused one when it first appears, unfocusing
802+ // any preexisting one
803+ if (root.state == "spread") {
804+ spreadItem.highlightedIndex = index;
805+ }
806+ claimFocus();
807+ }
808+
809+ refreshStage();
810+ _constructing = false;
811+ }
812+ Component.onDestruction: {
813+ if (!root.parent) {
814+ // This stage is about to be destroyed. Don't mess up with the model at this point
815+ return;
816+ }
817+
818+ if (visuallyMaximized) {
819+ priv.updateForegroundMaximizedApp();
820+ }
821+
822+ if (focus) {
823+ // focus some other window
824+ for (var i = 0; i < appRepeater.count; i++) {
825+ var appDelegate = appRepeater.itemAt(i);
826+ if (appDelegate && !appDelegate.minimized && i != index) {
827+ appDelegate.focus = true;
828+ return;
829+ }
830+ }
831+ }
832+ }
833+
834+ onVisuallyMaximizedChanged: priv.updateForegroundMaximizedApp()
835+
836+ property bool _constructing: true;
837+ onStageChanged: {
838+ if (!_constructing) {
839+ priv.updateMainAndSideStageIndexes();
840+ }
841+ }
842+
843+ visible: (
844+ !visuallyMinimized
845+ && !greeter.fullyShown
846+ && (priv.foregroundMaximizedAppDelegate === null || priv.foregroundMaximizedAppDelegate.normalZ <= z)
847+ )
848+ || appDelegate.fullscreen
849+ || focusAnimation.running || rightEdgeFocusAnimation.running || hidingAnimation.running
850+
851+ function close() {
852+ model.surface.close();
853+ }
854+
855+ function maximize(animated) {
856+ animationsEnabled = (animated === undefined) || animated;
857+ windowState = WindowStateStorage.WindowStateMaximized;
858+ }
859+ function maximizeLeft(animated) {
860+ animationsEnabled = (animated === undefined) || animated;
861+ windowState = WindowStateStorage.WindowStateMaximizedLeft;
862+ }
863+ function maximizeRight(animated) {
864+ animationsEnabled = (animated === undefined) || animated;
865+ windowState = WindowStateStorage.WindowStateMaximizedRight;
866+ }
867+ function maximizeHorizontally(animated) {
868+ animationsEnabled = (animated === undefined) || animated;
869+ windowState = WindowStateStorage.WindowStateMaximizedHorizontally;
870+ }
871+ function maximizeVertically(animated) {
872+ animationsEnabled = (animated === undefined) || animated;
873+ windowState = WindowStateStorage.WindowStateMaximizedVertically;
874+ }
875+ function maximizeTopLeft(animated) {
876+ animationsEnabled = (animated === undefined) || animated;
877+ windowState = WindowStateStorage.WindowStateMaximizedTopLeft;
878+ }
879+ function maximizeTopRight(animated) {
880+ animationsEnabled = (animated === undefined) || animated;
881+ windowState = WindowStateStorage.WindowStateMaximizedTopRight;
882+ }
883+ function maximizeBottomLeft(animated) {
884+ animationsEnabled = (animated === undefined) || animated;
885+ windowState = WindowStateStorage.WindowStateMaximizedBottomLeft;
886+ }
887+ function maximizeBottomRight(animated) {
888+ animationsEnabled = (animated === undefined) || animated;
889+ windowState = WindowStateStorage.WindowStateMaximizedBottomRight;
890+ }
891+ function minimize(animated) {
892+ animationsEnabled = (animated === undefined) || animated;
893+ windowState |= WindowStateStorage.WindowStateMinimized; // add the minimized bit
894+ }
895+ function restoreFromMaximized(animated) {
896+ animationsEnabled = (animated === undefined) || animated;
897+ windowState = WindowStateStorage.WindowStateRestored;
898+ }
899+ function restore(animated,state) {
900+ animationsEnabled = (animated === undefined) || animated;
901+ windowState = state || WindowStateStorage.WindowStateRestored;
902+ windowState &= ~WindowStateStorage.WindowStateMinimized; // clear the minimized bit
903+ focus = true;
904+ }
905+
906+ function playFocusAnimation() {
907+ if (state == "stagedRightEdge") {
908+ // TODO: Can we drop this if and find something that always works?
909+ if (root.mode == "staged") {
910+ rightEdgeFocusAnimation.targetX = 0
911+ rightEdgeFocusAnimation.start()
912+ } else if (root.mode == "stagedWithSideStage") {
913+ rightEdgeFocusAnimation.targetX = appDelegate.stage == ApplicationInfoInterface.SideStage ? sideStage.x : 0
914+ rightEdgeFocusAnimation.start()
915+ }
916+ } else if (state == "windowedRightEdge") {
917+ claimFocus();
918+ } else {
919+ focusAnimation.start()
920+ }
921+ }
922+ function playHidingAnimation() {
923+ if (state != "windowedRightEdge") {
924+ hidingAnimation.start()
925+ }
926+ }
927+
928+ function refreshStage() {
929+ var newStage = ApplicationInfoInterface.MainStage;
930+ if (priv.sideStageEnabled) { // we're in lanscape rotation.
931+ if (!isDash && application && application.supportedOrientations & (Qt.PortraitOrientation|Qt.InvertedPortraitOrientation)) {
932+ var defaultStage = ApplicationInfoInterface.SideStage; // if application supports portrait, it defaults to sidestage.
933+ if (application.supportedOrientations & (Qt.LandscapeOrientation|Qt.InvertedLandscapeOrientation)) {
934+ // if it supports lanscape, it defaults to mainstage.
935+ defaultStage = ApplicationInfoInterface.MainStage;
936+ }
937+ newStage = WindowStateStorage.getStage(application.appId, defaultStage);
938+ }
939+ }
940+
941+ stage = newStage;
942+ if (focus && stage == ApplicationInfoInterface.SideStage && !sideStage.shown) {
943+ sideStage.show();
944+ }
945+ }
946+
947+ UbuntuNumberAnimation {
948+ id: focusAnimation
949+ target: appDelegate
950+ property: "scale"
951+ from: 0.98
952+ to: 1
953+ duration: UbuntuAnimation.SnapDuration
954+ onStarted: {
955+ topLevelSurfaceList.raiseId(model.id);
956+ }
957+ onStopped: {
958+ appDelegate.claimFocus();
959+ }
960+ }
961+ ParallelAnimation {
962+ id: rightEdgeFocusAnimation
963+ property int targetX: 0
964+ UbuntuNumberAnimation { target: appDelegate; properties: "x"; to: rightEdgeFocusAnimation.targetX; duration: priv.animationDuration }
965+ UbuntuNumberAnimation { target: decoratedWindow; properties: "angle"; to: 0; duration: priv.animationDuration }
966+ UbuntuNumberAnimation { target: decoratedWindow; properties: "itemScale"; to: 1; duration: priv.animationDuration }
967+ onStopped: {
968+ appDelegate.focus = true
969+ }
970+ }
971+ ParallelAnimation {
972+ id: hidingAnimation
973+ UbuntuNumberAnimation { target: appDelegate; property: "opacity"; to: 0; duration: priv.animationDuration }
974+ onStopped: appDelegate.opacity = 1
975+ }
976+
977+ SpreadMaths {
978+ id: spreadMaths
979+ spread: spreadItem
980+ itemIndex: index
981+ flickable: floatingFlickable
982+ }
983+ StageMaths {
984+ id: stageMaths
985+ sceneWidth: root.width
986+ stage: appDelegate.stage
987+ thisDelegate: appDelegate
988+ mainStageDelegate: priv.mainStageDelegate
989+ sideStageDelegate: priv.sideStageDelegate
990+ sideStageWidth: sideStage.panelWidth
991+ sideStageX: sideStage.x
992+ itemIndex: appDelegate.itemIndex
993+ nextInStack: priv.nextInStack
994+ leftEdgeDragProgress: root.leftEdgeDragProgress
995+ }
996+
997+ StagedRightEdgeMaths {
998+ id: stagedRightEdgeMaths
999+ sceneWidth: appContainer.width - root.leftMargin
1000+ sceneHeight: appContainer.height
1001+ isMainStageApp: priv.mainStageDelegate == appDelegate
1002+ isSideStageApp: priv.sideStageDelegate == appDelegate
1003+ sideStageWidth: sideStage.width
1004+ sideStageOpen: sideStage.shown
1005+ itemIndex: index
1006+ nextInStack: priv.nextInStack
1007+ progress: 0
1008+ targetHeight: spreadItem.stackHeight
1009+ targetX: spreadMaths.targetX
1010+ startY: appDelegate.fullscreen ? 0 : PanelState.panelHeight
1011+ targetY: spreadMaths.targetY
1012+ targetAngle: spreadMaths.targetAngle
1013+ targetScale: spreadMaths.targetScale
1014+ shuffledZ: stageMaths.itemZ
1015+ breakPoint: spreadItem.rightEdgeBreakPoint
1016+ }
1017+
1018+ WindowedRightEdgeMaths {
1019+ id: windowedRightEdgeMaths
1020+ itemIndex: index
1021+ startWidth: appDelegate.requestedWidth
1022+ startHeight: appDelegate.requestedHeight
1023+ targetHeight: spreadItem.stackHeight
1024+ targetX: spreadMaths.targetX
1025+ targetY: spreadMaths.targetY
1026+ normalZ: appDelegate.normalZ
1027+ targetAngle: spreadMaths.targetAngle
1028+ targetScale: spreadMaths.targetScale
1029+ breakPoint: spreadItem.rightEdgeBreakPoint
1030+ }
1031+
1032+ states: [
1033+ State {
1034+ name: "spread"; when: root.state == "spread"
1035+ PropertyChanges {
1036+ target: decoratedWindow;
1037+ showDecoration: false;
1038+ angle: spreadMaths.targetAngle
1039+ itemScale: spreadMaths.targetScale
1040+ scaleToPreviewSize: spreadItem.stackHeight
1041+ scaleToPreviewProgress: 1
1042+ hasDecoration: root.mode === "windowed"
1043+ shadowOpacity: spreadMaths.shadowOpacity
1044+ showHighlight: spreadItem.highlightedIndex === index
1045+ darkening: spreadItem.highlightedIndex >= 0
1046+ anchors.topMargin: dragArea.distance
1047+ }
1048+ PropertyChanges {
1049+ target: appDelegate
1050+ x: spreadMaths.targetX
1051+ y: spreadMaths.targetY
1052+ z: index
1053+ height: spreadItem.spreadItemHeight
1054+ requestedWidth: decoratedWindow.oldRequestedWidth
1055+ requestedHeight: decoratedWindow.oldRequestedHeight
1056+ visible: spreadMaths.itemVisible
1057+ }
1058+ PropertyChanges { target: dragArea; enabled: true }
1059+ PropertyChanges { target: windowInfoItem; opacity: spreadMaths.tileInfoOpacity; visible: spreadMaths.itemVisible }
1060+ },
1061+ State {
1062+ name: "stagedRightEdge"
1063+ when: (root.mode == "staged" || root.mode == "stagedWithSideStage") && (root.state == "sideStagedRightEdge" || root.state == "stagedRightEdge" || rightEdgeFocusAnimation.running || hidingAnimation.running)
1064+ PropertyChanges {
1065+ target: stagedRightEdgeMaths
1066+ progress: Math.max(edgeBarrier.progress, rightEdgeDragArea.draggedProgress)
1067+ }
1068+ PropertyChanges {
1069+ target: appDelegate
1070+ x: stagedRightEdgeMaths.animatedX
1071+ y: stagedRightEdgeMaths.animatedY
1072+ z: stagedRightEdgeMaths.animatedZ
1073+ height: stagedRightEdgeMaths.animatedHeight
1074+ requestedWidth: decoratedWindow.oldRequestedWidth
1075+ requestedHeight: decoratedWindow.oldRequestedHeight
1076+ visible: appDelegate.x < root.width
1077+ }
1078+ PropertyChanges {
1079+ target: decoratedWindow
1080+ hasDecoration: false
1081+ angle: stagedRightEdgeMaths.animatedAngle
1082+ itemScale: stagedRightEdgeMaths.animatedScale
1083+ scaleToPreviewSize: spreadItem.stackHeight
1084+ scaleToPreviewProgress: stagedRightEdgeMaths.scaleToPreviewProgress
1085+ shadowOpacity: .3
1086+ }
1087+ },
1088+ State {
1089+ name: "windowedRightEdge"
1090+ when: root.mode == "windowed" && (root.state == "windowedRightEdge" || rightEdgeFocusAnimation.running || hidingAnimation.running || edgeBarrier.progress > 0)
1091+ PropertyChanges {
1092+ target: windowedRightEdgeMaths
1093+ progress: Math.max(rightEdgeDragArea.progress, edgeBarrier.progress)
1094+ }
1095+ PropertyChanges {
1096+ target: appDelegate
1097+ x: windowedRightEdgeMaths.animatedX
1098+ y: windowedRightEdgeMaths.animatedY
1099+ z: windowedRightEdgeMaths.animatedZ
1100+ height: stagedRightEdgeMaths.animatedHeight
1101+ requestedWidth: decoratedWindow.oldRequestedWidth
1102+ requestedHeight: decoratedWindow.oldRequestedHeight
1103+ }
1104+ PropertyChanges {
1105+ target: decoratedWindow
1106+ showDecoration: windowedRightEdgeMaths.decorationHeight
1107+ angle: windowedRightEdgeMaths.animatedAngle
1108+ itemScale: windowedRightEdgeMaths.animatedScale
1109+ scaleToPreviewSize: spreadItem.stackHeight
1110+ scaleToPreviewProgress: windowedRightEdgeMaths.scaleToPreviewProgress
1111+ shadowOpacity: .3
1112+ }
1113+ PropertyChanges {
1114+ target: opacityEffect;
1115+ opacityValue: windowedRightEdgeMaths.opacityMask
1116+ sourceItem: windowedRightEdgeMaths.opacityMask < 1 ? decoratedWindow : null
1117+ }
1118+ },
1119+ State {
1120+ name: "staged"; when: root.state == "staged"
1121+ PropertyChanges {
1122+ target: appDelegate
1123+ x: stageMaths.itemX
1124+ y: appDelegate.fullscreen ? 0 : PanelState.panelHeight
1125+ requestedWidth: appContainer.width
1126+ requestedHeight: appDelegate.fullscreen ? appContainer.height : appContainer.height - PanelState.panelHeight
1127+ visuallyMaximized: true
1128+ visible: appDelegate.x < root.width
1129+ }
1130+ PropertyChanges {
1131+ target: decoratedWindow
1132+ hasDecoration: false
1133+ }
1134+ PropertyChanges {
1135+ target: resizeArea
1136+ enabled: false
1137+ }
1138+ PropertyChanges {
1139+ target: stageMaths
1140+ animateX: !focusAnimation.running && itemIndex !== spreadItem.highlightedIndex
1141+ }
1142+ },
1143+ State {
1144+ name: "stagedWithSideStage"; when: root.state == "stagedWithSideStage"
1145+ PropertyChanges {
1146+ target: stageMaths
1147+ itemIndex: index
1148+ }
1149+ PropertyChanges {
1150+ target: appDelegate
1151+ x: stageMaths.itemX
1152+ y: appDelegate.fullscreen ? 0 : PanelState.panelHeight
1153+ z: stageMaths.itemZ
1154+ requestedWidth: stageMaths.itemWidth
1155+ requestedHeight: appDelegate.fullscreen ? appContainer.height : appContainer.height - PanelState.panelHeight
1156+ visuallyMaximized: true
1157+ visible: appDelegate.x < root.width
1158+ }
1159+ PropertyChanges {
1160+ target: decoratedWindow
1161+ hasDecoration: false
1162+ }
1163+ PropertyChanges {
1164+ target: resizeArea
1165+ enabled: false
1166+ }
1167+ },
1168+ State {
1169+ name: "maximized"; when: appDelegate.windowState == WindowStateStorage.WindowStateMaximized
1170+ PropertyChanges {
1171+ target: appDelegate;
1172+ requestedX: root.leftMargin;
1173+ requestedY: 0;
1174+ visuallyMinimized: false;
1175+ visuallyMaximized: true
1176+ requestedWidth: appContainer.width - root.leftMargin;
1177+ requestedHeight: appContainer.height;
1178+ }
1179+ PropertyChanges { target: touchControls; enabled: true }
1180+ },
1181+ State {
1182+ name: "fullscreen"; when: appDelegate.fullscreen && !appDelegate.minimized
1183+ PropertyChanges {
1184+ target: appDelegate;
1185+ requestedX: 0
1186+ requestedY: 0
1187+ requestedWidth: appContainer.width;
1188+ requestedHeight: appContainer.height;
1189+ }
1190+ PropertyChanges { target: decoratedWindow; hasDecoration: false }
1191+ },
1192+ State {
1193+ name: "normal";
1194+ when: appDelegate.windowState == WindowStateStorage.WindowStateNormal
1195+ PropertyChanges {
1196+ target: appDelegate
1197+ visuallyMinimized: false
1198+ visuallyMaximized: false
1199+ }
1200+ PropertyChanges { target: touchControls; enabled: true }
1201+ PropertyChanges { target: resizeArea; enabled: true }
1202+ PropertyChanges { target: decoratedWindow; shadowOpacity: .3}
1203+ },
1204+ State {
1205+ name: "restored";
1206+ when: appDelegate.windowState == WindowStateStorage.WindowStateRestored
1207+ extend: "normal"
1208+ PropertyChanges {
1209+ target: appDelegate;
1210+ windowedX: restoredX;
1211+ windowedY: restoredY;
1212+ }
1213+ },
1214+ State {
1215+ name: "semiMaximized"
1216+ PropertyChanges { target: touchControls; enabled: true }
1217+ PropertyChanges { target: resizeArea; enabled: true }
1218+ PropertyChanges { target: decoratedWindow; shadowOpacity: .3 }
1219+ },
1220+ State {
1221+ name: "maximizedLeft"; when: appDelegate.maximizedLeft && !appDelegate.minimized
1222+ extend: "semiMaximized"
1223+ PropertyChanges {
1224+ target: appDelegate
1225+ windowedX: root.leftMargin
1226+ windowedY: PanelState.panelHeight
1227+ windowedWidth: (appContainer.width - root.leftMargin)/2
1228+ windowedHeight: appContainer.height - PanelState.panelHeight
1229+ }
1230+ },
1231+ State {
1232+ name: "maximizedRight"; when: appDelegate.maximizedRight && !appDelegate.minimized
1233+ extend: "maximizedLeft"
1234+ PropertyChanges {
1235+ target: appDelegate;
1236+ windowedX: (appContainer.width + root.leftMargin)/2
1237+ }
1238+ },
1239+ State {
1240+ name: "maximizedTopLeft"; when: appDelegate.maximizedTopLeft && !appDelegate.minimized
1241+ extend: "semiMaximized"
1242+ PropertyChanges {
1243+ target: appDelegate
1244+ windowedX: root.leftMargin
1245+ windowedY: PanelState.panelHeight
1246+ windowedWidth: (appContainer.width - root.leftMargin)/2
1247+ windowedHeight: (appContainer.height - PanelState.panelHeight)/2
1248+ }
1249+ },
1250+ State {
1251+ name: "maximizedTopRight"; when: appDelegate.maximizedTopRight && !appDelegate.minimized
1252+ extend: "maximizedTopLeft"
1253+ PropertyChanges {
1254+ target: appDelegate
1255+ windowedX: (appContainer.width + root.leftMargin)/2
1256+ }
1257+ },
1258+ State {
1259+ name: "maximizedBottomLeft"; when: appDelegate.maximizedBottomLeft && !appDelegate.minimized
1260+ extend: "semiMaximized"
1261+ PropertyChanges {
1262+ target: appDelegate
1263+ windowedX: root.leftMargin
1264+ windowedY: (appContainer.height + PanelState.panelHeight)/2
1265+ windowedWidth: (appContainer.width - root.leftMargin)/2
1266+ windowedHeight: appContainer.height/2
1267+ }
1268+ },
1269+ State {
1270+ name: "maximizedBottomRight"; when: appDelegate.maximizedBottomRight && !appDelegate.minimized
1271+ extend: "maximizedBottomLeft"
1272+ PropertyChanges {
1273+ target: appDelegate
1274+ windowedX: (appContainer.width + root.leftMargin)/2
1275+ }
1276+ },
1277+ State {
1278+ name: "maximizedHorizontally"; when: appDelegate.maximizedHorizontally && !appDelegate.minimized
1279+ extend: "semiMaximized"
1280+ PropertyChanges { target: appDelegate; requestedX: root.leftMargin; requestedY: windowedY;
1281+ requestedWidth: appContainer.width - root.leftMargin; requestedHeight: appDelegate.windowedHeight }
1282+ },
1283+ State {
1284+ name: "maximizedVertically"; when: appDelegate.maximizedVertically && !appDelegate.minimized
1285+ extend: "semiMaximized"
1286+ PropertyChanges { target: appDelegate; requestedX: windowedX; requestedY: PanelState.panelHeight;
1287+ requestedWidth: appDelegate.windowedWidth; requestedHeight: appContainer.height - PanelState.panelHeight }
1288+ },
1289+ State {
1290+ name: "minimized"; when: appDelegate.minimized
1291+ PropertyChanges {
1292+ target: appDelegate
1293+ requestedX: -appDelegate.width / 2
1294+ scale: units.gu(5) / appDelegate.width
1295+ opacity: 0;
1296+ visuallyMinimized: true
1297+ visuallyMaximized: false
1298+ }
1299+ }
1300+ ]
1301+ transitions: [
1302+ Transition {
1303+ from: "staged,stagedWithSideStage"; to: "normal"
1304+ enabled: appDelegate.animationsEnabled
1305+ PropertyAction { target: appDelegate; properties: "visuallyMinimized,visuallyMaximized" }
1306+ UbuntuNumberAnimation { target: appDelegate; properties: "x,y,requestedX,requestedY,opacity,requestedWidth,requestedHeight,scale"; duration: priv.animationDuration }
1307+ },
1308+ Transition {
1309+ from: "normal,maximized,maximizedHorizontally,maximizedVertically,maximizedLeft,maximizedRight,maximizedTopLeft,maximizedBottomLeft,maximizedTopRight,maximizedBottomRight";
1310+ to: "staged,stagedWithSideStage"
1311+ UbuntuNumberAnimation { target: appDelegate; properties: "x,y,requestedX,requestedY,requestedWidth,requestedHeight"; duration: priv.animationDuration}
1312+ },
1313+ Transition {
1314+ from: "maximized,maximizedHorizontally,maximizedVertically,maximizedLeft,maximizedRight,maximizedTopLeft,maximizedBottomLeft,maximizedTopRight,maximizedBottomRight,minimized";
1315+ to: "normal,restored"
1316+ enabled: appDelegate.animationsEnabled
1317+ PropertyAction { target: appDelegate; properties: "visuallyMinimized,visuallyMaximized" }
1318+ UbuntuNumberAnimation { target: appDelegate; properties: "requestedX,requestedY,windowedX,windowedY,requestedWidth,requestedHeight,windowedWidth,windowedHeight,scale";
1319+ duration: priv.animationDuration }
1320+ },
1321+ Transition {
1322+ to: "minimized"
1323+ enabled: appDelegate.animationsEnabled
1324+ PropertyAction { target: appDelegate; property: "visuallyMaximized" }
1325+ SequentialAnimation {
1326+ UbuntuNumberAnimation { target: appDelegate; properties: "requestedX,requestedY,opacity,scale,requestedWidth,requestedHeight" }
1327+ PropertyAction { target: appDelegate; property: "visuallyMinimized" }
1328+ ScriptAction {
1329+ script: {
1330+ if (appDelegate.minimized) {
1331+ appDelegate.focus = false;
1332+ priv.focusNext();
1333+ }
1334+ }
1335+ }
1336+ }
1337+ },
1338+ Transition {
1339+ to: "spread"
1340+ // DecoratedWindow wants the scaleToPreviewSize set before enabling scaleToPreview
1341+ PropertyAction { target: appDelegate; properties: "z,visible" }
1342+ PropertyAction { target: decoratedWindow; property: "scaleToPreviewSize" }
1343+ UbuntuNumberAnimation { target: appDelegate; properties: "x,y,height"; duration: priv.animationDuration }
1344+ UbuntuNumberAnimation { target: decoratedWindow; properties: "width,height,itemScale,angle,scaleToPreviewProgress"; duration: priv.animationDuration }
1345+ },
1346+ Transition {
1347+ from: "normal,staged"; to: "stagedWithSideStage"
1348+ UbuntuNumberAnimation { target: appDelegate; properties: "x,y"; duration: priv.animationDuration }
1349+ UbuntuNumberAnimation { target: appDelegate; properties: "requestedWidth,requestedHeight"; duration: priv.animationDuration }
1350+ },
1351+ Transition {
1352+ to: "windowedRightEdge"
1353+ ScriptAction {
1354+ script: {
1355+ windowedRightEdgeMaths.startX = appDelegate.requestedX
1356+ windowedRightEdgeMaths.startY = appDelegate.requestedY
1357+
1358+ if (index == 1) {
1359+ var thisRect = { x: appDelegate.windowedX, y: appDelegate.windowedY, width: appDelegate.requestedWidth, height: appDelegate.requestedHeight }
1360+ var otherDelegate = appRepeater.itemAt(0);
1361+ var otherRect = { x: otherDelegate.windowedX, y: otherDelegate.windowedY, width: otherDelegate.requestedWidth, height: otherDelegate.requestedHeight }
1362+ var intersectionRect = MathUtils.intersectionRect(thisRect, otherRect)
1363+ var mappedInterSectionRect = appDelegate.mapFromItem(root, intersectionRect.x, intersectionRect.y)
1364+ opacityEffect.maskX = mappedInterSectionRect.x
1365+ opacityEffect.maskY = mappedInterSectionRect.y
1366+ opacityEffect.maskWidth = intersectionRect.width
1367+ opacityEffect.maskHeight = intersectionRect.height
1368+ }
1369+ }
1370+ }
1371+ },
1372+ Transition {
1373+ from: "stagedRightEdge"; to: "staged"
1374+ enabled: rightEdgeDragArea.cancelled // only transition back to state if the gesture was cancelled, in the other cases we play the focusAnimations.
1375+ SequentialAnimation {
1376+ ParallelAnimation {
1377+ UbuntuNumberAnimation { target: appDelegate; properties: "x,y,height,width,scale"; duration: priv.animationDuration }
1378+ UbuntuNumberAnimation { target: decoratedWindow; properties: "width,height,itemScale,angle,scaleToPreviewProgress"; duration: priv.animationDuration }
1379+ }
1380+ // We need to release scaleToPreviewSize at last
1381+ PropertyAction { target: decoratedWindow; property: "scaleToPreviewSize" }
1382+ PropertyAction { target: appDelegate; property: "visible" }
1383+ }
1384+ },
1385+ Transition {
1386+ from: "normal,maximized,maximizedLeft,maximizedRight,maximizedTop,maximizedBottom,maximizedTopLeft,maximizedTopRight,maximizedBottomLeft,maximizedBottomRight,maximizedHorizontally,maximizedVertically,fullscreen"
1387+ to: "normal,maximized,maximizedLeft,maximizedRight,maximizedTop,maximizedBottom,maximizedTopLeft,maximizedTopRight,maximizedBottomLeft,maximizedBottomRight,maximizedHorizontally,maximizedVertically,fullscreen"
1388+ enabled: appDelegate.animationsEnabled
1389+ SequentialAnimation {
1390+ PropertyAction { target: appDelegate; property: "visuallyMinimized" }
1391+ UbuntuNumberAnimation { target: appDelegate; properties: "requestedX,requestedY,windowedX,windowedY,opacity,scale,requestedWidth,requestedHeight,windowedWidth,windowedHeight";
1392+ duration: priv.animationDuration }
1393+ PropertyAction { target: appDelegate; property: "visuallyMaximized" }
1394+ ScriptAction { script: { fakeRectangle.stop(); } }
1395+ }
1396+ }
1397+ ]
1398+
1399+ Binding {
1400+ target: PanelState
1401+ property: "buttonsAlwaysVisible"
1402+ value: appDelegate && appDelegate.maximized && touchControls.overlayShown
1403+ }
1404+
1405+ WindowResizeArea {
1406+ id: resizeArea
1407+ objectName: "windowResizeArea"
1408+
1409+ // workaround so that it chooses the correct resize borders when you drag from a corner ResizeGrip
1410+ anchors.margins: touchControls.overlayShown ? borderThickness/2 : -borderThickness
1411+
1412+ target: appDelegate
1413+ minWidth: units.gu(10)
1414+ minHeight: units.gu(10)
1415+ borderThickness: units.gu(2)
1416+ windowId: model.application.appId // FIXME: Change this to point to windowId once we have such a thing
1417+ screenWidth: appContainer.width
1418+ screenHeight: appContainer.height
1419+ leftMargin: root.leftMargin
1420+ enabled: false
1421+ visible: enabled
1422+
1423+ onPressed: {
1424+ appDelegate.focus = true;
1425+ }
1426+
1427+ Component.onDestruction: {
1428+ saveWindowState();
1429+ }
1430+ }
1431+
1432+ DecoratedWindow {
1433+ id: decoratedWindow
1434+ objectName: "decoratedWindow"
1435+ anchors.left: appDelegate.left
1436+ anchors.top: appDelegate.top
1437+ application: model.application
1438+ surface: model.surface
1439+ active: appDelegate.focus
1440+ focus: true
1441+ interactive: root.interactive
1442+ showDecoration: 1
1443+ maximizeButtonShown: appDelegate.canBeMaximized
1444+ overlayShown: touchControls.overlayShown
1445+ width: implicitWidth
1446+ height: implicitHeight
1447+ highlightSize: windowInfoItem.iconMargin / 2
1448+ stageWidth: appContainer.width
1449+ stageHeight: appContainer.height
1450+
1451+ requestedWidth: appDelegate.requestedWidth
1452+ requestedHeight: appDelegate.requestedHeight
1453+
1454+ property int oldRequestedWidth: -1
1455+ property int oldRequestedHeight: -1
1456+
1457+ onRequestedWidthChanged: oldRequestedWidth = requestedWidth
1458+ onRequestedHeightChanged: oldRequestedHeight = requestedHeight
1459+
1460+ onCloseClicked: { appDelegate.close(); }
1461+ onMaximizeClicked: appDelegate.anyMaximized ? appDelegate.restoreFromMaximized() : appDelegate.maximize();
1462+ onMaximizeHorizontallyClicked: appDelegate.maximizedHorizontally ? appDelegate.restoreFromMaximized() : appDelegate.maximizeHorizontally()
1463+ onMaximizeVerticallyClicked: appDelegate.maximizedVertically ? appDelegate.restoreFromMaximized() : appDelegate.maximizeVertically()
1464+ onMinimizeClicked: appDelegate.minimize()
1465+ onDecorationPressed: { appDelegate.focus = true; }
1466+ onDecorationReleased: fakeRectangle.commit();
1467+
1468+ property real angle: 0
1469+ property real itemScale: 1
1470+ transform: [
1471+ Scale {
1472+ origin.x: 0
1473+ origin.y: decoratedWindow.implicitHeight / 2
1474+ xScale: decoratedWindow.itemScale
1475+ yScale: decoratedWindow.itemScale
1476+ },
1477+ Rotation {
1478+ origin { x: 0; y: (decoratedWindow.height / 2) }
1479+ axis { x: 0; y: 1; z: 0 }
1480+ angle: decoratedWindow.angle
1481+ }
1482+ ]
1483+ }
1484+
1485+ OpacityMask {
1486+ id: opacityEffect
1487+ anchors.fill: decoratedWindow
1488+ }
1489+
1490+ WindowControlsOverlay {
1491+ id: touchControls
1492+ target: appDelegate
1493+ enabled: false
1494+ visible: enabled
1495+ stageWidth: appContainer.width
1496+ stageHeight: appContainer.height
1497+
1498+ onFakeMaximizeAnimationRequested: if (!appDelegate.maximized) fakeRectangle.maximize(amount, true)
1499+ onFakeMaximizeLeftAnimationRequested: if (!appDelegate.maximizedLeft) fakeRectangle.maximizeLeft(amount, true)
1500+ onFakeMaximizeRightAnimationRequested: if (!appDelegate.maximizedRight) fakeRectangle.maximizeRight(amount, true)
1501+ onFakeMaximizeTopLeftAnimationRequested: if (!appDelegate.maximizedTopLeft) fakeRectangle.maximizeTopLeft(amount, true);
1502+ onFakeMaximizeTopRightAnimationRequested: if (!appDelegate.maximizedTopRight) fakeRectangle.maximizeTopRight(amount, true);
1503+ onFakeMaximizeBottomLeftAnimationRequested: if (!appDelegate.maximizedBottomLeft) fakeRectangle.maximizeBottomLeft(amount, true);
1504+ onFakeMaximizeBottomRightAnimationRequested: if (!appDelegate.maximizedBottomRight) fakeRectangle.maximizeBottomRight(amount, true);
1505+ onStopFakeAnimation: fakeRectangle.stop();
1506+ onDragReleased: fakeRectangle.commit();
1507+ }
1508+
1509+ WindowedFullscreenPolicy {
1510+ id: windowedFullscreenPolicy
1511+ active: root.mode == "windowed"
1512+ surface: model.surface
1513+ }
1514+ StagedFullscreenPolicy {
1515+ id: stagedFullscreenPolicy
1516+ active: root.mode == "staged" || root.mode == "stagedWithSideStage"
1517+ surface: model.surface
1518+ }
1519+
1520+ SpreadDelegateInputArea {
1521+ id: dragArea
1522+ objectName: "dragArea"
1523+ anchors.fill: decoratedWindow
1524+ enabled: false
1525+ closeable: !appDelegate.isDash
1526+
1527+ onClicked: {
1528+ spreadItem.highlightedIndex = index;
1529+ if (distance == 0) {
1530+ priv.goneToSpread = false;
1531+ }
1532+ }
1533+ onClose: {
1534+ priv.closingIndex = index
1535+ if (model.surface) { // could be stopped by OOM
1536+ model.surface.close()
1537+ } else if (model.application) {
1538+ root.applicationManager.stopApplication(model.application.appId);
1539+ }
1540+ }
1541+ }
1542+
1543+ WindowInfoItem {
1544+ id: windowInfoItem
1545+ objectName: "windowInfoItem"
1546+ anchors { left: parent.left; top: decoratedWindow.bottom; topMargin: units.gu(1) }
1547+ title: model.application.name
1548+ iconSource: model.application.icon
1549+ height: spreadItem.appInfoHeight
1550+ opacity: 0
1551+ z: 1
1552+ visible: opacity > 0
1553+ maxWidth: {
1554+ var nextApp = appRepeater.itemAt(index + 1);
1555+ if (nextApp) {
1556+ return nextApp.x - appDelegate.x - units.gu(1)
1557+ }
1558+ return appDelegate.width;
1559+ }
1560+
1561+ onClicked: {
1562+ spreadItem.highlightedIndex = index;
1563+ priv.goneToSpread = false;
1564+ }
1565+ }
1566+
1567+ Image {
1568+ id: closeImage
1569+ anchors { left: parent.left; top: parent.top; leftMargin: -height / 2; topMargin: -height / 2 + spreadMaths.closeIconOffset }
1570+ source: "graphics/window-close.svg"
1571+ readonly property var mousePos: hoverMouseArea.mapToItem(appDelegate, hoverMouseArea.mouseX, hoverMouseArea.mouseY)
1572+ visible: !appDelegate.isDash
1573+ && index == spreadItem.highlightedIndex
1574+ && mousePos.y < (decoratedWindow.height / 3)
1575+ && mousePos.y > -units.gu(4)
1576+ && mousePos.x > -units.gu(4)
1577+ && mousePos.x < (decoratedWindow.width * 2 / 3)
1578+ height: units.gu(2)
1579+ width: height
1580+ sourceSize.width: width
1581+ sourceSize.height: height
1582+
1583+ MouseArea {
1584+ id: closeMouseArea
1585+ objectName: "closeMouseArea"
1586+ anchors.fill: closeImage
1587+ anchors.margins: -units.gu(2)
1588+ onClicked: {
1589+ priv.closingIndex = index;
1590+ appDelegate.close();
1591+ }
1592+ }
1593+ }
1594+ }
1595+ }
1596+ }
1597+
1598+ FakeMaximizeDelegate {
1599+ id: fakeRectangle
1600+ target: priv.focusedAppDelegate
1601+ leftMargin: root.leftMargin
1602+ appContainerWidth: appContainer.width
1603+ appContainerHeight: appContainer.height
1604+ }
1605+
1606+ EdgeBarrier {
1607+ id: edgeBarrier
1608+
1609+ // NB: it does its own positioning according to the specified edge
1610+ edge: Qt.RightEdge
1611+
1612+ onPassed: priv.goneToSpread = true;
1613+
1614+ material: Component {
1615+ Item {
1616+ Rectangle {
1617+ width: parent.height
1618+ height: parent.width
1619+ rotation: 90
1620+ anchors.centerIn: parent
1621+ gradient: Gradient {
1622+ GradientStop { position: 0.0; color: Qt.rgba(0.16,0.16,0.16,0.5)}
1623+ GradientStop { position: 1.0; color: Qt.rgba(0.16,0.16,0.16,0)}
1624+ }
1625+ }
1626+ }
1627+ }
1628+ }
1629+
1630+ MouseArea {
1631+ id: hoverMouseArea
1632+ objectName: "hoverMouseArea"
1633+ anchors.fill: appContainer
1634+ propagateComposedEvents: true
1635+ hoverEnabled: true
1636+ enabled: false
1637+ visible: enabled
1638+
1639+ property int scrollAreaWidth: width / 3
1640+ property bool progressiveScrollingEnabled: false
1641+
1642+ onMouseXChanged: {
1643+ mouse.accepted = false
1644+
1645+ if (hoverMouseArea.pressed) {
1646+ return;
1647+ }
1648+
1649+ // Find the hovered item and mark it active
1650+ var mapped = mapToItem(appContainer, hoverMouseArea.mouseX, hoverMouseArea.mouseY)
1651+ var itemUnder = appContainer.childAt(mapped.x, mapped.y)
1652+ if (itemUnder) {
1653+ mapped = mapToItem(itemUnder, hoverMouseArea.mouseX, hoverMouseArea.mouseY)
1654+ var delegateChild = itemUnder.childAt(mapped.x, mapped.y)
1655+ if (delegateChild && (delegateChild.objectName === "dragArea" || delegateChild.objectName === "windowInfoItem")) {
1656+ spreadItem.highlightedIndex = appRepeater.indexOf(itemUnder)
1657+ }
1658+ }
1659+
1660+ if (floatingFlickable.contentWidth > floatingFlickable.width) {
1661+ var margins = floatingFlickable.width * 0.05;
1662+
1663+ if (!progressiveScrollingEnabled && mouseX < floatingFlickable.width - scrollAreaWidth) {
1664+ progressiveScrollingEnabled = true
1665+ }
1666+
1667+ // do we need to scroll?
1668+ if (mouseX < scrollAreaWidth + margins) {
1669+ var progress = Math.min(1, (scrollAreaWidth + margins - mouseX) / (scrollAreaWidth - margins));
1670+ var contentX = (1 - progress) * (floatingFlickable.contentWidth - floatingFlickable.width)
1671+ floatingFlickable.contentX = Math.max(0, Math.min(floatingFlickable.contentX, contentX))
1672+ }
1673+ if (mouseX > floatingFlickable.width - scrollAreaWidth && progressiveScrollingEnabled) {
1674+ var progress = Math.min(1, (mouseX - (floatingFlickable.width - scrollAreaWidth)) / (scrollAreaWidth - margins))
1675+ var contentX = progress * (floatingFlickable.contentWidth - floatingFlickable.width)
1676+ floatingFlickable.contentX = Math.min(floatingFlickable.contentWidth - floatingFlickable.width, Math.max(floatingFlickable.contentX, contentX))
1677+ }
1678+ }
1679+ }
1680+
1681+ onPressed: mouse.accepted = false
1682+ }
1683+
1684+ FloatingFlickable {
1685+ id: floatingFlickable
1686+ objectName: "spreadFlickable"
1687+ anchors.fill: appContainer
1688+ enabled: false
1689+ contentWidth: spreadItem.spreadTotalWidth
1690+
1691+ function snap(toIndex) {
1692+ var delegate = appRepeater.itemAt(toIndex)
1693+ var targetContentX = floatingFlickable.contentWidth / spreadItem.totalItemCount * toIndex;
1694+ if (targetContentX - floatingFlickable.contentX > spreadItem.rightStackXPos - (spreadItem.spreadItemWidth / 2)) {
1695+ var offset = (spreadItem.rightStackXPos - (spreadItem.spreadItemWidth / 2)) - (targetContentX - floatingFlickable.contentX)
1696+ snapAnimation.to = floatingFlickable.contentX - offset;
1697+ snapAnimation.start();
1698+ } else if (targetContentX - floatingFlickable.contentX < spreadItem.leftStackXPos + units.gu(1)) {
1699+ var offset = (spreadItem.leftStackXPos + units.gu(1)) - (targetContentX - floatingFlickable.contentX);
1700+ snapAnimation.to = floatingFlickable.contentX - offset;
1701+ snapAnimation.start();
1702+ }
1703+ }
1704+ UbuntuNumberAnimation {id: snapAnimation; target: floatingFlickable; property: "contentX"}
1705+ }
1706+
1707+ PropertyAnimation {
1708+ id: shortRightEdgeSwipeAnimation
1709+ property: "x"
1710+ to: 0
1711+ duration: priv.animationDuration
1712+ }
1713+
1714+ SwipeArea {
1715+ id: rightEdgeDragArea
1716+ objectName: "rightEdgeDragArea"
1717+ direction: Direction.Leftwards
1718+ anchors { top: parent.top; right: parent.right; bottom: parent.bottom }
1719+ width: root.dragAreaWidth
1720+
1721+ property var gesturePoints: []
1722+ property bool cancelled: false
1723+
1724+ property real progress: dragging ? -touchPosition.x / root.width : 0
1725+ onProgressChanged: {
1726+ if (dragging) {
1727+ draggedProgress = progress;
1728+ }
1729+ }
1730+
1731+ property real draggedProgress: 0
1732+
1733+ onTouchPositionChanged: {
1734+ gesturePoints.push(touchPosition.x);
1735+ if (gesturePoints.length > 10) {
1736+ gesturePoints.splice(0, gesturePoints.length - 10)
1737+ }
1738+ }
1739+
1740+ onDraggingChanged: {
1741+ if (dragging) {
1742+ // A potential edge-drag gesture has started. Start recording it
1743+ gesturePoints = [];
1744+ cancelled = false;
1745+ draggedProgress = 0;
1746+ } else {
1747+ // Ok. The user released. Did he drag far enough to go to full spread?
1748+ if (gesturePoints[gesturePoints.length - 1] < -spreadItem.rightEdgeBreakPoint * spreadItem.width ) {
1749+
1750+ // He dragged far enough, but if the last movement was a flick to the right again, he wants to cancel the spread again.
1751+ var oneWayFlickToRight = true;
1752+ var smallestX = gesturePoints[0]-1;
1753+ for (var i = 0; i < gesturePoints.length; i++) {
1754+ if (gesturePoints[i] <= smallestX) {
1755+ oneWayFlickToRight = false;
1756+ break;
1757+ }
1758+ smallestX = gesturePoints[i];
1759+ }
1760+
1761+ if (!oneWayFlickToRight) {
1762+ // Ok, the user made it, let's go to spread!
1763+ priv.goneToSpread = true;
1764+ } else {
1765+ cancelled = true;
1766+ }
1767+ } else {
1768+ // Ok, the user didn't drag far enough to cross the breakPoint
1769+ // Find out if it was a one-way movement to the left, in which case we just switch directly to next app.
1770+ var oneWayFlick = true;
1771+ var smallestX = rightEdgeDragArea.width;
1772+ for (var i = 0; i < gesturePoints.length; i++) {
1773+ if (gesturePoints[i] >= smallestX) {
1774+ oneWayFlick = false;
1775+ break;
1776+ }
1777+ smallestX = gesturePoints[i];
1778+ }
1779+
1780+ if (appRepeater.count > 1 &&
1781+ (oneWayFlick && rightEdgeDragArea.distance > units.gu(2) || rightEdgeDragArea.distance > spreadItem.rightEdgeBreakPoint * spreadItem.width)) {
1782+ var nextStage = appRepeater.itemAt(priv.nextInStack).stage
1783+ for (var i = 0; i < appRepeater.count; i++) {
1784+ if (i != priv.nextInStack && appRepeater.itemAt(i).stage == nextStage) {
1785+ appRepeater.itemAt(i).playHidingAnimation()
1786+ break;
1787+ }
1788+ }
1789+ appRepeater.itemAt(priv.nextInStack).playFocusAnimation()
1790+ if (appRepeater.itemAt(priv.nextInStack).stage == ApplicationInfoInterface.SideStage && !sideStage.shown) {
1791+ sideStage.show();
1792+ }
1793+
1794+ } else {
1795+ cancelled = true;
1796+ }
1797+
1798+ gesturePoints = [];
1799+ }
1800+ }
1801+ }
1802+ }
1803+
1804+ TabletSideStageTouchGesture {
1805+ id: triGestureArea
1806+ objectName: "triGestureArea"
1807+ anchors.fill: parent
1808+ enabled: false
1809+ property Item appDelegate
1810+
1811+ dragComponent: dragComponent
1812+ dragComponentProperties: { "appDelegate": appDelegate }
1813+
1814+ onPressed: {
1815+ function matchDelegate(obj) { return String(obj.objectName).indexOf("appDelegate") >= 0; }
1816+
1817+ var delegateAtCenter = Functions.itemAt(appContainer, x, y, matchDelegate);
1818+ if (!delegateAtCenter) return;
1819+
1820+ appDelegate = delegateAtCenter;
1821+ }
1822+
1823+ onClicked: {
1824+ if (sideStage.shown) {
1825+ sideStage.hide();
1826+ } else {
1827+ sideStage.show();
1828+ priv.updateMainAndSideStageIndexes()
1829+ }
1830+ }
1831+
1832+ onDragStarted: {
1833+ // If we're dragging to the sidestage.
1834+ if (!sideStage.shown) {
1835+ sideStage.show();
1836+ }
1837+ }
1838+
1839+ Component {
1840+ id: dragComponent
1841+ SurfaceContainer {
1842+ property Item appDelegate
1843+
1844+ surface: appDelegate ? appDelegate.surface : null
1845+
1846+ consumesInput: false
1847+ interactive: false
1848+ focus: false
1849+ requestedWidth: appDelegate.requestedWidth
1850+ requestedHeight: appDelegate.requestedHeight
1851+
1852+ width: units.gu(40)
1853+ height: units.gu(40)
1854+
1855+ Drag.hotSpot.x: width/2
1856+ Drag.hotSpot.y: height/2
1857+ // only accept opposite stage.
1858+ Drag.keys: {
1859+ if (!surface) return "Disabled";
1860+ if (appDelegate.isDash) return "Disabled";
1861+
1862+ if (appDelegate.stage === ApplicationInfo.MainStage) {
1863+ if (appDelegate.application.supportedOrientations
1864+ & (Qt.PortraitOrientation|Qt.InvertedPortraitOrientation)) {
1865+ return "MainStage";
1866+ }
1867+ return "Disabled";
1868+ }
1869+ return "SideStage";
1870+ }
1871+ }
1872+ }
1873+ }
1874+}
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
2323FocusScope {
2424 id: root
2525 objectName: "surfaceContainer"
26+ implicitWidth: surfaceItem.implicitWidth
27+ implicitHeight: surfaceItem.implicitHeight
2628
2729 // Must be set from outside
2830 property var surface: null
@@ -32,7 +34,6 @@ FocusScope {
3234 property int requestedHeight: -1
3335 property bool interactive
3436 property int surfaceOrientationAngle: 0
35− property bool resizeSurface: true
3637 property bool isPromptSurface: false
3738 // FIME - dont export, use interactive property. Need to fix qtmir to handle consumesInputChanged
3839 // to update surface activeFocus. See mock MirSurfaceItem.
@@ -58,35 +59,15 @@ FocusScope {
5859 MirSurfaceItem {
5960 id: surfaceItem
6061 objectName: "surfaceItem"
62+ anchors.fill: parent
6163
6264 focus: true
6365
6466 fillMode: MirSurfaceItem.PadOrCrop
6567 consumesInput: true
6668
67− surfaceWidth: {
68− if (root.resizeSurface) {
69− if (root.requestedWidth >= 0) {
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) {
82− return root.requestedHeight;
83− } else {
84− return height;
85− }
86− } else {
87− return -1;
88− }
89− }
69+ surfaceWidth: root.requestedWidth
70+ surfaceHeight: root.requestedHeight
9071
9172 enabled: root.interactive
9273 antialiasing: !root.interactive
@@ -99,34 +80,6 @@ FocusScope {
9980 enabled: surfaceItem.enabled
10081 }
10182
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−
13083 Loader {
13184 id: animationsLoader
13285 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 {
5555 startingUp = false;
5656 }
5757 }
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+ }
5867}
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
@@ -79,7 +79,7 @@ MouseArea {
7979 onMaximizeClicked: root.maximizeClicked();
8080 onMaximizeHorizontallyClicked: if (root.target.canBeMaximizedHorizontally) root.maximizeHorizontallyClicked();
8181 onMaximizeVerticallyClicked: if (root.target.canBeMaximizedVertically) root.maximizeVerticallyClicked();
82− closeButtonShown: root.target.application.appId !== "unity8-dash"
82+ closeButtonShown: root.target.appId !== "unity8-dash"
8383 }
8484
8585 Label {
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 {
7575
7676 function loadWindowState() {
7777 var windowGeometry = windowStateStorage.getGeometry(root.windowId,
78− Qt.rect(target.requestedX, target.requestedY, defaultWidth, defaultHeight));
78+ Qt.rect(target.windowedX, target.windowedY, defaultWidth, defaultHeight));
7979
80− target.requestedWidth = 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),
80+
81+ target.windowedWidth = Qt.binding(function() { return Math.min(Math.max(windowGeometry.width, d.minimumWidth), screenWidth - root.leftMargin); });
82+ target.windowedHeight = Qt.binding(function() { return Math.min(Math.max(windowGeometry.height, d.minimumHeight),
8283 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),
8485 (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); });
8687
8788 var windowState = windowStateStorage.getState(root.windowId, WindowStateStorage.WindowStateNormal)
8889 target.restore(false /* animated */, windowState);
@@ -111,28 +112,28 @@ MouseArea {
111112
112113 readonly property int minimumWidth: root.target ? Math.max(root.minWidth, root.target.minimumWidth) : root.minWidth
113114 onMinimumWidthChanged: {
114− if (target.requestedWidth < minimumWidth) {
115− target.requestedWidth = minimumWidth;
115+ if (target.windowedWidth < minimumWidth) {
116+ target.windowedWidth = minimumWidth;
116117 }
117118 }
118119 readonly property int minimumHeight: root.target ? Math.max(root.minHeight, root.target.minimumHeight) : root.minHeight
119120 onMinimumHeightChanged: {
120− if (target.requestedHeight < minimumHeight) {
121− target.requestedHeight = minimumHeight;
121+ if (target.windowedHeight < minimumHeight) {
122+ target.windowedHeight = minimumHeight;
122123 }
123124 }
124125 readonly property int maximumWidth: root.target && root.target.maximumWidth >= minimumWidth && root.target.maximumWidth > 0
125126 ? root.target.maximumWidth : maxSafeInt
126127 onMaximumWidthChanged: {
127− if (target.requestedWidth > maximumWidth) {
128− target.requestedWidth = maximumWidth;
128+ if (target.windowedWidth > maximumWidth) {
129+ target.windowedWidth = maximumWidth;
129130 }
130131 }
131132 readonly property int maximumHeight: root.target && root.target.maximumHeight >= minimumHeight && root.target.maximumHeight > 0
132133 ? root.target.maximumHeight : maxSafeInt
133134 onMaximumHeightChanged: {
134− if (target.requestedHeight > maximumHeight) {
135− target.requestedHeight = maximumHeight;
135+ if (target.windowedHeight > maximumHeight) {
136+ target.windowedHeight = maximumHeight;
136137 }
137138 }
138139 readonly property int widthIncrement: {
@@ -247,8 +248,8 @@ MouseArea {
247248 var pos = mapToItem(root.target.parent, mouseX, mouseY);
248249 d.startMousePosX = pos.x;
249250 d.startMousePosY = pos.y;
250− d.startX = target.requestedX;
251− d.startY = target.requestedY;
251+ d.startX = target.windowedX;
252+ d.startY = target.windowedY;
252253 d.startWidth = target.width;
253254 d.startHeight = target.height;
254255 d.currentWidth = target.width;
@@ -285,53 +286,53 @@ MouseArea {
285286
286287 if (d.leftBorder) {
287288 var newTargetX = d.startX + deltaX;
288− var rightBorderX = target.requestedX + target.width;
289+ var rightBorderX = target.windowedX + target.width;
289290 if (rightBorderX > newTargetX + d.minimumWidth) {
290291 if (rightBorderX < newTargetX + d.maximumWidth) {
291− target.requestedWidth = rightBorderX - newTargetX;
292+ target.windowedWidth = rightBorderX - newTargetX;
292293 } else {
293− target.requestedWidth = d.maximumWidth;
294+ target.windowedWidth = d.maximumWidth;
294295 }
295296 } else {
296− target.requestedWidth = d.minimumWidth;
297+ target.windowedWidth = d.minimumWidth;
297298 }
298299
299300 } else if (d.rightBorder) {
300301 var newWidth = d.startWidth + deltaX;
301302 if (newWidth > d.minimumWidth) {
302303 if (newWidth < d.maximumWidth) {
303− target.requestedWidth = newWidth;
304+ target.windowedWidth = newWidth;
304305 } else {
305− target.requestedWidth = d.maximumWidth;
306+ target.windowedWidth = d.maximumWidth;
306307 }
307308 } else {
308− target.requestedWidth = d.minimumWidth;
309+ target.windowedWidth = d.minimumWidth;
309310 }
310311 }
311312
312313 if (d.topBorder) {
313314 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;
315316 if (bottomBorderY > newTargetY + d.minimumHeight) {
316317 if (bottomBorderY < newTargetY + d.maximumHeight) {
317− target.requestedHeight = bottomBorderY - newTargetY;
318+ target.windowedHeight = bottomBorderY - newTargetY;
318319 } else {
319− target.requestedHeight = d.maximumHeight;
320+ target.windowedHeight = d.maximumHeight;
320321 }
321322 } else {
322− target.requestedHeight = d.minimumHeight;
323+ target.windowedHeight = d.minimumHeight;
323324 }
324325
325326 } else if (d.bottomBorder) {
326327 var newHeight = d.startHeight + deltaY;
327328 if (newHeight > d.minimumHeight) {
328329 if (newHeight < d.maximumHeight) {
329− target.requestedHeight = newHeight;
330+ target.windowedHeight = newHeight;
330331 } else {
331− target.requestedHeight = d.maximumHeight;
332+ target.windowedHeight = d.maximumHeight;
332333 }
333334 } else {
334− target.requestedHeight = d.minimumHeight;
335+ target.windowedHeight = d.minimumHeight;
335336 }
336337 }
337338 }
@@ -340,13 +341,13 @@ MouseArea {
340341 target: root.target
341342 onWidthChanged: {
342343 if (d.moveLeftBorder) {
343− target.requestedX += d.currentWidth - target.width;
344+ target.windowedX += d.currentWidth - target.width;
344345 }
345346 d.currentWidth = target.width;
346347 }
347348 onHeightChanged: {
348349 if (d.moveTopBorder) {
349− target.requestedY += d.currentHeight - target.height;
350+ target.windowedY += d.currentHeight - target.height;
350351 }
351352 d.currentHeight = target.height;
352353 }
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−157
@@ -1,157 +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−
21−FocusScope {
22− id: root
23−
24− width: !counterRotate ? applicationWindow.width : applicationWindow.height
25− height: visibleDecorationHeight + (!counterRotate ? applicationWindow.height : applicationWindow.width)
26−
27− property alias application: applicationWindow.application
28− property alias surface: applicationWindow.surface
29− readonly property alias focusedSurface: applicationWindow.focusedSurface
30− property alias active: decoration.active
31− readonly property alias title: applicationWindow.title
32− property alias fullscreen: applicationWindow.fullscreen
33− property alias maximizeButtonShown: decoration.maximizeButtonShown
34−
35− readonly property bool decorationShown: !fullscreen
36− property bool highlightShown: false
37− property real shadowOpacity: 1
38−
39− property real requestedWidth
40− property real requestedHeight
41−
42− property alias surfaceOrientationAngle: applicationWindow.surfaceOrientationAngle
43− readonly property real visibleDecorationHeight: root.decorationShown ? decoration.height : 0
44− readonly property bool counterRotate: surfaceOrientationAngle != 0 && surfaceOrientationAngle != 180
45−
46− readonly property int minimumWidth: !counterRotate ? applicationWindow.minimumWidth : applicationWindow.minimumHeight
47− readonly property int minimumHeight: visibleDecorationHeight + (!counterRotate ? applicationWindow.minimumHeight : applicationWindow.minimumWidth)
48− readonly property int maximumWidth: !counterRotate ? applicationWindow.maximumWidth : applicationWindow.maximumHeight
49− readonly property int maximumHeight: (root.decorationShown && applicationWindow.maximumHeight > 0 ? decoration.height : 0)
50− + (!counterRotate ? applicationWindow.maximumHeight : applicationWindow.maximumWidth)
51− readonly property int widthIncrement: !counterRotate ? applicationWindow.widthIncrement : applicationWindow.heightIncrement
52− readonly property int heightIncrement: !counterRotate ? applicationWindow.heightIncrement : applicationWindow.widthIncrement
53−
54− property alias overlayShown: decoration.overlayShown
55− property alias stageWidth: moveHandler.stageWidth
56− property alias stageHeight: moveHandler.stageHeight
57− readonly property alias dragging: moveHandler.dragging
58−
59− readonly property Item clientAreaItem: applicationWindow
60−
61− signal closeClicked()
62− signal maximizeClicked()
63− signal maximizeHorizontallyClicked()
64− signal maximizeVerticallyClicked()
65− signal minimizeClicked()
66− signal decorationPressed()
67− signal decorationReleased()
68−
69− Rectangle {
70− id: selectionHighlight
71− anchors.fill: parent
72− anchors.margins: -units.gu(1)
73− color: "white"
74− opacity: highlightShown ? 0.15 : 0
75− }
76−
77− Rectangle {
78− anchors { left: selectionHighlight.left; right: selectionHighlight.right; bottom: selectionHighlight.bottom; }
79− height: units.dp(2)
80− color: theme.palette.normal.focus
81− visible: highlightShown
82− }
83−
84− BorderImage {
85− anchors {
86− fill: root
87− margins: active ? -units.gu(2) : -units.gu(1.5)
88− }
89− source: "graphics/dropshadow2gu.sci"
90− opacity: root.shadowOpacity * .3
91− visible: !fullscreen
92− }
93−
94− WindowDecoration {
95− id: decoration
96− target: root.parent
97− objectName: "appWindowDecoration"
98− anchors { left: parent.left; top: parent.top; right: parent.right }
99− height: units.gu(3)
100− width: root.width
101− title: applicationWindow.title
102− visible: root.decorationShown
103−
104− onCloseClicked: root.closeClicked();
105− onMaximizeClicked: { root.decorationPressed(); root.maximizeClicked(); }
106− onMaximizeHorizontallyClicked: { root.decorationPressed(); root.maximizeHorizontallyClicked(); }
107− onMaximizeVerticallyClicked: { root.decorationPressed(); root.maximizeVerticallyClicked(); }
108− onMinimizeClicked: root.minimizeClicked();
109− onPressed: root.decorationPressed();
110−
111− onPressedChanged: moveHandler.handlePressedChanged(pressed, pressedButtons, mouseX, mouseY)
112− onPositionChanged: moveHandler.handlePositionChanged(mouse)
113− onReleased: {
114− root.decorationReleased();
115− moveHandler.handleReleased();
116− }
117− }
118−
119− MoveHandler {
120− id: moveHandler
121− objectName: "moveHandler"
122− target: root.parent
123− buttonsWidth: decoration.buttonsWidth
124− }
125−
126− ApplicationWindow {
127− id: applicationWindow
128− objectName: "appWindow"
129− anchors.top: parent.top
130− anchors.topMargin: decoration.height
131− anchors.left: parent.left
132− readonly property real requestedHeightMinusDecoration: root.requestedHeight - root.visibleDecorationHeight
133− requestedHeight: !counterRotate ? requestedHeightMinusDecoration : root.requestedWidth
134− requestedWidth: !counterRotate ? root.requestedWidth : requestedHeightMinusDecoration
135− interactive: true
136− focus: true
137−
138− transform: Rotation {
139− readonly property int rotationAngle: applicationWindow.application &&
140− applicationWindow.application.rotatesWindowContents
141− ? ((360 - applicationWindow.surfaceOrientationAngle) % 360) : 0
142− origin.x: {
143− if (rotationAngle == 90) return applicationWindow.height / 2;
144− else if (rotationAngle == 270) return applicationWindow.width / 2;
145− else if (rotationAngle == 180) return applicationWindow.width / 2;
146− else return 0;
147− }
148− origin.y: {
149− if (rotationAngle == 90) return applicationWindow.height / 2;
150− else if (rotationAngle == 270) return applicationWindow.width / 2;
151− else if (rotationAngle == 180) return applicationWindow.height / 2;
152− else return 0;
153− }
154− angle: rotationAngle
155− }
156− }
157−}
qml/Stages/DesktopStage.qmldeleted−825
@@ -1,825 +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: "buttonsVisible"
180− value: priv.focusedAppDelegate !== null && priv.focusedAppDelegate.maximized // FIXME for Locally integrated menus
181− && spread.state == ""
182− }
183−
184− Binding {
185− target: PanelState
186− property: "title"
187− value: {
188− if (priv.focusedAppDelegate !== null && 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: "dropShadow"
202− value: priv.focusedAppDelegate && !priv.focusedAppDelegate.maximized && priv.foregroundMaximizedAppDelegate !== null
203− }
204−
205− Binding {
206− target: PanelState
207− property: "closeButtonShown"
208− value: priv.focusedAppDelegate && priv.focusedAppDelegate.maximized && !priv.focusedAppDelegate.isDash
209− }
210−
211− Component.onDestruction: {
212− PanelState.title = "";
213− PanelState.buttonsVisible = false;
214− PanelState.dropShadow = false;
215− }
216−
217− Instantiator {
218− model: root.applicationManager
219− delegate: Binding {
220− target: model.application
221− property: "requestedState"
222−
223− // TODO: figure out some lifecycle policy, like suspending minimized apps
224− // if running on a tablet or something.
225− // TODO: If the device has a dozen suspended apps because it was running
226− // in staged mode, when it switches to Windowed mode it will suddenly
227− // resume all those apps at once. We might want to avoid that.
228− value: ApplicationInfoInterface.RequestedRunning // Always running for now
229− }
230− }
231−
232− Binding {
233− target: MirFocusController
234− property: "focusedSurface"
235− value: priv.focusedAppDelegate ? priv.focusedAppDelegate.focusedSurface : null
236− when: !appRepeater.startingUp && root.parent
237− }
238−
239− FocusScope {
240− id: appContainer
241− objectName: "appContainer"
242− anchors.fill: parent
243− focus: spread.state !== "altTab"
244−
245− Wallpaper {
246− id: wallpaper
247− anchors.fill: parent
248− source: root.background
249− }
250−
251− TopLevelSurfaceRepeater {
252− id: appRepeater
253− model: topLevelSurfaceList
254− objectName: "appRepeater"
255−
256− delegate: FocusScope {
257− id: appDelegate
258− objectName: "appDelegate_" + model.id
259− // z might be overriden in some cases by effects, but we need z ordering
260− // to calculate occlusion detection
261− property int normalZ: topLevelSurfaceList.count - index
262− onNormalZChanged: {
263− if (visuallyMaximized) {
264− priv.updateForegroundMaximizedApp();
265− }
266− }
267− z: normalZ
268− x: requestedX // may be overridden in some states. Do not directly write to this.
269− y: requestedY // may be overridden in some states. Do not directly write to this.
270− property real requestedX: priv.focusedAppDelegate ? priv.focusedAppDelegate.x + units.gu(3) : (normalZ - 1) * units.gu(3)
271− property real requestedY: priv.focusedAppDelegate ? priv.focusedAppDelegate.y + units.gu(3) : normalZ * units.gu(3)
272−
273− Binding {
274− target: appDelegate
275− property: "y"
276− value: appDelegate.requestedY -
277− Math.min(appDelegate.requestedY - PanelState.panelHeight,
278− Math.max(0, priv.virtualKeyboardHeight - (appContainer.height - (appDelegate.requestedY + appDelegate.height))))
279− when: root.oskEnabled && appDelegate.focus && (appDelegate.state == "normal" || appDelegate.state == "restored")
280− && SurfaceManager.inputMethodSurface
281− && SurfaceManager.inputMethodSurface.state != Mir.HiddenState
282− && SurfaceManager.inputMethodSurface.state != Mir.MinimizedState
283−
284− }
285−
286− width: decoratedWindow.width
287− height: decoratedWindow.height
288−
289− Connections {
290− target: root
291− onShellOrientationAngleChanged: {
292− // at this point decoratedWindow.surfaceOrientationAngle is the old shellOrientationAngle
293− if (application && application.rotatesWindowContents) {
294− if (state == "normal" || state == "restored") {
295− var angleDiff = decoratedWindow.surfaceOrientationAngle - shellOrientationAngle;
296− angleDiff = (360 + angleDiff) % 360;
297− if (angleDiff === 90 || angleDiff === 270) {
298− var aux = decoratedWindow.requestedHeight;
299− decoratedWindow.requestedHeight = decoratedWindow.requestedWidth + decoratedWindow.visibleDecorationHeight;
300− decoratedWindow.requestedWidth = aux - decoratedWindow.visibleDecorationHeight;
301− }
302− }
303− decoratedWindow.surfaceOrientationAngle = shellOrientationAngle;
304− } else {
305− decoratedWindow.surfaceOrientationAngle = 0;
306− }
307− }
308− }
309−
310− readonly property alias application: decoratedWindow.application
311− readonly property alias minimumWidth: decoratedWindow.minimumWidth
312− readonly property alias minimumHeight: decoratedWindow.minimumHeight
313− readonly property alias maximumWidth: decoratedWindow.maximumWidth
314− readonly property alias maximumHeight: decoratedWindow.maximumHeight
315− readonly property alias widthIncrement: decoratedWindow.widthIncrement
316− readonly property alias heightIncrement: decoratedWindow.heightIncrement
317− property int requestedWidth: -1
318− property int requestedHeight: -1
319−
320− readonly property bool maximized: windowState === WindowStateStorage.WindowStateMaximized
321− readonly property bool maximizedLeft: windowState === WindowStateStorage.WindowStateMaximizedLeft
322− readonly property bool maximizedRight: windowState === WindowStateStorage.WindowStateMaximizedRight
323− readonly property bool maximizedHorizontally: windowState === WindowStateStorage.WindowStateMaximizedHorizontally
324− readonly property bool maximizedVertically: windowState === WindowStateStorage.WindowStateMaximizedVertically
325− readonly property bool maximizedTopLeft: windowState === WindowStateStorage.WindowStateMaximizedTopLeft
326− readonly property bool maximizedTopRight: windowState === WindowStateStorage.WindowStateMaximizedTopRight
327− readonly property bool maximizedBottomLeft: windowState === WindowStateStorage.WindowStateMaximizedBottomLeft
328− readonly property bool maximizedBottomRight: windowState === WindowStateStorage.WindowStateMaximizedBottomRight
329− readonly property bool anyMaximized: maximized || maximizedLeft || maximizedRight || maximizedHorizontally || maximizedVertically ||
330− maximizedTopLeft || maximizedTopRight || maximizedBottomLeft || maximizedBottomRight
331−
332− readonly property bool minimized: windowState & WindowStateStorage.WindowStateMinimized
333− readonly property alias fullscreen: decoratedWindow.fullscreen
334−
335− readonly property bool canBeMaximized: canBeMaximizedHorizontally && canBeMaximizedVertically
336− readonly property bool canBeMaximizedLeftRight: (maximumWidth == 0 || maximumWidth >= appContainer.width/2) &&
337− (maximumHeight == 0 || maximumHeight >= appContainer.height)
338− readonly property bool canBeCornerMaximized: (maximumWidth == 0 || maximumWidth >= appContainer.width/2) &&
339− (maximumHeight == 0 || maximumHeight >= appContainer.height/2)
340− readonly property bool canBeMaximizedHorizontally: maximumWidth == 0 || maximumWidth >= appContainer.width
341− readonly property bool canBeMaximizedVertically: maximumHeight == 0 || maximumHeight >= appContainer.height
342−
343− property int windowState: WindowStateStorage.WindowStateNormal
344− property bool animationsEnabled: true
345− property alias title: decoratedWindow.title
346− readonly property string appName: model.application ? model.application.name : ""
347− property bool visuallyMaximized: false
348− property bool visuallyMinimized: false
349−
350− readonly property var surface: model.surface
351− readonly property alias resizeArea: resizeArea
352− readonly property alias focusedSurface: decoratedWindow.focusedSurface
353− readonly property bool dragging: touchControls.overlayShown ? touchControls.dragging : decoratedWindow.dragging
354−
355− readonly property bool isDash: model.application.appId == "unity8-dash"
356− readonly property alias clientAreaItem: decoratedWindow.clientAreaItem
357−
358− function claimFocus() {
359− if (spread.state == "altTab") {
360− spread.cancel();
361− }
362− appDelegate.restore(true /* animated */, appDelegate.windowState);
363− }
364− Connections {
365− target: model.surface
366− onFocusRequested: claimFocus();
367− }
368− Connections {
369− target: model.application
370− onFocusRequested: {
371− if (!model.surface) {
372− // when an app has no surfaces, we assume there's only one entry representing it:
373− // this delegate.
374− claimFocus();
375− } else {
376− // if the application has surfaces, focus request should be at surface-level.
377− }
378− }
379− }
380−
381− onFocusChanged: {
382− if (appRepeater.startingUp)
383− return;
384−
385− if (focus) {
386− // If we're orphan (!parent) it means this stage is no longer the current one
387− // and will be deleted shortly. So we should no longer have a say over the model
388− if (root.parent) {
389− topLevelSurfaceList.raiseId(model.id);
390− }
391−
392− priv.focusedAppDelegate = appDelegate;
393− } else if (!focus && priv.focusedAppDelegate === appDelegate) {
394− priv.focusedAppDelegate = null;
395− // FIXME: No idea why the Binding{} doens't update when focusedAppDelegate turns null
396− MirFocusController.focusedSurface = null;
397− }
398− }
399− Component.onCompleted: {
400− if (application && application.rotatesWindowContents) {
401− decoratedWindow.surfaceOrientationAngle = shellOrientationAngle;
402− } else {
403− decoratedWindow.surfaceOrientationAngle = 0;
404− }
405−
406− // NB: We're differentiating if this delegate was created in response to a new entry in the model
407− // or if the Repeater is just populating itself with delegates to match the model it received.
408− if (!appRepeater.startingUp) {
409− // a top level window is always the focused one when it first appears, unfocusing
410− // any preexisting one
411− focus = true;
412− }
413− }
414− Component.onDestruction: {
415− if (!root.parent) {
416− // This stage is about to be destroyed. Don't mess up with the model at this point
417− return;
418− }
419−
420− if (visuallyMaximized) {
421− priv.updateForegroundMaximizedApp();
422− }
423−
424− if (focus) {
425− // focus some other window
426− for (var i = 0; i < appRepeater.count; i++) {
427− var appDelegate = appRepeater.itemAt(i);
428− if (appDelegate && !appDelegate.minimized && i != index) {
429− appDelegate.focus = true;
430− return;
431− }
432− }
433− }
434− }
435−
436− onVisuallyMaximizedChanged: priv.updateForegroundMaximizedApp()
437−
438− visible: (
439− !visuallyMinimized
440− && !greeter.fullyShown
441− && (priv.foregroundMaximizedAppDelegate === null || priv.foregroundMaximizedAppDelegate.normalZ <= z)
442− )
443− || decoratedWindow.fullscreen
444− || (spread.state == "altTab" && index === spread.highlightedIndex)
445−
446− function close() {
447− model.surface.close();
448− }
449−
450− function maximize(animated) {
451− animationsEnabled = (animated === undefined) || animated;
452− windowState = WindowStateStorage.WindowStateMaximized;
453− }
454− function maximizeLeft(animated) {
455− animationsEnabled = (animated === undefined) || animated;
456− windowState = WindowStateStorage.WindowStateMaximizedLeft;
457− }
458− function maximizeRight(animated) {
459− animationsEnabled = (animated === undefined) || animated;
460− windowState = WindowStateStorage.WindowStateMaximizedRight;
461− }
462− function maximizeHorizontally(animated) {
463− animationsEnabled = (animated === undefined) || animated;
464− windowState = WindowStateStorage.WindowStateMaximizedHorizontally;
465− }
466− function maximizeVertically(animated) {
467− animationsEnabled = (animated === undefined) || animated;
468− windowState = WindowStateStorage.WindowStateMaximizedVertically;
469− }
470− function maximizeTopLeft(animated) {
471− animationsEnabled = (animated === undefined) || animated;
472− windowState = WindowStateStorage.WindowStateMaximizedTopLeft;
473− }
474− function maximizeTopRight(animated) {
475− animationsEnabled = (animated === undefined) || animated;
476− windowState = WindowStateStorage.WindowStateMaximizedTopRight;
477− }
478− function maximizeBottomLeft(animated) {
479− animationsEnabled = (animated === undefined) || animated;
480− windowState = WindowStateStorage.WindowStateMaximizedBottomLeft;
481− }
482− function maximizeBottomRight(animated) {
483− animationsEnabled = (animated === undefined) || animated;
484− windowState = WindowStateStorage.WindowStateMaximizedBottomRight;
485− }
486− function minimize(animated) {
487− animationsEnabled = (animated === undefined) || animated;
488− windowState |= WindowStateStorage.WindowStateMinimized; // add the minimized bit
489− }
490− function restoreFromMaximized(animated) {
491− animationsEnabled = (animated === undefined) || animated;
492− windowState = WindowStateStorage.WindowStateRestored;
493− }
494− function restore(animated,state) {
495− animationsEnabled = (animated === undefined) || animated;
496− windowState = state || WindowStateStorage.WindowStateRestored;
497− windowState &= ~WindowStateStorage.WindowStateMinimized; // clear the minimized bit
498− focus = true;
499− }
500−
501− function playFocusAnimation() {
502− focusAnimation.start()
503− }
504−
505− UbuntuNumberAnimation {
506− id: focusAnimation
507− target: appDelegate
508− property: "scale"
509− from: 0.98
510− to: 1
511− duration: UbuntuAnimation.SnapDuration
512− }
513−
514− // unlike requestedX/Y, this is the last known grab position before being pushed against edges/corners
515− // when restoring, the window should return to these, not to the place where it was dropped near the edge
516− property real restoredX
517− property real restoredY
518−
519− states: [
520− State {
521− name: "fullscreen"; when: appDelegate.fullscreen && !appDelegate.minimized
522− PropertyChanges {
523− target: appDelegate;
524− x: rotation == 0 ? 0 : (parent.width - width) / 2 + (shellOrientationAngle == 90 ? -PanelState.panelHeight : PanelState.panelHeight)
525− y: rotation == 0 ? -PanelState.panelHeight : (parent.height - height) / 2
526− requestedWidth: appContainer.width;
527− requestedHeight: appContainer.height;
528− }
529− },
530− State {
531− name: "normal";
532− when: appDelegate.windowState == WindowStateStorage.WindowStateNormal
533− PropertyChanges {
534− target: appDelegate;
535− visuallyMinimized: false;
536− visuallyMaximized: false
537− }
538− },
539− State {
540− name: "restored";
541− when: appDelegate.windowState == WindowStateStorage.WindowStateRestored
542− extend: "normal"
543− PropertyChanges {
544− target: appDelegate;
545− requestedX: restoredX;
546− requestedY: restoredY;
547− }
548− },
549− State {
550− name: "maximized"; when: appDelegate.maximized && !appDelegate.minimized
551− PropertyChanges {
552− target: appDelegate;
553− requestedX: root.leftMargin;
554− requestedY: 0;
555− requestedWidth: appContainer.width - root.leftMargin;
556− requestedHeight: appContainer.height;
557− visuallyMinimized: false;
558− visuallyMaximized: true
559− }
560− },
561− State {
562− name: "maximizedLeft"; when: appDelegate.maximizedLeft && !appDelegate.minimized
563− PropertyChanges {
564− target: appDelegate
565− requestedX: root.leftMargin
566− requestedY: PanelState.panelHeight
567− requestedWidth: (appContainer.width - root.leftMargin)/2
568− requestedHeight: appContainer.height - PanelState.panelHeight
569− }
570− },
571− State {
572− name: "maximizedRight"; when: appDelegate.maximizedRight && !appDelegate.minimized
573− extend: "maximizedLeft"
574− PropertyChanges {
575− target: appDelegate;
576− requestedX: (appContainer.width + root.leftMargin)/2
577− }
578− },
579− State {
580− name: "maximizedTopLeft"; when: appDelegate.maximizedTopLeft && !appDelegate.minimized
581− PropertyChanges {
582− target: appDelegate
583− requestedX: root.leftMargin
584− requestedY: PanelState.panelHeight
585− requestedWidth: (appContainer.width - root.leftMargin)/2
586− requestedHeight: (appContainer.height - PanelState.panelHeight)/2
587− }
588− },
589− State {
590− name: "maximizedTopRight"; when: appDelegate.maximizedTopRight && !appDelegate.minimized
591− extend: "maximizedTopLeft"
592− PropertyChanges {
593− target: appDelegate
594− requestedX: (appContainer.width + root.leftMargin)/2
595− }
596− },
597− State {
598− name: "maximizedBottomLeft"; when: appDelegate.maximizedBottomLeft && !appDelegate.minimized
599− PropertyChanges {
600− target: appDelegate
601− requestedX: root.leftMargin
602− requestedY: (appContainer.height + PanelState.panelHeight)/2
603− requestedWidth: (appContainer.width - root.leftMargin)/2
604− requestedHeight: appContainer.height/2
605− }
606− },
607− State {
608− name: "maximizedBottomRight"; when: appDelegate.maximizedBottomRight && !appDelegate.minimized
609− extend: "maximizedBottomLeft"
610− PropertyChanges {
611− target: appDelegate
612− requestedX: (appContainer.width + root.leftMargin)/2
613− }
614− },
615− State {
616− name: "maximizedHorizontally"; when: appDelegate.maximizedHorizontally && !appDelegate.minimized
617− PropertyChanges { target: appDelegate; requestedX: root.leftMargin; requestedY: requestedY; requestedWidth: appContainer.width - root.leftMargin }
618− },
619− State {
620− name: "maximizedVertically"; when: appDelegate.maximizedVertically && !appDelegate.minimized
621− PropertyChanges { target: appDelegate; requestedX: requestedX; requestedY: PanelState.panelHeight; requestedHeight: appContainer.height - PanelState.panelHeight }
622− },
623− State {
624− name: "minimized"; when: appDelegate.minimized
625− PropertyChanges {
626− target: appDelegate;
627− requestedX: -appDelegate.width / 2;
628− scale: units.gu(5) / appDelegate.width;
629− opacity: 0;
630− visuallyMinimized: true;
631− visuallyMaximized: false
632− }
633− }
634− ]
635− transitions: [
636− Transition {
637− to: "normal,restored"
638− enabled: appDelegate.animationsEnabled
639− PropertyAction { target: appDelegate; properties: "visuallyMinimized,visuallyMaximized" }
640− UbuntuNumberAnimation { target: appDelegate; properties: "requestedX,requestedY,opacity,scale,requestedWidth,requestedHeight" }
641− },
642− Transition {
643− to: "minimized"
644− enabled: appDelegate.animationsEnabled
645− PropertyAction { target: appDelegate; property: "visuallyMaximized" }
646− SequentialAnimation {
647− UbuntuNumberAnimation { target: appDelegate; properties: "requestedX,requestedY,opacity,scale,requestedWidth,requestedHeight" }
648− PropertyAction { target: appDelegate; property: "visuallyMinimized" }
649− ScriptAction {
650− script: {
651− if (appDelegate.minimized) {
652− appDelegate.focus = false;
653− priv.focusNext();
654− }
655− }
656− }
657− }
658− },
659− Transition {
660− to: "*" //maximized and fullscreen
661− enabled: appDelegate.animationsEnabled
662− PropertyAction { target: appDelegate; property: "visuallyMinimized" }
663− SequentialAnimation {
664− UbuntuNumberAnimation { target: appDelegate; properties: "requestedX,requestedY,opacity,scale,requestedWidth,requestedHeight" }
665− PropertyAction { target: appDelegate; property: "visuallyMaximized" }
666− ScriptAction { script: { fakeRectangle.stop(); } }
667− }
668− }
669− ]
670−
671− Binding {
672− id: previewBinding
673− target: appDelegate
674− property: "z"
675− value: topLevelSurfaceList.count + 1
676− when: index == spread.highlightedIndex && spread.ready
677− }
678−
679− Binding {
680− target: PanelState
681− property: "buttonsAlwaysVisible"
682− value: appDelegate && appDelegate.maximized && touchControls.overlayShown
683− }
684−
685− WindowResizeArea {
686− id: resizeArea
687− objectName: "windowResizeArea"
688−
689− // workaround so that it chooses the correct resize borders when you drag from a corner ResizeGrip
690− anchors.margins: touchControls.overlayShown ? borderThickness/2 : -borderThickness
691−
692− target: appDelegate
693− minWidth: units.gu(10)
694− minHeight: units.gu(10)
695− borderThickness: units.gu(2)
696− windowId: model.application.appId // FIXME: Change this to point to windowId once we have such a thing
697− screenWidth: appContainer.width
698− screenHeight: appContainer.height
699− leftMargin: root.leftMargin
700−
701− onPressed: { appDelegate.focus = true; }
702−
703− Component.onCompleted: {
704− loadWindowState();
705− }
706−
707− property bool saveStateOnDestruction: true
708− Connections {
709− target: root
710− onStageAboutToBeUnloaded: {
711− resizeArea.saveWindowState();
712− resizeArea.saveStateOnDestruction = false;
713− fullscreenPolicy.active = false;
714− }
715− }
716− Component.onDestruction: {
717− if (saveStateOnDestruction) {
718− saveWindowState();
719− }
720− }
721− }
722−
723− DecoratedWindow {
724− id: decoratedWindow
725− objectName: "decoratedWindow"
726− anchors.left: appDelegate.left
727− anchors.top: appDelegate.top
728− application: model.application
729− surface: model.surface
730− active: appDelegate.focus
731− focus: true
732− maximizeButtonShown: appDelegate.canBeMaximized
733− overlayShown: touchControls.overlayShown
734− stageWidth: appContainer.width
735− stageHeight: appContainer.height
736−
737− requestedWidth: appDelegate.requestedWidth
738− requestedHeight: appDelegate.requestedHeight
739−
740− onCloseClicked: { appDelegate.close(); }
741− onMaximizeClicked: appDelegate.anyMaximized ? appDelegate.restoreFromMaximized() : appDelegate.maximize();
742− onMaximizeHorizontallyClicked: appDelegate.maximizedHorizontally ? appDelegate.restoreFromMaximized() : appDelegate.maximizeHorizontally()
743− onMaximizeVerticallyClicked: appDelegate.maximizedVertically ? appDelegate.restoreFromMaximized() : appDelegate.maximizeVertically()
744− onMinimizeClicked: appDelegate.minimize()
745− onDecorationPressed: { appDelegate.focus = true; }
746− onDecorationReleased: fakeRectangle.commit();
747− }
748−
749− WindowControlsOverlay {
750− id: touchControls
751− target: appDelegate
752− stageWidth: appContainer.width
753− stageHeight: appContainer.height
754−
755− onFakeMaximizeAnimationRequested: if (!appDelegate.maximized) fakeRectangle.maximize(amount, true)
756− onFakeMaximizeLeftAnimationRequested: if (!appDelegate.maximizedLeft) fakeRectangle.maximizeLeft(amount, true)
757− onFakeMaximizeRightAnimationRequested: if (!appDelegate.maximizedRight) fakeRectangle.maximizeRight(amount, true)
758− onFakeMaximizeTopLeftAnimationRequested: if (!appDelegate.maximizedTopLeft) fakeRectangle.maximizeTopLeft(amount, true);
759− onFakeMaximizeTopRightAnimationRequested: if (!appDelegate.maximizedTopRight) fakeRectangle.maximizeTopRight(amount, true);
760− onFakeMaximizeBottomLeftAnimationRequested: if (!appDelegate.maximizedBottomLeft) fakeRectangle.maximizeBottomLeft(amount, true);
761− onFakeMaximizeBottomRightAnimationRequested: if (!appDelegate.maximizedBottomRight) fakeRectangle.maximizeBottomRight(amount, true);
762− onStopFakeAnimation: fakeRectangle.stop();
763− onDragReleased: fakeRectangle.commit();
764− }
765−
766− WindowedFullscreenPolicy {
767− id: fullscreenPolicy
768− active: true
769− surface: model.surface
770− }
771− }
772− }
773− }
774−
775− FakeMaximizeDelegate {
776− id: fakeRectangle
777− target: priv.focusedAppDelegate
778− leftMargin: root.leftMargin
779− appContainerWidth: appContainer.width
780− appContainerHeight: appContainer.height
781− }
782−
783− EdgeBarrier {
784− id: edgeBarrier
785−
786− // NB: it does its own positioning according to the specified edge
787− edge: Qt.RightEdge
788−
789− onPassed: { spread.show(); }
790− material: Component {
791− Item {
792− Rectangle {
793− width: parent.height
794− height: parent.width
795− rotation: 90
796− anchors.centerIn: parent
797− gradient: Gradient {
798− GradientStop { position: 0.0; color: Qt.rgba(0.16,0.16,0.16,0.5)}
799− GradientStop { position: 1.0; color: Qt.rgba(0.16,0.16,0.16,0)}
800− }
801− }
802− }
803− }
804− }
805−
806− SwipeArea {
807− direction: Direction.Leftwards
808− anchors { top: parent.top; right: parent.right; bottom: parent.bottom }
809− width: units.gu(1)
810− onDraggingChanged: { if (dragging) { spread.show(); } }
811− }
812−
813− DesktopSpread {
814− id: spread
815− objectName: "spread"
816− anchors.fill: appContainer
817− workspace: appContainer
818− focus: state == "altTab"
819− altTabPressed: root.altTabPressed
820−
821− onPlayFocusAnimation: {
822− appRepeater.itemAt(index).playFocusAnimation();
823− }
824− }
825−}
qml/Tutorial/TutorialRight.qml+1−1
@@ -24,7 +24,7 @@ TutorialPage {
2424 property string usageScenario
2525
2626 // 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
2828
2929 // Else on desktop, fade out when the spread is shown
3030 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()
7979{
8080 if (state() == ApplicationInfo::Stopped) { return; }
8181
82− QString surfaceName = name();
82+ QString surfaceName = name() + "s window title";
8383 if (m_surfaceList->count() > 0) {
8484 surfaceName.append(QString(" %1").arg(m_surfaceList->count()+1));
8585 }
@@ -138,7 +138,7 @@ void ApplicationInfo::createSurface()
138138
139139void ApplicationInfo::setIconId(const QString &iconId)
140140{
141− setIcon(QString("../../graphics/applicationIcons/%2@18.png")
141+ setIcon(QString(sourceDirectory() + "/tests/graphics/applicationIcons/%2@18.png")
142142 .arg(iconId));
143143}
144144
tests/mocks/Unity/Application/ApplicationManager.cpp+2
@@ -295,6 +295,7 @@ void ApplicationManager::buildListOfAvailableApplications()
295295 application->setAppId("unity8-dash");
296296 application->setName("Unity 8 Mock Dash");
297297 application->setScreenshotId("unity8-dash");
298+ application->setIconId("dash");
298299 m_availableApplications.append(application);
299300
300301 application = new ApplicationInfo(this);
@@ -403,6 +404,7 @@ void ApplicationManager::buildListOfAvailableApplications()
403404 application->setAppId("notes-app");
404405 application->setName("Notepad");
405406 application->setIconId("notepad");
407+// application->setStage(ApplicationInfoInterface::SideStage);
406408 m_availableApplications.append(application);
407409
408410 application = new ApplicationInfo(this);
tests/mocks/Unity/Application/MirSurface.cpp+1
@@ -256,6 +256,7 @@ void MirSurface::updateVisibility()
256256
257257 m_visible = newVisible;
258258 Q_EMIT visibleChanged(m_visible);
259+ updateInputBoundsAfterResize();
259260 }
260261}
261262
tests/mocks/Unity/Application/MirSurfaceItem.cpp+13
@@ -60,9 +60,13 @@ MirSurfaceItem::MirSurfaceItem(QQuickItem *parent)
6060
6161 connect(this, &QQuickItem::activeFocusChanged, this, &MirSurfaceItem::updateMirSurfaceActiveFocus);
6262 connect(this, &QQuickItem::visibleChanged, this, &MirSurfaceItem::updateMirSurfaceVisibility);
63+
6364 connect(this, &MirSurfaceItem::consumesInputChanged, this, [this]() {
6465 updateMirSurfaceActiveFocus(hasActiveFocus());
6566 });
67+
68+ // We're just clipping contents in the mock. The real QtMir would copy only relevant buffer instead
69+ setClip(true);
6670}
6771
6872MirSurfaceItem::~MirSurfaceItem()
@@ -181,6 +185,9 @@ void MirSurfaceItem::createQmlContentItem()
181185 m_qmlItem = qobject_cast<QQuickItem*>(m_qmlContentComponent->create());
182186 m_qmlItem->setParentItem(this);
183187
188+ m_qmlItem->setWidth(m_surfaceWidth);
189+ m_qmlItem->setHeight(m_surfaceHeight);
190+
184191 setImplicitWidth(m_qmlItem->implicitWidth());
185192 setImplicitHeight(m_qmlItem->implicitHeight());
186193
@@ -350,6 +357,7 @@ int MirSurfaceItem::surfaceWidth() const
350357
351358void MirSurfaceItem::setSurfaceWidth(int value)
352359{
360+// qDebug() << "setSurfaceWidth called" << value;
353361 if (value != -1 && m_surfaceWidth != value) {
354362 m_surfaceWidth = value;
355363 Q_EMIT surfaceWidthChanged(m_surfaceWidth);
@@ -375,6 +383,11 @@ void MirSurfaceItem::updateSurfaceSize()
375383{
376384 if (m_qmlSurface && m_surfaceWidth > 0 && m_surfaceHeight > 0) {
377385 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);
378391 }
379392}
380393
tests/mocks/Unity/Application/MirSurfaceListModel.cpp−1
@@ -84,7 +84,6 @@ void MirSurfaceListModel::prependSurface(MirSurface *surface)
8484
8585void MirSurfaceListModel::connectSurface(MirSurface *surface)
8686{
87− connect(surface, &MirSurface::raiseRequested, this, [this, surface](){ this->raise(surface); });
8887 connect(surface, &QObject::destroyed, this, [this, surface](){ this->removeSurface(surface); });
8988}
9089
tests/mocks/Unity/Application/VirtualKeyboard.cpp+9−7
@@ -39,13 +39,15 @@ void VirtualKeyboard::updateInputBoundsAfterResize()
3939{
4040 int width = this->width();
4141
42− int height;
43− if (this->width() > this->height()) {
44− // landscape
45− height = this->height() * 0.4;
46− } else {
47− // portrait
48− height = this->width() * 0.6;
42+ int height = 0;
43+ if (visible()) {
44+ if (this->width() > this->height()) {
45+ // landscape
46+ height = this->height() * 0.4;
47+ } else {
48+ // portrait
49+ height = this->width() * 0.6;
50+ }
4951 }
5052
5153 int x = 0;
tests/mocks/Unity/Application/resources/MirSurfaceItem.qml+2−5
@@ -20,11 +20,8 @@ Rectangle {
2020 id: root
2121 color: "pink"
2222
23− implicitWidth: units.gu(40)
24− implicitHeight: units.gu(70)
25−
26− width: parent ? parent.width : implicitWidth
27− height: parent ? parent.height : implicitHeight
23+ implicitWidth: width
24+ implicitHeight: height
2825
2926 property alias screenshotSource: screenshotImage.source
3027 property int orientationAngle
tests/qmltests/CMakeLists.txt+8−8
@@ -86,14 +86,14 @@ add_unity8_qmltest(Panel Panel)
8686add_unity8_qmltest(Panel/Indicators IndicatorsLight)
8787add_unity8_qmltest(Panel/Indicators MenuItemFactory)
8888add_unity8_qmltest(Panel/Indicators MessageMenuItemFactory)
89−add_unity8_qmltest(Stages ApplicationWindow)
90−add_unity8_qmltest(Stages DesktopStage)
91−add_unity8_qmltest(Stages PhoneStage)
92−add_unity8_qmltest(Stages SpreadDelegate)
93−add_unity8_qmltest(Stages SurfaceContainer)
94−add_unity8_qmltest(Stages TabletStage)
95−add_unity8_qmltest(Stages WindowResizeArea)
96−add_unity8_qmltest(Stages Splash)
89+add_unity8_qmltest(Stage ApplicationWindow)
90+add_unity8_qmltest(Stage DesktopStage)
91+add_unity8_qmltest(Stage PhoneStage)
92+add_unity8_qmltest(Stage SurfaceContainer)
93+add_unity8_qmltest(Stage TabletStage)
94+add_unity8_qmltest(Stage WindowResizeArea)
95+add_unity8_qmltest(Stage Splash)
96+add_unity8_qmltest(Stage DecoratedWindow)
9797add_unity8_qmltest(Tutorial Tutorial)
9898add_unity8_qmltest(Wizard Wizard ENVIRONMENT "OXIDE_NO_SANDBOX=1")
9999add_unity8_qmltest(utils/Unity/Test UnityTest)
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
1919import QtTest 1.0
2020import Unity.Test 0.1 as UT
2121import ".."
22−import "../../../qml/Stages"
22+import "../../../qml/Stage"
2323import Ubuntu.Components 1.3
2424import Ubuntu.Components.ListItems 1.3 as ListItem
2525import Unity.Application 0.1
tests/qmltests/Stage/tst_DecoratedWindow.qmlnew file+232
@@ -0,0 +1,232 @@
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/Stage"
23+import Ubuntu.Components 1.3
24+import Ubuntu.Components.ListItems 1.3 as ListItem
25+import Unity.Application 0.1
26+
27+Rectangle {
28+ color: "red"
29+ id: root
30+ width: fakeShell.shortestDimension + controls.width
31+ height: fakeShell.longestDimension
32+
33+ property QtObject fakeApplication: null
34+
35+ Item {
36+ id: fakeShell
37+
38+ readonly property real shortestDimension: units.gu(100)
39+ readonly property real longestDimension: units.gu(70)
40+
41+ width: landscape ? longestDimension : shortestDimension
42+ height: landscape ? shortestDimension : longestDimension
43+
44+ x: landscape ? (height - width) / 2 : 0
45+ y: landscape ? (width - height) / 2 : 0
46+
47+ property bool landscape: orientationAngle == 90 || orientationAngle == 270
48+ property int orientationAngle: shellOrientationAngleSelector.value
49+
50+ rotation: orientationAngle
51+
52+ Loader {
53+ id: loader
54+ property int windowedX: units.gu(1)
55+ property int windowedY: units.gu(1)
56+ property int windowedWidth: units.gu(50)
57+ property int windowedHeight: units.gu(40)
58+ x: windowedX
59+ y: windowedY
60+ width: item ? item.implicitWidth : 0
61+ height: item ? item.implicitHeight : 0
62+
63+ active: false
64+ property bool itemDestroyed: false
65+
66+ sourceComponent: DecoratedWindow {
67+ anchors.fill: parent
68+ application: fakeApplication
69+ requestedWidth: loader.windowedWidth
70+ requestedHeight: loader.windowedHeight
71+ surface: fakeApplication && fakeApplication.surfaceList.count > 0 ? fakeApplication.surfaceList.get(0) : null
72+
73+ Component.onDestruction: {
74+ loader.itemDestroyed = true;
75+ }
76+ Component.onCompleted: {
77+ loader.itemDestroyed = false;
78+ }
79+ }
80+
81+ Rectangle { anchors.fill: parent; color: "green"; opacity: 1 }
82+ }
83+ WindowResizeArea {
84+ target: loader
85+ borderThickness: units.gu(2)
86+ }
87+ }
88+
89+
90+ Rectangle {
91+ id: controls
92+ color: "white"
93+ width: units.gu(30)
94+ anchors {
95+ top: parent.top
96+ bottom: parent.bottom
97+ right: parent.right
98+ }
99+
100+ Column {
101+ anchors { left: parent.left; right: parent.right; top: parent.top; margins: units.gu(1) }
102+ spacing: units.gu(1)
103+ Button {
104+ id: loadWithWeatherApp
105+ text: "Load with ubuntu-weather-app"
106+ onClicked: { testCase.restartWithApp("ubuntu-weather-app"); }
107+ }
108+ Button {
109+ id: loadWithGalleryApp
110+ text: "Load with gallery-app"
111+ onClicked: { testCase.restartWithApp("gallery-app"); }
112+ }
113+ Button {
114+ text: "toggle has decoration"
115+ onClicked: loader.item.hasDecoration = !loader.item.hasDecoration
116+ }
117+ Button {
118+ text: "show/hide decoration"
119+ onClicked: loader.item.showDecoration = !loader.item.showDecoration
120+ }
121+ Label {
122+ text: "scale to preview progress"
123+ }
124+
125+ Slider {
126+ value: 0
127+ minimumValue: 0
128+ maximumValue: 1
129+ live: true
130+ onValueChanged: loader.item.scaleToPreviewProgress = value
131+ }
132+ ListItem.ItemSelector {
133+ id: shellOrientationAngleSelector
134+ anchors { left: parent.left; right: parent.right }
135+ text: "shellOrientationAngle"
136+ model: ["0", "90", "180", "270"]
137+ property int value: selectedIndex * 90
138+ }
139+ Button {
140+ text: "matchShellOrientation()"
141+ onClicked: { loader.item.matchShellOrientation(); }
142+ }
143+ Button {
144+ text: "animateToShellOrientation()"
145+ onClicked: { loader.item.animateToShellOrientation(); }
146+ }
147+ }
148+ }
149+
150+ UT.UnityTestCase {
151+ id: testCase
152+ name: "DecoratedWindow"
153+ when: windowShown
154+
155+ property Item decoratedWindow: loader.item
156+
157+ function init() {
158+ }
159+
160+ function cleanup() {
161+ unloadWindow();
162+ root.fakeApplication = null;
163+ killApps();
164+ }
165+
166+ function restartWithApp(appId) {
167+ if (loader.active) {
168+ unloadWindow();
169+ }
170+ if (root.fakeApplication) {
171+ ApplicationManager.stopApplication(root.fakeApplication.appId);
172+ }
173+
174+ root.fakeApplication = ApplicationManager.startApplication(appId);
175+ loader.active = true;
176+ tryCompare(loader, "status", Loader.Ready);
177+ }
178+
179+ function unloadWindow() {
180+ loader.active = false;
181+ tryCompare(loader, "status", Loader.Null);
182+ tryCompare(loader, "item", null);
183+ // Loader.status might be Loader.Null and Loader.item might be null but the Loader
184+ // item might still be alive. So if we set Loader.active back to true
185+ // again right now we will get the very same Shell instance back. So no reload
186+ // actually took place. Likely because Loader waits until the next event loop
187+ // iteration to do its work. So to ensure the reload, we will wait until the
188+ // Shell instance gets destroyed.
189+ tryCompare(loader, "itemDestroyed", true);
190+
191+ }
192+
193+ function test_keepsSceneTransformationWhenShellRotates_data() {
194+ return [
195+ {tag: "0", selectedIndex: 0},
196+ {tag: "90", selectedIndex: 1},
197+ {tag: "180", selectedIndex: 2},
198+ {tag: "270", selectedIndex: 3}
199+ ];
200+ }
201+ function test_keepsSceneTransformationWhenShellRotates(data) {
202+ loadWithGalleryApp.clicked();
203+
204+ // Wait until it reaches the state we are interested on.
205+ // It begins with "startingUp"
206+ tryCompare(decoratedWindow, "counterRotate", false);
207+ var oldWidth = decoratedWindow.width
208+ var oldHeight = decoratedWindow.height
209+ var oldX = decoratedWindow.x
210+ var oldY = decoratedWindow.y
211+
212+ shellOrientationAngleSelector.selectedIndex = data.selectedIndex;
213+
214+ // must keep same aspect ratio
215+ compare(decoratedWindow.width, oldWidth);
216+ compare(decoratedWindow.height, oldHeight);
217+
218+
219+ // and scene transformation must be the identity (ie, no rotation or translation)
220+ compare(decoratedWindow.x, oldX);
221+ compare(decoratedWindow.y, oldY);
222+ }
223+
224+ function test_showHighLight() {
225+ loadWithGalleryApp.clicked();
226+ var highlightRect = findChild(loader.item, "selectionHighlight")
227+ tryCompare(highlightRect, "visible", false)
228+ loader.item.showHighlight = true;
229+ tryCompare(highlightRect, "visible", true)
230+ }
231+ }
232+}
tests/qmltests/Stages/tst_DesktopStage.qml → tests/qmltests/Stage/tst_DesktopStage.qmlrenamed+29−71
@@ -24,14 +24,14 @@ import WindowManager 0.1
2424import Utils 0.1
2525
2626import ".." // For EdgeBarrierControls
27−import "../../../qml/Stages"
27+import "../../../qml/Stage"
2828import "../../../qml/Components"
2929import "../../../qml/Components/PanelState"
3030
3131Item {
3232 id: root
33− width: desktopStageLoader.width + controls.width
34− height: desktopStageLoader.height
33+ width: stageLoader.width + controls.width
34+ height: stageLoader.height
3535
3636 property var greeter: { fullyShown: true }
3737
@@ -63,7 +63,7 @@ Item {
6363 }
6464
6565 Loader {
66− id: desktopStageLoader
66+ id: stageLoader
6767 x: ((root.width - controls.width) - width) / 2
6868 y: (root.height - height) / 2
6969 width: units.gu(160*0.9)
@@ -73,7 +73,7 @@ Item {
7373
7474 property bool itemDestroyed: false
7575 sourceComponent: Component {
76− DesktopStage {
76+ Stage {
7777 anchors.fill: parent
7878 background: "/usr/share/backgrounds/warty-final-ubuntu.png"
7979 focus: true
@@ -82,17 +82,19 @@ Item {
8282 edgeBarrierControls.target = testCase.findChild(this, "edgeBarrierController");
8383 }
8484 Component.onDestruction: {
85− desktopStageLoader.itemDestroyed = true;
85+ stageLoader.itemDestroyed = true;
8686 }
8787 orientations: Orientations {}
8888 applicationManager: ApplicationManager
8989 topLevelSurfaceList: topSurfaceList
90+ interactive: true
91+ mode: "windowed"
9092 }
9193 }
9294
9395 MouseArea {
9496 id: clickThroughTester
95− anchors.fill: desktopStageLoader.item
97+ anchors.fill: stageLoader.item
9698 acceptedButtons: Qt.AllButtons
9799 hoverEnabled: true
98100 }
@@ -130,7 +132,7 @@ Item {
130132 id: edgeBarrierControls
131133 text: "Drag here to pull out spread"
132134 backgroundColor: "blue"
133− onDragged: { desktopStageLoader.item.pushRightEdge(amount); }
135+ onDragged: { stageLoader.item.pushRightEdge(amount); }
134136 }
135137
136138 Divider {}
@@ -157,7 +159,7 @@ Item {
157159 name: "DesktopStage"
158160 when: windowShown
159161
160− property Item desktopStage: desktopStageLoader.status === Loader.Ready ? desktopStageLoader.item : null
162+ property Item stage: stageLoader.status === Loader.Ready ? stageLoader.item : null
161163
162164 function init() {
163165 // wait until unity8-dash is up and running.
@@ -173,29 +175,29 @@ Item {
173175 }
174176
175177 function cleanup() {
176− desktopStageLoader.itemDestroyed = false;
177− desktopStageLoader.active = false;
178+ stageLoader.itemDestroyed = false;
179+ stageLoader.active = false;
178180
179− tryCompare(desktopStageLoader, "status", Loader.Null);
180− tryCompare(desktopStageLoader, "item", null);
181+ tryCompare(stageLoader, "status", Loader.Null);
182+ tryCompare(stageLoader, "item", null);
181183 // Loader.status might be Loader.Null and Loader.item might be null but the Loader
182184 // actually took place. Likely because Loader waits until the next event loop
183185 // iteration to do its work. So to ensure the reload, we will wait until the
184186 // Shell instance gets destroyed.
185− tryCompare(desktopStageLoader, "itemDestroyed", true);
187+ tryCompare(stageLoader, "itemDestroyed", true);
186188
187189 killApps();
188190
189191 root.resetGeometry();
190192
191− desktopStageLoader.active = true;
192− tryCompare(desktopStageLoader, "status", Loader.Ready);
193+ stageLoader.active = true;
194+ tryCompare(stageLoader, "status", Loader.Ready);
193195
194196 mouseEaterSpy.clear();
195197 }
196198
197199 function waitUntilAppSurfaceShowsUp(surfaceId) {
198− var appDelegate = findChild(desktopStage, "appDelegate_" + surfaceId);
200+ var appDelegate = findChild(stage, "appDelegate_" + surfaceId);
199201 verify(appDelegate);
200202 var appWindow = findChild(appDelegate, "appWindow");
201203 verify(appWindow);
@@ -213,7 +215,7 @@ Item {
213215 if (app) {
214216 for (var i = 0; i < topSurfaceList.count; i++) {
215217 if (topSurfaceList.applicationAt(i).appId === appId) {
216− var appRepeater = findChild(desktopStage, "appRepeater");
218+ var appRepeater = findChild(stage, "appRepeater");
217219 verify(appRepeater);
218220 return appRepeater.itemAt(i);
219221 }
@@ -226,7 +228,7 @@ Item {
226228 waitUntilAppSurfaceShowsUp(surfaceId);
227229 compare(app.surfaceList.count, 1);
228230
229− return findChild(desktopStage, "appDelegate_" + surfaceId);
231+ return findChild(stage, "appDelegate_" + surfaceId);
230232 } catch(err) {
231233 throw new Error("startApplication("+appId+") called from line " + util.callerLine(1) + " failed!");
232234 }
@@ -324,7 +326,7 @@ Item {
324326 }
325327
326328 function findDecoratedWindow(surfaceId) {
327− var appDelegate = findChild(desktopStage, "appDelegate_" + surfaceId);
329+ var appDelegate = findChild(stage, "appDelegate_" + surfaceId);
328330 if (!appDelegate) {
329331 console.warn("Could not find appDelegate for surfaceId="+surfaceId);
330332 return null;
@@ -333,7 +335,7 @@ Item {
333335 }
334336
335337 function findWindowDecoration(surfaceId) {
336− var appDelegate = findChild(desktopStage, "appDelegate_" + surfaceId);
338+ var appDelegate = findChild(stage, "appDelegate_" + surfaceId);
337339 if (!appDelegate) {
338340 console.warn("Could not find appDelegate for surfaceId="+surfaceId);
339341 return null;
@@ -465,8 +467,8 @@ Item {
465467
466468 mouseClick(dialerDelegate);
467469
468− var desktopStagePriv = findInvisibleChild(desktopStage, "DesktopStagePrivate");
469− tryCompare(desktopStagePriv, "focusedAppDelegate", dialerDelegate);
470+ var stagePriv = findInvisibleChild(stage, "DesktopStagePrivate");
471+ tryCompare(stagePriv, "focusedAppDelegate", dialerDelegate);
470472
471473 keyClick(Qt.Key_F4, Qt.AltModifier); // Alt+F4 shortcut to close
472474
@@ -517,35 +519,6 @@ Item {
517519 tryCompare(MirFocusController, "focusedSurface", null); // verify still no surface is focused
518520 }
519521
520− function test_oskDisplacesWindow_data() {
521− return [
522− {tag: "no need to displace", windowHeight: units.gu(10), windowY: units.gu(5), targetDisplacement: units.gu(5), oskEnabled: true},
523− {tag: "displace to top", windowHeight: units.gu(50), windowY: units.gu(10), targetDisplacement: PanelState.panelHeight, oskEnabled: true},
524− {tag: "displace to top", windowHeight: units.gu(50), windowY: units.gu(10), targetDisplacement: PanelState.panelHeight, oskEnabled: true},
525− {tag: "osk not on this screen", windowHeight: units.gu(40), windowY: units.gu(10), targetDisplacement: units.gu(10), oskEnabled: false},
526− ]
527− }
528−
529− function test_oskDisplacesWindow(data) {
530− desktopStageLoader.item.oskEnabled = data.oskEnabled
531− var dashAppDelegate = startApplication("unity8-dash");
532− var oldOSKState = SurfaceManager.inputMethodSurface.state;
533− SurfaceManager.inputMethodSurface.state = Mir.RestoredState;
534− verify(dashAppDelegate);
535− dashAppDelegate.requestedHeight = data.windowHeight;
536− dashAppDelegate.requestedY = data.windowY;
537− SurfaceManager.inputMethodSurface.setInputBounds(Qt.rect(0, 0, 0, 0));
538− var initialY = dashAppDelegate.y;
539− verify(initialY > PanelState.panelHeight);
540−
541− SurfaceManager.inputMethodSurface.setInputBounds(Qt.rect(0, root.height / 2, root.width, root.height / 2));
542− tryCompare(dashAppDelegate, "y", data.targetDisplacement);
543−
544− SurfaceManager.inputMethodSurface.setInputBounds(Qt.rect(0, 0, 0, 0));
545− tryCompare(dashAppDelegate, "y", initialY);
546− SurfaceManager.inputMethodSurface.state = oldOSKState;
547− }
548−
549522 function test_minimizeApplicationHidesSurface() {
550523 compare(topSurfaceList.applicationAt(0).appId, "unity8-dash");
551524 var dashSurface = topSurfaceList.surfaceAt(0);
@@ -598,6 +571,8 @@ Item {
598571 var gmailDelegate = startApplication("gmail-webapp");
599572 verify(gmailDelegate);
600573
574+ wait(2000)
575+
601576 var gmailMaximizeButton = findChild(gmailDelegate, "maximizeWindowButton");
602577 verify(gmailMaximizeButton);
603578 mouseClick(gmailMaximizeButton);
@@ -610,6 +585,7 @@ Item {
610585 tryCompare(mapApp.surfaceList.get(0), "visible", false);
611586
612587 ApplicationManager.stopApplication("gmail-webapp");
588+ wait(2000)
613589
614590 tryCompare(mapApp.surfaceList.get(0), "visible", true);
615591 tryCompare(dialerApp.surfaceList.get(0), "visible", true);
@@ -709,7 +685,7 @@ Item {
709685 tryCompare(overlay, "visible", data.result);
710686
711687 if (data.result) { // if shown, try to hide it by clicking outside
712− mouseClick(desktopStage);
688+ mouseClick(stage);
713689 tryCompare(overlay, "visible", false);
714690 }
715691 }
@@ -768,24 +744,6 @@ Item {
768744 tryCompareFunction(function(){return posBefore == posAfter;}, data.button !== Qt.LeftButton ? true : false);
769745 }
770746
771− function test_preventMouseEventsThruDesktopSpread() {
772− var spread = findChild(desktopStage, "spread");
773− verify(spread);
774− spread.show();
775− tryCompareFunction( function(){ return spread.ready }, true );
776−
777− mouseEaterSpy.signalName = "wheel";
778− mouseWheel(spread, spread.width/2, spread.height/2, 10, 10);
779− tryCompare(mouseEaterSpy, "count", 0);
780−
781− mouseEaterSpy.clear();
782− mouseEaterSpy.signalName = "clicked";
783− mouseClick(spread, spread.width/2, spread.height/2, Qt.RightButton);
784− tryCompare(mouseEaterSpy, "count", 0);
785−
786− spread.cancel();
787− }
788−
789747 function test_eatWindowDecorationMouseEvents_data() {
790748 return [
791749 {tag: "left mouse click", signalName: "clicked", button: Qt.LeftButton },
tests/qmltests/Stages/tst_PhoneStage.qml → tests/qmltests/Stage/tst_PhoneStage.qmlrenamed+144−211
@@ -19,7 +19,7 @@ import QtTest 1.0
1919import Unity.Test 0.1 as UT
2020import ".."
2121import "../../../qml/Components"
22−import "../../../qml/Stages"
22+import "../../../qml/Stage"
2323import Ubuntu.Components 1.3
2424import Unity.Application 0.1
2525import WindowManager 0.1
@@ -31,16 +31,16 @@ Item {
3131
3232 property var greeter: { fullyShown: true }
3333
34− PhoneStage {
35− id: phoneStage
34+ Stage {
35+ id: stage
3636 anchors { fill: parent; rightMargin: units.gu(30) }
3737 focus: true
3838 dragAreaWidth: units.gu(2)
39− maximizedAppTopMargin: units.gu(3)
4039 interactive: true
4140 shellOrientation: Qt.PortraitOrientation
4241 orientations: Orientations {}
4342 applicationManager: ApplicationManager
43+ mode: "staged"
4444 topLevelSurfaceList: TopLevelSurfaceList {
4545 id: topLevelSurfaceList
4646 applicationsModel: ApplicationManager
@@ -66,9 +66,9 @@ Item {
6666 id: edgeBarrierControls
6767 text: "Drag here to pull out spread"
6868 backgroundColor: "blue"
69− onDragged: { phoneStage.pushRightEdge(amount); }
69+ onDragged: { stage.pushRightEdge(amount); }
7070 Component.onCompleted: {
71− edgeBarrierControls.target = testCase.findChild(phoneStage, "edgeBarrierController");
71+ edgeBarrierControls.target = testCase.findChild(stage, "edgeBarrierController");
7272 }
7373 }
7474 Repeater {
@@ -84,11 +84,37 @@ Item {
8484 name: "PhoneStage"
8585 when: windowShown
8686
87+ function init() {
88+ // wait until unity8-dash is up and running.
89+ // it's started automatically by ApplicationManager mock implementation
90+ tryCompare(ApplicationManager, "count", 1);
91+ var dashApp = ApplicationManager.findApplication("unity8-dash");
92+ verify(dashApp);
93+ tryCompare(dashApp, "state", ApplicationInfoInterface.Running);
94+ }
95+
96+ function cleanup() {
97+ ApplicationManager.requestFocusApplication("unity8-dash");
98+ tryCompare(ApplicationManager, "focusedApplicationId", "unity8-dash");
99+ tryCompare(stage, "state", "staged");
100+ waitForRendering(stage);
101+
102+ killApps();
103+ // wait for Stage to stabilize back into its initial state
104+ var appRepeater = findChild(stage, "appRepeater");
105+ tryCompare(appRepeater, "count", 1);
106+ tryCompare(appRepeater.itemAt(0), "x", 0);
107+
108+ stage.shellOrientationAngle = 0;
109+
110+ waitForRendering(stage)
111+ }
112+
87113 function findAppWindowForSurfaceId(surfaceId) {
88− var delegateObjectName = "spreadDelegate_" + surfaceId;
89− var spreadDelegate = findChild(phoneStage, delegateObjectName);
114+ var delegateObjectName = "appDelegate_" + surfaceId;
115+ var spreadDelegate = findChild(stage, delegateObjectName);
90116 if (!spreadDelegate) {
91− console.warn("Failed to find " + delegateObjectName + " in phoneStage ("+phoneStage+")");
117+ console.warn("Failed to find " + delegateObjectName + " in stage");
92118 return null;
93119 }
94120 var appWindow = findChild(spreadDelegate, "appWindow");
@@ -108,33 +134,29 @@ Item {
108134 function addApps(count) {
109135 if (count == undefined) count = 1;
110136 for (var i = 0; i < count; i++) {
137+ var startingAppId = ApplicationManager.availableApplications[ApplicationManager.count];
111138 var appSurfaceId = topLevelSurfaceList.nextId;
112− var app = ApplicationManager.startApplication(ApplicationManager.availableApplications[ApplicationManager.count])
139+ var app = ApplicationManager.startApplication(startingAppId)
113140 tryCompare(app, "state", ApplicationInfoInterface.Running)
114− var spreadView = findChild(phoneStage, "spreadView");
115− tryCompare(spreadView, "contentX", -spreadView.shift);
116141 waitUntilAppSurfaceShowsUp(appSurfaceId);
117− waitForRendering(phoneStage)
142+ waitForRendering(stage)
143+ tryCompare(ApplicationManager, "focusedApplicationId", startingAppId)
118144 }
119145 }
120146
121147 function performEdgeSwipeToShowAppSpread() {
122− var spreadView = findChild(phoneStage, "spreadView");
123−
124− // Keep it inside the PhoneStage otherwise the controls on the right side will
148+ // Keep it inside the Stage otherwise the controls on the right side will
125149 // capture the press thus the "- 2" on startX.
126− var startX = phoneStage.width - 2;
127− var startY = phoneStage.height / 2;
150+ var startX = stage.width - 2;
151+ var startY = stage.height / 2;
128152 var endY = startY;
129− var endX = phoneStage.width / 2;
153+ var endX = stage.width / 2;
130154
131− touchFlick(phoneStage, startX, startY, endX, endY,
155+ touchFlick(stage, startX, startY, endX, endY,
132156 true /* beginTouch */, true /* endTouch */, units.gu(10), 50);
133157
134− tryCompare(spreadView, "phase", 2);
135− tryCompare(spreadView, "flicking", false);
136− tryCompare(spreadView, "moving", false);
137− waitForRendering(phoneStage);
158+ tryCompare(stage, "state", "spread");
159+ waitForRendering(stage);
138160 }
139161
140162 function swipeSurfaceUpwards(surfaceId) {
@@ -163,7 +185,7 @@ Item {
163185
164186 function waitUntilAppDelegateStopsMoving(targetSurfaceId)
165187 {
166− var targetAppDelegate = findChild(phoneStage, "spreadDelegate_" + targetSurfaceId);
188+ var targetAppDelegate = findChild(stage, "appDelegate_" + targetSurfaceId);
167189 verify(targetAppDelegate);
168190 var lastValue = undefined;
169191 do {
@@ -172,79 +194,39 @@ Item {
172194 } while (lastValue != targetAppDelegate.animatedProgress);
173195 }
174196
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−
196197 function test_enterSpread_data() {
197198 return [
198− {tag: "<position1 (linear movement)", positionMarker: "positionMarker1", linear: true, offset: 0, endPhase: 0, targetPhase: 0, newFocusedIndex: 1 },
199− {tag: "<position1 (non-linear movement)", positionMarker: "positionMarker1", linear: false, offset: 0, endPhase: 0, targetPhase: 0, newFocusedIndex: 0 },
200− {tag: ">position1", positionMarker: "positionMarker1", linear: true, offset: +5, endPhase: 0, targetPhase: 0, newFocusedIndex: 1 },
201− {tag: "<position2 (linear)", positionMarker: "positionMarker2", linear: true, offset: 0, endPhase: 0, targetPhase: 0, newFocusedIndex: 1 },
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 },
199+ {tag: "<breakPoint (trigger)", progress: .2, cancel: false, endState: "staged", newFocusedIndex: 1 },
200+ {tag: "<breakPoint (cancel)", progress: .2, cancel: true, endState: "staged", newFocusedIndex: 0 },
201+ {tag: ">breakPoint (trigger)", progress: .5, cancel: false, endState: "spread", newFocusedIndex: 0 },
202+ {tag: ">breakPoint (cancel)", progress: .8, cancel: true, endState: "staged", newFocusedIndex: 0 },
206203 ];
207204 }
208205
209206 function test_enterSpread(data) {
210207 addApps(5)
211208
212− var spreadView = findChild(phoneStage, "spreadView");
213−
214− // Keep it inside the PhoneStage otherwise the controls on the right side will
209+ // Keep it inside the Stage otherwise the controls on the right side will
215210 // capture the press thus the "- 2" on startX.
216− var startX = phoneStage.width - 2;
217− var startY = phoneStage.height / 2;
211+ var startX = stage.width - 2;
212+ var startY = stage.height / 2;
218213 var endY = startY;
219− var endX = spreadView.width - (spreadView.width * spreadView[data.positionMarker]) - data.offset
220− - phoneStage.dragAreaWidth;
214+ var endX = stage.width - (stage.width * data.progress) - stage.dragAreaWidth;
221215
222216 var oldFocusedApp = ApplicationManager.get(0);
223217 var newFocusedApp = ApplicationManager.get(data.newFocusedIndex);
224218
225− touchFlick(phoneStage, startX, startY, endX, endY,
219+ touchFlick(stage, startX, startY, endX, endY,
226220 true /* beginTouch */, false /* endTouch */, units.gu(10), 50);
227221
228− tryCompare(spreadView, "phase", data.endPhase)
229−
230− if (!data.linear) {
231− touchFlick(phoneStage, endX, endY, endX + units.gu(.5), endY,
232− false /* beginTouch */, false /* endTouch */, units.gu(10), 50);
233− touchFlick(phoneStage, endY + units.gu(.5), endY, endX, endY,
234− false /* beginTouch */, false /* endTouch */, units.gu(10), 50);
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− }
222+ if (data.cancel) {
223+ touchFlick(stage, endX, endY, endX + units.gu(5), endY,
224+ false /* beginTouch */, true /* endTouch */, units.gu(10), 50);
225+ } else {
226+ touchRelease(stage, endX, endY); }
246227
247− tryCompare(ApplicationManager, "focusedApplicationId", newFocusedApp.appId);
228+ tryCompare(stage, "state", data.endState);
229+ tryCompare(ApplicationManager, "focusedApplicationId", data.endState == "spread" ? oldFocusedApp.appId : newFocusedApp.appId);
248230 }
249231
250232 function test_selectAppFromSpread_data() {
@@ -263,32 +245,26 @@ Item {
263245 function test_selectAppFromSpread(data) {
264246 addApps(data.total)
265247
266− var spreadView = findChild(phoneStage, "spreadView");
267−
268248 performEdgeSwipeToShowAppSpread();
269249
270− tryCompare(spreadView, "phase", 2);
271−
272− var tile = findChild(spreadView, "spreadDelegate_" + topLevelSurfaceList.idAt(data.index));
250+ var tile = findChild(stage, "appDelegate_" + topLevelSurfaceList.idAt(data.index));
273251 var appId = ApplicationManager.get(data.index).appId;
274252
275− if (tile.mapToItem(spreadView, 0, 0).x > spreadView.width) {
253+ if (tile.mapToItem(stage, 0, 0).x > stage.width - units.gu(3)) {
276254 // Item is not visible... Need to flick the spread
277− var startX = phoneStage.width - units.gu(1);
278− var startY = phoneStage.height / 2;
255+ var startX = stage.width - units.gu(1);
256+ var startY = stage.height / 2;
279257 var endY = startY;
280258 var endX = units.gu(2);
281− touchFlick(phoneStage, startX, startY, endX, endY, true, true, units.gu(10), 50)
282− tryCompare(spreadView, "flicking", false);
283− tryCompare(spreadView, "moving", false);
284−// waitForRendering(phoneStage);
259+ touchFlick(stage, startX, startY, endX, endY, true, true, units.gu(10), 50)
285260 }
286261
287262 console.log("clicking app", data.index, "(", appId, ")")
288− tryCompare(tile, "swipeToCloseEnabled", true);
289− mouseClick(spreadView, tile.mapToItem(spreadView, 0, 0).x + units.gu(1), spreadView.height / 2)
263+ var dragArea = findChild(tile, "dragArea");
264+ tryCompare(dragArea, "closeable", true);
265+ mouseClick(stage, tile.mapToItem(stage, 0, 0).x + units.gu(1), stage.height / 2)
290266 tryCompare(ApplicationManager, "focusedApplicationId", appId);
291− tryCompare(spreadView, "phase", 0);
267+ tryCompare(stage, "state", "staged");
292268 }
293269
294270 function test_select_data() {
@@ -302,16 +278,22 @@ Item {
302278 function test_select(data) {
303279 addApps(5);
304280
305− var spreadView = findChild(phoneStage, "spreadView");
306281 var selectedApp = ApplicationManager.get(data.index);
282+ var appRepeater = findChild(stage, "appRepeater");
283+ var selectedAppDeleage = appRepeater.itemAt(data.index);
307284
308285 performEdgeSwipeToShowAppSpread();
309286
310− phoneStage.select(selectedApp.appId);
287+ print("tapping", selectedAppDeleage.appId, selectedAppDeleage.visible)
288+ if (selectedAppDeleage.x > stage.width - units.gu(5)) {
289+ touchFlick(stage, stage.width - units.gu(2), stage.height / 2, units.gu(2), stage.height / 2, true, true, units.gu(2), 10)
290+ }
291+
292+ tap(selectedAppDeleage, 1, 1);
311293
312− tryCompare(spreadView, "contentX", -spreadView.shift);
294+ tryCompare(stage, "state", "staged");
313295
314− compare(ApplicationManager.focusedApplicationId, selectedApp.appId);
296+ tryCompare(ApplicationManager, "focusedApplicationId", selectedApp.appId);
315297 }
316298
317299 function test_backgroundClickCancelsSpread() {
@@ -320,37 +302,14 @@ Item {
320302 var focusedAppId = ApplicationManager.focusedApplicationId;
321303
322304 performEdgeSwipeToShowAppSpread();
305+ tryCompare(stage, "state", "spread");
323306
324− mouseClick(phoneStage, units.gu(1), units.gu(1));
307+ mouseClick(stage, units.gu(1), units.gu(1));
325308
326− // Make sure the spread is in the idle position
327− var spreadView = findChild(phoneStage, "spreadView");
328− tryCompare(spreadView, "contentX", -spreadView.shift);
309+ tryCompare(stage, "state", "staged");
329310
330311 // Make sure the same app is still focused
331− compare(focusedAppId, ApplicationManager.focusedApplicationId);
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− }
312+ tryCompare(ApplicationManager, "focusedApplicationId", focusedAppId);
354313 }
355314
356315 function test_focusNewTopMostAppAfterFocusedOneClosesItself() {
@@ -370,60 +329,9 @@ Item {
370329 tryCompare(firstApp, "focused", true);
371330 }
372331
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−
424332 function test_leftEdge_data() {
425333 return [
426− { tag: "normal", inSpread: false, leftEdgeDragWidth: units.gu(5), shouldMoveApp: true },
334+ { tag: "normal", inSpread: false, leftEdgeDragWidth: units.gu(20), shouldMoveApp: true },
427335 { tag: "inSpread", inSpread: true, leftEdgeDragWidth: units.gu(5), shouldMoveApp: false }
428336 ]
429337 }
@@ -435,22 +343,24 @@ Item {
435343 performEdgeSwipeToShowAppSpread();
436344 }
437345
438− var focusedDelegate = findChild(phoneStage, "spreadDelegate_" + topLevelSurfaceList.idAt(0));
439− phoneStage.inverseProgress = data.leftEdgeDragWidth;
346+ var focusedDelegate = findChild(stage, "appDelegate_" + topLevelSurfaceList.idAt(0));
347+ var currentX = focusedDelegate.x;
348+
349+ stage.leftEdgeDragProgress = data.leftEdgeDragWidth;
440350
441− tryCompare(focusedDelegate, "x", data.shouldMoveApp ? data.leftEdgeDragWidth : 0);
351+ tryCompare(focusedDelegate, "x", data.shouldMoveApp ? data.leftEdgeDragWidth : currentX);
442352
443− phoneStage.inverseProgress = 0;
353+ stage.leftEdgeDragProgress = 0;
444354
445− tryCompare(focusedDelegate, "x", 0);
355+ tryCompare(focusedDelegate, "x", currentX);
446356 }
447357
448358 function test_focusedAppIsTheOnlyRunningApp() {
449359 addApps(2);
450360
451− var delegateA = findChild(phoneStage, "spreadDelegate_" + topLevelSurfaceList.idAt(0));
361+ var delegateA = findChild(stage, "appDelegate_" + topLevelSurfaceList.idAt(0));
452362 verify(delegateA);
453− var delegateB = findChild(phoneStage, "spreadDelegate_" + topLevelSurfaceList.idAt(1));
363+ var delegateB = findChild(stage, "appDelegate_" + topLevelSurfaceList.idAt(1));
454364 verify(delegateB);
455365
456366 // A is focused and running, B is unfocused and suspended
@@ -461,7 +371,7 @@ Item {
461371
462372 // Switch foreground/focused appp from A to B
463373 performEdgeSwipeToShowAppSpread();
464− phoneStage.select(delegateB.application.appId);
374+ tap(delegateB, 1, 1);
465375
466376 // Now it's the other way round
467377 // A is unfocused and suspended, B is focused and running
@@ -474,15 +384,15 @@ Item {
474384 function test_dashRemainsRunningIfStageIsToldSo() {
475385 addApps(1);
476386
477− var delegateDash = findChild(phoneStage, "spreadDelegate_" + topLevelSurfaceList.idAt(1));
387+ var delegateDash = findChild(stage, "appDelegate_" + topLevelSurfaceList.idAt(1));
478388 verify(delegateDash);
479389 compare(delegateDash.application.appId, "unity8-dash");
480390
481− var delegateOther = findChild(phoneStage, "spreadDelegate_" + topLevelSurfaceList.idAt(0));
391+ var delegateOther = findChild(stage, "appDelegate_" + topLevelSurfaceList.idAt(0));
482392 verify(delegateOther);
483393
484394 performEdgeSwipeToShowAppSpread();
485− phoneStage.select("unity8-dash");
395+ tap(delegateDash, 1, 1);
486396
487397 tryCompare(delegateDash, "focus", true);
488398 tryCompare(delegateDash.application, "requestedState", ApplicationInfoInterface.RequestedRunning);
@@ -490,41 +400,40 @@ Item {
490400 compare(delegateOther.application.requestedState, ApplicationInfoInterface.RequestedSuspended);
491401
492402 performEdgeSwipeToShowAppSpread();
493− phoneStage.select(delegateOther.application.appId);
494−
403+ tap(delegateOther, 1, 1);
495404 // The other app gets focused and running but dash is kept running despite being unfocused
405+ tryCompare(delegateOther, "focus", true);
406+ tryCompare(delegateOther.application, "requestedState", ApplicationInfoInterface.RequestedRunning);
496407 tryCompare(delegateDash, "focus", false);
497408 tryCompare(delegateDash.application, "requestedState", ApplicationInfoInterface.RequestedRunning);
498− compare(delegateOther.focus, true);
499− compare(delegateOther.application.requestedState, ApplicationInfoInterface.RequestedRunning);
500409 }
501410
502411 function test_foregroundAppIsSuspendedWhenStageIsSuspended() {
503412 addApps(1);
504413
505− var delegate = findChild(phoneStage, "spreadDelegate_" + topLevelSurfaceList.idAt(0));
414+ var delegate = findChild(stage, "appDelegate_" + topLevelSurfaceList.idAt(0));
506415 verify(delegate);
507416
508417 compare(delegate.focus, true);
509418 compare(delegate.application.requestedState, ApplicationInfoInterface.RequestedRunning);
510419
511− phoneStage.suspended = true;
420+ stage.suspended = true;
512421
513422 tryCompare(delegate.application, "requestedState", ApplicationInfoInterface.RequestedSuspended);
514423
515− phoneStage.suspended = false;
424+ stage.suspended = false;
516425
517426 tryCompare(delegate.application, "requestedState", ApplicationInfoInterface.RequestedRunning);
518427 }
519428
520429 function test_mouseEdgePush() {
521− var spreadView = findChild(phoneStage, "spreadView")
522430 addApps(1);
523− mouseMove(phoneStage, phoneStage.width - 1, units.gu(10));
431+ mouseMove(stage, stage.width - 1, units.gu(10));
524432 for (var i = 0; i < units.gu(10); i++) {
525− phoneStage.pushRightEdge(1);
433+ stage.pushRightEdge(1);
526434 }
527− tryCompare(spreadView, "phase", 2);
435+ mouseMove(stage, stage.width - units.gu(5), units.gu(10));
436+ compare(stage.state, "spread");
528437 }
529438
530439 function test_closeSurfaceOfMultiSurfaceApp() {
@@ -539,19 +448,44 @@ Item {
539448
540449 performEdgeSwipeToShowAppSpread();
541450
542− var appDelegate = findChild(phoneStage, "spreadDelegate_" + surface1Id);
543− verify(appDelegate);
544− tryCompare(appDelegate, "swipeToCloseEnabled", true);
451+ var appDelegate = findChild(stage, "appDelegate_" + surface1Id);
452+ var dragArea = findChild(appDelegate, "dragArea")
453+ verify(dragArea);
454+ tryCompare(dragArea, "closeable", true);
545455
546456 compare(webbrowserApp.surfaceList.count, 2);
547− compare(webbrowserApp.state, ApplicationInfoInterface.Running);
548457
549458 swipeSurfaceUpwards(surface1Id);
550459
551460 // Surface must eventually be gone
552461 tryCompareFunction(function() { return topLevelSurfaceList.indexForId(surface1Id); }, -1);
553462 tryCompare(webbrowserApp.surfaceList, "count", 1);
554− compare(webbrowserApp.state, ApplicationInfoInterface.Running);
463+ }
464+
465+ function test_swipeToClose_data() {
466+ return [
467+ { tag: "closeable", closeable: true },
468+ { tag: "not closeable", closeable: false }
469+ ]
470+ }
471+
472+ function test_swipeToClose(data) {
473+ var surface1Id = topLevelSurfaceList.nextId;
474+ var webbrowserApp = ApplicationManager.startApplication("webbrowser-app");
475+ waitUntilAppSurfaceShowsUp(surface1Id);
476+
477+ performEdgeSwipeToShowAppSpread();
478+
479+ var appDelegate = findChild(stage, "appDelegate_" + surface1Id);
480+ var dragArea = findChild(appDelegate, "dragArea")
481+ verify(dragArea);
482+ dragArea.closeable = data.closeable;
483+
484+ var oldCount = ApplicationManager.count;
485+
486+ swipeSurfaceUpwards(surface1Id);
487+
488+ tryCompare(ApplicationManager, "count", data.closeable ? oldCount - 1 : oldCount);
555489 }
556490
557491 /*
@@ -632,11 +566,10 @@ Item {
632566
633567 performEdgeSwipeToShowAppSpread();
634568
635− {
636− var appDelegate = findChild(phoneStage, "spreadDelegate_" + webbrowserSurfaceId);
637− verify(appDelegate);
638− tryCompare(appDelegate, "swipeToCloseEnabled", true);
639− }
569+ var appDelegate = findChild(stage, "appDelegate_" + webbrowserSurfaceId);
570+ var dragArea = findChild(appDelegate, "dragArea");
571+ verify(dragArea);
572+ tryCompare(dragArea, "closeable", true);
640573
641574 swipeSurfaceUpwards(webbrowserSurfaceId);
642575
tests/qmltests/Stages/tst_Splash.qml → tests/qmltests/Stage/tst_Splash.qmlrenamed+1−1
@@ -18,7 +18,7 @@ import QtQuick 2.4
1818import QtTest 1.0
1919import Unity.Test 0.1 as UT
2020import ".."
21−import "../../../qml/Stages"
21+import "../../../qml/Stage"
2222import Ubuntu.Components 1.3
2323import Unity.Application 0.1
2424
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
2020import Unity.Test 0.1 as UT
2121import Ubuntu.Components 1.3
2222import Unity.Application 0.1
23−import "../../../qml/Stages"
23+import "../../../qml/Stage"
2424
2525Rectangle {
2626 color: "red"
@@ -87,7 +87,7 @@ Rectangle {
8787 }
8888 Row {
8989 CheckBox {id: promptCheckbox; checked: false; activeFocusOnPress: false
90− enabled: surfaceContainerLoader.item.surface === null }
90+ enabled: surfaceContainerLoader.item && surfaceContainerLoader.item.surface === null }
9191 Label { text: "isPromptSurface" }
9292 }
9393
tests/qmltests/Stages/tst_TabletStage.qml → tests/qmltests/Stage/tst_TabletStage.qmlrenamed+102−239
@@ -24,53 +24,35 @@ import Utils 0.1
2424import WindowManager 0.1
2525
2626import ".."
27−import "../../../qml/Stages"
27+import "../../../qml/Stage"
2828import "../../../qml/Components"
2929
3030Rectangle {
3131 id: root
3232 color: "grey"
33− width: tabletStageLoader.width + controls.width
34− height: tabletStageLoader.height
33+ width: units.gu(160*0.7)
34+ height: units.gu(100*0.7)
3535
3636 property var greeter: { fullyShown: true }
3737
38− TopLevelSurfaceList {
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−
38+ Stage {
39+ id: stage
40+ anchors { fill: parent; rightMargin: units.gu(30) }
41+ dragAreaWidth: units.gu(2)
42+ interactive: true
43+ shellOrientation: Qt.LandscapeOrientation
44+ nativeWidth: width
45+ nativeHeight: height
46+ orientations: Orientations {
47+ native_: Qt.LandscapeOrientation
48+ primary: Qt.LandscapeOrientation
49+ }
5150 focus: true
52−
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
72− topLevelSurfaceList: topSurfaceList
73− }
51+ mode: "stagedWithSideStage"
52+ applicationManager: ApplicationManager
53+ topLevelSurfaceList: TopLevelSurfaceList {
54+ id: topLevelSurfaceList
55+ applicationsModel: ApplicationManager
7456 }
7557 }
7658
@@ -84,7 +66,7 @@ Rectangle {
8466 right: parent.right
8567 }
8668
87− // don't let mouse clicks in the controls area disturb the TabletStage behind it
69+ // don't let mouse clicks in the controls area disturb the Stage behind it
8870 MouseArea { anchors.fill: parent }
8971
9072 Column {
@@ -95,15 +77,16 @@ Rectangle {
9577 id: edgeBarrierControls
9678 text: "Drag here to pull out spread"
9779 backgroundColor: "blue"
98− onDragged: { tabletStageLoader.item.pushRightEdge(amount); }
80+ onDragged: { stage.pushRightEdge(amount); }
9981 Component.onCompleted: {
100− edgeBarrierControls.target = testCase.findChild(tabletStageLoader, "edgeBarrierController");
82+ edgeBarrierControls.target = testCase.findChild(stage, "edgeBarrierController");
10183 }
10284 }
10385
10486 Button {
10587 text: testCase.sideStage ? testCase.sideStage.shown ? "Hide Side-stage" : "Show Side-stage" : ""
10688 enabled: testCase.sideStage
89+ activeFocusOnPress: false
10790 onClicked: {
10891 if (testCase.sideStage.shown) testCase.sideStage.hide();
10992 else testCase.sideStage.show();
@@ -140,46 +123,50 @@ Rectangle {
140123 name: "TabletStage"
141124 when: windowShown
142125
143− property Item tabletStage: tabletStageLoader.status === Loader.Ready ? tabletStageLoader.item : null
144− property Item sideStage: tabletStage ? findChild(tabletStage, "sideStage") : null
126+ readonly property alias topSurfaceList: stage.topLevelSurfaceList
127+ property Item sideStage: stage ? findChild(stage, "sideStage") : null
145128
146129 function init() {
147130 stageSaver.clear();
148− tabletStageLoader.active = true;
149− tryCompare(tabletStageLoader, "status", Loader.Ready);
150131
151132 tryCompare(topSurfaceList, "count", 1);
152133 compare(topSurfaceList.applicationAt(0).appId, "unity8-dash");
153134
154135 // this is very strange, but sometimes the test starts without
155− // TabletStage components having finished loading themselves
136+ // Stage components having finished loading themselves
156137 var appWindow = null
157138 while (!appWindow) {
158139 appWindow = findAppWindowForSurfaceId(topSurfaceList.idAt(0));
159140 if (!appWindow) {
160− console.log("didn't find unity8-dash appWindow in " + tabletStage + ". Trying again...");
141+ console.log("didn't find unity8-dash appWindow in Stage. Trying again...");
161142 wait(50);
162143 }
163144 }
164145
165146 waitUntilAppSurfaceShowsUp(topSurfaceList.idAt(0));
166147 sideStage.hideNow()
148+ tryCompare(sideStage, "x", stage.width)
167149 }
168150
169151 function cleanup() {
170− tabletStageLoader.itemDestroyed = false;
171− tabletStageLoader.active = false;
172−
173− tryCompare(tabletStageLoader, "status", Loader.Null);
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);
152+ ApplicationManager.requestFocusApplication("unity8-dash");
153+ tryCompare(ApplicationManager, "focusedApplicationId", "unity8-dash");
154+ tryCompare(stage, "state", "stagedWithSideStage");
155+ waitForRendering(stage);
180156
181157 killApps();
158+
159+ // wait for Stage to stabilize back into its initial state
160+ var appRepeater = findChild(stage, "appRepeater");
161+ tryCompare(appRepeater, "count", 1);
162+ tryCompare(appRepeater.itemAt(0), "x", 0);
163+
164+ sideStage.hideNow();
165+ tryCompare(sideStage, "x", stage.width)
166+ waitForRendering(stage)
167+
182168 WindowStateStorage.clear();
169+ wait(100)
183170 }
184171
185172 function waitUntilAppSurfaceShowsUp(surfaceId) {
@@ -191,7 +178,7 @@ Rectangle {
191178 }
192179
193180 function findAppWindowForSurfaceId(surfaceId) {
194− var spreadDelegate = findChild(tabletStage, "spreadDelegate_" + surfaceId);
181+ var spreadDelegate = findChild(stage, "appDelegate_" + surfaceId);
195182 if (!spreadDelegate) {
196183 return null;
197184 }
@@ -210,7 +197,7 @@ Rectangle {
210197
211198 function waitUntilAppDelegateStopsMoving(targetSurfaceId)
212199 {
213− var targetAppDelegate = findChild(tabletStage, "spreadDelegate_" + targetSurfaceId);
200+ var targetAppDelegate = findChild(stage, "appDelegate_" + targetSurfaceId);
214201 verify(targetAppDelegate);
215202 var lastValue = undefined;
216203 do {
@@ -220,15 +207,9 @@ Rectangle {
220207 }
221208
222209 function performEdgeSwipeToShowAppSpread() {
223− touchFlick(tabletStage,
224− tabletStage.width - (tabletStage.dragAreaWidth / 2), tabletStage.height / 2,
225− tabletStage.x + 1, tabletStage.height / 2);
210+ touchFlick(stage, stage.width - (stage.dragAreaWidth / 2), stage.height / 2, stage.x + 1, stage.height / 2);
226211
227− var spreadView = findChild(tabletStage, "spreadView");
228− verify(spreadView);
229− tryCompare(spreadView, "phase", 2);
230− tryCompare(spreadView, "flicking", false);
231− tryCompare(spreadView, "moving", false);
212+ tryCompare(stage, "state", "spread");
232213 }
233214
234215 function swipeSurfaceUpwards(surfaceId) {
@@ -244,17 +225,12 @@ Rectangle {
244225
245226 function dragToSideStage(surfaceId) {
246227 sideStage.showNow();
247− var targetAppDelegate = findChild(tabletStage, "spreadDelegate_" + surfaceId);
228+ var targetAppDelegate = findChild(stage, "appDelegate_" + surfaceId);
248229
249− var pos = tabletStage.width - sideStage.width - (tabletStage.width - sideStage.width) / 2;
250− var end_pos = tabletStage.width - sideStage.width / 2;
230+ var pos = stage.width - sideStage.width - (stage.width - sideStage.width) / 2;
231+ var end_pos = stage.width - sideStage.width / 2;
251232
252− multiTouchDragUntil([0,1,2],
253− tabletStage,
254− pos,
255− tabletStage.height / 2,
256− units.gu(3),
257− 0,
233+ multiTouchDragUntil([0,1,2], stage, pos, stage.height / 2, units.gu(3), 0,
258234 function() {
259235 pos += units.gu(3);
260236 return sideStage.shown && !sideStage.showAnimation.running &&
@@ -265,16 +241,16 @@ Rectangle {
265241
266242 function dragToMainStage(surfaceId) {
267243 sideStage.showNow();
268− var targetAppDelegate = findChild(tabletStage, "spreadDelegate_" + surfaceId);
244+ var targetAppDelegate = findChild(stage, "appDelegate_" + surfaceId);
269245 verify(targetAppDelegate);
270246
271− var pos = tabletStage.width - sideStage.width / 2;
272− var end_pos = tabletStage.width - sideStage.width - (tabletStage.width - sideStage.width) / 2;
247+ var pos = stage.width - sideStage.width / 2;
248+ var end_pos = stage.width - sideStage.width - (stage.width - sideStage.width) / 2;
273249
274250 multiTouchDragUntil([0,1,2],
275− tabletStage,
251+ stage,
276252 pos,
277− tabletStage.height / 2,
253+ stage.height / 2,
278254 -units.gu(3),
279255 0,
280256 function() {
@@ -290,7 +266,7 @@ Rectangle {
290266 var webbrowserSurfaceId = topSurfaceList.nextId;
291267 webbrowserCheckBox.checked = true;
292268 waitUntilAppSurfaceShowsUp(webbrowserSurfaceId);
293− var webbrowserDelegate = findChild(tabletStage, "spreadDelegate_" + webbrowserSurfaceId);
269+ var webbrowserDelegate = findChild(stage, "appDelegate_" + webbrowserSurfaceId);
294270 verify(webbrowserDelegate);
295271 compare(webbrowserDelegate.stage, ApplicationInfoInterface.MainStage);
296272 var webbrowserWindow = findAppWindowForSurfaceId(webbrowserSurfaceId);
@@ -303,7 +279,7 @@ Rectangle {
303279 waitUntilAppSurfaceShowsUp(dialerSurfaceId);
304280
305281 var dialerApp = ApplicationManager.findApplication(dialerCheckBox.appId);
306− var dialerDelegate = findChild(tabletStage, "spreadDelegate_" + dialerSurfaceId);
282+ var dialerDelegate = findChild(stage, "appDelegate_" + dialerSurfaceId);
307283 verify(dialerDelegate);
308284 compare(dialerDelegate.stage, ApplicationInfoInterface.SideStage);
309285
@@ -336,17 +312,18 @@ Rectangle {
336312
337313 performEdgeSwipeToShowAppSpread();
338314
339− var appDelegate = findChild(tabletStage, "spreadDelegate_" + dialerSurfaceId);
340− verify(appDelegate);
315+ var appDelegate = findChild(stage, "appDelegate_" + dialerSurfaceId);
316+ var dragArea = findChild(appDelegate, "dragArea");
317+ verify(dragArea);
341318 compare(appDelegate.stage, ApplicationInfoInterface.SideStage);
342− tryCompare(appDelegate, "swipeToCloseEnabled", true);
319+ tryCompare(dragArea, "closeable", true);
343320
344321 swipeSurfaceUpwards(dialerSurfaceId);
345322
346323 // Check that dialer-app has been closed
347324
348325 tryCompareFunction(function() {
349− return findChild(tabletStage, "appWindow_" + dialerCheckBox.appId);
326+ return findChild(stage, "appWindow_" + dialerCheckBox.appId);
350327 }, null);
351328
352329 tryCompareFunction(function() {
@@ -359,7 +336,7 @@ Rectangle {
359336 webbrowserCheckBox.checked = true;
360337 waitUntilAppSurfaceShowsUp(webbrowserSurfaceId);
361338 var webbrowserApp = ApplicationManager.findApplication(webbrowserCheckBox.appId);
362− var webbrowserDelegate = findChild(tabletStage, "spreadDelegate_" + webbrowserSurfaceId);
339+ var webbrowserDelegate = findChild(stage, "appDelegate_" + webbrowserSurfaceId);
363340 compare(webbrowserDelegate.stage, ApplicationInfoInterface.MainStage);
364341
365342 tryCompare(webbrowserApp, "state", ApplicationInfoInterface.Running);
@@ -368,7 +345,7 @@ Rectangle {
368345 galleryCheckBox.checked = true;
369346 waitUntilAppSurfaceShowsUp(gallerySurfaceId);
370347 var galleryApp = ApplicationManager.findApplication(galleryCheckBox.appId);
371− var galleryDelegate = findChild(tabletStage, "spreadDelegate_" + gallerySurfaceId);
348+ var galleryDelegate = findChild(stage, "appDelegate_" + gallerySurfaceId);
372349 compare(galleryDelegate.stage, ApplicationInfoInterface.MainStage);
373350
374351 tryCompare(galleryApp, "state", ApplicationInfoInterface.Running);
@@ -389,7 +366,7 @@ Rectangle {
389366 WindowStateStorage.saveStage(facebookCheckBox.appId, ApplicationInfoInterface.SideStage)
390367 WindowStateStorage.saveStage(dialerCheckBox.appId, ApplicationInfoInterface.SideStage)
391368
392− var stagesPriv = findInvisibleChild(tabletStage, "stagesPriv");
369+ var stagesPriv = findInvisibleChild(stage, "DesktopStagePrivate");
393370 verify(stagesPriv);
394371
395372 // launch two main stage apps
@@ -398,7 +375,7 @@ Rectangle {
398375 var webbrowserSurfaceId = topSurfaceList.nextId;
399376 webbrowserCheckBox.checked = true;
400377 waitUntilAppSurfaceShowsUp(webbrowserSurfaceId);
401− var webbrowserDelegate = findChild(tabletStage, "spreadDelegate_" + webbrowserSurfaceId);
378+ var webbrowserDelegate = findChild(stage, "appDelegate_" + webbrowserSurfaceId);
402379 verify(webbrowserDelegate);
403380 compare(webbrowserDelegate.stage, ApplicationInfoInterface.MainStage);
404381 var webbrowserApp = ApplicationManager.findApplication(webbrowserCheckBox.appId);
@@ -407,7 +384,7 @@ Rectangle {
407384 galleryCheckBox.checked = true;
408385 waitUntilAppSurfaceShowsUp(gallerySurfaceId);
409386 var galleryApp = ApplicationManager.findApplication(galleryCheckBox.appId);
410− var galleryDelegate = findChild(tabletStage, "spreadDelegate_" + gallerySurfaceId);
387+ var galleryDelegate = findChild(stage, "appDelegate_" + gallerySurfaceId);
411388 compare(galleryDelegate.stage, ApplicationInfoInterface.MainStage);
412389
413390 compare(stagesPriv.mainStageAppId, galleryCheckBox.appId);
@@ -419,14 +396,14 @@ Rectangle {
419396 dialerCheckBox.checked = true;
420397 waitUntilAppSurfaceShowsUp(dialerSurfaceId);
421398 var dialerApp = ApplicationManager.findApplication(dialerCheckBox.appId);
422− var dialerDelegate = findChild(tabletStage, "spreadDelegate_" + dialerSurfaceId);
399+ var dialerDelegate = findChild(stage, "appDelegate_" + dialerSurfaceId);
423400 compare(dialerDelegate.stage, ApplicationInfoInterface.SideStage);
424401
425402 var facebookSurfaceId = topSurfaceList.nextId;
426403 facebookCheckBox.checked = true;
427404 waitUntilAppSurfaceShowsUp(facebookSurfaceId);
428405 var facebookApp = ApplicationManager.findApplication(facebookCheckBox.appId);
429− var facebookDelegate = findChild(tabletStage, "spreadDelegate_" + facebookSurfaceId);
406+ var facebookDelegate = findChild(stage, "appDelegate_" + facebookSurfaceId);
430407 compare(facebookDelegate.stage, ApplicationInfoInterface.SideStage);
431408
432409 compare(stagesPriv.sideStageAppId, facebookCheckBox.appId);
@@ -461,40 +438,31 @@ Rectangle {
461438 webbrowserCheckBox.checked = true;
462439 waitUntilAppSurfaceShowsUp(webbrowserSurfaceId);
463440 var webbrowserApp = ApplicationManager.findApplication(webbrowserCheckBox.appId);
464− var webbrowserDelegate = findChild(tabletStage, "spreadDelegate_" + webbrowserSurfaceId);
441+ var webbrowserDelegate = findChild(stage, "appDelegate_" + webbrowserSurfaceId);
465442 compare(webbrowserDelegate.stage, ApplicationInfoInterface.MainStage);
466443
467444 var dialerSurfaceId = topSurfaceList.nextId;
468445 dialerCheckBox.checked = true;
469446 waitUntilAppSurfaceShowsUp(dialerSurfaceId);
470447 var dialerApp = ApplicationManager.findApplication(dialerCheckBox.appId);
471− var dialerDelegate = findChild(tabletStage, "spreadDelegate_" + dialerSurfaceId);
448+ var dialerDelegate = findChild(stage, "appDelegate_" + dialerSurfaceId);
472449 compare(dialerDelegate.stage, ApplicationInfoInterface.SideStage);
473450
474451
475452 compare(webbrowserApp.requestedState, ApplicationInfoInterface.RequestedRunning);
476453 compare(dialerApp.requestedState, ApplicationInfoInterface.RequestedRunning);
477454
478− tabletStage.suspended = true;
455+ stage.suspended = true;
479456
480457 tryCompare(webbrowserApp, "requestedState", ApplicationInfoInterface.RequestedSuspended);
481458 tryCompare(dialerApp, "requestedState", ApplicationInfoInterface.RequestedSuspended);
482459
483− tabletStage.suspended = false;
460+ stage.suspended = false;
484461
485462 tryCompare(webbrowserApp, "requestedState", ApplicationInfoInterface.RequestedRunning);
486463 tryCompare(dialerApp, "requestedState", ApplicationInfoInterface.RequestedRunning);
487464 }
488465
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−
498466 function test_threeFingerTapOpensSideStage_data() {
499467 return [
500468 { tag: "1 finger", touchIds: [0], result: false },
@@ -505,7 +473,7 @@ Rectangle {
505473 }
506474
507475 function test_threeFingerTapOpensSideStage(data) {
508− multiTouchTap(data.touchIds, tabletStage, tabletStage.width / 2, tabletStage.height / 2);
476+ multiTouchTap(data.touchIds, stage, stage.width / 2, stage.height / 2);
509477 wait(200);
510478 tryCompare(sideStage, "shown", data.result);
511479 }
@@ -523,18 +491,13 @@ Rectangle {
523491 function test_threeFingerTapClosesSideStage(data) {
524492 sideStage.showNow();
525493
526− multiTouchTap(data.touchIds, tabletStage, tabletStage.width / 2, tabletStage.height / 2);
494+ multiTouchTap(data.touchIds, stage, stage.width / 2, stage.height / 2);
527495 wait(200);
528496 tryCompare(sideStage, "shown", data.result);
529497 }
530498
531499 function test_threeFingerDragOpensSidestage() {
532− multiTouchDragUntil([0,1,2],
533− tabletStage,
534− tabletStage.width / 4,
535− tabletStage.height / 4,
536− units.gu(1),
537− 0,
500+ multiTouchDragUntil([0,1,2], stage, stage.width / 4, stage.height / 4, units.gu(1), 0,
538501 function() { return sideStage.shown; });
539502 }
540503
@@ -546,7 +509,7 @@ Rectangle {
546509 }
547510
548511 function test_applicationLoadsInDefaultStage(data) {
549− var stagesPriv = findInvisibleChild(tabletStage, "stagesPriv");
512+ var stagesPriv = findInvisibleChild(stage, "DesktopStagePrivate");
550513 verify(stagesPriv);
551514
552515 tryCompare(stagesPriv, "mainStageAppId", "unity8-dash");
@@ -570,7 +533,7 @@ Rectangle {
570533 function test_applicationLoadsInSavedStage(data) {
571534 WindowStateStorage.saveStage(webbrowserCheckBox.appId, data.stage)
572535
573− var stagesPriv = findInvisibleChild(tabletStage, "stagesPriv");
536+ var stagesPriv = findInvisibleChild(stage, "DesktopStagePrivate");
574537 verify(stagesPriv);
575538
576539 tryCompare(stagesPriv, "mainStageAppId", "unity8-dash");
@@ -595,7 +558,7 @@ Rectangle {
595558 WindowStateStorage.saveStage(webbrowserCheckBox.appId, data.fromStage);
596559 stageSaver.clear();
597560
598− var stagesPriv = findInvisibleChild(tabletStage, "stagesPriv");
561+ var stagesPriv = findInvisibleChild(stage, "DesktopStagePrivate");
599562 verify(stagesPriv);
600563
601564 tryCompare(stagesPriv, "mainStageAppId", "unity8-dash");
@@ -618,67 +581,38 @@ Rectangle {
618581
619582 function test_loadSideStageByDraggingFromMainStage() {
620583 sideStage.showNow();
584+ print("sidestage now shown. launching browser")
621585 var webbrowserSurfaceId = topSurfaceList.nextId;
622586 webbrowserCheckBox.checked = true;
623587 waitUntilAppSurfaceShowsUp(webbrowserSurfaceId);
624588
625− var appDelegate = findChild(tabletStage, "spreadDelegate_" + webbrowserSurfaceId);
589+ var appDelegate = findChild(stage, "appDelegate_" + webbrowserSurfaceId);
626590 verify(appDelegate);
591+ waitForRendering(stage);
627592 compare(appDelegate.stage, ApplicationInfoInterface.MainStage);
628593
629594 dragToSideStage(webbrowserSurfaceId);
630595
631− var spreadView = findChild(tabletStageLoader, "spreadView")
632− tryCompare(spreadView, "surfaceDragging", false);
633596 tryCompare(appDelegate, "stage", ApplicationInfoInterface.SideStage);
634597 }
635598
636− function test_unloadSideStageByDraggingFromStageStage() {
599+ function test_unloadSideStageByDraggingFromSideStage() {
637600 sideStage.showNow();
638601 WindowStateStorage.saveStage(webbrowserCheckBox.appId, ApplicationInfoInterface.SideStage)
639602 var webbrowserSurfaceId = topSurfaceList.nextId;
640603 webbrowserCheckBox.checked = true;
641604 waitUntilAppSurfaceShowsUp(webbrowserSurfaceId);
642605
643− var appDelegate = findChild(tabletStage, "spreadDelegate_" + webbrowserSurfaceId);
606+ var appDelegate = findChild(stage, "appDelegate_" + webbrowserSurfaceId);
644607 verify(appDelegate);
608+ waitForRendering(stage);
645609 compare(appDelegate.stage, ApplicationInfoInterface.SideStage);
646610
647611 dragToMainStage(webbrowserSurfaceId);
648612
649− var spreadView = findChild(tabletStageLoader, "spreadView")
650− tryCompare(spreadView, "surfaceDragging", false);
651613 tryCompare(appDelegate, "stage", ApplicationInfoInterface.MainStage);
652614 }
653615
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−
682616 /*
683617 1- Suspended app gets killed behind the scenes, causing its surface to go zombie.
684618 2- Surface gets screenshotted and removed. Its slot in the topSurfaceList remains,
@@ -724,64 +658,12 @@ Rectangle {
724658 compare(webbrowserApp.surfaceList.count, 1);
725659 }
726660
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−
779661 function test_draggingSurfaceKeepsSurfaceFocus() {
780662 var webbrowserSurfaceId = topSurfaceList.nextId;
781663 webbrowserCheckBox.checked = true;
782664 waitUntilAppSurfaceShowsUp(webbrowserSurfaceId);
783665
784− var appDelegate = findChild(tabletStage, "spreadDelegate_" + webbrowserSurfaceId);
666+ var appDelegate = findChild(stage, "appDelegate_" + webbrowserSurfaceId);
785667 verify(appDelegate);
786668 compare(appDelegate.stage, ApplicationInfoInterface.MainStage);
787669
@@ -789,9 +671,8 @@ Rectangle {
789671
790672 dragToSideStage(webbrowserSurfaceId);
791673
792− var spreadView = findChild(tabletStageLoader, "spreadView")
793− tryCompare(spreadView, "surfaceDragging", false);
794674 tryCompare(appDelegate.surface, "activeFocus", true);
675+ tryCompare(appDelegate, "stage", ApplicationInfoInterface.SideStage);
795676 }
796677
797678 function test_dashDoesNotDragToSidestage() {
@@ -799,59 +680,41 @@ Rectangle {
799680 compare(topSurfaceList.applicationAt(0).appId, "unity8-dash");
800681 var dashSurfaceId = topSurfaceList.idAt(0);
801682
802− var appDelegate = findChild(tabletStage, "spreadDelegate_" + dashSurfaceId);
683+ var appDelegate = findChild(stage, "appDelegate_" + dashSurfaceId);
803684 verify(appDelegate);
804685 compare(appDelegate.stage, ApplicationInfoInterface.MainStage);
805686
806− var pos = tabletStage.width - sideStage.width - (tabletStage.width - sideStage.width) / 2;
807− var end_pos = tabletStage.width - sideStage.width / 2;
687+ var pos = stage.width - sideStage.width - (stage.width - sideStage.width) / 2;
688+ var end_pos = stage.width - sideStage.width / 2;
808689
809− multiTouchDragUntil([0,1,2],
810− tabletStage,
811− pos,
812− tabletStage.height / 2,
813− units.gu(3),
814− 0,
690+ multiTouchDragUntil([0,1,2], stage, pos, stage.height / 2, units.gu(3), 0,
815691 function() {
816692 pos += units.gu(3);
817693 return sideStage.shown && !sideStage.showAnimation.running &&
818694 pos >= end_pos;
819695 });
820696
821− var spreadView = findChild(tabletStageLoader, "spreadView")
822− tryCompare(spreadView, "surfaceDragging", false);
697+ waitForRendering(stage);
823698 tryCompare(appDelegate, "stage", ApplicationInfoInterface.MainStage);
824699 }
825700
826− function test_switchStageOnRotation() {
701+ function test_switchRestoreStageOnRotation() {
827702 WindowStateStorage.saveStage(webbrowserCheckBox.appId, ApplicationInfoInterface.SideStage)
828703 var webbrowserSurfaceId = topSurfaceList.nextId;
829704 webbrowserCheckBox.checked = true;
830705 waitUntilAppSurfaceShowsUp(webbrowserSurfaceId);
831706
832− var appDelegate = findChild(tabletStage, "spreadDelegate_" + webbrowserSurfaceId);
707+ var appDelegate = findChild(stage, "appDelegate_" + webbrowserSurfaceId);
833708 verify(appDelegate);
834709 compare(appDelegate.stage, ApplicationInfoInterface.SideStage);
835710
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−
848711 dragToSideStage(webbrowserSurfaceId);
849712
850713 // will be in sidestage now
851− tabletStage.shellOrientation = Qt.PortraitOrientation;
714+ stage.shellOrientation = Qt.PortraitOrientation;
852715 tryCompare(appDelegate, "stage", ApplicationInfoInterface.MainStage);
853716
854− tabletStage.shellOrientation = Qt.LandscapeOrientation;
717+ stage.shellOrientation = Qt.LandscapeOrientation;
855718 tryCompare(appDelegate, "stage", ApplicationInfoInterface.SideStage);
856719 }
857720
@@ -860,25 +723,25 @@ Rectangle {
860723 webbrowserCheckBox.checked = true;
861724 waitUntilAppSurfaceShowsUp(webbrowserSurfaceId);
862725
863− var appDelegate = findChild(tabletStage, "spreadDelegate_" + webbrowserSurfaceId);
726+ var appDelegate = findChild(stage, "appDelegate_" + webbrowserSurfaceId);
864727 verify(appDelegate);
865728
866729 dragToSideStage(webbrowserSurfaceId);
867730 // will be in sidestage now
868− tabletStage.shellOrientation = Qt.PortraitOrientation;
731+ stage.shellOrientation = Qt.PortraitOrientation;
869732 tryCompare(appDelegate, "stage", ApplicationInfoInterface.MainStage);
870733
871734 webbrowserCheckBox.checked = false;
872735 tryCompare(ApplicationManager, "count", 1);
873736
874737 // back to landscape
875− tabletStage.shellOrientation = Qt.LandscapeOrientation;
738+ stage.shellOrientation = Qt.LandscapeOrientation;
876739
877740 webbrowserSurfaceId = topSurfaceList.nextId;
878741 webbrowserCheckBox.checked = true;
879742 waitUntilAppSurfaceShowsUp(webbrowserSurfaceId);
880743
881− appDelegate = findChild(tabletStage, "spreadDelegate_" + webbrowserSurfaceId);
744+ appDelegate = findChild(stage, "appDelegate_" + webbrowserSurfaceId);
882745 verify(appDelegate);
883746 tryCompare(appDelegate, "stage", ApplicationInfoInterface.SideStage);
884747 }
tests/qmltests/Stages/tst_WindowResizeArea.qml → tests/qmltests/Stage/tst_WindowResizeArea.qmlrenamed+40−36
@@ -20,7 +20,7 @@ import QtTest 1.0
2020import Unity.Test 0.1
2121import ".."
2222import "../../../qml/Components/PanelState"
23−import "../../../qml/Stages"
23+import "../../../qml/Stage"
2424import Ubuntu.Components 1.3
2525import Ubuntu.Components.ListItems 1.3 as ListItem
2626import Unity.Application 0.1
@@ -34,7 +34,7 @@ Item {
3434 Binding {
3535 target: PanelState
3636 property: "panelHeight"
37− value: units.gu(2)
37+ value: units.gu(3)
3838 }
3939
4040 Component {
@@ -46,12 +46,16 @@ Item {
4646 property alias resizeAreaMinHeight: windowResizeArea.minHeight
4747 x: requestedX
4848 y: requestedY
49− property real requestedX: units.gu(20)
50− property real requestedY: units.gu(20)
49+ property real requestedX: windowedX
50+ property real requestedY: windowedY
5151 width: requestedWidth
5252 height: requestedHeight
53− property real requestedWidth
54− property real requestedHeight
53+ property real requestedWidth: windowedWidth
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
5559 property real minimumWidth: 0
5660 property real minimumHeight: 0
5761 property real maximumWidth: 0
@@ -236,10 +240,10 @@ Item {
236240 property var fakeWindow: windowLoader.item
237241
238242 function init() {
239− fakeWindow.requestedX = units.gu(20)
240− fakeWindow.requestedY = units.gu(20)
241− fakeWindow.requestedWidth = units.gu(20)
242− fakeWindow.requestedHeight = units.gu(20)
243+ fakeWindow.windowedX = units.gu(20)
244+ fakeWindow.windowedY = units.gu(20)
245+ fakeWindow.windowedWidth = units.gu(20)
246+ fakeWindow.windowedHeight = units.gu(20)
243247 fakeWindow.resizeAreaMinWidth = units.gu(15);
244248 fakeWindow.resizeAreaMinHeight = units.gu(10);
245249 fakeWindow.minimumWidth = 0;
@@ -264,8 +268,8 @@ Item {
264268 }
265269
266270 function test_resizeWindowRightBottom(data) {
267− var initialWindowX = fakeWindow.requestedX;
268− var initialWindowY = fakeWindow.requestedY;
271+ var initialWindowX = fakeWindow.windowedX;
272+ var initialWindowY = fakeWindow.windowedY;
269273 var initialWindowWidth = fakeWindow.width
270274 var initialWindowHeight = fakeWindow.height
271275
@@ -290,8 +294,8 @@ Item {
290294 }
291295
292296 function test_resizeWindowLeftTop(data) {
293− var initialWindowX = fakeWindow.requestedX;
294− var initialWindowY = fakeWindow.requestedY;
297+ var initialWindowX = fakeWindow.windowedX;
298+ var initialWindowY = fakeWindow.windowedY;
295299 var initialWindowWidth = fakeWindow.width
296300 var initialWindowHeight = fakeWindow.height
297301
@@ -309,8 +313,8 @@ Item {
309313 }
310314
311315 function test_saveRestoreSize() {
312− var initialWindowX = fakeWindow.requestedX;
313− var initialWindowY = fakeWindow.requestedY;
316+ var initialWindowX = fakeWindow.windowedX;
317+ var initialWindowY = fakeWindow.windowedY;
314318 var initialWindowWidth = fakeWindow.width
315319 var initialWindowHeight = fakeWindow.height
316320
@@ -342,8 +346,8 @@ Item {
342346 }
343347
344348 function test_resizeSmallerAndLarger(data) {
345− var initialWindowX = fakeWindow.requestedX;
346− var initialWindowY = fakeWindow.requestedY;
349+ var initialWindowX = fakeWindow.windowedX;
350+ var initialWindowY = fakeWindow.windowedY;
347351 var initialWindowWidth = fakeWindow.width
348352 var initialWindowHeight = fakeWindow.height
349353
@@ -358,18 +362,18 @@ Item {
358362 }
359363
360364 function test_saveRestoreMaximized() {
361− var initialWindowX = fakeWindow.requestedX;
362− var initialWindowY = fakeWindow.requestedY;
365+ var initialWindowX = fakeWindow.windowedX;
366+ var initialWindowY = fakeWindow.windowedY;
363367
364368 var moveDelta = units.gu(5);
365369
366− fakeWindow.requestedX = initialWindowX + moveDelta
367− fakeWindow.requestedY = initialWindowY + moveDelta
370+ fakeWindow.windowedX = initialWindowX + moveDelta
371+ fakeWindow.windowedY = initialWindowY + moveDelta
368372
369373 // Now change the state to maximized. The window should not keep updating the stored values
370374 fakeWindow.maximize()
371− fakeWindow.requestedX = 31415 // 0 is too risky to pass the test even when broken
372− fakeWindow.requestedY = 31415
375+ fakeWindow.windowedX = 31415 // 0 is too risky to pass the test even when broken
376+ fakeWindow.windowedY = 31415
373377
374378 // This will destroy the window and recreate it
375379 windowLoader.active = false;
@@ -399,8 +403,8 @@ Item {
399403 }
400404
401405 function test_restoreMovesIntoBounds(data) {
402− fakeWindow.requestedX = data.x;
403− fakeWindow.requestedY = data.y;
406+ fakeWindow.windowedX = data.x;
407+ fakeWindow.windowedY = data.y;
404408 fakeWindow.width = data.w;
405409 fakeWindow.height = data.h;
406410 waitForRendering(root);
@@ -427,8 +431,8 @@ Item {
427431 and height) increment value.
428432 */
429433 function test_sizeIncrement() {
430− var initialWindowX = fakeWindow.requestedX;
431− var initialWindowY = fakeWindow.requestedY;
434+ var initialWindowX = fakeWindow.windowedX;
435+ var initialWindowY = fakeWindow.windowedY;
432436 var initialWindowWidth = fakeWindow.width
433437 var initialWindowHeight = fakeWindow.height
434438
@@ -458,12 +462,12 @@ Item {
458462 Tests that when dragging a window border you cannot make it bigger than its maximum size
459463 */
460464 function test_maximumSize() {
461− fakeWindow.requestedX = units.gu(1);
462− fakeWindow.requestedY = units.gu(1);
465+ fakeWindow.windowedX = units.gu(1);
466+ fakeWindow.windowedY = units.gu(1);
463467 fakeWindow.resizeAreaMinWidth = 1; // so it does not interfere with anything
464468 fakeWindow.resizeAreaMinHeight = 1; // so it does not interfere with anything
465− fakeWindow.requestedWidth = units.gu(10);
466− fakeWindow.requestedHeight = units.gu(10);
469+ fakeWindow.windowedWidth = units.gu(10);
470+ fakeWindow.windowedHeight = units.gu(10);
467471
468472 fakeWindow.maximumWidth = units.gu(20);
469473 fakeWindow.maximumHeight = units.gu(20);
@@ -488,12 +492,12 @@ Item {
488492 Tests that when dragging a window border you cannot make it smaller than its minimum size
489493 */
490494 function test_minimumSize() {
491− fakeWindow.requestedX = units.gu(1);
492− fakeWindow.requestedY = units.gu(1);
495+ fakeWindow.windowedX = units.gu(1);
496+ fakeWindow.windowedY = units.gu(1);
493497 fakeWindow.resizeAreaMinWidth = 1; // so it does not interfere with anything
494498 fakeWindow.resizeAreaMinHeight = 1; // so it does not interfere with anything
495− fakeWindow.requestedWidth = units.gu(20);
496− fakeWindow.requestedHeight = units.gu(20);
499+ fakeWindow.windowedWidth = units.gu(20);
500+ fakeWindow.windowedHeight = units.gu(20);
497501
498502 fakeWindow.minimumWidth = units.gu(10);
499503 fakeWindow.minimumHeight = units.gu(10);
tests/qmltests/tst_OrientedShell.qml+38−198
@@ -29,7 +29,8 @@ import Utils 0.1
2929
3030import "../../qml"
3131import "../../qml/Components"
32−import "Stages"
32+import "../../qml/Components/PanelState"
33+import "Stage"
3334
3435Rectangle {
3536 id: root
@@ -443,7 +444,7 @@ Rectangle {
443444 SignalSpy { id: signalSpy2 }
444445
445446 Connections {
446− id: spreadRepeaterConnections
447+ id: appRepeaterConnections
447448 ignoreUnknownSignals : true
448449 property var itemAddedCallback: null
449450 onItemAdded: {
@@ -483,8 +484,8 @@ Rectangle {
483484 while (keyboardsModel.count > 0)
484485 MockInputDeviceBackend.removeDevice("/kbd" + (keyboardsModel.count - 1))
485486
486− spreadRepeaterConnections.target = null;
487− spreadRepeaterConnections.itemAddedCallback = null;
487+ appRepeaterConnections.target = null;
488+ appRepeaterConnections.itemAddedCallback = null;
488489 signalSpy.target = null;
489490 signalSpy.signalName = "";
490491
@@ -511,7 +512,7 @@ Rectangle {
511512
512513 var primaryAppWindow = findAppWindowForSurfaceId(primarySurfaceId);
513514 verify(primaryAppWindow)
514− var primaryDelegate = findChild(shell, "spreadDelegate_" + primarySurfaceId);
515+ var primaryDelegate = findChild(shell, "appDelegate_" + primarySurfaceId);
515516
516517 compare(primaryDelegate.focus, true);
517518 compare(primaryApp.rotatesWindowContents, false);
@@ -559,7 +560,7 @@ Rectangle {
559560 compare(ApplicationManager.focusedApplicationId, "primary-oriented-app");
560561 compare(primaryApp.rotatesWindowContents, false);
561562 compare(primaryApp.supportedOrientations, Qt.PrimaryOrientation);
562− var primaryDelegate = findChild(shell, "spreadDelegate_" + primarySurfaceId);
563+ var primaryDelegate = findChild(shell, "appDelegate_" + primarySurfaceId);
563564 compare(primaryDelegate.stage, ApplicationInfoInterface.MainStage);
564565
565566 tryCompareFunction(function(){return primaryApp.surfaceList.count > 0;}, true);
@@ -736,7 +737,7 @@ Rectangle {
736737 compare(musicApp.supportedOrientations, Qt.PortraitOrientation | Qt.LandscapeOrientation
737738 | Qt.InvertedPortraitOrientation | Qt.InvertedLandscapeOrientation);
738739 if (data.deviceName === "manta" || data.deviceName === "flo") {
739− var musicDelegate = findChild(shell, "spreadDelegate_" + musicSurfaceId);
740+ var musicDelegate = findChild(shell, "appDelegate_" + musicSurfaceId);
740741 compare(musicDelegate.stage, ApplicationInfoInterface.MainStage);
741742 }
742743
@@ -873,9 +874,9 @@ Rectangle {
873874 var greeter = findChild(shell, "greeter");
874875 tryCompare(greeter, "animating", false);
875876
876− var twitterDelegate = findChild(shell, "spreadDelegate_" + topLevelSurfaceList.idAt(1));
877+ var twitterDelegate = findChild(shell, "appDelegate_" + topLevelSurfaceList.idAt(1));
877878 compare(twitterDelegate.application.appId, "twitter-webapp");
878− twitterDelegate.clicked();
879+ tap(twitterDelegate, 1, 1);
879880
880881 // now it should finally follow the physical orientation
881882 tryCompare(shell, "transformRotationAngle", 90);
@@ -894,24 +895,10 @@ Rectangle {
894895 WindowStateStorage.saveStage("twitter-webapp", ApplicationInfoInterface.SideStage)
895896 loadShell(data.deviceName);
896897
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−
911898 var twitterSurfaceId = topLevelSurfaceList.nextId;
912899 var twitterApp = ApplicationManager.startApplication("twitter-webapp");
913900 verify(twitterApp);
914− var twitterDelegate = findChild(shell, "spreadDelegate_" + twitterSurfaceId);
901+ var twitterDelegate = findChild(shell, "appDelegate_" + twitterSurfaceId);
915902 compare(twitterDelegate.stage, ApplicationInfoInterface.SideStage);
916903
917904 // ensure the mock twitter-webapp is as we expect
@@ -919,15 +906,11 @@ Rectangle {
919906 compare(twitterApp.supportedOrientations, Qt.PortraitOrientation | Qt.LandscapeOrientation
920907 | Qt.InvertedPortraitOrientation | Qt.InvertedLandscapeOrientation);
921908
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−
926909 tryCompare(twitterDelegate, "orientationChangesEnabled", true);
927910
928− var appWindowWithShadow = findChild(twitterDelegate, "appWindowWithShadow");
929− verify(appWindowWithShadow);
930− tryCompare(appWindowWithShadow, "state", "keepSceneRotation");
911+ var decoratedWindow = findChild(twitterDelegate, "decoratedWindow");
912+ verify(decoratedWindow);
913+ tryCompare(decoratedWindow, "counterRotate", false);
931914
932915 // no reason for any rotation animation to have taken place
933916 compare(signalSpy.count, 0);
@@ -943,8 +926,8 @@ Rectangle {
943926 loadShell(data.deviceName);
944927
945928 var dialerDelegate = null;
946− verify(spreadRepeaterConnections.target);
947− spreadRepeaterConnections.itemAddedCallback = function(item) {
929+ verify(appRepeaterConnections.target);
930+ appRepeaterConnections.itemAddedCallback = function(item) {
948931 dialerDelegate = item;
949932 verify(item.application.appId, "dialer-app");
950933 }
@@ -960,16 +943,12 @@ Rectangle {
960943 tryCompareFunction(function(){ return dialerDelegate != null; }, true);
961944 tryCompare(dialerDelegate, "orientationChangesEnabled", true);
962945
963− var appWindowWithShadow = findChild(dialerDelegate, "appWindowWithShadow");
964− verify(appWindowWithShadow);
965− tryCompare(appWindowWithShadow, "state", "keepSceneRotation");
946+ var decoratedWindow = findChild(dialerDelegate, "decoratedWindow");
947+ verify(decoratedWindow);
948+ tryCompare(decoratedWindow, "counterRotate", false);
966949
967950 // app must have portrait aspect ratio
968− verify(appWindowWithShadow.width < appWindowWithShadow.height);
969−
970− compare(appWindowWithShadow.rotation, 0);
971−
972− verifyAppWindowWithinSpreadDelegateBoundaries(dialerDelegate);
951+ verify(decoratedWindow.width < decoratedWindow.height);
973952
974953 // shell should remain in its primery orientation as the app in the main stage
975954 // is the one that dictates its orientation. In this case it's unity8-dash
@@ -977,83 +956,6 @@ Rectangle {
977956 compare(shell.orientation, orientedShell.orientations.primary);
978957 }
979958
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−
1057959 function test_launchedAppHasActiveFocus_data() {
1058960 return [
1059961 {tag: "mako", deviceName: "mako"},
@@ -1449,11 +1351,10 @@ Rectangle {
14491351 function waitUntilAppDelegateIsFullyInit(spreadDelegate) {
14501352 tryCompare(spreadDelegate, "orientationChangesEnabled", true);
14511353
1452− var appWindowWithShadow = findChild(spreadDelegate, "appWindowWithShadow");
1453− verify(appWindowWithShadow);
1454− tryCompare(appWindowWithShadow, "state", "keepSceneRotation");
1354+ var decoratedWindow = findChild(spreadDelegate, "decoratedWindow");
1355+ tryCompare(decoratedWindow, "counterRotate", false);
14551356
1456− var appWindowStates = findInvisibleChild(appWindowWithShadow, "applicationWindowStateGroup");
1357+ var appWindowStates = findInvisibleChild(decoratedWindow, "applicationWindowStateGroup");
14571358 verify(appWindowStates);
14581359 tryCompare(appWindowStates, "state", "surface");
14591360 }
@@ -1491,8 +1392,7 @@ Rectangle {
14911392 }
14921393
14931394 function performLeftEdgeSwipeToSwitchToDash() {
1494− var spreadView = findChild(shell, "spreadView");
1495− var swipeLength = spreadView.width * 0.7;
1395+ var swipeLength = shell.width * 0.7;
14961396
14971397 var touchStartX = 1;
14981398 var touchStartY = shell.height / 2;
@@ -1507,35 +1407,13 @@ Rectangle {
15071407 // swipe just enough to ensure an app switch action.
15081408 // If we swipe too much we will trigger the spread mode
15091409 // and we don't want that.
1510− var spreadView = findChild(shell, "spreadView");
1511− verify(spreadView);
1512−
15131410 verify(topLevelSurfaceList.count >= 2);
15141411 var previousSurfaceId = topLevelSurfaceList.idAt(1);
15151412
15161413 var touchStartX = shell.width - 1;
15171414 var touchStartY = shell.height / 2;
15181415
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,
1534− -units.gu(1), 0,
1535− condition);
1536−
1537− // ensure the app switch animation has ended
1538− tryCompare(spreadView, "shiftedContentX", 0);
1416+ touchFlick(shell, touchStartX, touchStartY, touchStartX - units.gu(8), touchStartY, units.gu(4), 10);
15391417
15401418 tryCompareFunction(function(){ return topLevelSurfaceList.idAt(0); }, previousSurfaceId);
15411419 }
@@ -1546,11 +1424,9 @@ Rectangle {
15461424 shell.width - 1, touchStartY,
15471425 0, touchStartY);
15481426
1549− var spreadView = findChild(shell, "spreadView");
1550− verify(spreadView);
1551− tryCompare(spreadView, "phase", 2);
1552− tryCompare(spreadView, "flicking", false);
1553− tryCompare(spreadView, "moving", false);
1427+ var stage = findChild(shell, "stage");
1428+ tryCompare(stage, "state", "spread");
1429+ waitForRendering(stage);
15541430 }
15551431
15561432 function showPowerDialog() {
@@ -1559,19 +1435,6 @@ Rectangle {
15591435 dialogsPrivate.showPowerDialog();
15601436 }
15611437
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−
15751438 function swipeAwayGreeter() {
15761439 var greeter = findChild(shell, "greeter");
15771440 tryCompare(greeter, "fullyShown", true);
@@ -1606,9 +1469,6 @@ Rectangle {
16061469 topLevelSurfaceList = findInvisibleChild(shell, "topLevelSurfaceList");
16071470 verify(topLevelSurfaceList);
16081471
1609− var stageLoader = findChild(shell, "applicationsDisplayLoader");
1610− verify(stageLoader);
1611−
16121472 tryCompare(shell, "waitingOnGreeter", false); // reset by greeter when ready
16131473
16141474 waitUntilShellIsInOrientation(root.physicalOrientation0);
@@ -1617,9 +1477,9 @@ Rectangle {
16171477
16181478 swipeAwayGreeter();
16191479
1620− var spreadRepeater = findChild(stageLoader, "spreadRepeater");
1621− if (spreadRepeater) {
1622− spreadRepeaterConnections.target = spreadRepeater;
1480+ var appRepeater = findChild(shell, "appRepeater");
1481+ if (appRepeater) {
1482+ appRepeaterConnections.target = appRepeater;
16231483 }
16241484 }
16251485
@@ -1644,15 +1504,6 @@ Rectangle {
16441504 return false;
16451505 }
16461506
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−
16561507 var surfaceItem = findSurfaceItem(item, surface);
16571508 if (!surfaceItem) {
16581509 console.warn("no surfaceItem rendering app surface");
@@ -1660,15 +1511,16 @@ Rectangle {
16601511 }
16611512 var point = surfaceItem.mapToItem(orientedShell, 0, 0);
16621513
1514+ print("exptectedAngle", expectedAngle, point.x, point.y)
16631515 switch (expectedAngle) {
16641516 case 0:
1665− return point.x === 0. && point.y === topMargin;
1517+ return point.x === 0 && point.y === PanelState.panelHeight;
16661518 case 90:
1667− return point.x === orientedShell.width - topMargin && point.y === 0;
1519+ return point.x === orientedShell.width - PanelState.panelHeight && point.y === 0;
16681520 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;
16701522 default: // 270
1671− return point.x === topMargin && point.y === orientedShell.height;
1523+ return point.x === PanelState.panelHeight && point.y === orientedShell.height;
16721524 }
16731525 }
16741526
@@ -1690,24 +1542,12 @@ Rectangle {
16901542 }
16911543
16921544 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));
16971546 verify(delegateToClose);
16981547
1699− var appIdToClose = ApplicationManager.get(0).appId;;
1548+ var appIdToClose = ApplicationManager.get(0).appId;
17001549 var appCountBefore = ApplicationManager.count;
17011550
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−
17111551 // Swipe up close to its left edge, as it is the only area of it guaranteed to be exposed
17121552 // in the spread. Eg: its center could be covered by some other delegate.
17131553 touchFlick(delegateToClose,
tests/qmltests/tst_Shell.qml+182−163
@@ -36,7 +36,7 @@ import Utils 0.1
3636import "../../qml"
3737import "../../qml/Components"
3838import "../../qml/Components/PanelState"
39−import "Stages"
39+import "Stage"
4040
4141Rectangle {
4242 id: root
@@ -51,6 +51,8 @@ Rectangle {
5151 shellLoader.active = true;
5252 }
5353
54+ property var shell: shellLoader.item ? shellLoader.item : null
55+
5456 Item {
5557 id: shellContainer
5658 anchors.left: root.left
@@ -108,6 +110,7 @@ Rectangle {
108110 sourceComponent: Component {
109111 Shell {
110112 id: __shell
113+ objectName: "shell"
111114 usageScenario: usageScenarioSelector.model[usageScenarioSelector.selectedIndex]
112115 nativeWidth: width
113116 nativeHeight: height
@@ -184,22 +187,44 @@ Rectangle {
184187 callManager.foregroundCall = callManager.foregroundCall ? null : phoneCall;
185188 }
186189 }
187− }
188− Button {
189− text: "Show Launcher"
190− activeFocusOnPress: false
191− onClicked: {
192− if (shellLoader.status !== Loader.Ready)
193− return;
190+ Button {
191+ text: "Show Launcher"
192+ activeFocusOnPress: false
193+ onClicked: {
194+ if (shellLoader.status !== Loader.Ready)
195+ return;
194196
195− var launcher = testCase.findChild(shellLoader.item, "launcher");
196− launcher.state = "visible";
197+ var launcher = testCase.findChild(shellLoader.item, "launcher");
198+ launcher.state = "visible";
199+ }
200+ }
201+ Button {
202+ text: "Print focused"
203+ activeFocusOnPress: false
204+ onClicked: {
205+ var childs = new Array(0);
206+ childs.push(shellLoader.item)
207+ while (childs.length > 0) {
208+ if (childs[0].activeFocus && childs[0].focus && childs[0].objectName != "shell") {
209+ console.log("Active focus is on item:", childs[0]);
210+ return;
211+ }
212+ for (var i in childs[0].children) {
213+ childs.push(childs[0].children[i])
214+ }
215+ childs.splice(0, 1);
216+ }
217+ console.log("No active focused item found within shell.")
218+ }
197219 }
198220 }
221+ Label {
222+ text: "LightDM mock mode"
223+ }
224+
199225 ListItem.ItemSelector {
200226 anchors { left: parent.left; right: parent.right }
201227 activeFocusOnPress: false
202− text: "LightDM mock mode"
203228 model: ["single", "single-passphrase", "single-pin", "full"]
204229 onSelectedIndexChanged: {
205230 shellLoader.active = false;
@@ -208,33 +233,41 @@ Rectangle {
208233 shellLoader.active = true;
209234 }
210235 }
236+ Label {
237+ text: "Size"
238+ }
239+
211240 ListItem.ItemSelector {
241+ id: sizeSelector
212242 anchors { left: parent.left; right: parent.right }
213243 activeFocusOnPress: false
214− text: "Size"
215244 model: ["phone", "tablet", "desktop"]
216245 onSelectedIndexChanged: {
217− shellLoader.active = false;
218246 shellLoader.state = model[selectedIndex];
219− shellLoader.active = true;
220247 }
221248 }
249+ Label {
250+ text: "Usage scenario"
251+ }
252+
222253 ListItem.ItemSelector {
223254 id: usageScenarioSelector
224255 anchors { left: parent.left; right: parent.right }
225256 activeFocusOnPress: false
226− text: "Usage scenario"
227257 model: ["phone", "tablet", "desktop"]
228258 }
229259 MouseTouchEmulationCheckbox {
230260 id: mouseEmulation
231261 checked: true
232262 }
263+ Label {
264+ text: "Ctrl key as"
265+ }
266+
233267 ListItem.ItemSelector {
234268 id: ctrlModifier
235269 anchors { left: parent.left; right: parent.right }
236270 activeFocusOnPress: false
237− text: "Ctrl key as"
238271 model: ["Ctrl", "Alt", "Super"]
239272 onSelectedIndexChanged: {
240273 var keyMapper = testCase.findChild(shellContainer, "physicalKeysMapper");
@@ -261,6 +294,7 @@ Rectangle {
261294 Button {
262295 text: "Start all apps"
263296 width: parent.width
297+ activeFocusOnPress: false
264298 onClicked: {
265299 for (var i = 0; i < ApplicationManager.availableApplications.length; i++) {
266300 var appId = ApplicationManager.availableApplications[i];
@@ -270,7 +304,7 @@ Rectangle {
270304 }
271305
272306 Repeater {
273− id: appRepeater
307+ id: appCheckBoxRepeater
274308 model: ApplicationManager.availableApplications
275309 ApplicationCheckBox {
276310 appId: modelData
@@ -571,6 +605,38 @@ Rectangle {
571605 compare(ApplicationManager.get(0).appId, "unity8-dash");
572606 }
573607
608+ function test_phoneLeftEdgeDrag_data() {
609+ return [
610+ {tag: "without launcher",
611+ revealLauncher: false, swipeLength: units.gu(30), appHides: true, focusedApp: "dialer-app",
612+ launcherHides: true, greeterShown: false},
613+
614+ {tag: "with launcher",
615+ revealLauncher: true, swipeLength: units.gu(30), appHides: true, focusedApp: "dialer-app",
616+ launcherHides: true, greeterShown: false},
617+
618+ {tag: "small swipe",
619+ revealLauncher: false, swipeLength: units.gu(25), appHides: false, focusedApp: "dialer-app",
620+ launcherHides: false, greeterShown: false},
621+
622+ {tag: "long swipe",
623+ revealLauncher: false, swipeLength: units.gu(30), appHides: true, focusedApp: "dialer-app",
624+ launcherHides: true, greeterShown: false},
625+
626+ {tag: "small swipe with greeter",
627+ revealLauncher: false, swipeLength: units.gu(25), appHides: false, focusedApp: "dialer-app",
628+ launcherHides: false, greeterShown: true},
629+
630+ {tag: "long swipe with greeter",
631+ revealLauncher: false, swipeLength: units.gu(30), appHides: true, focusedApp: "dialer-app",
632+ launcherHides: true, greeterShown: true},
633+
634+ {tag: "swipe over dash",
635+ revealLauncher: false, swipeLength: units.gu(30), appHides: true, focusedApp: "unity8-dash",
636+ launcherHides: false, greeterShown: false},
637+ ];
638+ }
639+
574640 function test_snapDecisionDismissalReturnsFocus() {
575641 loadShell("phone");
576642 swipeAwayGreeter();
@@ -635,38 +701,6 @@ Rectangle {
635701 mockNotificationsModel.append(n)
636702 }
637703
638− function test_phoneLeftEdgeDrag_data() {
639− return [
640− {tag: "without launcher",
641− revealLauncher: false, swipeLength: units.gu(30), appHides: true, focusedApp: "dialer-app",
642− launcherHides: true, greeterShown: false},
643−
644− {tag: "with launcher",
645− revealLauncher: true, swipeLength: units.gu(30), appHides: true, focusedApp: "dialer-app",
646− launcherHides: true, greeterShown: false},
647−
648− {tag: "small swipe",
649− revealLauncher: false, swipeLength: units.gu(25), appHides: false, focusedApp: "dialer-app",
650− launcherHides: false, greeterShown: false},
651−
652− {tag: "long swipe",
653− revealLauncher: false, swipeLength: units.gu(30), appHides: true, focusedApp: "dialer-app",
654− launcherHides: true, greeterShown: false},
655−
656− {tag: "small swipe with greeter",
657− revealLauncher: false, swipeLength: units.gu(25), appHides: false, focusedApp: "dialer-app",
658− launcherHides: false, greeterShown: true},
659−
660− {tag: "long swipe with greeter",
661− revealLauncher: false, swipeLength: units.gu(30), appHides: true, focusedApp: "dialer-app",
662− launcherHides: true, greeterShown: true},
663−
664− {tag: "swipe over dash",
665− revealLauncher: false, swipeLength: units.gu(30), appHides: true, focusedApp: "unity8-dash",
666− launcherHides: false, greeterShown: false},
667− ];
668− }
669−
670704 function test_phoneLeftEdgeDrag(data) {
671705 loadShell("phone");
672706 swipeAwayGreeter();
@@ -1365,7 +1399,7 @@ Rectangle {
13651399 function test_tapOnRightEdgeReachesApplicationSurface() {
13661400 loadShell("phone");
13671401 swipeAwayGreeter();
1368− var topmostSpreadDelegate = findChild(shell, "spreadDelegate_" + topLevelSurfaceList.idAt(0));
1402+ var topmostSpreadDelegate = findChild(shell, "appDelegate_" + topLevelSurfaceList.idAt(0));
13691403 verify(topmostSpreadDelegate);
13701404
13711405 waitUntilFocusedApplicationIsShowingItsSurface();
@@ -1373,7 +1407,7 @@ Rectangle {
13731407 var topmostSurfaceItem = findChild(topmostSpreadDelegate, "surfaceItem");
13741408 verify(topmostSurfaceItem);
13751409
1376− var rightEdgeDragArea = findChild(shell, "spreadDragArea");
1410+ var rightEdgeDragArea = findChild(shell, "rightEdgeDragArea");
13771411 topmostSurfaceItem.touchPressCount = 0;
13781412 topmostSurfaceItem.touchReleaseCount = 0;
13791413
@@ -1394,9 +1428,9 @@ Rectangle {
13941428 function test_rightEdgeDragDoesNotReachApplicationSurface() {
13951429 loadShell("phone");
13961430 swipeAwayGreeter();
1397− var topmostSpreadDelegate = findChild(shell, "spreadDelegate_" + topLevelSurfaceList.idAt(0));
1431+ var topmostSpreadDelegate = findChild(shell, "appDelegate_" + topLevelSurfaceList.idAt(0));
13981432 var topmostSurfaceItem = findChild(topmostSpreadDelegate, "surfaceItem");
1399− var rightEdgeDragArea = findChild(shell, "spreadDragArea");
1433+ var rightEdgeDragArea = findChild(shell, "rightEdgeDragArea");
14001434
14011435 topmostSurfaceItem.touchPressCount = 0;
14021436 topmostSurfaceItem.touchReleaseCount = 0;
@@ -1414,7 +1448,7 @@ Rectangle {
14141448
14151449 function waitUntilFocusedApplicationIsShowingItsSurface()
14161450 {
1417− var spreadDelegate = findChild(shell, "spreadDelegate_" + topLevelSurfaceList.idAt(0));
1451+ var spreadDelegate = findChild(shell, "appDelegate_" + topLevelSurfaceList.idAt(0));
14181452 var appState = findInvisibleChild(spreadDelegate, "applicationWindowStateGroup");
14191453 tryCompare(appState, "state", "surface");
14201454 var transitions = appState.transitions;
@@ -1433,8 +1467,7 @@ Rectangle {
14331467
14341468 // check if it's indeed showing the spread
14351469 var stage = findChild(shell, "stage");
1436− var spreadView = findChild(stage, "spreadView");
1437− tryCompare(spreadView, "phase", 2);
1470+ tryCompare(stage, "state", "spread");
14381471 }
14391472
14401473 function test_tapUbuntuIconInLauncherOverAppSpread() {
@@ -1470,8 +1503,7 @@ Rectangle {
14701503 // check that the stage has left spread mode.
14711504 {
14721505 var stage = findChild(shell, "stage");
1473− var spreadView = findChild(stage, "spreadView");
1474− tryCompare(spreadView, "phase", 0);
1506+ tryCompare(stage, "state", "staged");
14751507 }
14761508
14771509 // check that the launcher got dismissed
@@ -1538,21 +1570,6 @@ Rectangle {
15381570 }
15391571 }
15401572
1541− function test_stageLoader_data() {
1542− return [
1543− {tag: "phone", source: "Stages/PhoneStage.qml", formFactor: "phone", usageScenario: "phone"},
1544− {tag: "tablet", source: "Stages/TabletStage.qml", formFactor: "tablet", usageScenario: "tablet"},
1545− {tag: "desktop", source: "Stages/DesktopStage.qml", formFactor: "tablet", usageScenario: "desktop"}
1546− ]
1547− }
1548−
1549− function test_stageLoader(data) {
1550− loadShell(data.formFactor);
1551− shell.usageScenario = data.usageScenario;
1552− var stageLoader = findChild(shell, "applicationsDisplayLoader");
1553− verify(String(stageLoader.source).indexOf(data.source) >= 0);
1554− }
1555−
15561573 function test_launcherInverted_data() {
15571574 return [
15581575 {tag: "phone", formFactor: "phone", usageScenario: "phone", launcherInverted: true},
@@ -1666,47 +1683,41 @@ Rectangle {
16661683 function test_altTabWrapAround() {
16671684 loadDesktopShellWithApps();
16681685
1669− var desktopStage = findChild(shell, "stage");
1670− verify(desktopStage !== null)
1671−
1672− var desktopSpread = findChild(shell, "spread");
1673− verify(desktopSpread !== null)
1674−
1675− var spreadContainer = findInvisibleChild(shell, "spreadContainer")
1676− verify(spreadContainer !== null)
1686+ var stage = findChild(shell, "stage");
1687+ verify(stage !== null)
16771688
1678− var spreadRepeater = findInvisibleChild(shell, "spreadRepeater")
1679− verify(spreadRepeater !== null)
1689+ var spread = findChild(shell, "spreadItem");
1690+ verify(spread !== null)
16801691
16811692 // remember the focused appId
16821693 var focused = ApplicationManager.get(ApplicationManager.findApplication(ApplicationManager.focusedApplicationId));
16831694
1684− tryCompare(desktopSpread, "state", "")
1695+ tryCompare(stage, "state", "windowed")
16851696
16861697 // Just press Alt, make sure the spread comes up
16871698 keyPress(Qt.Key_Alt);
16881699 keyClick(Qt.Key_Tab);
1689− tryCompare(desktopSpread, "state", "altTab")
1690− tryCompare(spreadRepeater, "highlightedIndex", 1)
1700+ tryCompare(stage, "state", "spread")
1701+ tryCompare(spread, "highlightedIndex", 1)
16911702 waitForRendering(shell)
16921703
16931704 // Now press and hold Tab, make sure the highlight moves all the way but stops at the last one
16941705 // We can't simulate a pressed key with keyPress() currently, so let's inject the events
16951706 // at API level. Jump for 10 times, verify that it's still at the last one and didn't wrap around.
16961707 for (var i = 0; i < 10; i++) {
1697− desktopSpread.selectNext(true); // true == isAutoRepeat
1708+ spread.selectNext(true); // true == isAutoRepeat
16981709 wait(0); // Trigger the event loop to make sure all the things happen
16991710 }
1700− tryCompare(spreadRepeater, "highlightedIndex", 6)
1711+ tryCompare(spread, "highlightedIndex", 6)
17011712
17021713 // Now release it once, and verify that it does wrap around with an additional Tab press
17031714 keyRelease(Qt.Key_Tab);
17041715 keyClick(Qt.Key_Tab);
1705− tryCompare(spreadRepeater, "highlightedIndex", 0)
1716+ tryCompare(spread, "highlightedIndex", 0)
17061717
17071718 // Release control, check if spread disappears
17081719 keyRelease(Qt.Key_Alt)
1709− tryCompare(desktopSpread, "state", "")
1720+ tryCompare(stage, "state", "windowed")
17101721
17111722 // Make sure that after wrapping around once, we have the same one focused as at the beginning
17121723 var focusedAppSurface = focused.surfaceList.get(0);
@@ -1717,30 +1728,30 @@ Rectangle {
17171728 function test_altBackTabNavigation() {
17181729 loadDesktopShellWithApps();
17191730
1720− var spreadRepeater = findInvisibleChild(shell, "spreadRepeater");
1721− verify(spreadRepeater !== null);
1731+ var spreadItem = findChild(shell, "spreadItem");
1732+ verify(spreadItem !== null);
17221733
17231734 keyPress(Qt.Key_Alt)
17241735 keyClick(Qt.Key_Tab);
1725− tryCompare(spreadRepeater, "highlightedIndex", 1);
1736+ tryCompare(spreadItem, "highlightedIndex", 1);
17261737
17271738 keyClick(Qt.Key_Tab);
1728− tryCompare(spreadRepeater, "highlightedIndex", 2);
1739+ tryCompare(spreadItem, "highlightedIndex", 2);
17291740
17301741 keyClick(Qt.Key_Tab);
1731− tryCompare(spreadRepeater, "highlightedIndex", 3);
1742+ tryCompare(spreadItem, "highlightedIndex", 3);
17321743
17331744 keyClick(Qt.Key_Tab);
1734− tryCompare(spreadRepeater, "highlightedIndex", 4);
1745+ tryCompare(spreadItem, "highlightedIndex", 4);
17351746
17361747 keyClick(Qt.Key_Backtab);
1737− tryCompare(spreadRepeater, "highlightedIndex", 3);
1748+ tryCompare(spreadItem, "highlightedIndex", 3);
17381749
17391750 keyClick(Qt.Key_Backtab);
1740− tryCompare(spreadRepeater, "highlightedIndex", 2);
1751+ tryCompare(spreadItem, "highlightedIndex", 2);
17411752
17421753 keyClick(Qt.Key_Backtab);
1743− tryCompare(spreadRepeater, "highlightedIndex", 1);
1754+ tryCompare(spreadItem, "highlightedIndex", 1);
17441755
17451756 keyRelease(Qt.Key_Alt);
17461757 }
@@ -1776,21 +1787,24 @@ Rectangle {
17761787 function test_closeFromSpread() {
17771788 loadDesktopShellWithApps()
17781789
1779− var spreadRepeater = findInvisibleChild(shell, "spreadRepeater");
1780− verify(spreadRepeater !== null);
1790+ var appRepeater = findInvisibleChild(shell, "appRepeater");
1791+ verify(appRepeater !== null);
1792+
1793+ var spreadItem = findChild(shell, "spreadItem");
1794+ verify(spreadItem !== null);
17811795
17821796 keyPress(Qt.Key_Alt)
17831797 keyClick(Qt.Key_Tab);
17841798
17851799 var surfaceId = topLevelSurfaceList.idAt(2);
1786− var spreadDelegate2 = spreadRepeater.itemAt(2);
1800+ var spreadDelegate2 = appRepeater.itemAt(2);
17871801 var closeMouseArea = findChild(spreadDelegate2, "closeMouseArea");
17881802
17891803 // Move the mosue over tile 2 and verify the close button becomes visible
17901804 var x = 0;
17911805 var y = shell.height * .5;
17921806 mouseMove(shell, x, y)
1793− while (spreadRepeater.highlightedIndex !== 2 && x <= 4000) {
1807+ while (spreadItem.highlightedIndex !== 2 && x <= 4000) {
17941808 x+=10;
17951809 mouseMove(shell, x, y)
17961810 wait(0); // spin the loop so bindings get evaluated
@@ -1820,37 +1834,37 @@ Rectangle {
18201834 loadDesktopShellWithApps()
18211835
18221836 var stage = findChild(shell, "stage");
1823− var spread = findChild(stage, "spread");
1824− waitForRendering(spread)
1837+ var spreadItem = findChild(stage, "spreadItem");
1838+// waitForRendering(spread)
18251839
1826− var spreadRepeater = findInvisibleChild(shell, "spreadRepeater");
1827− verify(spreadRepeater !== null);
1840+ var appRepeater = findInvisibleChild(shell, "appRepeater");
1841+ verify(appRepeater !== null);
18281842
18291843 keyPress(Qt.Key_Alt)
18301844 keyClick(Qt.Key_Tab);
18311845
18321846 var surface = topLevelSurfaceList.surfaceAt(2);
1833− var spreadDelegate2 = spreadRepeater.itemAt(2);
1834− var clippedSpreadDelegate = findChild(spreadDelegate2, "clippedSpreadDelegate");
1847+ var spreadDelegate2 = appRepeater.itemAt(2);
1848+ var decoratedWindow = findChild(spreadDelegate2, "decoratedWindow");
18351849
1836− tryCompare(spread, "state", "altTab");
1850+ tryCompare(stage, "state", "spread");
18371851
18381852 // Move the mouse over tile 2 and verify the highlight becomes visible
18391853 var x = 0;
1840− var y = shell.height * (data.tileInfo ? .95 : 0.5)
1854+ var y = shell.height * (data.tileInfo ? .9 : 0.5)
18411855 mouseMove(shell, x, y)
1842− while (spreadRepeater.highlightedIndex !== 2 && x <= 4000) {
1856+ while (spreadItem.highlightedIndex !== 2 && x <= 4000) {
18431857 x+=10;
18441858 mouseMove(shell, x, y)
18451859 wait(0); // spin the loop so bindings get evaluated
18461860 }
1847− tryCompare(clippedSpreadDelegate, "highlightShown", true);
1861+ tryCompare(decoratedWindow, "showHighlight", true);
18481862
18491863 // Click the tile
1850− mouseClick(clippedSpreadDelegate, clippedSpreadDelegate.width / 2, clippedSpreadDelegate.height / 2)
1864+ mouseClick(decoratedWindow, units.gu(2), decoratedWindow.height / 2)
18511865
18521866 // Verify that we left the spread and app2 is the focused one now
1853− tryCompare(stage, "state", "");
1867+ tryCompare(stage, "state", "windowed");
18541868 tryCompare(surface, "focused", true);
18551869
18561870 keyRelease(Qt.Key_Alt);
@@ -1912,41 +1926,6 @@ Rectangle {
19121926 tryCompare(hoverMouseArea, "visible", false)
19131927 }
19141928
1915− function test_workspacePreviewsHighlightedApp() {
1916− loadDesktopShellWithApps()
1917−
1918− var targetZ = topLevelSurfaceList.count + 1;
1919−
1920− var spreadRepeater = findInvisibleChild(shell, "spreadRepeater");
1921− verify(spreadRepeater !== null);
1922−
1923− var appRepeater = findInvisibleChild(shell, "appRepeater");
1924− verify(appRepeater !== null);
1925−
1926− keyPress(Qt.Key_Alt)
1927− keyClick(Qt.Key_Tab);
1928−
1929− tryCompare(spreadRepeater, "highlightedIndex", 1);
1930− tryCompare(appRepeater.itemAt(1), "z", targetZ)
1931−
1932− var x = 0;
1933− var y = shell.height * .75;
1934− mouseMove(shell, x, y)
1935−
1936− for (var i = 0; i < 7; i++) {
1937− while (spreadRepeater.highlightedIndex != i && x <= 4000) {
1938− tryCompare(appRepeater.itemAt(spreadRepeater.highlightedIndex), "z", targetZ)
1939− x+=10;
1940− mouseMove(shell, x, y)
1941− wait(0); // spin the loop so bindings get evaluated
1942− }
1943− }
1944−
1945− verify(y < 4000);
1946−
1947− keyRelease(Qt.Key_Alt);
1948− }
1949−
19501929 function test_focusAppFromLauncherExitsSpread_data() {
19511930 return [
19521931 {tag: "autohide launcher", launcherLocked: false },
@@ -1957,7 +1936,7 @@ Rectangle {
19571936 function test_focusAppFromLauncherExitsSpread(data) {
19581937 loadDesktopShellWithApps()
19591938 var launcher = findChild(shell, "launcher");
1960− var desktopSpread = findChild(shell, "spread");
1939+ var stage = findChild(shell, "stage");
19611940 var bfb = findChild(launcher, "buttonShowDashHome");
19621941
19631942 GSettingsController.setAutohideLauncher(!data.launcherLocked);
@@ -1966,7 +1945,7 @@ Rectangle {
19661945 keyPress(Qt.Key_Alt)
19671946 keyClick(Qt.Key_Tab);
19681947
1969− tryCompare(desktopSpread, "state", "altTab")
1948+ tryCompare(stage, "state", "spread")
19701949
19711950 if (!data.launcherLocked) {
19721951 revealLauncherByEdgePushWithMouse();
@@ -1979,7 +1958,7 @@ Rectangle {
19791958 if (!data.launcherLocked) {
19801959 tryCompare(launcher, "state", "")
19811960 }
1982− tryCompare(desktopSpread, "state", "")
1961+ tryCompare(stage, "state", "windowed")
19831962
19841963 tryCompare(ApplicationManager, "focusedApplicationId", "unity8-dash")
19851964
@@ -2147,10 +2126,10 @@ Rectangle {
21472126
21482127 // Sanity checking
21492128 if (data.usageScenario === "tablet") {
2150− var app1Delegate = findChild(shell, "spreadDelegate_" + app1SurfaceId);
2129+ var app1Delegate = findChild(shell, "appDelegate_" + app1SurfaceId);
21512130 compare(app1Delegate.stage, ApplicationInfoInterface.MainStage);
21522131
2153− var app2Delegate = findChild(shell, "spreadDelegate_" + app2SurfaceId);
2132+ var app2Delegate = findChild(shell, "appDelegate_" + app2SurfaceId);
21542133 compare(app2Delegate.stage, ApplicationInfoInterface.MainStage);
21552134 }
21562135 verify(!app1.isTouchApp);
@@ -2188,10 +2167,10 @@ Rectangle {
21882167
21892168 // Sanity checking
21902169 if (data.usageScenario === "tablet") {
2191− var app1Delegate = findChild(shell, "spreadDelegate_" + app1SurfaceId);
2170+ var app1Delegate = findChild(shell, "appDelegate_" + app1SurfaceId);
21922171 compare(app1Delegate.stage, ApplicationInfoInterface.MainStage);
21932172
2194− var app2Delegate = findChild(shell, "spreadDelegate_" + app2SurfaceId);
2173+ var app2Delegate = findChild(shell, "appDelegate_" + app2SurfaceId);
21952174 compare(app2Delegate.stage, ApplicationInfoInterface.MainStage);
21962175 }
21972176
@@ -2278,19 +2257,19 @@ Rectangle {
22782257 function test_superTabToCycleLauncher(data) {
22792258 loadShell("desktop");
22802259 shell.usageScenario = "desktop";
2260+ waitForRendering(shell);
22812261 GSettingsController.setAutohideLauncher(!data.launcherLocked);
22822262 waitForRendering(shell);
22832263
2264+ var stage = findChild(shell, "stage");
22842265 var launcher = findChild(shell, "launcher");
22852266 var launcherPanel = findChild(launcher, "launcherPanel");
22862267 var firstAppInLauncher = LauncherModel.get(0).appId;
2287−
22882268 compare(launcher.state, data.launcherLocked ? "visible": "");
22892269 compare(launcherPanel.highlightIndex, -2);
22902270 compare(ApplicationManager.focusedApplicationId, "unity8-dash");
22912271
22922272 // Use Super + Tab Tab to cycle to the first entry in the launcher
2293− wait(1000);
22942273 keyPress(Qt.Key_Super_L, Qt.MetaModifier);
22952274 keyClick(Qt.Key_Tab);
22962275 tryCompare(launcher, "state", "visible");
@@ -2311,6 +2290,7 @@ Rectangle {
23112290 tryCompare(launcher, "state", data.launcherLocked ? "visible" : "");
23122291 tryCompare(launcherPanel, "highlightIndex", -2);
23132292 tryCompare(ApplicationManager, "focusedApplicationId", "unity8-dash");
2293+ tryCompare(stage, "focus", true)
23142294 }
23152295
23162296 function test_longpressSuperOpensLauncherAndShortcutsOverlay() {
@@ -2371,6 +2351,7 @@ Rectangle {
23712351 waitForRendering(shell);
23722352 var appContainer = findChild(shell, "appContainer");
23732353 var launcher = findChild(shell, "launcher");
2354+ var launcherPanel = findChild(launcher, "launcherPanel");
23742355
23752356 var appSurfaceId = topLevelSurfaceList.nextId;
23762357 var app = ApplicationManager.startApplication("music-app");
@@ -2381,10 +2362,12 @@ Rectangle {
23812362 waitForRendering(shell);
23822363
23832364 GSettingsController.setAutohideLauncher(true);
2365+ tryCompare(launcherPanel, "x", -launcher.panelWidth)
23842366 waitForRendering(shell)
23852367 var hiddenSize = appDelegate.width;
23862368
23872369 GSettingsController.setAutohideLauncher(false);
2370+ tryCompare(launcherPanel, "x", 0)
23882371 waitForRendering(shell)
23892372 var shownSize = appDelegate.width;
23902373
@@ -2422,9 +2405,9 @@ Rectangle {
24222405
24232406 function test_inputEventsOnEdgesEndUpInAppSurface_data() {
24242407 return [
2425− { tag: "phone", repeaterName: "spreadRepeater" },
2426− { tag: "tablet", repeaterName: "spreadRepeater" },
2427− { tag: "desktop", repeaterName: "appRepeater" },
2408+ { tag: "phone" },
2409+ { tag: "tablet" },
2410+ { tag: "desktop" },
24282411 ]
24292412 }
24302413
@@ -2439,7 +2422,7 @@ Rectangle {
24392422 var app = ApplicationManager.startApplication("camera-app");
24402423 waitUntilAppWindowIsFullyLoaded(appSurfaceId);
24412424
2442− var appRepeater = findChild(shell, data.repeaterName);
2425+ var appRepeater = findChild(shell, "appRepeater");
24432426 var topmostAppDelegate = appRepeater.itemAt(0);
24442427 verify(topmostAppDelegate);
24452428
@@ -2714,5 +2697,41 @@ Rectangle {
27142697 tryCompare(topLevelSurfaceList, "count", countBeforeClose - 1);
27152698 tryCompareFunction(function() { return ApplicationManager.focusedApplicationId; }, "calendar-app");
27162699 }
2700+
2701+ function test_oskDisplacesWindow_data() {
2702+ return [
2703+ {tag: "no need to displace", windowHeight: units.gu(10), windowY: units.gu(5), targetDisplacement: units.gu(5), oskEnabled: true},
2704+ {tag: "displace to top", windowHeight: units.gu(50), windowY: units.gu(10), targetDisplacement: PanelState.panelHeight, oskEnabled: true},
2705+ {tag: "displace to top", windowHeight: units.gu(50), windowY: units.gu(10), targetDisplacement: PanelState.panelHeight, oskEnabled: true},
2706+ {tag: "osk not on this screen", windowHeight: units.gu(40), windowY: units.gu(10), targetDisplacement: units.gu(10), oskEnabled: false},
2707+ ]
2708+ }
2709+
2710+ function test_oskDisplacesWindow(data) {
2711+ loadShell("desktop");
2712+ shell.usageScenario = "desktop";
2713+ waitForRendering(shell);
2714+ swipeAwayGreeter();
2715+ shell.oskEnabled = data.oskEnabled;
2716+
2717+ var oldOSKState = SurfaceManager.inputMethodSurface.state;
2718+ SurfaceManager.inputMethodSurface.state = Mir.RestoredState;
2719+ var appRepeater = findChild(shell, "appRepeater");
2720+ var dashAppDelegate = appRepeater.itemAt(0);
2721+ verify(dashAppDelegate);
2722+ dashAppDelegate.requestedHeight = data.windowHeight;
2723+ dashAppDelegate.requestedY = data.windowY;
2724+ SurfaceManager.inputMethodSurface.setInputBounds(Qt.rect(0, 0, 0, 0));
2725+ var initialY = dashAppDelegate.y;
2726+ print("intial", initialY, "panel", PanelState.panelHeight);
2727+ verify(initialY > PanelState.panelHeight);
2728+
2729+ SurfaceManager.inputMethodSurface.setInputBounds(Qt.rect(0, root.height / 2, root.width, root.height / 2));
2730+ tryCompare(dashAppDelegate, "y", data.targetDisplacement);
2731+
2732+ SurfaceManager.inputMethodSurface.setInputBounds(Qt.rect(0, 0, 0, 0));
2733+ tryCompare(dashAppDelegate, "y", initialY);
2734+ SurfaceManager.inputMethodSurface.state = oldOSKState;
2735+ }
27172736 }
27182737}
tests/qmltests/tst_ShellWithPin.qml+9−11
@@ -393,24 +393,23 @@ Item {
393393 // dialer to a side stage and give access to other apps. So just
394394 // confirm that such an attack doesn't work.
395395
396− var applicationsDisplayLoader = findChild(shell, "applicationsDisplayLoader")
396+ var stage = findChild(shell, "stage")
397397
398398 // We start in phone mode
399− compare(shell.usageScenario, "phone");
400− compare(applicationsDisplayLoader.usageScenario, "phone");
399+ compare(stage.usageScenario, "phone");
401400
402401 tap(findChild(shell, "emergencyCallLabel"));
403402 confirmLockedApp("dialer-app")
404403
405404 // OK, we're in. Now try (but fail) to switch to tablet mode
406405 shell.usageScenario = "tablet";
407− compare(applicationsDisplayLoader.usageScenario, "phone");
406+ compare(stage.usageScenario, "phone");
408407
409408 // And when we kill the app, we go back to locked tablet mode
410409 killApps()
411410 var greeter = findChild(shell, "greeter")
412411 tryCompare(greeter, "fullyShown", true)
413− compare(applicationsDisplayLoader.usageScenario, "tablet");
412+ compare(stage.usageScenario, "tablet");
414413 }
415414
416415 function test_emergencyDialerIncoming() {
@@ -497,13 +496,13 @@ Item {
497496
498497 function test_suspend() {
499498 var greeter = findChild(shell, "greeter");
500− var applicationsDisplayLoader = findChild(shell, "applicationsDisplayLoader")
499+ var stage = findChild(shell, "stage")
501500
502501 // Put it to sleep
503502 Powerd.setStatus(Powerd.Off, Powerd.Unknown);
504503
505− // If locked, applicationsDisplayLoader.item.suspended should be true
506− tryCompare(applicationsDisplayLoader.item, "suspended", true);
504+ // If locked, stage.suspended should be true
505+ tryCompare(stage, "suspended", true);
507506
508507 // And wake up
509508 Powerd.setStatus(Powerd.On, Powerd.Unknown);
@@ -513,13 +512,12 @@ Item {
513512 swipeAwayGreeter(true);
514513
515514 // We have a lockscreen, make sure we're still suspended
516− tryCompare(applicationsDisplayLoader.item, "suspended", true);
515+ tryCompare(stage, "suspended", true);
517516
518517 enterPin("1234")
519518
520519 // Now that the lockscreen has gone too, make sure we're waking up
521− tryCompare(applicationsDisplayLoader.item, "suspended", false);
522−
520+ tryCompare(stage, "suspended", false);
523521 }
524522
525523 /* We had a bug (1395075) where if a user kept swiping as the greeter