@@ -119,8 +119,7 @@ FocusScope {
122− property Item itemConfiningMouseCursor: !spreadShown && priv.focusedAppDelegate && priv.focusedAppDelegate.surface &&
122+ property Item itemConfiningMouseCursor: !spreadShown && priv.focusedAppDelegate && priv.focusedAppDelegate.window.confinesMousePointer ?
123− priv.focusedAppDelegate.surface.confinesMousePointer ?
124 priv.focusedAppDelegate.clientAreaItem : null;
123 priv.focusedAppDelegate.clientAreaItem : null;
126 signal itemSnapshotRequested(Item item)
125 signal itemSnapshotRequested(Item item)
@@ -186,29 +185,34 @@ FocusScope {
186 GlobalShortcut {
185 GlobalShortcut {
187 id: maximizeWindowShortcut
186 id: maximizeWindowShortcut
188 shortcut: Qt.MetaModifier|Qt.ControlModifier|Qt.Key_Up
187 shortcut: Qt.MetaModifier|Qt.ControlModifier|Qt.Key_Up
189− onTriggered: priv.focusedAppDelegate.maximize()
188+ onTriggered: priv.focusedAppDelegate.requestMaximize()
190 active: root.state == "windowed" && priv.focusedAppDelegate && priv.focusedAppDelegate.canBeMaximized
189 active: root.state == "windowed" && priv.focusedAppDelegate && priv.focusedAppDelegate.canBeMaximized
193 GlobalShortcut {
192 GlobalShortcut {
194 id: maximizeWindowLeftShortcut
193 id: maximizeWindowLeftShortcut
195 shortcut: Qt.MetaModifier|Qt.ControlModifier|Qt.Key_Left
194 shortcut: Qt.MetaModifier|Qt.ControlModifier|Qt.Key_Left
196− onTriggered: priv.focusedAppDelegate.maximizeLeft()
195+ onTriggered: priv.focusedAppDelegate.requestMaximizeLeft()
197 active: root.state == "windowed" && priv.focusedAppDelegate && priv.focusedAppDelegate.canBeMaximizedLeftRight
196 active: root.state == "windowed" && priv.focusedAppDelegate && priv.focusedAppDelegate.canBeMaximizedLeftRight
200 GlobalShortcut {
199 GlobalShortcut {
201 id: maximizeWindowRightShortcut
200 id: maximizeWindowRightShortcut
202 shortcut: Qt.MetaModifier|Qt.ControlModifier|Qt.Key_Right
201 shortcut: Qt.MetaModifier|Qt.ControlModifier|Qt.Key_Right
203− onTriggered: priv.focusedAppDelegate.maximizeRight()
202+ onTriggered: priv.focusedAppDelegate.requestMaximizeRight()
204 active: root.state == "windowed" && priv.focusedAppDelegate && priv.focusedAppDelegate.canBeMaximizedLeftRight
203 active: root.state == "windowed" && priv.focusedAppDelegate && priv.focusedAppDelegate.canBeMaximizedLeftRight
207 GlobalShortcut {
206 GlobalShortcut {
208 id: minimizeRestoreShortcut
207 id: minimizeRestoreShortcut
209 shortcut: Qt.MetaModifier|Qt.ControlModifier|Qt.Key_Down
208 shortcut: Qt.MetaModifier|Qt.ControlModifier|Qt.Key_Down
210− onTriggered: priv.focusedAppDelegate.anyMaximized
210+ if (priv.focusedAppDelegate.anyMaximized) {
211− ? priv.focusedAppDelegate.restoreFromMaximized() : priv.focusedAppDelegate.minimize()
211+ priv.focusedAppDelegate.requestRestore();
213+ priv.focusedAppDelegate.requestMinimize();
212 active: root.state == "windowed" && priv.focusedAppDelegate
216 active: root.state == "windowed" && priv.focusedAppDelegate
@@ -244,20 +248,10 @@ FocusScope {
246 function minimizeAllWindows() {
250 function minimizeAllWindows() {
247− for (var i = 0; i < appRepeater.count; i++) {
251+ for (var i = appRepeater.count - 1; i >= 0; i--) {
248− var appDelegate = appRepeater.itemAt(i);
249− if (appDelegate && !appDelegate.minimized) {
250− appDelegate.minimize();
255− function focusNext() {
256− for (var i = 0; i < appRepeater.count; i++) {
257 var appDelegate = appRepeater.itemAt(i);
252 var appDelegate = appRepeater.itemAt(i);
258 if (appDelegate && !appDelegate.minimized) {
253 if (appDelegate && !appDelegate.minimized) {
259− appDelegate.focus = true;
254+ appDelegate.requestMinimize();
@@ -358,8 +352,8 @@ FocusScope {
358 Connections {
352 Connections {
359 target: PanelState
353 target: PanelState
360 onCloseClicked: { if (priv.focusedAppDelegate) { priv.focusedAppDelegate.close(); } }
354 onCloseClicked: { if (priv.focusedAppDelegate) { priv.focusedAppDelegate.close(); } }
361− onMinimizeClicked: { if (priv.focusedAppDelegate) { priv.focusedAppDelegate.minimize(); } }
355+ onMinimizeClicked: { if (priv.focusedAppDelegate) { priv.focusedAppDelegate.requestMinimize(); } }
362− onRestoreClicked: { if (priv.focusedAppDelegate) { priv.focusedAppDelegate.restoreFromMaximized(); } }
356+ onRestoreClicked: { if (priv.focusedAppDelegate) { priv.focusedAppDelegate.requestRestore(); } }
365 Binding {
359 Binding {
@@ -434,13 +428,6 @@ FocusScope {
438− target: MirFocusController
439− property: "focusedSurface"
440− value: priv.focusedAppDelegate ? priv.focusedAppDelegate.focusedSurface : null
441− when: !appRepeater.startingUp && root.parent
444 states: [
431 states: [
446 name: "spread"; when: priv.goneToSpread
433 name: "spread"; when: priv.goneToSpread
@@ -633,7 +620,7 @@ FocusScope {
634 onShownChanged: {
621 onShownChanged: {
635 if (!shown && priv.mainStageDelegate && !root.spreadShown) {
622 if (!shown && priv.mainStageDelegate && !root.spreadShown) {
636− priv.mainStageDelegate.claimFocus();
623+ priv.mainStageDelegate.activate();
@@ -666,14 +653,23 @@ FocusScope {
669− TopLevelSurfaceRepeater {
656+ Repeater {
670 id: appRepeater
657 id: appRepeater
671 model: topLevelSurfaceList
658 model: topLevelSurfaceList
672 objectName: "appRepeater"
659 objectName: "appRepeater"
661+ function indexOf(delegateItem) {
662+ for (var i = 0; i < count; i++) {
663+ if (itemAt(i) === delegateItem) {
674 delegate: FocusScope {
670 delegate: FocusScope {
675 id: appDelegate
671 id: appDelegate
676− objectName: "appDelegate_" + model.id
672+ objectName: "appDelegate_" + model.window.id
677 property int itemIndex: index // We need this from outside the repeater
673 property int itemIndex: index // We need this from outside the repeater
678 // z might be overriden in some cases by effects, but we need z ordering
674 // z might be overriden in some cases by effects, but we need z ordering
679 // to calculate occlusion detection
675 // to calculate occlusion detection
@@ -685,11 +681,11 @@ FocusScope {
686 z: normalZ
682 z: normalZ
688− // Normally we want x/y where we request it to be. Width/height of our delegate will
684+ // Normally we want x/y where the surface thinks it is. Width/height of our delegate will
689 // match what the actual surface size is.
685 // match what the actual surface size is.
690 // Don't write to those, they will be set by states
686 // Don't write to those, they will be set by states
691− x: requestedX
687+ x: model.window.position.x - clientAreaItem.x
692− y: requestedY
688+ y: model.window.position.y - clientAreaItem.y
693 width: decoratedWindow.implicitWidth
689 width: decoratedWindow.implicitWidth
694 height: decoratedWindow.implicitHeight
690 height: decoratedWindow.implicitHeight
@@ -699,6 +695,12 @@ FocusScope {
699 property real requestedY: windowedY
695 property real requestedY: windowedY
700 property real requestedWidth: windowedWidth
696 property real requestedWidth: windowedWidth
701 property real requestedHeight: windowedHeight
697 property real requestedHeight: windowedHeight
699+ target: model.window; property: "requestedPosition"
700+ // miral doesn't know about our window decorations. So we have to deduct them
701+ value: Qt.point(appDelegate.requestedX + appDelegate.clientAreaItem.x,
702+ appDelegate.requestedY + appDelegate.clientAreaItem.y)
703 // In those are for windowed mode. Those values basically store the window's properties
705 // In those are for windowed mode. Those values basically store the window's properties
704 // when having a floating window. If you want to move/resize a window in normal mode, this is what you want to write to.
706 // when having a floating window. If you want to move/resize a window in normal mode, this is what you want to write to.
@@ -767,7 +769,7 @@ FocusScope {
767 maximizedTopLeft || maximizedTopRight || maximizedBottomLeft || maximizedBottomRight
769 maximizedTopLeft || maximizedTopRight || maximizedBottomLeft || maximizedBottomRight
769 readonly property bool minimized: windowState & WindowStateStorage.WindowStateMinimized
771 readonly property bool minimized: windowState & WindowStateStorage.WindowStateMinimized
770− readonly property bool fullscreen: surface ? surface.state === Mir.FullscreenState : application.fullscreen
772+ readonly property bool fullscreen: window.state === Mir.FullscreenState
772 readonly property bool canBeMaximized: canBeMaximizedHorizontally && canBeMaximizedVertically
774 readonly property bool canBeMaximized: canBeMaximizedHorizontally && canBeMaximizedVertically
773 readonly property bool canBeMaximizedLeftRight: (maximumWidth == 0 || maximumWidth >= appContainer.width/2) &&
775 readonly property bool canBeMaximizedLeftRight: (maximumWidth == 0 || maximumWidth >= appContainer.width/2) &&
@@ -793,7 +795,9 @@ FocusScope {
793 priv.updateMainAndSideStageIndexes()
795 priv.updateMainAndSideStageIndexes()
796− readonly property var surface: model.surface
798+ readonly property var surface: model.window.surface
799+ readonly property var window: model.window
797 readonly property alias resizeArea: resizeArea
801 readonly property alias resizeArea: resizeArea
798 readonly property alias focusedSurface: decoratedWindow.focusedSurface
802 readonly property alias focusedSurface: decoratedWindow.focusedSurface
799 readonly property bool dragging: touchControls.overlayShown ? touchControls.dragging : decoratedWindow.dragging
803 readonly property bool dragging: touchControls.overlayShown ? touchControls.dragging : decoratedWindow.dragging
@@ -802,6 +806,25 @@ FocusScope {
802 readonly property bool isDash: appId == "unity8-dash"
806 readonly property bool isDash: appId == "unity8-dash"
803 readonly property alias clientAreaItem: decoratedWindow.clientAreaItem
807 readonly property alias clientAreaItem: decoratedWindow.clientAreaItem
809+ function activate() {
810+ if (model.window.focused) {
811+ updateQmlFocusFromMirSurfaceFocus();
813+ model.window.activate();
816+ function requestMaximize() { model.window.requestState(Mir.MaximizedState); }
817+ function requestMaximizeVertically() { model.window.requestState(Mir.VertMaximizedState); }
818+ function requestMaximizeHorizontally() { model.window.requestState(Mir.HorizMaximizedState); }
819+ function requestMaximizeLeft() { model.window.requestState(Mir.MaximizedLeftState); }
820+ function requestMaximizeRight() { model.window.requestState(Mir.MaximizedRightState); }
821+ function requestMaximizeTopLeft() { model.window.requestState(Mir.MaximizedTopLeftState); }
822+ function requestMaximizeTopRight() { model.window.requestState(Mir.MaximizedTopRightState); }
823+ function requestMaximizeBottomLeft() { model.window.requestState(Mir.MaximizedBottomLeftState); }
824+ function requestMaximizeBottomRight() { model.window.requestState(Mir.MaximizedBottomRightState); }
825+ function requestMinimize() { model.window.requestState(Mir.MinimizedState); }
826+ function requestRestore() { model.window.requestState(Mir.RestoredState); }
805 function claimFocus() {
828 function claimFocus() {
806 if (root.state == "spread") {
829 if (root.state == "spread") {
807 spreadItem.highlightedIndex = index
830 spreadItem.highlightedIndex = index
@@ -813,45 +836,60 @@ FocusScope {
814 priv.updateMainAndSideStageIndexes();
837 priv.updateMainAndSideStageIndexes();
817 if (root.mode == "windowed") {
839 if (root.mode == "windowed") {
818 appDelegate.restore(true /* animated */, appDelegate.windowState);
840 appDelegate.restore(true /* animated */, appDelegate.windowState);
820− appDelegate.focus = true;
842+ appDelegate.focus = true;
824− target: model.surface
845+ function updateQmlFocusFromMirSurfaceFocus() {
825− onFocusRequested: {
846+ if (model.window.focused) {
826 claimFocus();
847 claimFocus();
848+ priv.focusedAppDelegate = appDelegate;
829 Connections {
852 Connections {
830− target: model.application
853+ target: model.window
855+ updateQmlFocusFromMirSurfaceFocus();
831 onFocusRequested: {
857 onFocusRequested: {
832− if (!model.surface) {
858+ appDelegate.activate();
833− // when an app has no surfaces, we assume there's only one entry representing it:
859+ }
834− // this delegate.
860+ onStateChanged: {
835− claimFocus();
861+ if (model.window.state === Mir.MinimizedState) {
836− } else {
862+ appDelegate.minimize();
837− // if the application has surfaces, focus request should be at surface-level.
863+ } else if (model.window.state === Mir.MaximizedState) {
864+ appDelegate.maximize();
865+ } else if (model.window.state === Mir.VertMaximizedState) {
866+ appDelegate.maximizeVertically();
867+ } else if (model.window.state === Mir.HorizMaximizedState) {
868+ appDelegate.maximizeHorizontally();
869+ } else if (model.window.state === Mir.MaximizedLeftState) {
870+ appDelegate.maximizeLeft();
871+ } else if (model.window.state === Mir.MaximizedRightState) {
872+ appDelegate.maximizeRight();
873+ } else if (model.window.state === Mir.MaximizedTopLeftState) {
874+ appDelegate.maximizeTopLeft();
875+ } else if (model.window.state === Mir.MaximizedTopRightState) {
876+ appDelegate.maximizeTopRight();
877+ } else if (model.window.state === Mir.MaximizedBottomLeftState) {
878+ appDelegate.maximizeBottomLeft();
879+ } else if (model.window.state === Mir.MaximizedBottomRightState) {
880+ appDelegate.maximizeBottomRight();
881+ } else if (model.window.state === Mir.RestoredState) {
882+ if (decoratedWindow.dragging) {
883+ appDelegate.restore(false, WindowStateStorage.WindowStateNormal);
884+ } else if (appDelegate.anyMaximized) {
885+ appDelegate.restoreFromMaximized()
887+ appDelegate.restore();
843− if (appRepeater.startingUp)
847− topLevelSurfaceList.raiseId(model.id);
848− priv.focusedAppDelegate = appDelegate;
849− } else if (!focus && priv.focusedAppDelegate === appDelegate && root.state != "spread") {
850− priv.focusedAppDelegate = null;
851− // FIXME: No idea why the Binding{} doens't update when focusedAppDelegate turns null
852− MirFocusController.focusedSurface = null;
855 Component.onCompleted: {
893 Component.onCompleted: {
856 if (application && application.rotatesWindowContents) {
894 if (application && application.rotatesWindowContents) {
857 decoratedWindow.surfaceOrientationAngle = shellOrientationAngle;
895 decoratedWindow.surfaceOrientationAngle = shellOrientationAngle;
@@ -865,16 +903,7 @@ FocusScope {
865 // Now load any saved state. This needs to happen *after* the cascading!
903 // Now load any saved state. This needs to happen *after* the cascading!
866 resizeArea.loadWindowState();
904 resizeArea.loadWindowState();
868− // NB: We're differentiating if this delegate was created in response to a new entry in the model
906+ updateQmlFocusFromMirSurfaceFocus();
869− // or if the Repeater is just populating itself with delegates to match the model it received.
870− if (!appRepeater.startingUp) {
871− // a top level window is always the focused one when it first appears, unfocusing
872− // any preexisting one
873− if (root.state == "spread") {
874− spreadItem.highlightedIndex = index;
879 refreshStage();
908 refreshStage();
880 _constructing = false;
909 _constructing = false;
@@ -889,16 +918,6 @@ FocusScope {
889 priv.updateForegroundMaximizedApp();
918 priv.updateForegroundMaximizedApp();
893− // focus some other window
894− for (var i = 0; i < appRepeater.count; i++) {
895− var appDelegate = appRepeater.itemAt(i);
896− if (appDelegate && !appDelegate.minimized && i != index) {
897− appDelegate.focus = true;
904 onVisuallyMaximizedChanged: priv.updateForegroundMaximizedApp()
923 onVisuallyMaximizedChanged: priv.updateForegroundMaximizedApp()
@@ -919,7 +938,7 @@ FocusScope {
919 || focusAnimation.running || rightEdgeFocusAnimation.running || hidingAnimation.running
938 || focusAnimation.running || rightEdgeFocusAnimation.running || hidingAnimation.running
921 function close() {
940 function close() {
922− model.surface.close();
941+ model.window.close();
925 function maximize(animated) {
944 function maximize(animated) {
@@ -970,7 +989,6 @@ FocusScope {
970 animationsEnabled = (animated === undefined) || animated;
989 animationsEnabled = (animated === undefined) || animated;
971 windowState = state || WindowStateStorage.WindowStateRestored;
990 windowState = state || WindowStateStorage.WindowStateRestored;
972 windowState &= ~WindowStateStorage.WindowStateMinimized; // clear the minimized bit
991 windowState &= ~WindowStateStorage.WindowStateMinimized; // clear the minimized bit
976 function playFocusAnimation() {
994 function playFocusAnimation() {
@@ -984,7 +1002,7 @@ FocusScope {
984 rightEdgeFocusAnimation.start()
1002 rightEdgeFocusAnimation.start()
986 } else if (state == "windowedRightEdge" || state == "windowed") {
1004 } else if (state == "windowedRightEdge" || state == "windowed") {
987− claimFocus();
1005+ activate();
988 } else {
1006 } else {
989 focusAnimation.start()
1007 focusAnimation.start()
@@ -1022,10 +1040,10 @@ FocusScope {
1023 duration: UbuntuAnimation.SnapDuration
1041 duration: UbuntuAnimation.SnapDuration
1024 onStarted: {
1042 onStarted: {
1025− topLevelSurfaceList.raiseId(model.id);
1043+ topLevelSurfaceList.raiseId(model.window.id);
1027 onStopped: {
1045 onStopped: {
1028− appDelegate.claimFocus();
1046+ appDelegate.activate();
1031 ParallelAnimation {
1049 ParallelAnimation {
@@ -1035,7 +1053,7 @@ FocusScope {
1035 UbuntuNumberAnimation { target: decoratedWindow; properties: "angle"; to: 0; duration: priv.animationDuration }
1053 UbuntuNumberAnimation { target: decoratedWindow; properties: "angle"; to: 0; duration: priv.animationDuration }
1036 UbuntuNumberAnimation { target: decoratedWindow; properties: "itemScale"; to: 1; duration: priv.animationDuration }
1054 UbuntuNumberAnimation { target: decoratedWindow; properties: "itemScale"; to: 1; duration: priv.animationDuration }
1037 onStopped: {
1055 onStopped: {
1038− appDelegate.focus = true
1056+ appDelegate.activate();
1041 ParallelAnimation {
1059 ParallelAnimation {
@@ -1399,14 +1417,6 @@ FocusScope {
1399 SequentialAnimation {
1417 SequentialAnimation {
1400 UbuntuNumberAnimation { target: appDelegate; properties: "requestedX,requestedY,opacity,scale,requestedWidth,requestedHeight" }
1418 UbuntuNumberAnimation { target: appDelegate; properties: "requestedX,requestedY,opacity,scale,requestedWidth,requestedHeight" }
1401 PropertyAction { target: appDelegate; property: "visuallyMinimized" }
1419 PropertyAction { target: appDelegate; property: "visuallyMinimized" }
1404− if (appDelegate.minimized) {
1405− appDelegate.focus = false;
1412 Transition {
1422 Transition {
@@ -1497,7 +1507,7 @@ FocusScope {
1497 visible: enabled
1507 visible: enabled
1499 onPressed: {
1509 onPressed: {
1500− appDelegate.focus = true;
1510+ appDelegate.activate();
1503 Component.onDestruction: {
1513 Component.onDestruction: {
@@ -1511,7 +1521,7 @@ FocusScope {
1511 anchors.left: appDelegate.left
1521 anchors.left: appDelegate.left
1512 anchors.top: appDelegate.top
1522 anchors.top: appDelegate.top
1513 application: model.application
1523 application: model.application
1514− surface: model.surface
1524+ surface: model.window.surface
1515 active: appDelegate.focus
1525 active: appDelegate.focus
1516 focus: true
1526 focus: true
1517 interactive: root.interactive
1527 interactive: root.interactive
@@ -1536,21 +1546,21 @@ FocusScope {
1536 onCloseClicked: { appDelegate.close(); }
1546 onCloseClicked: { appDelegate.close(); }
1537 onMaximizeClicked: {
1547 onMaximizeClicked: {
1538 if (appDelegate.canBeMaximized) {
1548 if (appDelegate.canBeMaximized) {
1539− appDelegate.anyMaximized ? appDelegate.restoreFromMaximized() : appDelegate.maximize();
1549+ appDelegate.anyMaximized ? appDelegate.requestRestore() : appDelegate.requestMaximize();
1542 onMaximizeHorizontallyClicked: {
1552 onMaximizeHorizontallyClicked: {
1543 if (appDelegate.canBeMaximizedHorizontally) {
1553 if (appDelegate.canBeMaximizedHorizontally) {
1544− appDelegate.maximizedHorizontally ? appDelegate.restoreFromMaximized() : appDelegate.maximizeHorizontally()
1554+ appDelegate.maximizedHorizontally ? appDelegate.requestRestore() : appDelegate.requestMaximizeHorizontally()
1547 onMaximizeVerticallyClicked: {
1557 onMaximizeVerticallyClicked: {
1548 if (appDelegate.canBeMaximizedVertically) {
1558 if (appDelegate.canBeMaximizedVertically) {
1549− appDelegate.maximizedVertically ? appDelegate.restoreFromMaximized() : appDelegate.maximizeVertically()
1559+ appDelegate.maximizedVertically ? appDelegate.requestRestore() : appDelegate.requestMaximizeVertically()
1552− onMinimizeClicked: appDelegate.minimize()
1562+ onMinimizeClicked: { appDelegate.requestMinimize(); }
1553− onDecorationPressed: { appDelegate.focus = true; }
1563+ onDecorationPressed: { appDelegate.activate(); }
1554 onDecorationReleased: fakeRectangle.commit();
1564 onDecorationReleased: fakeRectangle.commit();
1556 property real angle: 0
1566 property real angle: 0
@@ -1597,12 +1607,12 @@ FocusScope {
1597 WindowedFullscreenPolicy {
1607 WindowedFullscreenPolicy {
1598 id: windowedFullscreenPolicy
1608 id: windowedFullscreenPolicy
1599 active: root.mode == "windowed"
1609 active: root.mode == "windowed"
1600− surface: model.surface
1610+ surface: model.window.surface
1602 StagedFullscreenPolicy {
1612 StagedFullscreenPolicy {
1603 id: stagedFullscreenPolicy
1613 id: stagedFullscreenPolicy
1604 active: root.mode == "staged" || root.mode == "stagedWithSideStage"
1614 active: root.mode == "staged" || root.mode == "stagedWithSideStage"
1605− surface: model.surface
1615+ surface: model.window.surface
1608 SpreadDelegateInputArea {
1618 SpreadDelegateInputArea {
@@ -1615,16 +1625,13 @@ FocusScope {
1615 onClicked: {
1625 onClicked: {
1616 spreadItem.highlightedIndex = index;
1626 spreadItem.highlightedIndex = index;
1617 if (distance == 0) {
1627 if (distance == 0) {
1628+ model.window.activate();
1618 priv.goneToSpread = false;
1629 priv.goneToSpread = false;
1621 onClose: {
1632 onClose: {
1622 priv.closingIndex = index
1633 priv.closingIndex = index
1623− if (model.surface) { // could be stopped by OOM
1634+ model.window.close();
1624− model.surface.close()
1625− } else if (model.application) {
1626− root.applicationManager.stopApplication(model.application.appId);