@@ -46,7 +46,7 @@ AbstractStage {
46 if (delta < 0) { delta += 360; }
46 if (delta < 0) { delta += 360; }
47 delta = delta % 360;
47 delta = delta % 360;
49− var supportedOrientations = spreadDelegate.application.supportedOrientations;
49+ var supportedOrientations = spreadDelegate.supportedOrientations;
50 if (supportedOrientations === Qt.PrimaryOrientation) {
50 if (supportedOrientations === Qt.PrimaryOrientation) {
51 supportedOrientations = spreadDelegate.orientations.primary;
51 supportedOrientations = spreadDelegate.orientations.primary;
@@ -78,9 +78,24 @@ AbstractStage {
79 orientationChangesEnabled: priv.mainAppOrientationChangesEnabled
79 orientationChangesEnabled: priv.mainAppOrientationChangesEnabled
81+ supportedOrientations: {
81− supportedOrientations: mainApp ? mainApp.supportedOrientations
83+ var orientations = mainApp.supportedOrientations;
84+ orientations |= Qt.LandscapeOrientation | Qt.InvertedLandscapeOrientation;
85+ if (priv.sideStageAppId && !spreadView.surfaceDragging) {
86+ // If we have a sidestage app, support Portrait orientation
87+ // so that it will switch the sidestage app to mainstage on rotate
82− : (Qt.PortraitOrientation | Qt.LandscapeOrientation
88+ orientations |= Qt.PortraitOrientation|Qt.InvertedPortraitOrientation;
92+ // we just don't care
93+ return Qt.PortraitOrientation |
94+ Qt.LandscapeOrientation |
95+ Qt.InvertedPortraitOrientation |
83− | Qt.InvertedPortraitOrientation | Qt.InvertedLandscapeOrientation)
96+ Qt.InvertedLandscapeOrientation;
85 onWidthChanged: {
100 onWidthChanged: {
86 spreadView.selectedIndex = -1;
101 spreadView.selectedIndex = -1;
@@ -88,13 +103,6 @@ AbstractStage {
88 spreadView.contentX = -spreadView.shift;
103 spreadView.contentX = -spreadView.shift;
91− onShellOrientationChanged: {
92− if (shellOrientation == Qt.PortraitOrientation || shellOrientation == Qt.InvertedPortraitOrientation) {
93− ApplicationManager.focusApplication(priv.mainStageAppId);
94− priv.sideStageAppId = "";
98 onInverseProgressChanged: {
106 onInverseProgressChanged: {
99 // This can't be a simple binding because that would be triggered after this handler
107 // This can't be a simple binding because that would be triggered after this handler
100 // while we need it active before doing the anition left/right
108 // while we need it active before doing the anition left/right
@@ -170,20 +178,7 @@ AbstractStage {
171 property int highlightIndex: 0
179 property int highlightIndex: 0
173− onFocusedAppIdChanged: {
181+ onFocusedAppIdChanged: updateStageApps()
174− if (priv.focusedAppId.length > 0) {
175− var focusedApp = ApplicationManager.findApplication(focusedAppId);
176− if (focusedApp.stage == ApplicationInfoInterface.SideStage) {
177− priv.sideStageAppId = focusedAppId;
179− priv.mainStageAppId = focusedAppId;
180− root.mainApp = focusedApp;
184− appId0 = ApplicationManager.count >= 1 ? ApplicationManager.get(0).appId : "";
185− appId1 = ApplicationManager.count > 1 ? ApplicationManager.get(1).appId : "";
188 onFocusedAppDelegateChanged: {
183 onFocusedAppDelegateChanged: {
189 if (focusedAppDelegate) {
184 if (focusedAppDelegate) {
@@ -229,6 +224,46 @@ AbstractStage {
229 onHighlightIndexChanged: {
224 onHighlightIndexChanged: {
230 spreadView.contentX = highlightIndex * spreadView.contentWidth / (spreadRepeater.count + 2)
225 spreadView.contentX = highlightIndex * spreadView.contentWidth / (spreadRepeater.count + 2)
228+ function getTopApp(stage) {
229+ for (var i = 0; i < ApplicationManager.count; i++) {
230+ var app = ApplicationManager.get(i)
231+ if (app.stage === stage) {
238+ function setAppStage(appId, stage, save) {
239+ var app = ApplicationManager.findApplication(appId);
243+ WindowStateStorage.saveStage(appId, stage);
248+ function updateStageApps() {
249+ var app = priv.getTopApp(ApplicationInfoInterface.MainStage);
250+ priv.mainStageAppId = app ? app.appId : ""
253+ if (sideStage.shown) {
254+ app = priv.getTopApp(ApplicationInfoInterface.SideStage);
255+ priv.sideStageAppId = app ? app.appId : ""
257+ priv.sideStageAppId = "";
260+ appId0 = ApplicationManager.count >= 1 ? ApplicationManager.get(0).appId : "";
261+ appId1 = ApplicationManager.count > 1 ? ApplicationManager.get(1).appId : "";
264+ readonly property bool sideStageEnabled: root.shellOrientation == Qt.LandscapeOrientation ||
265+ root.shellOrientation == Qt.InvertedLandscapeOrientation
266+ Component.onCompleted: updateStageApps();
234 Connections {
269 Connections {
@@ -256,7 +291,8 @@ AbstractStage {
256 ApplicationManager.focusApplication("unity8-dash")
291 ApplicationManager.focusApplication("unity8-dash")
258 if (priv.sideStageAppId == appId) {
293 if (priv.sideStageAppId == appId) {
294+ var app = priv.getTopApp(ApplicationInfoInterface.SideStage);
259− priv.sideStageAppId = "";
295+ priv.sideStageAppId = app === null ? "" : app.appId;
262 if (ApplicationManager.count == 0) {
298 if (ApplicationManager.count == 0) {
@@ -267,6 +303,7 @@ AbstractStage {
267 // lets make sure the spread doesn't mess up by the changing app list.
303 // lets make sure the spread doesn't mess up by the changing app list.
268 spreadView.phase = 0;
304 spreadView.phase = 0;
269 spreadView.contentX = -spreadView.shift;
305 spreadView.contentX = -spreadView.shift;
270 ApplicationManager.focusApplication(ApplicationManager.get(0).appId);
307 ApplicationManager.focusApplication(ApplicationManager.get(0).appId);
@@ -322,6 +359,7 @@ AbstractStage {
322 property int selectedIndex: -1
359 property int selectedIndex: -1
323 property int draggedDelegateCount: 0
360 property int draggedDelegateCount: 0
324 property int closingIndex: -1
361 property int closingIndex: -1
362+ property var selectedApplication: selectedIndex !== -1 ? ApplicationManager.get(selectedIndex) : null
326 // FIXME: Workaround Flickable's not keepping its contentX still when resized
364 // FIXME: Workaround Flickable's not keepping its contentX still when resized
327 onContentXChanged: { forceItToRemainStillIfBeingResized(); }
365 onContentXChanged: { forceItToRemainStillIfBeingResized(); }
@@ -343,15 +381,8 @@ AbstractStage {
346− property bool sideStageDragging: sideStageDragHandle.dragging
347− property real sideStageDragProgress: sideStageDragHandle.progress
384+ property real sideStageDragProgress: sideStage.progress
348−
385+ property bool surfaceDragging: triGestureArea.recognisedDrag
349− onSideStageDragProgressChanged: {
350− if (sideStageDragProgress == 1) {
351− ApplicationManager.focusApplication(priv.mainStageAppId);
352− priv.sideStageAppId = "";
356 // In case the ApplicationManager already holds an app when starting up we're missing animations
387 // In case the ApplicationManager already holds an app when starting up we're missing animations
357 // Make sure we end up in the same state
388 // Make sure we end up in the same state
@@ -402,7 +433,7 @@ AbstractStage {
405− if (priv.mainStageAppId && !priv.sideStageAppId) {
436+ if ((priv.mainStageAppId && !priv.sideStageAppId) || !priv.sideStageEnabled) {
406 return "main";
437 return "main";
408 if (!priv.mainStageAppId && priv.sideStageAppId) {
439 if (!priv.mainStageAppId && priv.sideStageAppId) {
@@ -419,12 +450,26 @@ AbstractStage {
419 // Flickabe.contentX wiggles during resizes. Don't react to it.
450 // Flickabe.contentX wiggles during resizes. Don't react to it.
456+ // the "spreadEnabled" part is because when code does "phase = 0; contentX = -shift" to
457+ // dismiss the spread because spreadEnabled went to false, for some reason, during tests,
458+ // Flickable might jump in and change contentX value back, causing the code below to do
459+ // "phase = 1" which will make the spread stay.
460+ // It sucks that we have no control whatsoever over whether or when Flickable animates its
422− if (spreadView.phase == 0 && spreadView.shiftedContentX > spreadView.width * spreadView.positionMarker2) {
462+ if (root.spreadEnabled && shiftedContentX > width * positionMarker2) {
423− spreadView.phase = 1;
463+ phase = 1;
467+ if (shiftedContentX < width * positionMarker2) {
424− } else if (spreadView.phase == 1 && spreadView.shiftedContentX > spreadView.width * spreadView.positionMarker4) {
469+ } else if (shiftedContentX >= width * positionMarker4 && !spreadDragArea.dragging) {
425− spreadView.phase = 2;
470+ phase = 2;
426− } else if (spreadView.phase == 1 && spreadView.shiftedContentX < spreadView.width * spreadView.positionMarker2) {
471+ }
427− spreadView.phase = 0;
472+ break;
@@ -446,6 +491,7 @@ AbstractStage {
448 function snapTo(index) {
493 function snapTo(index) {
494+ snapAnimation.stop();
449 spreadView.selectedIndex = index;
495 spreadView.selectedIndex = index;
450 snapAnimation.targetContentX = -shift;
496 snapAnimation.targetContentX = -shift;
451 snapAnimation.start();
497 snapAnimation.start();
@@ -455,55 +501,41 @@ AbstractStage {
455 // We don't want to really reorder them in the model because that allows us to keep track
501 // We don't want to really reorder them in the model because that allows us to keep track
456 // of the last focused order.
502 // of the last focused order.
457 function indexToZIndex(index) {
503 function indexToZIndex(index) {
504+ // only shuffle when we've got a main and overlay
505+ if (state !== "mainAndOverlay") return index;
458 var app = ApplicationManager.get(index);
507 var app = ApplicationManager.get(index);
459 if (!app) {
508 if (!app) {
460 return index;
509 return index;
512+ // don't shuffle indexes greater than "actives or next"
513+ if (index > 2) return index;
463− var active = app.appId == priv.mainStageAppId || app.appId == priv.sideStageAppId;
515+ if (app.appId === priv.mainStageAppId) {
464− if (active && app.stage == ApplicationInfoInterface.MainStage) {
516+ // Active main stage always at 0
465− // if this app is active, and its the MainStage, always put it to index 0
466 return 0;
517 return 0;
468− if (active && app.stage == ApplicationInfoInterface.SideStage) {
469− if (!priv.mainStageAppId) {
470− // Only have SS apps running. Put the active one at 0
474− // Precondition now: There's an active MS app and this is SS app:
520+ if (spreadView.nextInStack > 0) {
475− if (spreadView.nextInStack >= 0 && ApplicationManager.get(spreadView.nextInStack).stage == ApplicationInfoInterface.MainStage) {
521+ var nextAppInStack = ApplicationManager.get(spreadView.nextInStack);
476− // If the next app coming from the right is a MS app, we need to elevate this SS ap above it.
522+
477− // Put it to at least level 2, or higher if there's more apps coming in before this one.
523+ if (index === spreadView.nextInStack) {
478− return Math.max(index, 2);
524+ // this is the next app in stack.
480− // if this is no next app to come in from the right, place this one at index 1, just on top the active MS app.
526+ if (app.stage === ApplicationInfoInterface.SideStage) {
527+ // if the next app in stack is a sidestage app, it must order on top of other side stage app
528+ return Math.min(2, ApplicationManager.count-1);
481 return 1;
530 return 1;
484− if (index <= 2 && app.stage == ApplicationInfoInterface.MainStage && priv.sideStageAppId) {
485− // Ok, this is an inactive MS app. If there's an active SS app around, we need to place this one
486− // in between the active MS app and the active SS app, so that it comes in from there when dragging from the right.
487− // If there's now active SS app, just leave it where it is.
488− return priv.indexOf(priv.sideStageAppId) < index ? index - 1 : index;
490− if (index == spreadView.nextInStack && app.stage == ApplicationInfoInterface.SideStage) {
532+ if (nextAppInStack.stage === ApplicationInfoInterface.SideStage) {
491− // This is a SS app and the next one to come in from the right:
533+ // if the next app in stack is a sidestage app, it must order on top of other side stage app
492− if (priv.sideStageAppId && priv.mainStageAppId) {
493− // If there's both, an active MS and an active SS app, put this one right on top of that
494− return 2;
534+ return 1;
496− // Or if there's only one other active app, put it on top of that.
536+ return Math.min(2, ApplicationManager.count-1);
497− // The case that there isn't any other active app is already handled above.
500− if (index == 2 && spreadView.nextInStack == 1 && priv.sideStageAppId) {
501− // If its index 2 but not the next one to come in, it means
502− // we've pulled another one down to index 2. Move this one up to 2 instead.
505− // don't touch all others... (mostly index > 3 + simple cases where the above doesn't shuffle much)
538+ return Math.min(index+1, ApplicationManager.count-1);
509 SequentialAnimation {
541 SequentialAnimation {
@@ -521,8 +553,12 @@ AbstractStage {
521 script: {
553 script: {
522 if (spreadView.selectedIndex >= 0) {
554 if (spreadView.selectedIndex >= 0) {
523 var newIndex = spreadView.selectedIndex;
555 var newIndex = spreadView.selectedIndex;
556+ var application = ApplicationManager.get(newIndex);
557+ if (application.stage === ApplicationInfoInterface.SideStage) {
558+ sideStage.showNow();
524 spreadView.selectedIndex = -1;
560 spreadView.selectedIndex = -1;
525− ApplicationManager.focusApplication(ApplicationManager.get(newIndex).appId);
561+ ApplicationManager.focusApplication(application.appId);
526 spreadView.phase = 0;
562 spreadView.phase = 0;
527 spreadView.contentX = -spreadView.shift;
563 spreadView.contentX = -spreadView.shift;
@@ -545,87 +581,82 @@ AbstractStage {
545 spreadView.snapTo(0);
581 spreadView.snapTo(0);
548− Rectangle {
584+ DropArea {
549− id: sideStageBackground
585+ objectName: "MainStageDropArea"
550− color: "black"
586+ anchors {
551− width: spreadView.sideStageWidth * (1 - sideStageDragHandle.progress)
587+ left: parent.left
552− height: priv.landscapeHeight
588+ top: parent.top
589+ bottom: parent.bottom
553− x: spreadView.width - width
591+ width: spreadView.width - sideStage.width
554− z: spreadView.indexToZIndex(priv.indexOf(priv.sideStageAppId))
592+ enabled: priv.sideStageEnabled
555− opacity: spreadView.phase == 0 ? 1 : 0
593+
556− Behavior on opacity { UbuntuNumberAnimation {} }
594+ onDropped: {
595+ priv.setAppStage(drag.source.appId, ApplicationInfoInterface.MainStage, true);
596+ ApplicationManager.focusApplication(drag.source.appId);
559− Item {
601+ SideStage {
560− id: sideStageDragHandle
602+ id: sideStage
561− anchors.right: sideStageBackground.left
603+ objectName: "sideStage"
562− anchors.top: sideStageBackground.top
564 height: priv.landscapeHeight
604 height: priv.landscapeHeight
565− z: sideStageBackground.z
605+ x: spreadView.width - width
566− opacity: spreadView.phase <= 0 && spreadView.sideStageVisible ? 1 : 0
606+ z: {
567− property real progress: 0
607+ if (!priv.mainStageAppId) return 0;
568− property bool dragging: false
570− Behavior on opacity { UbuntuNumberAnimation {} }
609+ if (priv.sideStageAppId && spreadView.nextInStack > 0) {
610+ var nextAppInStack = ApplicationManager.get(spreadView.nextInStack);
572− Connections {
612+ if (nextAppInStack.stage === ApplicationInfoInterface.MainStage) {
573− target: spreadView
613+ // if the next app in stack is a main stage app, put the sidestage on top of it.
574− onSideStageVisibleChanged: {
614+ return 2;
575− if (spreadView.sideStageVisible) {
576− sideStageDragHandle.progress = 0;
621+ visible: progress != 0
622+ enabled: priv.sideStageEnabled && sideStageDropArea.dropAllowed
623+ opacity: priv.sideStageEnabled && !spreadView.active ? 1 : 0
624+ Behavior on opacity { UbuntuNumberAnimation {} }
581− Image {
626+ onShownChanged: {
582− anchors.centerIn: parent
627+ if (!shown && ApplicationManager.focusedApplicationId == priv.sideStageAppId) {
583− width: sideStageDragHandleMouseArea.pressed ? parent.width * 2 : parent.width
628+ ApplicationManager.requestFocusApplication(priv.mainStageAppId);
584− height: parent.height
629+ }
585− source: "graphics/sidestage_handle@20.png"
630+ priv.updateStageApps();
586− Behavior on width { UbuntuNumberAnimation {} }
631+ if (shown && priv.sideStageAppId) {
632+ ApplicationManager.requestFocusApplication(priv.sideStageAppId);
589− MouseArea {
636+ DropArea {
590− id: sideStageDragHandleMouseArea
637+ id: sideStageDropArea
638+ objectName: "SideStageDropArea"
591 anchors.fill: parent
639 anchors.fill: parent
592− enabled: spreadView.shiftedContentX == 0
640+
593− property int startX
641+ property bool dropAllowed: true
594− property var gesturePoints: new Array()
642+
595− property real totalDiff
643+ onEntered: {
596−
644+ dropAllowed = drag.keys != "Disabled";
601− sideStageDragHandle.progress = 0;
602− sideStageDragHandle.dragging = true;
605− totalDiff += mouseX - startX;
606− if (priv.mainStageAppId) {
607− sideStageDragHandle.progress = Math.max(0, totalDiff / spreadView.sideStageWidth);
609− gesturePoints.push(mouseX);
611− onReleased: {
646+ onExited: {
612− if (priv.mainStageAppId) {
647+ dropAllowed = true;
613− var oneWayFlick = priv.evaluateOneWayFlick(gesturePoints);
648+ }
614− sideStageDragSnapAnimation.to = sideStageDragHandle.progress > 0.5 || oneWayFlick ? 1 : 0;
649+ onDropped: {
615− sideStageDragSnapAnimation.start();
650+ if (drop.keys == "MainStage") {
616− } else {
651+ priv.setAppStage(drop.source.appId, ApplicationInfoInterface.SideStage, true);
617− sideStageDragHandle.dragging = false;
652+ ApplicationManager.requestFocusApplication(drop.source.appId);
621− UbuntuNumberAnimation {
656+ onSourceChanged: {
622− id: sideStageDragSnapAnimation
657+ if (!sideStageDropArea.drag.source) {
623− target: sideStageDragHandle
658+ dropAllowed = true;
624− property: "progress"
659+ }
628− sideStageDragHandle.dragging = false;
@@ -640,37 +671,53 @@ AbstractStage {
640 id: spreadTile
671 id: spreadTile
641 objectName: model.appId ? "tabletSpreadDelegate_" + model.appId
672 objectName: model.appId ? "tabletSpreadDelegate_" + model.appId
642 : "tabletSpreadDelegate_null";
673 : "tabletSpreadDelegate_null";
644− if (wantsMainStage) {
645− return spreadView.width;
674+ width: spreadView.width
647− return spreadView.sideStageWidth;
651− if (wantsMainStage) {
652− return spreadView.height;
675+ height: spreadView.height
654− return priv.landscapeHeight;
657− active: model.appId == priv.mainStageAppId || model.appId == priv.sideStageAppId
676+ active: appId == priv.mainStageAppId || appId == priv.sideStageAppId
658− zIndex: spreadView.indexToZIndex(index)
677+ zIndex: selected && stage == ApplicationInfoInterface.MainStage ? 0 : spreadView.indexToZIndex(index)
659 selected: spreadView.selectedIndex == index
678 selected: spreadView.selectedIndex == index
660 otherSelected: spreadView.selectedIndex >= 0 && !selected
679 otherSelected: spreadView.selectedIndex >= 0 && !selected
661− isInSideStage: priv.sideStageAppId == model.appId
680+ isInSideStage: priv.sideStageAppId === appId
662 interactive: !spreadView.interactive && spreadView.phase === 0 && root.interactive
681 interactive: !spreadView.interactive && spreadView.phase === 0 && root.interactive
663 swipeToCloseEnabled: spreadView.interactive && !snapAnimation.running
682 swipeToCloseEnabled: spreadView.interactive && !snapAnimation.running
664 maximizedAppTopMargin: root.maximizedAppTopMargin
683 maximizedAppTopMargin: root.maximizedAppTopMargin
665− dragOffset: !isDash && model.appId == priv.mainStageAppId && root.inverseProgress > 0 && spreadView.phase === 0 ? root.inverseProgress : 0
684+ dragOffset: !isDash && appId == priv.mainStageAppId && root.inverseProgress > 0 && spreadView.phase === 0 ? root.inverseProgress : 0
666 application: ApplicationManager.get(index)
685 application: ApplicationManager.get(index)
667 closeable: !isDash
686 closeable: !isDash
668 highlightShown: root.altTabPressed && priv.highlightIndex == zIndex
687 highlightShown: root.altTabPressed && priv.highlightIndex == zIndex
670 readonly property bool wantsMainStage: model.stage == ApplicationInfoInterface.MainStage
689 readonly property bool wantsMainStage: model.stage == ApplicationInfoInterface.MainStage
691+ readonly property string appId: model.appId
672 readonly property bool isDash: model.appId == "unity8-dash"
692 readonly property bool isDash: model.appId == "unity8-dash"
696+ if (mainApp && stage === ApplicationInfoInterface.SideStage) {
697+ return mainApp.fullscreen;
699+ return application ? application.fullscreen : false;
702+ supportedOrientations: {
704+ var orientations = application.supportedOrientations;
705+ if (stage == ApplicationInfoInterface.MainStage) {
706+ // When an app is in the mainstage, it always supports Landscape|InvertedLandscape
707+ // so that we can drag it from the main stage to the side stage
708+ orientations |= Qt.LandscapeOrientation | Qt.InvertedLandscapeOrientation;
710+ return orientations;
712+ // we just don't care
713+ return Qt.PortraitOrientation |
714+ Qt.LandscapeOrientation |
715+ Qt.InvertedPortraitOrientation |
716+ Qt.InvertedLandscapeOrientation;
674 Binding {
721 Binding {
675 target: spreadTile.application
722 target: spreadTile.application
676 property: "exemptFromLifecycle"
723 property: "exemptFromLifecycle"
@@ -701,6 +748,28 @@ AbstractStage {
701 enabled: spreadView.closingIndex >= 0
748 enabled: spreadView.closingIndex >= 0
702 UbuntuNumberAnimation {}
749 UbuntuNumberAnimation {}
753+ onSideStageEnabledChanged: refreshStage()
756+ Component.onCompleted: {
758+ stageChanged.connect(priv.updateStageApps);
761+ function refreshStage() {
762+ var stage = ApplicationInfoInterface.MainStage;
763+ if (priv.sideStageEnabled) {
764+ if (application && application.supportedOrientations & (Qt.PortraitOrientation|Qt.InvertedPortraitOrientation)) {
765+ stage = WindowStateStorage.getStage(appId);
769+ if (model.stage !== stage) {
770+ priv.setAppStage(appId, stage, false);
705 // This is required because none of the bindings are triggered in some cases:
774 // This is required because none of the bindings are triggered in some cases:
706 // When an app is closed, it might happen that ApplicationManager.get(nextInStack)
775 // When an app is closed, it might happen that ApplicationManager.get(nextInStack)
@@ -725,7 +794,7 @@ AbstractStage {
726 // TODO: Hiding tile when progress is such that it will be off screen.
795 // TODO: Hiding tile when progress is such that it will be off screen.
727 property bool occluded: {
796 property bool occluded: {
728− if (spreadView.active) return false;
797+ if (spreadView.active && !offScreen) return false;
729 else if (spreadTile.active) return false;
798 else if (spreadTile.active) return false;
730 else if (xTranslateAnimating) return false;
799 else if (xTranslateAnimating) return false;
731 else if (z <= 1 && priv.focusedAppDelegateIsDislocated) return false;
800 else if (z <= 1 && priv.focusedAppDelegateIsDislocated) return false;
@@ -749,17 +818,87 @@ AbstractStage {
749 return progress;
818 return progress;
752− shellOrientationAngle: wantsMainStage ? root.shellOrientationAngle : 0
821+ shellOrientationAngle: root.shellOrientationAngle
822+ shellOrientation: root.shellOrientation
823+ orientations: root.orientations
828+ when: spreadTile.stage == ApplicationInfoInterface.MainStage
832+ when: spreadTile.stage == ApplicationInfoInterface.SideStage
836+ width: spreadView.sideStageWidth
837+ height: priv.landscapeHeight
839+ supportedOrientations: Qt.PortraitOrientation
840+ shellOrientationAngle: 0
753− shellOrientation: wantsMainStage ? root.shellOrientation : Qt.PortraitOrientation
841+ shellOrientation: Qt.PortraitOrientation
842+ orientations: sideStageOrientations
754− orientations: Orientations {
847+ Orientations {
848+ id: sideStageOrientations
755− primary: spreadTile.wantsMainStage ? root.orientations.primary : Qt.PortraitOrientation
849+ primary: Qt.PortraitOrientation
756− native_: spreadTile.wantsMainStage ? root.orientations.native_ : Qt.PortraitOrientation
850+ native_: Qt.PortraitOrientation
757 portrait: root.orientations.portrait
851 portrait: root.orientations.portrait
758 invertedPortrait: root.orientations.invertedPortrait
852 invertedPortrait: root.orientations.invertedPortrait
759 landscape: root.orientations.landscape
853 landscape: root.orientations.landscape
760 invertedLandscape: root.orientations.invertedLandscape
854 invertedLandscape: root.orientations.invertedLandscape
860+ SequentialAnimation {
863+ properties: "width,height,supportedOrientations,shellOrientationAngle,shellOrientation,orientations"
867+ // rotate immediately.
868+ spreadTile.matchShellOrientation();
869+ if (ApplicationManager.focusedApplicationId === spreadTile.appId &&
870+ priv.sideStageEnabled && !sideStage.shown) {
871+ // Sidestage was focused, so show the side stage.
873+ // if we've switched to a main app which doesnt support portrait, hide the side stage.
874+ } else if (mainApp && (mainApp.supportedOrientations & (Qt.PortraitOrientation|Qt.InvertedPortraitOrientation)) == 0) {
875+ sideStage.hideNow();
883+ SequentialAnimation {
886+ if (priv.sideStageAppId === spreadTile.appId &&
887+ mainApp && (mainApp.supportedOrientations & (Qt.PortraitOrientation|Qt.InvertedPortraitOrientation)) == 0) {
888+ // The mainstage app did not natively support portrait orientation, so focus the sidestage.
889+ ApplicationManager.requestFocusApplication(spreadTile.appId);
895+ properties: "width,height,supportedOrientations,shellOrientationAngle,shellOrientation,orientations"
897+ ScriptAction { script: { spreadTile.matchShellOrientation(); } }
763 onClicked: {
902 onClicked: {
764 if (spreadView.phase == 2) {
903 if (spreadView.phase == 2) {
765 spreadView.snapTo(index);
904 spreadView.snapTo(index);
@@ -779,6 +918,16 @@ AbstractStage {
779 ApplicationManager.stopApplication(ApplicationManager.get(index).appId);
918 ApplicationManager.stopApplication(ApplicationManager.get(index).appId);
922+ if (focus && ApplicationManager.focusedApplicationId !== appId) {
923+ ApplicationManager.focusApplication(appId);
926+ if (focus && priv.sideStageEnabled && stage === ApplicationInfoInterface.SideStage) {
782 Binding {
931 Binding {
783 target: root
932 target: root
784 when: model.appId == priv.mainStageAppId
933 when: model.appId == priv.mainStageAppId
@@ -803,6 +952,71 @@ AbstractStage {
955+ TabletSideStageTouchGesture {
957+ anchors.fill: parent
958+ enabled: priv.sideStageEnabled && !spreadView.active
959+ property var dragObject: null
960+ property string appId: ""
961+ dragComponent: dragComponent
962+ dragComponentProperties: { "appId": appId }
965+ function matchDelegate(obj) { return String(obj.objectName).indexOf("tabletSpreadDelegate") >= 0; }
967+ var delegateAtCenter = Functions.itemAt(spreadRow, x, y, matchDelegate);
968+ if (!delegateAtCenter) return;
970+ appId = delegateAtCenter.appId;
974+ if (sideStage.shown) {
982+ // If we're dragging to the sidestage.
983+ if (!sideStage.shown) {
991+ property string appId: ""
992+ property var application: ApplicationManager.findApplication(appId)
994+ session: application ? application.session : null
996+ resizeSurface: false
1000+ height: units.gu(40)
1002+ Drag.hotSpot.x: width/2
1003+ Drag.hotSpot.y: height/2
1004+ // only accept opposite stage.
1006+ if (!application) return "Disabled";
1008+ if (application.stage === ApplicationInfo.MainStage) {
1009+ if (application.supportedOrientations & (Qt.PortraitOrientation|Qt.InvertedPortraitOrientation)) {
1010+ return "MainStage";
1014+ return "SideStage";
806 //eat touch events during the right edge gesture
1020 //eat touch events during the right edge gesture
807 MouseArea {
1021 MouseArea {
808 anchors.fill: parent
1022 anchors.fill: parent
@@ -812,7 +1026,8 @@ AbstractStage {
812 DirectionalDragArea {
1026 DirectionalDragArea {
813 id: spreadDragArea
1027 id: spreadDragArea
814 objectName: "spreadDragArea"
1028 objectName: "spreadDragArea"
1029+ x: parent.width - root.dragAreaWidth
815− anchors { top: parent.top; right: parent.right; bottom: parent.bottom }
1030+ anchors { top: parent.top; bottom: parent.bottom }
816 width: root.dragAreaWidth
1031 width: root.dragAreaWidth
817 direction: Direction.Leftwards
1032 direction: Direction.Leftwards
818 enabled: (spreadView.phase != 2 && root.spreadEnabled) || dragging
1033 enabled: (spreadView.phase != 2 && root.spreadEnabled) || dragging