on xenial help sign in
prevent windows to be moved under the panel

If they happen to have a saved state which is under the panel (might happen on alt+drag later), they will be moved below the panel on close and reopen. This is how unity7 behaves in this regard. Fixes: #1438465 Approved by: Lukáš Tinkl

commita806148e458821b37edf8002d1cb290689b535ba authorMichael Zanetti <michael.zanetti@canonical.com> dateThu 12 Nov 2015, 20:40 (11 years ago) parentd3df9715f66058
7 files changed+97−9
qml/Components/PanelState/PanelState.qml+2 qml/Panel/Panel.qml+6 qml/Stages/DesktopStage.qml+2 qml/Stages/WindowDecoration.qml+2−1 qml/Stages/WindowResizeArea.qml+7−4 tests/qmltests/Stages/tst_WindowResizeArea.qml+43 tests/qmltests/tst_Shell.qml+35−4
qml/Components/PanelState/PanelState.qml+2
@@ -23,6 +23,8 @@ QtObject {
2323 property string title: ""
2424 property bool buttonsVisible: false
2525
26+ property int panelHeight: 0
27+
2628 signal close()
2729 signal minimize()
2830 signal maximize()
qml/Panel/Panel.qml+6
@@ -32,6 +32,12 @@ Item {
3232
3333 opacity: fullscreenMode && indicators.fullyClosed ? 0.0 : 1.0
3434
35+ Binding {
36+ target: PanelState
37+ property: "panelHeight"
38+ value: root.panelHeight
39+ }
40+
3541 Rectangle {
3642 id: darkenedArea
3743 property real darkenedOpacity: 0.6
qml/Stages/DesktopStage.qml+2
@@ -391,6 +391,8 @@ AbstractStage {
391391 minHeight: units.gu(10)
392392 borderThickness: units.gu(2)
393393 windowId: model.appId // FIXME: Change this to point to windowId once we have such a thing
394+ screenWidth: root.width
395+ screenHeight: root.height
394396
395397 onPressed: { ApplicationManager.focusApplication(model.appId) }
396398 }
qml/Stages/WindowDecoration.qml+2−1
@@ -18,6 +18,7 @@ import QtQuick 2.4
1818import Unity.Application 0.1 // For Mir singleton
1919import Ubuntu.Components 1.3
2020import "../Components"
21+import "../Components/PanelState"
2122
2223MouseArea {
2324 id: root
@@ -56,7 +57,7 @@ MouseArea {
5657 Mir.cursorName = "grabbing";
5758 var pos = mapToItem(root.target.parent, mouseX, mouseY);
5859 root.target.x = pos.x - priv.distanceX;
59− root.target.y = pos.y - priv.distanceY;
60+ root.target.y = Math.max(pos.y - priv.distanceY, PanelState.panelHeight);
6061 }
6162 }
6263
qml/Stages/WindowResizeArea.qml+7−4
@@ -18,6 +18,7 @@ import QtQuick 2.4
1818import Ubuntu.Components 1.3
1919import Utils 0.1
2020import Unity.Application 0.1 // for Mir.cursorName
21+import "../Components/PanelState"
2122
2223MouseArea {
2324 id: root
@@ -35,6 +36,8 @@ MouseArea {
3536 property int borderThickness: 0
3637 property int minWidth: 0
3738 property int minHeight: 0
39+ property int screenWidth: 0
40+ property int screenHeight: 0
3841
3942 QtObject {
4043 id: priv
@@ -66,10 +69,10 @@ MouseArea {
6669 Component.onCompleted: {
6770 var windowGeometry = windowStateStorage.getGeometry(root.windowId, Qt.rect(target.x, target.y, target.width, target.height))
6871 if (windowGeometry !== undefined) {
69− target.x = windowGeometry.x
70− target.y = windowGeometry.y
71− target.width = windowGeometry.width
72− target.height = windowGeometry.height
72+ target.width = Math.min(windowGeometry.width, root.screenWidth)
73+ target.height = Math.min(windowGeometry.height, root.screenHeight - PanelState.panelHeight)
74+ target.x = Math.max(Math.min(windowGeometry.x, root.screenWidth - target.width), 0)
75+ target.y = Math.max(Math.min(windowGeometry.y, root.screenHeight - target.height), PanelState.panelHeight)
7376 }
7477 var windowState = windowStateStorage.getState(root.windowId, WindowStateStorage.WindowStateNormal)
7578 if (windowState === WindowStateStorage.WindowStateMaximized) {
tests/qmltests/Stages/tst_WindowResizeArea.qml+43
@@ -19,6 +19,7 @@ import QtQuick.Layouts 1.1
1919import QtTest 1.0
2020import Unity.Test 0.1
2121import ".."
22+import "../../../qml/Components/PanelState"
2223import "../../../qml/Stages"
2324import Ubuntu.Components 1.3
2425import Ubuntu.Components.ListItems 1.3 as ListItem
@@ -31,6 +32,12 @@ Item {
3132
3233 property var fakeWindow: windowLoader.item
3334
35+ Binding {
36+ target: PanelState
37+ property: "panelHeight"
38+ value: units.gu(2)
39+ }
40+
3441 Component {
3542 id: fakeWindowComponent
3643
@@ -57,6 +64,8 @@ Item {
5764 minWidth: units.gu(15)
5865 minHeight: units.gu(10)
5966 windowId: "test-window-id"
67+ screenWidth: root.width
68+ screenHeight: root.height
6069 }
6170
6271 Rectangle {
@@ -228,5 +237,39 @@ Item {
228237 // clean up
229238 fakeWindow.state = "normal"
230239 }
240+
241+
242+ function test_restoreMovesIntoBounds_data() {
243+ return [
244+ {tag: "left off", x: -units.gu(5), y: units.gu(5), w: units.gu(10), h: units.gu(10)},
245+ {tag: "top off", x: units.gu(5), y: -units.gu(5), w: units.gu(10), h: units.gu(10)},
246+ {tag: "right off", x: root.width - units.gu(5), y: units.gu(5), w: units.gu(10), h: units.gu(10)},
247+ {tag: "bottom off", x: units.gu(5), y: root.height - units.gu(5), w: units.gu(10), h: units.gu(10)},
248+ {tag: "width too large", x: units.gu(5), y: units.gu(5), w: root.width * 2, h: units.gu(10)},
249+ {tag: "height too large", x: units.gu(5), y: units.gu(5), w: units.gu(10), h: root.height * 2}
250+ ]
251+ }
252+
253+ function test_restoreMovesIntoBounds(data) {
254+ fakeWindow.x = data.x;
255+ fakeWindow.y = data.y;
256+ fakeWindow.width = data.w;
257+ fakeWindow.height = data.h;
258+ waitForRendering(root);
259+
260+ // This will destroy the window and recreate it
261+ windowLoader.active = false;
262+ waitForRendering(root);
263+ windowLoader.active = true;
264+ waitForRendering(root)
265+
266+ // Make sure it's again where we left it in normal state before destroying
267+ compare(fakeWindow.x >= 0, true)
268+ compare(fakeWindow.y >= PanelState.panelHeight, true)
269+ compare(fakeWindow.x + fakeWindow.width <= root.width, true)
270+ compare(fakeWindow.y + fakeWindow.height <= root.height, true)
271+
272+ waitForRendering(root)
273+ }
231274 }
232275}
tests/qmltests/tst_Shell.qml+35−4
@@ -344,9 +344,9 @@ Rectangle {
344344 var app2 = ApplicationManager.startApplication("webbrowser-app")
345345 var app3 = ApplicationManager.startApplication("camera-app")
346346 var app4 = ApplicationManager.startApplication("facebook-webapp")
347− var app5 = ApplicationManager.startApplication("calendar-app")
347+ var app5 = ApplicationManager.startApplication("camera-app")
348348 var app6 = ApplicationManager.startApplication("gallery-app")
349− var app7 = ApplicationManager.startApplication("camera-app")
349+ var app7 = ApplicationManager.startApplication("calendar-app")
350350 waitUntilAppWindowIsFullyLoaded(app7);
351351 }
352352
@@ -1710,11 +1710,11 @@ Rectangle {
17101710 keyPress(Qt.Key_Control)
17111711 keyClick(Qt.Key_Tab);
17121712
1713−
17141713 tryCompare(desktopSpread, "state", "altTab")
17151714
1716− mouseMove(shell, 0, 0);
1715+ mouseMove(shell, 0, shell.height / 2);
17171716 tryCompare(launcher, "state", "visibleTemporary")
1717+ waitForRendering(shell)
17181718
17191719 mouseClick(bfb, bfb.width / 2, bfb.height / 2)
17201720 tryCompare(launcher, "state", "")
@@ -1809,6 +1809,37 @@ Rectangle {
18091809 tryCompare(panelButtons, "visible", true);
18101810 }
18111811
1812+ function test_cantMoveWindowUnderPanel() {
1813+ loadDesktopShellWithApps();
1814+ var appRepeater = findChild(shell, "appRepeater")
1815+ var appDelegate = appRepeater.itemAt(0);
1816+
1817+ mousePress(appDelegate, appDelegate.width / 2, units.gu(1))
1818+ mouseMove(appDelegate, appDelegate.width / 2, -units.gu(100))
1819+
1820+ compare(appDelegate.y >= PanelState.panelHeight, true);
1821+ }
1822+
1823+ function test_restoreWindowStateFixesIfUnderPanel() {
1824+ loadDesktopShellWithApps();
1825+ var appRepeater = findChild(shell, "appRepeater")
1826+ var appId = ApplicationManager.get(0).appId;
1827+ var appDelegate = appRepeater.itemAt(0);
1828+
1829+ // Move it under the panel programmatically (might happen later with an alt+drag)
1830+ appDelegate.y = -units.gu(10)
1831+
1832+ ApplicationManager.stopApplication(appId)
1833+ ApplicationManager.startApplication(appId)
1834+ waitForRendering(shell)
1835+
1836+ // Make sure the newly started one is at index 0 again
1837+ tryCompare(ApplicationManager.get(0), "appId", appId);
1838+
1839+ appDelegate = appRepeater.itemAt(0);
1840+ compare(appDelegate.y >= PanelState.panelHeight, true);
1841+ }
1842+
18121843 function test_lifecyclePolicyForNonTouchApp_data() {
18131844 return [
18141845 {tag: "phone", formFactor: "phone", usageScenario: "phone"},