@@ -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,37 +671,53 @@ 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
669688
670689 readonly property bool wantsMainStage: model.stage == ApplicationInfoInterface.MainStage
671690
691+ readonly property string appId: model.appId
672692 readonly property bool isDash: model.appId == "unity8-dash"
673693
694+ stage: model.stage
695+ fullscreen: {
696+ if (mainApp && stage === ApplicationInfoInterface.SideStage) {
697+ return mainApp.fullscreen;
698+ }
699+ return application ? application.fullscreen : false;
700+ }
701+
702+ supportedOrientations: {
703+ if (application) {
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;
709+ }
710+ return orientations;
711+ } else {
712+ // we just don't care
713+ return Qt.PortraitOrientation |
714+ Qt.LandscapeOrientation |
715+ Qt.InvertedPortraitOrientation |
716+ Qt.InvertedLandscapeOrientation;
717+ }
718+ }
719+
720+
674721 Binding {
675722 target: spreadTile.application
676723 property: "exemptFromLifecycle"
@@ -701,6 +748,28 @@ AbstractStage {
701748 enabled: spreadView.closingIndex >= 0
702749 UbuntuNumberAnimation {}
703750 }
751+ Connections {
752+ target: priv
753+ onSideStageEnabledChanged: refreshStage()
754+ }
755+
756+ Component.onCompleted: {
757+ refreshStage()
758+ stageChanged.connect(priv.updateStageApps);
759+ }
760+
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);
766+ }
767+ }
768+
769+ if (model.stage !== stage) {
770+ priv.setAppStage(appId, stage, false);
771+ }
772+ }
704773
705774 // This is required because none of the bindings are triggered in some cases:
706775 // When an app is closed, it might happen that ApplicationManager.get(nextInStack)
@@ -725,7 +794,7 @@ AbstractStage {
725794
726795 // TODO: Hiding tile when progress is such that it will be off screen.
727796 property bool occluded: {
728− if (spreadView.active) return false;
797+ if (spreadView.active && !offScreen) return false;
729798 else if (spreadTile.active) return false;
730799 else if (xTranslateAnimating) return false;
731800 else if (z <= 1 && priv.focusedAppDelegateIsDislocated) return false;
@@ -749,17 +818,87 @@ AbstractStage {
749818 return progress;
750819 }
751820
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
821+ shellOrientationAngle: root.shellOrientationAngle
822+ shellOrientation: root.shellOrientation
823+ orientations: root.orientations
824+
825+ states: [
826+ State {
827+ name: "MainStage"
828+ when: spreadTile.stage == ApplicationInfoInterface.MainStage
829+ },
830+ State {
831+ name: "SideStage"
832+ when: spreadTile.stage == ApplicationInfoInterface.SideStage
833+
834+ PropertyChanges {
835+ target: spreadTile
836+ width: spreadView.sideStageWidth
837+ height: priv.landscapeHeight
838+
839+ supportedOrientations: Qt.PortraitOrientation
840+ shellOrientationAngle: 0
841+ shellOrientation: Qt.PortraitOrientation
842+ orientations: sideStageOrientations
843+ }
844+ }
845+ ]
846+
847+ Orientations {
848+ id: sideStageOrientations
849+ primary: Qt.PortraitOrientation
850+ native_: Qt.PortraitOrientation
757851 portrait: root.orientations.portrait
758852 invertedPortrait: root.orientations.invertedPortrait
759853 landscape: root.orientations.landscape
760854 invertedLandscape: root.orientations.invertedLandscape
761855 }
762856
857+ transitions: [
858+ Transition {
859+ to: "SideStage"
860+ SequentialAnimation {
861+ PropertyAction {
862+ target: spreadTile
863+ properties: "width,height,supportedOrientations,shellOrientationAngle,shellOrientation,orientations"
864+ }
865+ ScriptAction {
866+ script: {
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.
872+ sideStage.show();
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();
876+ }
877+ }
878+ }
879+ }
880+ },
881+ Transition {
882+ from: "SideStage"
883+ SequentialAnimation {
884+ ScriptAction {
885+ script: {
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);
890+ }
891+ }
892+ }
893+ PropertyAction {
894+ target: spreadTile
895+ properties: "width,height,supportedOrientations,shellOrientationAngle,shellOrientation,orientations"
896+ }
897+ ScriptAction { script: { spreadTile.matchShellOrientation(); } }
898+ }
899+ }
900+ ]
901+
763902 onClicked: {
764903 if (spreadView.phase == 2) {
765904 spreadView.snapTo(index);
@@ -779,6 +918,16 @@ AbstractStage {
779918 ApplicationManager.stopApplication(ApplicationManager.get(index).appId);
780919 }
781920
921+ onFocusChanged: {
922+ if (focus && ApplicationManager.focusedApplicationId !== appId) {
923+ ApplicationManager.focusApplication(appId);
924+ }
925+
926+ if (focus && priv.sideStageEnabled && stage === ApplicationInfoInterface.SideStage) {
927+ sideStage.show();
928+ }
929+ }
930+
782931 Binding {
783932 target: root
784933 when: model.appId == priv.mainStageAppId
@@ -803,6 +952,71 @@ AbstractStage {
803952 }
804953 }
805954
955+ TabletSideStageTouchGesture {
956+ id: triGestureArea
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 }
963+
964+ onPressed: {
965+ function matchDelegate(obj) { return String(obj.objectName).indexOf("tabletSpreadDelegate") >= 0; }
966+
967+ var delegateAtCenter = Functions.itemAt(spreadRow, x, y, matchDelegate);
968+ if (!delegateAtCenter) return;
969+
970+ appId = delegateAtCenter.appId;
971+ }
972+
973+ onClicked: {
974+ if (sideStage.shown) {
975+ sideStage.hide();
976+ } else {
977+ sideStage.show();
978+ }
979+ }
980+
981+ onDragStarted: {
982+ // If we're dragging to the sidestage.
983+ if (!sideStage.shown) {
984+ sideStage.show();
985+ }
986+ }
987+
988+ Component {
989+ id: dragComponent
990+ SessionContainer {
991+ property string appId: ""
992+ property var application: ApplicationManager.findApplication(appId)
993+
994+ session: application ? application.session : null
995+ interactive: false
996+ resizeSurface: false
997+ focus: false
998+
999+ width: units.gu(40)
1000+ height: units.gu(40)
1001+
1002+ Drag.hotSpot.x: width/2
1003+ Drag.hotSpot.y: height/2
1004+ // only accept opposite stage.
1005+ Drag.keys: {
1006+ if (!application) return "Disabled";
1007+
1008+ if (application.stage === ApplicationInfo.MainStage) {
1009+ if (application.supportedOrientations & (Qt.PortraitOrientation|Qt.InvertedPortraitOrientation)) {
1010+ return "MainStage";
1011+ }
1012+ return "Disabled";
1013+ }
1014+ return "SideStage";
1015+ }
1016+ }
1017+ }
1018+ }
1019+
8061020 //eat touch events during the right edge gesture
8071021 MouseArea {
8081022 anchors.fill: parent
@@ -812,7 +1026,8 @@ AbstractStage {
8121026 DirectionalDragArea {
8131027 id: spreadDragArea
8141028 objectName: "spreadDragArea"
815− anchors { top: parent.top; right: parent.right; bottom: parent.bottom }
1029+ x: parent.width - root.dragAreaWidth
1030+ anchors { top: parent.top; bottom: parent.bottom }
8161031 width: root.dragAreaWidth
8171032 direction: Direction.Leftwards
8181033 enabled: (spreadView.phase != 2 && root.spreadEnabled) || dragging