@@ -68,28 +68,27 @@ AbstractStage {
6868 id: maximizeWindowShortcut
6969 shortcut: Qt.MetaModifier|Qt.ControlModifier|Qt.Key_Up
7070 onTriggered: priv.focusedAppDelegate.maximize()
71− active: priv.focusedAppDelegate !== null
71+ active: priv.focusedAppDelegate !== null && priv.focusedAppDelegate.canBeMaximized
7272 }
7373
7474 GlobalShortcut {
7575 id: maximizeWindowLeftShortcut
7676 shortcut: Qt.MetaModifier|Qt.ControlModifier|Qt.Key_Left
7777 onTriggered: priv.focusedAppDelegate.maximizeLeft()
78− active: priv.focusedAppDelegate !== null
78+ active: priv.focusedAppDelegate !== null && priv.focusedAppDelegate.canBeMaximizedLeftRight
7979 }
8080
8181 GlobalShortcut {
8282 id: maximizeWindowRightShortcut
8383 shortcut: Qt.MetaModifier|Qt.ControlModifier|Qt.Key_Right
8484 onTriggered: priv.focusedAppDelegate.maximizeRight()
85− active: priv.focusedAppDelegate !== null
85+ active: priv.focusedAppDelegate !== null && priv.focusedAppDelegate.canBeMaximizedLeftRight
8686 }
8787
8888 GlobalShortcut {
8989 id: minimizeRestoreShortcut
9090 shortcut: Qt.MetaModifier|Qt.ControlModifier|Qt.Key_Down
91− onTriggered: priv.focusedAppDelegate.maximized || priv.focusedAppDelegate.maximizedLeft || priv.focusedAppDelegate.maximizedRight ||
92− priv.focusedAppDelegate.maximizedHorizontally || priv.focusedAppDelegate.maximizedVertically
91+ onTriggered: priv.focusedAppDelegate.anyMaximized
9392 ? priv.focusedAppDelegate.restoreFromMaximized() : priv.focusedAppDelegate.minimize()
9493 active: priv.focusedAppDelegate !== null
9594 }
@@ -276,7 +275,7 @@ AbstractStage {
276275 value: appDelegate.requestedY -
277276 Math.min(appDelegate.requestedY - PanelState.panelHeight,
278277 Math.max(0, priv.virtualKeyboardHeight - (appContainer.height - (appDelegate.requestedY + appDelegate.height))))
279− when: root.oskEnabled && appDelegate.focus && appDelegate.state == "normal"
278+ when: root.oskEnabled && appDelegate.focus && (appDelegate.state == "normal" || appDelegate.state == "restored")
280279 && SurfaceManager.inputMethodSurface
281280 && SurfaceManager.inputMethodSurface.state != Mir.HiddenState
282281 && SurfaceManager.inputMethodSurface.state != Mir.MinimizedState
@@ -291,7 +290,7 @@ AbstractStage {
291290 onShellOrientationAngleChanged: {
292291 // at this point decoratedWindow.surfaceOrientationAngle is the old shellOrientationAngle
293292 if (application && application.rotatesWindowContents) {
294− if (state == "normal") {
293+ if (state == "normal" || state == "restored") {
295294 var angleDiff = decoratedWindow.surfaceOrientationAngle - shellOrientationAngle;
296295 angleDiff = (360 + angleDiff) % 360;
297296 if (angleDiff === 90 || angleDiff === 270) {
@@ -317,14 +316,29 @@ AbstractStage {
317316 property int requestedWidth: -1
318317 property int requestedHeight: -1
319318
320− readonly property bool maximized: windowState & WindowStateStorage.WindowStateMaximized
321− readonly property bool maximizedLeft: windowState & WindowStateStorage.WindowStateMaximizedLeft
322− readonly property bool maximizedRight: windowState & WindowStateStorage.WindowStateMaximizedRight
323− readonly property bool maximizedHorizontally: windowState & WindowStateStorage.WindowStateMaximizedHorizontally
324− readonly property bool maximizedVertically: windowState & WindowStateStorage.WindowStateMaximizedVertically
319+ readonly property bool maximized: windowState === WindowStateStorage.WindowStateMaximized
320+ readonly property bool maximizedLeft: windowState === WindowStateStorage.WindowStateMaximizedLeft
321+ readonly property bool maximizedRight: windowState === WindowStateStorage.WindowStateMaximizedRight
322+ readonly property bool maximizedHorizontally: windowState === WindowStateStorage.WindowStateMaximizedHorizontally
323+ readonly property bool maximizedVertically: windowState === WindowStateStorage.WindowStateMaximizedVertically
324+ readonly property bool maximizedTopLeft: windowState === WindowStateStorage.WindowStateMaximizedTopLeft
325+ readonly property bool maximizedTopRight: windowState === WindowStateStorage.WindowStateMaximizedTopRight
326+ readonly property bool maximizedBottomLeft: windowState === WindowStateStorage.WindowStateMaximizedBottomLeft
327+ readonly property bool maximizedBottomRight: windowState === WindowStateStorage.WindowStateMaximizedBottomRight
328+ readonly property bool anyMaximized: maximized || maximizedLeft || maximizedRight || maximizedHorizontally || maximizedVertically ||
329+ maximizedTopLeft || maximizedTopRight || maximizedBottomLeft || maximizedBottomRight
330+
325331 readonly property bool minimized: windowState & WindowStateStorage.WindowStateMinimized
326332 readonly property alias fullscreen: decoratedWindow.fullscreen
327333
334+ readonly property bool canBeMaximized: canBeMaximizedHorizontally && canBeMaximizedVertically
335+ readonly property bool canBeMaximizedLeftRight: (maximumWidth == 0 || maximumWidth >= appContainer.width/2) &&
336+ (maximumHeight == 0 || maximumHeight >= appContainer.height)
337+ readonly property bool canBeCornerMaximized: (maximumWidth == 0 || maximumWidth >= appContainer.width/2) &&
338+ (maximumHeight == 0 || maximumHeight >= appContainer.height/2)
339+ readonly property bool canBeMaximizedHorizontally: maximumWidth == 0 || maximumWidth >= appContainer.width
340+ readonly property bool canBeMaximizedVertically: maximumHeight == 0 || maximumHeight >= appContainer.height
341+
328342 property int windowState: WindowStateStorage.WindowStateNormal
329343 property bool animationsEnabled: true
330344 property alias title: decoratedWindow.title
@@ -342,7 +356,7 @@ AbstractStage {
342356 if (spread.state == "altTab") {
343357 spread.cancel();
344358 }
345− appDelegate.restore();
359+ appDelegate.restore(true /* animated */, appDelegate.windowState);
346360 }
347361 Connections {
348362 target: model.surface
@@ -362,9 +376,6 @@ AbstractStage {
362376 }
363377
364378 onFocusChanged: {
365− if (appRepeater.startingUp)
366− return;
367−
368379 if (focus) {
369380 // If we're orphan (!parent) it means this stage is no longer the current one
370381 // and will be deleted shortly. So we should no longer have a say over the model
@@ -450,28 +461,34 @@ AbstractStage {
450461 animationsEnabled = (animated === undefined) || animated;
451462 windowState = WindowStateStorage.WindowStateMaximizedVertically;
452463 }
464+ function maximizeTopLeft(animated) {
465+ animationsEnabled = (animated === undefined) || animated;
466+ windowState = WindowStateStorage.WindowStateMaximizedTopLeft;
467+ }
468+ function maximizeTopRight(animated) {
469+ animationsEnabled = (animated === undefined) || animated;
470+ windowState = WindowStateStorage.WindowStateMaximizedTopRight;
471+ }
472+ function maximizeBottomLeft(animated) {
473+ animationsEnabled = (animated === undefined) || animated;
474+ windowState = WindowStateStorage.WindowStateMaximizedBottomLeft;
475+ }
476+ function maximizeBottomRight(animated) {
477+ animationsEnabled = (animated === undefined) || animated;
478+ windowState = WindowStateStorage.WindowStateMaximizedBottomRight;
479+ }
453480 function minimize(animated) {
454481 animationsEnabled = (animated === undefined) || animated;
455482 windowState |= WindowStateStorage.WindowStateMinimized; // add the minimized bit
456483 }
457484 function restoreFromMaximized(animated) {
458485 animationsEnabled = (animated === undefined) || animated;
459− windowState = WindowStateStorage.WindowStateNormal;
486+ windowState = WindowStateStorage.WindowStateRestored;
460487 }
461− function restore(animated) {
488+ function restore(animated,state) {
462489 animationsEnabled = (animated === undefined) || animated;
490+ windowState = state || WindowStateStorage.WindowStateRestored;
463491 windowState &= ~WindowStateStorage.WindowStateMinimized; // clear the minimized bit
464− if (maximized)
465− maximize();
466− else if (maximizedLeft)
467− maximizeLeft();
468− else if (maximizedRight)
469− maximizeRight();
470− else if (maximizedHorizontally)
471− maximizeHorizontally();
472− else if (maximizedVertically)
473− maximizeVertically();
474−
475492 focus = true;
476493 }
477494
@@ -488,9 +505,12 @@ AbstractStage {
488505 duration: UbuntuAnimation.SnapDuration
489506 }
490507
508+ property real restoredX
509+ property real restoredY
510+
491511 states: [
492512 State {
493− name: "fullscreen"; when: decoratedWindow.fullscreen && !appDelegate.minimized
513+ name: "fullscreen"; when: appDelegate.fullscreen && !appDelegate.minimized
494514 PropertyChanges {
495515 target: appDelegate;
496516 x: rotation == 0 ? 0 : (parent.width - width) / 2 + (shellOrientationAngle == 90 ? -PanelState.panelHeight : PanelState.panelHeight)
@@ -509,61 +529,94 @@ AbstractStage {
509529 }
510530 },
511531 State {
512− name: "maximized"; when: appDelegate.maximized && !appDelegate.minimized
532+ name: "restored";
533+ when: appDelegate.windowState == WindowStateStorage.WindowStateRestored
534+ extend: "normal"
513535 PropertyChanges {
514536 target: appDelegate;
515− x: root.leftMargin;
516− y: 0;
517− visuallyMinimized: false;
518− visuallyMaximized: true
537+ requestedX: restoredX;
538+ requestedY: restoredY;
519539 }
540+ },
541+ State {
542+ name: "maximized"; when: appDelegate.maximized && !appDelegate.minimized
520543 PropertyChanges {
521− target: decoratedWindow
544+ target: appDelegate;
545+ requestedX: root.leftMargin;
546+ requestedY: 0;
522547 requestedWidth: appContainer.width - root.leftMargin;
523548 requestedHeight: appContainer.height;
549+ visuallyMinimized: false;
550+ visuallyMaximized: true
524551 }
525552 },
526553 State {
527554 name: "maximizedLeft"; when: appDelegate.maximizedLeft && !appDelegate.minimized
528555 PropertyChanges {
529556 target: appDelegate
530− x: root.leftMargin
531− y: PanelState.panelHeight
532− }
533− PropertyChanges {
534− target: decoratedWindow
557+ requestedX: root.leftMargin
558+ requestedY: PanelState.panelHeight
535559 requestedWidth: (appContainer.width - root.leftMargin)/2
536560 requestedHeight: appContainer.height - PanelState.panelHeight
537561 }
538562 },
539563 State {
540564 name: "maximizedRight"; when: appDelegate.maximizedRight && !appDelegate.minimized
565+ extend: "maximizedLeft"
541566 PropertyChanges {
542567 target: appDelegate;
543− x: (appContainer.width + root.leftMargin)/2
544− y: PanelState.panelHeight
568+ requestedX: (appContainer.width + root.leftMargin)/2
545569 }
570+ },
571+ State {
572+ name: "maximizedTopLeft"; when: appDelegate.maximizedTopLeft && !appDelegate.minimized
546573 PropertyChanges {
547− target: decoratedWindow
574+ target: appDelegate
575+ requestedX: root.leftMargin
576+ requestedY: PanelState.panelHeight
548577 requestedWidth: (appContainer.width - root.leftMargin)/2
549− requestedHeight: appContainer.height - PanelState.panelHeight
578+ requestedHeight: (appContainer.height - PanelState.panelHeight)/2
579+ }
580+ },
581+ State {
582+ name: "maximizedTopRight"; when: appDelegate.maximizedTopRight && !appDelegate.minimized
583+ extend: "maximizedTopLeft"
584+ PropertyChanges {
585+ target: appDelegate
586+ requestedX: (appContainer.width + root.leftMargin)/2
587+ }
588+ },
589+ State {
590+ name: "maximizedBottomLeft"; when: appDelegate.maximizedBottomLeft && !appDelegate.minimized
591+ PropertyChanges {
592+ target: appDelegate
593+ requestedX: root.leftMargin
594+ requestedY: (appContainer.height + PanelState.panelHeight)/2
595+ requestedWidth: (appContainer.width - root.leftMargin)/2
596+ requestedHeight: appContainer.height/2
597+ }
598+ },
599+ State {
600+ name: "maximizedBottomRight"; when: appDelegate.maximizedBottomRight && !appDelegate.minimized
601+ extend: "maximizedBottomLeft"
602+ PropertyChanges {
603+ target: appDelegate
604+ requestedX: (appContainer.width + root.leftMargin)/2
550605 }
551606 },
552607 State {
553608 name: "maximizedHorizontally"; when: appDelegate.maximizedHorizontally && !appDelegate.minimized
554− PropertyChanges { target: appDelegate; x: root.leftMargin }
555− PropertyChanges { target: decoratedWindow; requestedWidth: appContainer.width - root.leftMargin }
609+ PropertyChanges { target: appDelegate; requestedX: root.leftMargin; requestedY: requestedY; requestedWidth: appContainer.width - root.leftMargin }
556610 },
557611 State {
558612 name: "maximizedVertically"; when: appDelegate.maximizedVertically && !appDelegate.minimized
559− PropertyChanges { target: appDelegate; y: PanelState.panelHeight }
560− PropertyChanges { target: decoratedWindow; requestedHeight: appContainer.height - PanelState.panelHeight }
613+ PropertyChanges { target: appDelegate; requestedX: requestedX; requestedY: PanelState.panelHeight; requestedHeight: appContainer.height - PanelState.panelHeight }
561614 },
562615 State {
563616 name: "minimized"; when: appDelegate.minimized
564617 PropertyChanges {
565618 target: appDelegate;
566− x: -appDelegate.width / 2;
619+ requestedX: -appDelegate.width / 2;
567620 scale: units.gu(5) / appDelegate.width;
568621 opacity: 0;
569622 visuallyMinimized: true;
@@ -573,21 +626,17 @@ AbstractStage {
573626 ]
574627 transitions: [
575628 Transition {
576− to: "normal"
629+ to: "normal,restored"
577630 enabled: appDelegate.animationsEnabled
578631 PropertyAction { target: appDelegate; properties: "visuallyMinimized,visuallyMaximized" }
579− UbuntuNumberAnimation { target: appDelegate; properties: "x,y,opacity,requestedWidth,requestedHeight,scale"; duration: UbuntuAnimation.FastDuration }
580− UbuntuNumberAnimation { target: decoratedWindow; properties: "requestedWidth,requestedHeight"; duration: UbuntuAnimation.FastDuration }
632+ UbuntuNumberAnimation { target: appDelegate; properties: "requestedX,requestedY,opacity,scale,requestedWidth,requestedHeight" }
581633 },
582634 Transition {
583635 to: "minimized"
584636 enabled: appDelegate.animationsEnabled
585637 PropertyAction { target: appDelegate; property: "visuallyMaximized" }
586638 SequentialAnimation {
587− ParallelAnimation {
588− UbuntuNumberAnimation { target: appDelegate; properties: "x,y,opacity,scale"; duration: UbuntuAnimation.FastDuration }
589− UbuntuNumberAnimation { target: decoratedWindow; properties: "requestedWidth,requestedHeight"; duration: UbuntuAnimation.FastDuration }
590− }
639+ UbuntuNumberAnimation { target: appDelegate; properties: "requestedX,requestedY,opacity,scale,requestedWidth,requestedHeight" }
591640 PropertyAction { target: appDelegate; property: "visuallyMinimized" }
592641 ScriptAction {
593642 script: {
@@ -604,10 +653,8 @@ AbstractStage {
604653 enabled: appDelegate.animationsEnabled
605654 PropertyAction { target: appDelegate; property: "visuallyMinimized" }
606655 SequentialAnimation {
607− ParallelAnimation {
608− UbuntuNumberAnimation { target: appDelegate; properties: "x,y,opacity,scale"; duration: UbuntuAnimation.FastDuration }
609− UbuntuNumberAnimation { target: decoratedWindow; properties: "requestedWidth,requestedHeight"; duration: UbuntuAnimation.FastDuration }
610− }
656+ ScriptAction { script: { fakeRectangle.stop(); } }
657+ UbuntuNumberAnimation { target: appDelegate; properties: "requestedX,requestedY,opacity,scale,requestedWidth,requestedHeight" }
611658 PropertyAction { target: appDelegate; property: "visuallyMaximized" }
612659 }
613660 }
@@ -674,27 +721,45 @@ AbstractStage {
674721 surface: model.surface
675722 active: appDelegate.focus
676723 focus: true
677− maximizeButtonShown: (maximumWidth == 0 || maximumWidth >= appContainer.width) &&
678− (maximumHeight == 0 || maximumHeight >= appContainer.height)
724+ maximizeButtonShown: appDelegate.canBeMaximized
679725 overlayShown: touchControls.overlayShown
726+ stageWidth: appContainer.width
727+ stageHeight: appContainer.height
680728
681729 requestedWidth: appDelegate.requestedWidth
682730 requestedHeight: appDelegate.requestedHeight
683731
684732 onCloseClicked: { appDelegate.close(); }
685− onMaximizeClicked: appDelegate.maximized || appDelegate.maximizedLeft || appDelegate.maximizedRight
686− || appDelegate.maximizedHorizontally || appDelegate.maximizedVertically
687− ? appDelegate.restoreFromMaximized() : appDelegate.maximize()
733+ onMaximizeClicked: appDelegate.anyMaximized ? appDelegate.restoreFromMaximized() : appDelegate.maximize();
688734 onMaximizeHorizontallyClicked: appDelegate.maximizedHorizontally ? appDelegate.restoreFromMaximized() : appDelegate.maximizeHorizontally()
689735 onMaximizeVerticallyClicked: appDelegate.maximizedVertically ? appDelegate.restoreFromMaximized() : appDelegate.maximizeVertically()
690736 onMinimizeClicked: appDelegate.minimize()
691737 onDecorationPressed: { appDelegate.focus = true; }
738+
739+ onFakeMaximizeAnimationRequested: if (!appDelegate.maximized) fakeRectangle.maximize(progress)
740+ onFakeMaximizeLeftAnimationRequested: if (!appDelegate.maximizedLeft) fakeRectangle.maximizeLeft(progress)
741+ onFakeMaximizeRightAnimationRequested: if (!appDelegate.maximizedRight) fakeRectangle.maximizeRight(progress)
742+ onFakeMaximizeTopLeftAnimationRequested: if (!appDelegate.maximizedTopLeft) fakeRectangle.maximizeTopLeft(progress);
743+ onFakeMaximizeTopRightAnimationRequested: if (!appDelegate.maximizedTopRight) fakeRectangle.maximizeTopRight(progress);
744+ onFakeMaximizeBottomLeftAnimationRequested: if (!appDelegate.maximizedBottomLeft) fakeRectangle.maximizeBottomLeft(progress);
745+ onFakeMaximizeBottomRightAnimationRequested: if (!appDelegate.maximizedBottomRight) fakeRectangle.maximizeBottomRight(progress);
746+ onStopFakeAnimation: fakeRectangle.stop();
692747 }
693748
694749 WindowControlsOverlay {
695750 id: touchControls
696− anchors.fill: appDelegate
697751 target: appDelegate
752+ stageWidth: appContainer.width
753+ stageHeight: appContainer.height
754+
755+ onFakeMaximizeAnimationRequested: decoratedWindow.fakeMaximizeAnimationRequested(progress)
756+ onFakeMaximizeLeftAnimationRequested: decoratedWindow.fakeMaximizeLeftAnimationRequested(progress)
757+ onFakeMaximizeRightAnimationRequested: decoratedWindow.fakeMaximizeRightAnimationRequested(progress)
758+ onFakeMaximizeTopLeftAnimationRequested: decoratedWindow.fakeMaximizeTopLeftAnimationRequested(progress)
759+ onFakeMaximizeTopRightAnimationRequested: decoratedWindow.fakeMaximizeTopRightAnimationRequested(progress)
760+ onFakeMaximizeBottomLeftAnimationRequested: decoratedWindow.fakeMaximizeBottomLeftAnimationRequested(progress)
761+ onFakeMaximizeBottomRightAnimationRequested: decoratedWindow.fakeMaximizeBottomRightAnimationRequested(progress)
762+ onStopFakeAnimation: decoratedWindow.stopFakeAnimation()
698763 }
699764
700765 WindowedFullscreenPolicy {
@@ -706,6 +771,14 @@ AbstractStage {
706771 }
707772 }
708773
774+ FakeMaximizeDelegate {
775+ id: fakeRectangle
776+ target: priv.focusedAppDelegate
777+ leftMargin: root.leftMargin
778+ appContainerWidth: appContainer.width
779+ appContainerHeight: appContainer.height
780+ }
781+
709782 EdgeBarrier {
710783 id: edgeBarrier
711784