on xenial help sign in
Take save/restore functions out of WindowResizeArea
1d037c5Daniel d'Andrada
qml/Stage/Stage.qml+39−9
@@ -847,6 +847,38 @@ FocusScope {
847 MirFocusController.focusedSurface = null;
847 MirFocusController.focusedSurface = null;
848 }
848 }
849 }
849 }
850+
851+ function loadWindowState() {
852+ var defaultWidth = units.gu(60);
853+ var defaultHeight = units.gu(50);
854+ var windowGeometry = WindowStateStorage.getGeometry(appDelegate.appId,
855+ Qt.rect(appDelegate.windowedX, appDelegate.windowedY, defaultWidth, defaultHeight));
856+
857+ appDelegate.windowedWidth = Qt.binding(function() { return Math.min(Math.max(windowGeometry.width, appDelegate.minimumWidth), appContainer.width - root.leftMargin); });
858+ appDelegate.windowedHeight = Qt.binding(function() { return Math.min(Math.max(windowGeometry.height, appDelegate.minimumHeight),
859+ appContainer.height - (appDelegate.fullscreen ? 0 : PanelState.panelHeight)); });
860+ appDelegate.windowedX = Qt.binding(function() { return Math.max(Math.min(windowGeometry.x, appContainer.width - root.leftMargin - appDelegate.windowedWidth),
861+ (appDelegate.fullscreen ? 0 : root.leftMargin)); });
862+ appDelegate.windowedY = Qt.binding(function() { return Math.max(Math.min(windowGeometry.y, appContainer.height - appDelegate.windowedHeight), PanelState.panelHeight); });
863+
864+ var windowState = WindowStateStorage.getState(appDelegate.appId, WindowStateStorage.WindowStateNormal)
865+ appDelegate.restore(false /* animated */, windowState);
866+
867+ // initialize the x/y to restore to
868+ appDelegate.restoredX = windowGeometry.x;
869+ appDelegate.restoredY = windowGeometry.y;
870+ }
871+ function saveWindowState() {
872+ var state = appDelegate.windowState;
873+ if (state === WindowStateStorage.WindowStateRestored) {
874+ state = WindowStateStorage.WindowStateNormal;
875+ }
876+
877+ WindowStateStorage.saveState(appDelegate.appId, state & ~WindowStateStorage.WindowStateMinimized); // clear the minimized bit when saving
878+ WindowStateStorage.saveGeometry(appDelegate.appId, Qt.rect(appDelegate.windowedX, appDelegate.windowedY,
879+ appDelegate.windowedWidth, appDelegate.windowedHeight));
880+ }
881+
850 Component.onCompleted: {
882 Component.onCompleted: {
851 if (application && application.rotatesWindowContents) {
883 if (application && application.rotatesWindowContents) {
852 decoratedWindow.surfaceOrientationAngle = shellOrientationAngle;
884 decoratedWindow.surfaceOrientationAngle = shellOrientationAngle;
@@ -858,7 +890,8 @@ FocusScope {
858 windowedX = priv.focusedAppDelegate ? priv.focusedAppDelegate.windowedX + units.gu(3) : (normalZ - 1) * units.gu(3)
890 windowedX = priv.focusedAppDelegate ? priv.focusedAppDelegate.windowedX + units.gu(3) : (normalZ - 1) * units.gu(3)
859 windowedY = priv.focusedAppDelegate ? priv.focusedAppDelegate.windowedY + units.gu(3) : normalZ * units.gu(3)
891 windowedY = priv.focusedAppDelegate ? priv.focusedAppDelegate.windowedY + units.gu(3) : normalZ * units.gu(3)
860 // Now load any saved state. This needs to happen *after* the cascading!
892 // Now load any saved state. This needs to happen *after* the cascading!
893+ loadWindowState();
861− resizeArea.loadWindowState();
894+ resizeArea.init();
862
895
863 // NB: We're differentiating if this delegate was created in response to a new entry in the model
896 // NB: We're differentiating if this delegate was created in response to a new entry in the model
864 // or if the Repeater is just populating itself with delegates to match the model it received.
897 // or if the Repeater is just populating itself with delegates to match the model it received.
@@ -875,6 +908,8 @@ FocusScope {
875 _constructing = false;
908 _constructing = false;
876 }
909 }
877 Component.onDestruction: {
910 Component.onDestruction: {
911+ saveWindowState();
912+
878 if (!root.parent) {
913 if (!root.parent) {
879 // This stage is about to be destroyed. Don't mess up with the model at this point
914 // This stage is about to be destroyed. Don't mess up with the model at this point
880 return;
915 return;
@@ -1477,27 +1512,22 @@ FocusScope {
1477 id: resizeArea
1512 id: resizeArea
1478 objectName: "windowResizeArea"
1513 objectName: "windowResizeArea"
1479
1514
1515+ anchors.fill: appDelegate
1516+
1480 // workaround so that it chooses the correct resize borders when you drag from a corner ResizeGrip
1517 // workaround so that it chooses the correct resize borders when you drag from a corner ResizeGrip
1481 anchors.margins: touchControls.overlayShown ? borderThickness/2 : -borderThickness
1518 anchors.margins: touchControls.overlayShown ? borderThickness/2 : -borderThickness
1482
1519
1483 target: appDelegate
1520 target: appDelegate
1521+ minimumY: PanelState.panelHeight // disallow resizing up past Panel
1484 minWidth: units.gu(10)
1522 minWidth: units.gu(10)
1485 minHeight: units.gu(10)
1523 minHeight: units.gu(10)
1486 borderThickness: units.gu(2)
1524 borderThickness: units.gu(2)
1487− windowId: model.application.appId // FIXME: Change this to point to windowId once we have such a thing
1488− screenWidth: appContainer.width
1489− screenHeight: appContainer.height
1490− leftMargin: root.leftMargin
1491 enabled: false
1525 enabled: false
1492 visible: enabled
1526 visible: enabled
1493
1527
1494 onPressed: {
1528 onPressed: {
1495 appDelegate.focus = true;
1529 appDelegate.focus = true;
1496 }
1530 }
1497−
1498− Component.onDestruction: {
1499− saveWindowState();
1500− }
1501 }
1531 }
1502
1532
1503 DecoratedWindow {
1533 DecoratedWindow {
qml/Stage/WindowResizeArea.qml+6−41
@@ -18,17 +18,14 @@ import QtQuick 2.4
18import Ubuntu.Components 1.3
18import Ubuntu.Components 1.3
19import Utils 0.1
19import Utils 0.1
20import Unity.Application 0.1 // for Mir.cursorName
20import Unity.Application 0.1 // for Mir.cursorName
21−import "../Components/PanelState"
22
21
23MouseArea {
22MouseArea {
24 id: root
23 id: root
25
24
26− anchors.fill: target
27 anchors.margins: -borderThickness
25 anchors.margins: -borderThickness
28
26
29 hoverEnabled: target && !target.maximized // don't grab the resize under the panel
27 hoverEnabled: target && !target.maximized // don't grab the resize under the panel
30
28
31− property var windowStateStorage: WindowStateStorage
32 readonly property alias dragging: d.dragging
29 readonly property alias dragging: d.dragging
33 readonly property alias normalWidth: priv.normalWidth
30 readonly property alias normalWidth: priv.normalWidth
34 readonly property alias normalHeight: priv.normalHeight
31 readonly property alias normalHeight: priv.normalHeight
@@ -36,15 +33,14 @@ MouseArea {
36 // The target item managed by this. Must be a parent or a sibling
33 // The target item managed by this. Must be a parent or a sibling
37 // The area will anchor to it and manage resize events
34 // The area will anchor to it and manage resize events
38 property Item target: null
35 property Item target: null
39− property string windowId: ""
40 property int borderThickness: 0
36 property int borderThickness: 0
37+ property real minimumY: -100000000 // By default, impose no limit
41 property int minWidth: 0
38 property int minWidth: 0
42 property int minHeight: 0
39 property int minHeight: 0
43− property int defaultWidth: units.gu(60)
40+
44− property int defaultHeight: units.gu(50)
41+ function init() {
45− property int screenWidth: 0
42+ priv.updateNormalGeometry();
46− property int screenHeight: 0
43+ }
47− property int leftMargin: 0
48
44
49 QtObject {
45 QtObject {
50 id: priv
46 id: priv
@@ -73,37 +69,6 @@ MouseArea {
73 onHeightChanged: priv.updateNormalGeometry();
69 onHeightChanged: priv.updateNormalGeometry();
74 }
70 }
75
71
76− function loadWindowState() {
77− var windowGeometry = windowStateStorage.getGeometry(root.windowId,
78− Qt.rect(target.windowedX, target.windowedY, defaultWidth, defaultHeight));
79−
80−
81− target.windowedWidth = Qt.binding(function() { return Math.min(Math.max(windowGeometry.width, d.minimumWidth), screenWidth - root.leftMargin); });
82− target.windowedHeight = Qt.binding(function() { return Math.min(Math.max(windowGeometry.height, d.minimumHeight),
83− root.screenHeight - (target.fullscreen ? 0 : PanelState.panelHeight)); });
84− target.windowedX = Qt.binding(function() { return Math.max(Math.min(windowGeometry.x, root.screenWidth - root.leftMargin - target.windowedWidth),
85− (target.fullscreen ? 0 : root.leftMargin)); });
86− target.windowedY = Qt.binding(function() { return Math.max(Math.min(windowGeometry.y, root.screenHeight - target.windowedHeight), PanelState.panelHeight); });
87−
88− var windowState = windowStateStorage.getState(root.windowId, WindowStateStorage.WindowStateNormal)
89− target.restore(false /* animated */, windowState);
90−
91− priv.updateNormalGeometry();
92−
93− // initialize the x/y to restore to
94− target.restoredX = priv.normalX;
95− target.restoredY = priv.normalY;
96− }
97−
98− function saveWindowState() {
99− var state = target.windowState;
100− if (state === WindowStateStorage.WindowStateRestored) {
101− state = WindowStateStorage.WindowStateNormal;
102− }
103− windowStateStorage.saveState(root.windowId, state & ~WindowStateStorage.WindowStateMinimized); // clear the minimized bit when saving
104− windowStateStorage.saveGeometry(root.windowId, Qt.rect(priv.normalX, priv.normalY, priv.normalWidth, priv.normalHeight));
105− }
106−
107 QtObject {
72 QtObject {
108 id: d
73 id: d
109
74
@@ -311,7 +276,7 @@ MouseArea {
311 }
276 }
312
277
313 if (d.topBorder) {
278 if (d.topBorder) {
314− var newTargetY = Math.max(d.startY + deltaY, PanelState.panelHeight); // disallow resizing up past Panel
279+ var newTargetY = Math.max(d.startY + deltaY, root.minimumY);
315 var bottomBorderY = target.windowedY + target.height;
280 var bottomBorderY = target.windowedY + target.height;
316 if (bottomBorderY > newTargetY + d.minimumHeight) {
281 if (bottomBorderY > newTargetY + d.minimumHeight) {
317 if (bottomBorderY < newTargetY + d.maximumHeight) {
282 if (bottomBorderY < newTargetY + d.maximumHeight) {
tests/qmltests/Stage/tst_DesktopStage.qml+72
@@ -789,5 +789,77 @@ Item {
789
789
790 tryCompare(dialerAppDelegate, "state", "maximized");
790 tryCompare(dialerAppDelegate, "state", "maximized");
791 }
791 }
792+
793+ function test_saveRestoreSize() {
794+ var originalWindowCount = topSurfaceList.count;
795+ var appDelegate = startApplication("dialer-app");
796+ compare(topSurfaceList.count, originalWindowCount + 1);
797+
798+ var initialWindowX = appDelegate.windowedX;
799+ var initialWindowY = appDelegate.windowedY;
800+ var initialWindowWidth = appDelegate.width
801+ var initialWindowHeight = appDelegate.height
802+
803+ var resizeDelta = units.gu(5)
804+ var startDragX = initialWindowX + initialWindowWidth + 1
805+ var startDragY = initialWindowY + initialWindowHeight + 1
806+ mouseFlick(root, startDragX, startDragY, startDragX + resizeDelta, startDragY + resizeDelta, true, true, units.gu(.5), 10);
807+
808+ tryCompare(appDelegate, "width", initialWindowWidth + resizeDelta);
809+ tryCompare(appDelegate, "height", initialWindowHeight + resizeDelta);
810+
811+ // Close the window and restart the application
812+ var closeButton = findChild(appDelegate, "closeWindowButton");
813+ appDelegate = null;
814+ verify(closeButton);
815+ mouseClick(closeButton);
816+ tryCompare(topSurfaceList, "count", originalWindowCount);
817+ wait(100); // plus some spare room
818+ appDelegate = startApplication("dialer-app");
819+
820+ // Make sure its size is again the same as before
821+ tryCompare(appDelegate, "width", initialWindowWidth + resizeDelta);
822+ tryCompare(appDelegate, "height", initialWindowHeight + resizeDelta);
823+ }
824+
825+ function test_saveRestoreMaximized() {
826+ var originalWindowCount = topSurfaceList.count;
827+ var appDelegate = startApplication("dialer-app");
828+ compare(topSurfaceList.count, originalWindowCount + 1);
829+
830+ var initialWindowX = appDelegate.windowedX;
831+ var initialWindowY = appDelegate.windowedY;
832+
833+ var moveDelta = units.gu(5);
834+
835+ appDelegate.windowedX = initialWindowX + moveDelta
836+ appDelegate.windowedY = initialWindowY + moveDelta
837+
838+ // Now change the state to maximized. The window should not keep updating the stored values
839+ maximizeAppDelegate(appDelegate);
840+
841+ // Close the window and restart the application
842+ var closeButton = findChild(appDelegate, "closeWindowButton");
843+ appDelegate = null;
844+ verify(closeButton);
845+ mouseClick(closeButton);
846+ closeButton = null;
847+ tryCompare(topSurfaceList, "count", originalWindowCount);
848+ wait(100); // plus some spare room
849+ appDelegate = startApplication("dialer-app");
850+
851+ // Make sure it's again where we left it in normal state before destroying
852+ tryCompare(appDelegate, "windowedX", initialWindowX + moveDelta)
853+ tryCompare(appDelegate, "windowedY", initialWindowY + moveDelta)
854+
855+ // Make sure maximize() has been called after restoring
856+ tryCompare(appDelegate, "state", "maximized")
857+
858+ // clean up
859+ // click on restore button (same one as maximize)
860+ var maximizeButton = findChild(appDelegate, "maximizeWindowButton");
861+ mouseClick(maximizeButton);
862+ }
792 }
863 }
864+
793}
865}
tests/qmltests/Stage/tst_WindowResizeArea.qml+1−66
@@ -88,22 +88,11 @@ Item {
88
88
89 WindowResizeArea {
89 WindowResizeArea {
90 id: windowResizeArea
90 id: windowResizeArea
91+ anchors.fill: parent
91 target: fakeWindow
92 target: fakeWindow
92 borderThickness: units.gu(2)
93 borderThickness: units.gu(2)
93 minWidth: units.gu(15)
94 minWidth: units.gu(15)
94 minHeight: units.gu(10)
95 minHeight: units.gu(10)
95− defaultWidth: units.gu(20)
96− defaultHeight: units.gu(20)
97− windowId: "test-window-id"
98− screenWidth: root.width
99− screenHeight: root.height
100−
101− Component.onCompleted: {
102− loadWindowState();
103− }
104− Component.onDestruction: {
105− saveWindowState();
106− }
107 }
96 }
108
97
109 Rectangle {
98 Rectangle {
@@ -312,30 +301,6 @@ Item {
312 compare(fakeWindow.requestedY, Math.min(initialWindowY + data.dy, initialWindowY + maxMoveY));
301 compare(fakeWindow.requestedY, Math.min(initialWindowY + data.dy, initialWindowY + maxMoveY));
313 }
302 }
314
303
315− function test_saveRestoreSize() {
316− var initialWindowX = fakeWindow.windowedX;
317− var initialWindowY = fakeWindow.windowedY;
318− var initialWindowWidth = fakeWindow.width
319− var initialWindowHeight = fakeWindow.height
320−
321− var resizeDelta = units.gu(5)
322− var startDragX = initialWindowX + initialWindowWidth + 1
323− var startDragY = initialWindowY + initialWindowHeight + 1
324− mouseFlick(root, startDragX, startDragY, startDragX + resizeDelta, startDragY + resizeDelta, true, true, units.gu(.5), 10);
325−
326− tryCompare(fakeWindow, "width", Math.max(initialWindowWidth + resizeDelta, fakeWindow.resizeAreaMinWidth));
327− tryCompare(fakeWindow, "height", Math.max(initialWindowHeight + resizeDelta, fakeWindow.resizeAreaMinHeight));
328−
329− // This will destroy the window and recreate it
330− windowLoader.active = false;
331− waitForRendering(root);
332− windowLoader.active = true;
333−
334− // Make sure its size is again the same as before
335− tryCompare(fakeWindow, "width", Math.max(initialWindowWidth + resizeDelta, fakeWindow.resizeAreaMinWidth));
336− tryCompare(fakeWindow, "height", Math.max(initialWindowHeight + resizeDelta, fakeWindow.resizeAreaMinHeight));
337− }
338−
339 // This tests if dragging smaller than minSize and then larger again, will keep the edge sticking
304 // This tests if dragging smaller than minSize and then larger again, will keep the edge sticking
340 // to the mouse, instead of immediately making the window grow again when switching direction
305 // to the mouse, instead of immediately making the window grow again when switching direction
341 function test_resizeSmallerAndLarger_data() {
306 function test_resizeSmallerAndLarger_data() {
@@ -361,36 +326,6 @@ Item {
361 tryCompare(fakeWindow, "height", initialWindowHeight);
326 tryCompare(fakeWindow, "height", initialWindowHeight);
362 }
327 }
363
328
364− function test_saveRestoreMaximized() {
365− var initialWindowX = fakeWindow.windowedX;
366− var initialWindowY = fakeWindow.windowedY;
367−
368− var moveDelta = units.gu(5);
369−
370− fakeWindow.windowedX = initialWindowX + moveDelta
371− fakeWindow.windowedY = initialWindowY + moveDelta
372−
373− // Now change the state to maximized. The window should not keep updating the stored values
374− fakeWindow.maximize()
375− fakeWindow.windowedX = 31415 // 0 is too risky to pass the test even when broken
376− fakeWindow.windowedY = 31415
377−
378− // This will destroy the window and recreate it
379− windowLoader.active = false;
380− waitForRendering(root);
381− windowLoader.active = true;
382−
383− // Make sure it's again where we left it in normal state before destroying
384− tryCompare(fakeWindow, "x", initialWindowX + moveDelta)
385− tryCompare(fakeWindow, "y", initialWindowX + moveDelta)
386−
387− // Make sure maximize() has been called after restoring
388− tryCompare(fakeWindow, "state", "maximized")
389−
390− // clean up
391− fakeWindow.restoreFromMaximized()
392− }
393−
394 function test_restoreMovesIntoBounds_data() {
329 function test_restoreMovesIntoBounds_data() {
395 return [
330 return [
396 {tag: "left off", x: -units.gu(5), y: units.gu(5), w: units.gu(10), h: units.gu(10)},
331 {tag: "left off", x: -units.gu(5), y: units.gu(5), w: units.gu(10), h: units.gu(10)},