@@ -46,7 +46,7 @@ AbstractStage {
4646 if (delta < 0) { delta += 360; }
4747 delta = delta % 360;
4848
49− var supportedOrientations = spreadDelegate.application.supportedOrientations;
49+ var supportedOrientations = spreadDelegate.supportedOrientations;
5050 if (supportedOrientations === Qt.PrimaryOrientation) {
5151 supportedOrientations = spreadDelegate.orientations.primary;
5252 }
@@ -78,9 +78,24 @@ AbstractStage {
7878
7979 orientationChangesEnabled: priv.mainAppOrientationChangesEnabled
8080
81− supportedOrientations: mainApp ? mainApp.supportedOrientations
82− : (Qt.PortraitOrientation | Qt.LandscapeOrientation
83− | Qt.InvertedPortraitOrientation | Qt.InvertedLandscapeOrientation)
81+ supportedOrientations: {
82+ if (mainApp) {
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
88+ orientations |= Qt.PortraitOrientation|Qt.InvertedPortraitOrientation;
89+ }
90+ return orientations;
91+ } else {
92+ // we just don't care
93+ return Qt.PortraitOrientation |
94+ Qt.LandscapeOrientation |
95+ Qt.InvertedPortraitOrientation |
96+ Qt.InvertedLandscapeOrientation;
97+ }
98+ }
8499
85100 onWidthChanged: {
86101 spreadView.selectedIndex = -1;
@@ -88,13 +103,6 @@ AbstractStage {
88103 spreadView.contentX = -spreadView.shift;
89104 }
90105
91− onShellOrientationChanged: {
92− if (shellOrientation == Qt.PortraitOrientation || shellOrientation == Qt.InvertedPortraitOrientation) {
93− ApplicationManager.focusApplication(priv.mainStageAppId);
94− priv.sideStageAppId = "";
95− }
96− }
97−
98106 onInverseProgressChanged: {
99107 // This can't be a simple binding because that would be triggered after this handler
100108 // while we need it active before doing the anition left/right
@@ -170,20 +178,7 @@ AbstractStage {
170178
171179 property int highlightIndex: 0
172180
173− onFocusedAppIdChanged: {
174− if (priv.focusedAppId.length > 0) {
175− var focusedApp = ApplicationManager.findApplication(focusedAppId);
176− if (focusedApp.stage == ApplicationInfoInterface.SideStage) {
177− priv.sideStageAppId = focusedAppId;
178− } else {
179− priv.mainStageAppId = focusedAppId;
180− root.mainApp = focusedApp;
181− }
182− }
183−
184− appId0 = ApplicationManager.count >= 1 ? ApplicationManager.get(0).appId : "";
185− appId1 = ApplicationManager.count > 1 ? ApplicationManager.get(1).appId : "";
186− }
181+ onFocusedAppIdChanged: updateStageApps()
187182
188183 onFocusedAppDelegateChanged: {
189184 if (focusedAppDelegate) {
@@ -229,6 +224,46 @@ AbstractStage {
229224 onHighlightIndexChanged: {
230225 spreadView.contentX = highlightIndex * spreadView.contentWidth / (spreadRepeater.count + 2)
231226 }
227+
228+ function getTopApp(stage) {
229+ for (var i = 0; i < ApplicationManager.count; i++) {
230+ var app = ApplicationManager.get(i)
231+ if (app.stage === stage) {
232+ return app;
233+ }
234+ }
235+ return null;
236+ }
237+
238+ function setAppStage(appId, stage, save) {
239+ var app = ApplicationManager.findApplication(appId);
240+ if (app) {
241+ app.stage = stage;
242+ if (save) {
243+ WindowStateStorage.saveStage(appId, stage);
244+ }
245+ }
246+ }
247+
248+ function updateStageApps() {
249+ var app = priv.getTopApp(ApplicationInfoInterface.MainStage);
250+ priv.mainStageAppId = app ? app.appId : ""
251+ root.mainApp = app;
252+
253+ if (sideStage.shown) {
254+ app = priv.getTopApp(ApplicationInfoInterface.SideStage);
255+ priv.sideStageAppId = app ? app.appId : ""
256+ } else {
257+ priv.sideStageAppId = "";
258+ }
259+
260+ appId0 = ApplicationManager.count >= 1 ? ApplicationManager.get(0).appId : "";
261+ appId1 = ApplicationManager.count > 1 ? ApplicationManager.get(1).appId : "";
262+ }
263+
264+ readonly property bool sideStageEnabled: root.shellOrientation == Qt.LandscapeOrientation ||
265+ root.shellOrientation == Qt.InvertedLandscapeOrientation
266+ Component.onCompleted: updateStageApps();
232267 }
233268
234269 Connections {
@@ -256,7 +291,8 @@ AbstractStage {
256291 ApplicationManager.focusApplication("unity8-dash")
257292 }
258293 if (priv.sideStageAppId == appId) {
259− priv.sideStageAppId = "";
294+ var app = priv.getTopApp(ApplicationInfoInterface.SideStage);
295+ priv.sideStageAppId = app === null ? "" : app.appId;
260296 }
261297
262298 if (ApplicationManager.count == 0) {
@@ -267,6 +303,7 @@ AbstractStage {
267303 // lets make sure the spread doesn't mess up by the changing app list.
268304 spreadView.phase = 0;
269305 spreadView.contentX = -spreadView.shift;
306+
270307 ApplicationManager.focusApplication(ApplicationManager.get(0).appId);
271308 }
272309 }
@@ -322,6 +359,7 @@ AbstractStage {
322359 property int selectedIndex: -1
323360 property int draggedDelegateCount: 0
324361 property int closingIndex: -1
362+ property var selectedApplication: selectedIndex !== -1 ? ApplicationManager.get(selectedIndex) : null
325363
326364 // FIXME: Workaround Flickable's not keepping its contentX still when resized
327365 onContentXChanged: { forceItToRemainStillIfBeingResized(); }
@@ -343,15 +381,8 @@ AbstractStage {
343381 }
344382 }
345383
346− property bool sideStageDragging: sideStageDragHandle.dragging
347− property real sideStageDragProgress: sideStageDragHandle.progress
348−
349− onSideStageDragProgressChanged: {
350− if (sideStageDragProgress == 1) {
351− ApplicationManager.focusApplication(priv.mainStageAppId);
352− priv.sideStageAppId = "";
353− }
354− }
384+ property real sideStageDragProgress: sideStage.progress
385+ property bool surfaceDragging: triGestureArea.recognisedDrag
355386
356387 // In case the ApplicationManager already holds an app when starting up we're missing animations
357388 // Make sure we end up in the same state
@@ -402,7 +433,7 @@ AbstractStage {
402433 }
403434 ]
404435 state: {
405− if (priv.mainStageAppId && !priv.sideStageAppId) {
436+ if ((priv.mainStageAppId && !priv.sideStageAppId) || !priv.sideStageEnabled) {
406437 return "main";
407438 }
408439 if (!priv.mainStageAppId && priv.sideStageAppId) {
@@ -419,12 +450,26 @@ AbstractStage {
419450 // Flickabe.contentX wiggles during resizes. Don't react to it.
420451 return;
421452 }
422− if (spreadView.phase == 0 && spreadView.shiftedContentX > spreadView.width * spreadView.positionMarker2) {
423− spreadView.phase = 1;
424− } else if (spreadView.phase == 1 && spreadView.shiftedContentX > spreadView.width * spreadView.positionMarker4) {
425− spreadView.phase = 2;
426− } else if (spreadView.phase == 1 && spreadView.shiftedContentX < spreadView.width * spreadView.positionMarker2) {
427− spreadView.phase = 0;
453+
454+ switch (phase) {
455+ case 0:
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
461+ // contentX.
462+ if (root.spreadEnabled && shiftedContentX > width * positionMarker2) {
463+ phase = 1;
464+ }
465+ break;
466+ case 1:
467+ if (shiftedContentX < width * positionMarker2) {
468+ phase = 0;
469+ } else if (shiftedContentX >= width * positionMarker4 && !spreadDragArea.dragging) {
470+ phase = 2;
471+ }
472+ break;
428473 }
429474 }
430475
@@ -446,6 +491,7 @@ AbstractStage {
446491 }
447492
448493 function snapTo(index) {
494+ snapAnimation.stop();
449495 spreadView.selectedIndex = index;
450496 snapAnimation.targetContentX = -shift;
451497 snapAnimation.start();
@@ -455,55 +501,41 @@ AbstractStage {
455501 // We don't want to really reorder them in the model because that allows us to keep track
456502 // of the last focused order.
457503 function indexToZIndex(index) {
504+ // only shuffle when we've got a main and overlay
505+ if (state !== "mainAndOverlay") return index;
506+
458507 var app = ApplicationManager.get(index);
459508 if (!app) {
460509 return index;
461510 }
462511
463− var active = app.appId == priv.mainStageAppId || app.appId == priv.sideStageAppId;
464− if (active && app.stage == ApplicationInfoInterface.MainStage) {
465− // if this app is active, and its the MainStage, always put it to index 0
512+ // don't shuffle indexes greater than "actives or next"
513+ if (index > 2) return index;
514+
515+ if (app.appId === priv.mainStageAppId) {
516+ // Active main stage always at 0
466517 return 0;
467518 }
468− if (active && app.stage == ApplicationInfoInterface.SideStage) {
469− if (!priv.mainStageAppId) {
470− // Only have SS apps running. Put the active one at 0
471− return 0;
472− }
473519
474− // Precondition now: There's an active MS app and this is SS app:
475− if (spreadView.nextInStack >= 0 && ApplicationManager.get(spreadView.nextInStack).stage == ApplicationInfoInterface.MainStage) {
476− // If the next app coming from the right is a MS app, we need to elevate this SS ap above it.
477− // Put it to at least level 2, or higher if there's more apps coming in before this one.
478− return Math.max(index, 2);
479− } else {
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.
520+ if (spreadView.nextInStack > 0) {
521+ var nextAppInStack = ApplicationManager.get(spreadView.nextInStack);
522+
523+ if (index === spreadView.nextInStack) {
524+ // this is the next app in stack.
525+
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);
529+ }
481530 return 1;
482531 }
483− }
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;
489− }
490− if (index == spreadView.nextInStack && app.stage == ApplicationInfoInterface.SideStage) {
491− // This is a SS app and the next one to come in from the right:
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;
532+ if (nextAppInStack.stage === ApplicationInfoInterface.SideStage) {
533+ // if the next app in stack is a sidestage app, it must order on top of other side stage app
534+ return 1;
495535 }
496− // Or if there's only one other active app, put it on top of that.
497− // The case that there isn't any other active app is already handled above.
498− return 1;
499− }
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.
503− return 3;
536+ return Math.min(2, ApplicationManager.count-1);
504537 }
505− // don't touch all others... (mostly index > 3 + simple cases where the above doesn't shuffle much)
506− return index;
538+ return Math.min(index+1, ApplicationManager.count-1);
507539 }
508540
509541 SequentialAnimation {
@@ -521,8 +553,12 @@ AbstractStage {
521553 script: {
522554 if (spreadView.selectedIndex >= 0) {
523555 var newIndex = spreadView.selectedIndex;
556+ var application = ApplicationManager.get(newIndex);
557+ if (application.stage === ApplicationInfoInterface.SideStage) {
558+ sideStage.showNow();
559+ }
524560 spreadView.selectedIndex = -1;
525− ApplicationManager.focusApplication(ApplicationManager.get(newIndex).appId);
561+ ApplicationManager.focusApplication(application.appId);
526562 spreadView.phase = 0;
527563 spreadView.contentX = -spreadView.shift;
528564 }
@@ -545,87 +581,82 @@ AbstractStage {
545581 spreadView.snapTo(0);
546582 }
547583
548− Rectangle {
549− id: sideStageBackground
550− color: "black"
551− width: spreadView.sideStageWidth * (1 - sideStageDragHandle.progress)
552− height: priv.landscapeHeight
553− x: spreadView.width - width
554− z: spreadView.indexToZIndex(priv.indexOf(priv.sideStageAppId))
555− opacity: spreadView.phase == 0 ? 1 : 0
556− Behavior on opacity { UbuntuNumberAnimation {} }
584+ DropArea {
585+ objectName: "MainStageDropArea"
586+ anchors {
587+ left: parent.left
588+ top: parent.top
589+ bottom: parent.bottom
590+ }
591+ width: spreadView.width - sideStage.width
592+ enabled: priv.sideStageEnabled
593+
594+ onDropped: {
595+ priv.setAppStage(drag.source.appId, ApplicationInfoInterface.MainStage, true);
596+ ApplicationManager.focusApplication(drag.source.appId);
597+ }
598+ keys: "SideStage"
557599 }
558600
559− Item {
560− id: sideStageDragHandle
561− anchors.right: sideStageBackground.left
562− anchors.top: sideStageBackground.top
563− width: units.gu(2)
601+ SideStage {
602+ id: sideStage
603+ objectName: "sideStage"
564604 height: priv.landscapeHeight
565− z: sideStageBackground.z
566− opacity: spreadView.phase <= 0 && spreadView.sideStageVisible ? 1 : 0
567− property real progress: 0
568− property bool dragging: false
605+ x: spreadView.width - width
606+ z: {
607+ if (!priv.mainStageAppId) return 0;
569608
570− Behavior on opacity { UbuntuNumberAnimation {} }
609+ if (priv.sideStageAppId && spreadView.nextInStack > 0) {
610+ var nextAppInStack = ApplicationManager.get(spreadView.nextInStack);
571611
572− Connections {
573− target: spreadView
574− onSideStageVisibleChanged: {
575− if (spreadView.sideStageVisible) {
576− sideStageDragHandle.progress = 0;
612+ if (nextAppInStack.stage === ApplicationInfoInterface.MainStage) {
613+ // if the next app in stack is a main stage app, put the sidestage on top of it.
614+ return 2;
577615 }
616+ return 1;
578617 }
618+
619+ return 1;
579620 }
621+ visible: progress != 0
622+ enabled: priv.sideStageEnabled && sideStageDropArea.dropAllowed
623+ opacity: priv.sideStageEnabled && !spreadView.active ? 1 : 0
624+ Behavior on opacity { UbuntuNumberAnimation {} }
580625
581− Image {
582− anchors.centerIn: parent
583− width: sideStageDragHandleMouseArea.pressed ? parent.width * 2 : parent.width
584− height: parent.height
585− source: "graphics/sidestage_handle@20.png"
586− Behavior on width { UbuntuNumberAnimation {} }
626+ onShownChanged: {
627+ if (!shown && ApplicationManager.focusedApplicationId == priv.sideStageAppId) {
628+ ApplicationManager.requestFocusApplication(priv.mainStageAppId);
629+ }
630+ priv.updateStageApps();
631+ if (shown && priv.sideStageAppId) {
632+ ApplicationManager.requestFocusApplication(priv.sideStageAppId);
633+ }
587634 }
588635
589− MouseArea {
590− id: sideStageDragHandleMouseArea
636+ DropArea {
637+ id: sideStageDropArea
638+ objectName: "SideStageDropArea"
591639 anchors.fill: parent
592− enabled: spreadView.shiftedContentX == 0
593− property int startX
594− property var gesturePoints: new Array()
595− property real totalDiff
596−
597− onPressed: {
598− gesturePoints = [];
599− startX = mouseX;
600− totalDiff = 0.0;
601− sideStageDragHandle.progress = 0;
602− sideStageDragHandle.dragging = true;
603− }
604− onMouseXChanged: {
605− totalDiff += mouseX - startX;
606− if (priv.mainStageAppId) {
607− sideStageDragHandle.progress = Math.max(0, totalDiff / spreadView.sideStageWidth);
608− }
609− gesturePoints.push(mouseX);
640+
641+ property bool dropAllowed: true
642+
643+ onEntered: {
644+ dropAllowed = drag.keys != "Disabled";
610645 }
611− onReleased: {
612− if (priv.mainStageAppId) {
613− var oneWayFlick = priv.evaluateOneWayFlick(gesturePoints);
614− sideStageDragSnapAnimation.to = sideStageDragHandle.progress > 0.5 || oneWayFlick ? 1 : 0;
615− sideStageDragSnapAnimation.start();
616− } else {
617− sideStageDragHandle.dragging = false;
646+ onExited: {
647+ dropAllowed = true;
648+ }
649+ onDropped: {
650+ if (drop.keys == "MainStage") {
651+ priv.setAppStage(drop.source.appId, ApplicationInfoInterface.SideStage, true);
652+ ApplicationManager.requestFocusApplication(drop.source.appId);
618653 }
619654 }
620− }
621− UbuntuNumberAnimation {
622− id: sideStageDragSnapAnimation
623− target: sideStageDragHandle
624− property: "progress"
625−
626− onRunningChanged: {
627− if (!running) {
628− sideStageDragHandle.dragging = false;
655+ drag {
656+ onSourceChanged: {
657+ if (!sideStageDropArea.drag.source) {
658+ dropAllowed = true;
659+ }
629660 }
630661 }
631662 }
@@ -640,29 +671,17 @@ AbstractStage {
640671 id: spreadTile
641672 objectName: model.appId ? "tabletSpreadDelegate_" + model.appId
642673 : "tabletSpreadDelegate_null";
643− width: {
644− if (wantsMainStage) {
645− return spreadView.width;
646− } else {
647− return spreadView.sideStageWidth;
648− }
649− }
650− height: {
651− if (wantsMainStage) {
652− return spreadView.height;
653− } else {
654− return priv.landscapeHeight;
655− }
656− }
657− active: model.appId == priv.mainStageAppId || model.appId == priv.sideStageAppId
658− zIndex: spreadView.indexToZIndex(index)
674+ width: spreadView.width
675+ height: spreadView.height
676+ active: appId == priv.mainStageAppId || appId == priv.sideStageAppId
677+ zIndex: selected && stage == ApplicationInfoInterface.MainStage ? 0 : spreadView.indexToZIndex(index)
659678 selected: spreadView.selectedIndex == index
660679 otherSelected: spreadView.selectedIndex >= 0 && !selected
661− isInSideStage: priv.sideStageAppId == model.appId
680+ isInSideStage: priv.sideStageAppId === appId
662681 interactive: !spreadView.interactive && spreadView.phase === 0 && root.interactive
663682 swipeToCloseEnabled: spreadView.interactive && !snapAnimation.running
664683 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
666685 application: ApplicationManager.get(index)
667686 closeable: !isDash
668687 highlightShown: root.altTabPressed && priv.highlightIndex == zIndex
@@ -671,6 +690,35 @@ AbstractStage {
671690
672691 readonly property bool isDash: model.appId == "unity8-dash"
673692
693+ stage: model.stage
694+ fullscreen: {
695+ if (mainApp && stage === ApplicationInfoInterface.SideStage) {
696+ return mainApp.fullscreen;
697+ }
698+ return application ? application.fullscreen : false;
699+ }
700+
701+ supportedOrientations: {
702+ if (application) {
703+ var orientations = application.supportedOrientations;
704+ if (stage == ApplicationInfoInterface.MainStage) {
705+ // When an app is in the mainstage, it always supports Landscape|InvertedLandscape
706+ // so that we can drag it from the main stage to the side stage
707+ orientations |= Qt.LandscapeOrientation | Qt.InvertedLandscapeOrientation;
708+ }
709+ return orientations;
710+ } else {
711+ // we just don't care
712+ return Qt.PortraitOrientation |
713+ Qt.LandscapeOrientation |
714+ Qt.InvertedPortraitOrientation |
715+ Qt.InvertedLandscapeOrientation;
716+ }
717+ }
718+
719+ readonly property string appId: model.appId
720+ readonly property bool isDash: appId == "unity8-dash"
721+
674722 Binding {
675723 target: spreadTile.application
676724 property: "exemptFromLifecycle"
@@ -701,6 +749,28 @@ AbstractStage {
701749 enabled: spreadView.closingIndex >= 0
702750 UbuntuNumberAnimation {}
703751 }
752+ Connections {
753+ target: priv
754+ onSideStageEnabledChanged: refreshStage()
755+ }
756+
757+ Component.onCompleted: {
758+ refreshStage()
759+ stageChanged.connect(priv.updateStageApps);
760+ }
761+
762+ function refreshStage() {
763+ var stage = ApplicationInfoInterface.MainStage;
764+ if (priv.sideStageEnabled) {
765+ if (application && application.supportedOrientations & (Qt.PortraitOrientation|Qt.InvertedPortraitOrientation)) {
766+ stage = WindowStateStorage.getStage(appId);
767+ }
768+ }
769+
770+ if (model.stage !== stage) {
771+ priv.setAppStage(appId, stage, false);
772+ }
773+ }
704774
705775 // This is required because none of the bindings are triggered in some cases:
706776 // When an app is closed, it might happen that ApplicationManager.get(nextInStack)
@@ -725,7 +795,7 @@ AbstractStage {
725795
726796 // TODO: Hiding tile when progress is such that it will be off screen.
727797 property bool occluded: {
728− if (spreadView.active) return false;
798+ if (spreadView.active && !offScreen) return false;
729799 else if (spreadTile.active) return false;
730800 else if (xTranslateAnimating) return false;
731801 else if (z <= 1 && priv.focusedAppDelegateIsDislocated) return false;
@@ -749,17 +819,87 @@ AbstractStage {
749819 return progress;
750820 }
751821
752− shellOrientationAngle: wantsMainStage ? root.shellOrientationAngle : 0
753− shellOrientation: wantsMainStage ? root.shellOrientation : Qt.PortraitOrientation
754− orientations: Orientations {
755− primary: spreadTile.wantsMainStage ? root.orientations.primary : Qt.PortraitOrientation
756− native_: spreadTile.wantsMainStage ? root.orientations.native_ : Qt.PortraitOrientation
822+ shellOrientationAngle: root.shellOrientationAngle
823+ shellOrientation: root.shellOrientation
824+ orientations: root.orientations
825+
826+ states: [
827+ State {
828+ name: "MainStage"
829+ when: spreadTile.stage == ApplicationInfoInterface.MainStage
830+ },
831+ State {
832+ name: "SideStage"
833+ when: spreadTile.stage == ApplicationInfoInterface.SideStage
834+
835+ PropertyChanges {
836+ target: spreadTile
837+ width: spreadView.sideStageWidth
838+ height: priv.landscapeHeight
839+
840+ supportedOrientations: Qt.PortraitOrientation
841+ shellOrientationAngle: 0
842+ shellOrientation: Qt.PortraitOrientation
843+ orientations: sideStageOrientations
844+ }
845+ }
846+ ]
847+
848+ Orientations {
849+ id: sideStageOrientations
850+ primary: Qt.PortraitOrientation
851+ native_: Qt.PortraitOrientation
757852 portrait: root.orientations.portrait
758853 invertedPortrait: root.orientations.invertedPortrait
759854 landscape: root.orientations.landscape
760855 invertedLandscape: root.orientations.invertedLandscape
761856 }
762857
858+ transitions: [
859+ Transition {
860+ to: "SideStage"
861+ SequentialAnimation {
862+ PropertyAction {
863+ target: spreadTile
864+ properties: "width,height,supportedOrientations,shellOrientationAngle,shellOrientation,orientations"
865+ }
866+ ScriptAction {
867+ script: {
868+ // rotate immediately.
869+ spreadTile.matchShellOrientation();
870+ if (ApplicationManager.focusedApplicationId === spreadTile.appId &&
871+ priv.sideStageEnabled && !sideStage.shown) {
872+ // Sidestage was focused, so show the side stage.
873+ sideStage.show();
874+ // if we've switched to a main app which doesnt support portrait, hide the side stage.
875+ } else if (mainApp && (mainApp.supportedOrientations & (Qt.PortraitOrientation|Qt.InvertedPortraitOrientation)) == 0) {
876+ sideStage.hideNow();
877+ }
878+ }
879+ }
880+ }
881+ },
882+ Transition {
883+ from: "SideStage"
884+ SequentialAnimation {
885+ ScriptAction {
886+ script: {
887+ if (priv.sideStageAppId === spreadTile.appId &&
888+ mainApp && (mainApp.supportedOrientations & (Qt.PortraitOrientation|Qt.InvertedPortraitOrientation)) == 0) {
889+ // The mainstage app did not natively support portrait orientation, so focus the sidestage.
890+ ApplicationManager.requestFocusApplication(spreadTile.appId);
891+ }
892+ }
893+ }
894+ PropertyAction {
895+ target: spreadTile
896+ properties: "width,height,supportedOrientations,shellOrientationAngle,shellOrientation,orientations"
897+ }
898+ ScriptAction { script: { spreadTile.matchShellOrientation(); } }
899+ }
900+ }
901+ ]
902+
763903 onClicked: {
764904 if (spreadView.phase == 2) {
765905 spreadView.snapTo(index);
@@ -779,6 +919,16 @@ AbstractStage {
779919 ApplicationManager.stopApplication(ApplicationManager.get(index).appId);
780920 }
781921
922+ onFocusChanged: {
923+ if (focus && ApplicationManager.focusedApplicationId !== appId) {
924+ ApplicationManager.focusApplication(appId);
925+ }
926+
927+ if (focus && priv.sideStageEnabled && stage === ApplicationInfoInterface.SideStage) {
928+ sideStage.show();
929+ }
930+ }
931+
782932 Binding {
783933 target: root
784934 when: model.appId == priv.mainStageAppId
@@ -803,6 +953,71 @@ AbstractStage {
803953 }
804954 }
805955
956+ TabletSideStageTouchGesture {
957+ id: triGestureArea
958+ anchors.fill: parent
959+ enabled: priv.sideStageEnabled && !spreadView.active
960+ property var dragObject: null
961+ property string appId: ""
962+ dragComponent: dragComponent
963+ dragComponentProperties: { "appId": appId }
964+
965+ onPressed: {
966+ function matchDelegate(obj) { return String(obj.objectName).indexOf("tabletSpreadDelegate") >= 0; }
967+
968+ var delegateAtCenter = Functions.itemAt(spreadRow, x, y, matchDelegate);
969+ if (!delegateAtCenter) return;
970+
971+ appId = delegateAtCenter.appId;
972+ }
973+
974+ onClicked: {
975+ if (sideStage.shown) {
976+ sideStage.hide();
977+ } else {
978+ sideStage.show();
979+ }
980+ }
981+
982+ onDragStarted: {
983+ // If we're dragging to the sidestage.
984+ if (!sideStage.shown) {
985+ sideStage.show();
986+ }
987+ }
988+
989+ Component {
990+ id: dragComponent
991+ SessionContainer {
992+ property string appId: ""
993+ property var application: ApplicationManager.findApplication(appId)
994+
995+ session: application ? application.session : null
996+ interactive: false
997+ resizeSurface: false
998+ focus: false
999+
1000+ width: units.gu(40)
1001+ height: units.gu(40)
1002+
1003+ Drag.hotSpot.x: width/2
1004+ Drag.hotSpot.y: height/2
1005+ // only accept opposite stage.
1006+ Drag.keys: {
1007+ if (!application) return "Disabled";
1008+
1009+ if (application.stage === ApplicationInfo.MainStage) {
1010+ if (application.supportedOrientations & (Qt.PortraitOrientation|Qt.InvertedPortraitOrientation)) {
1011+ return "MainStage";
1012+ }
1013+ return "Disabled";
1014+ }
1015+ return "SideStage";
1016+ }
1017+ }
1018+ }
1019+ }
1020+
8061021 //eat touch events during the right edge gesture
8071022 MouseArea {
8081023 anchors.fill: parent
@@ -812,7 +1027,8 @@ AbstractStage {
8121027 DirectionalDragArea {
8131028 id: spreadDragArea
8141029 objectName: "spreadDragArea"
815− anchors { top: parent.top; right: parent.right; bottom: parent.bottom }
1030+ x: parent.width - root.dragAreaWidth
1031+ anchors { top: parent.top; bottom: parent.bottom }
8161032 width: root.dragAreaWidth
8171033 direction: Direction.Leftwards
8181034 enabled: (spreadView.phase != 2 && root.spreadEnabled) || dragging