on xenial help sign in
Window Size Hints
commit998108cf5c93d88d35ac731627b99ea675924703 authorDaniel d'Andrada <daniel.dandrada@canonical.com> dateMon 30 Nov 2015, 16:25 (11 years ago) parenta3c5737
15 files changed+645−74
CMakeLists.txt+1−1 debian/control+3−3 qml/Stages/ApplicationWindow.qml+7 qml/Stages/DecoratedWindow.qml+7 qml/Stages/DesktopStage.qml+6 qml/Stages/WindowResizeArea.qml+95−16 tests/mocks/Unity/Application/MirSurface.cpp+48 tests/mocks/Unity/Application/MirSurface.h+21 tests/mocks/Unity/Application/SurfaceManager.cpp+56 tests/mocks/Unity/Application/SurfaceManager.h+40 tests/qmltests/Stages/SizeHintField.qml+33 tests/qmltests/Stages/SurfaceManagerControls.qml+33 tests/qmltests/Stages/SurfaceManagerField.qml+40 tests/qmltests/Stages/tst_DesktopStage.qml+30−24 tests/qmltests/Stages/tst_WindowResizeArea.qml+225−30
CMakeLists.txt+1−1
@@ -57,7 +57,7 @@ find_package(Qt5DBus 5.4 REQUIRED)
5757find_package(Qt5Concurrent 5.4 REQUIRED)
5858find_package(Qt5Sql 5.4 REQUIRED)
5959
60−pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=11)
60+pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=12)
6161
6262# Standard install paths
6363include(GNUInstallDirs)
debian/control+3−3
@@ -29,7 +29,7 @@ Build-Depends: cmake,
2929 libqt5xmlpatterns5-dev,
3030 libsystemsettings-dev,
3131 libudev-dev,
32− libunity-api-dev (>= 7.103),
32+ libunity-api-dev (>= 7.104),
3333 libusermetricsoutput1-dev,
3434 libxcb1-dev,
3535 pkg-config,
@@ -128,7 +128,7 @@ Depends: qml-module-qtquick-layouts,
128128 qtdeclarative5-ubuntu-ui-toolkit-plugin (>= 1.3.1627) | qtdeclarative5-ubuntu-ui-toolkit-plugin-gles (>= 1.3.1627),
129129 qtdeclarative5-unity-notifications-plugin (>= 0.1.2) | unity-notifications-impl,
130130 ubuntu-thumbnailer-impl-0,
131− unity-application-impl-11,
131+ unity-application-impl-12,
132132 unity-notifications-impl-3,
133133 unity-plugin-scopes | unity-scopes-impl,
134134 unity-scopes-impl-7,
@@ -174,7 +174,7 @@ Pre-Depends: ${misc:Pre-Depends},
174174Depends: ${misc:Depends},
175175 ${shlibs:Depends},
176176Provides: unity-application-impl,
177− unity-application-impl-11,
177+ unity-application-impl-12,
178178Replaces: unity8-autopilot (<< 8.02+15.04.20150422-0ubuntu1)
179179Description: Fake environment for running Unity 8 shell
180180 Provides fake implementations of some QML modules used by Unity 8 shell
qml/Stages/ApplicationWindow.qml+7
@@ -37,6 +37,13 @@ FocusScope {
3737 property int requestedWidth: -1
3838 property int requestedHeight: -1
3939
40+ readonly property int minimumWidth: sessionContainer.surface ? sessionContainer.surface.minimumWidth : 0
41+ readonly property int minimumHeight: sessionContainer.surface ? sessionContainer.surface.minimumHeight : 0
42+ readonly property int maximumWidth: sessionContainer.surface ? sessionContainer.surface.maximumWidth : 0
43+ readonly property int maximumHeight: sessionContainer.surface ? sessionContainer.surface.maximumHeight : 0
44+ readonly property int widthIncrement: sessionContainer.surface ? sessionContainer.surface.widthIncrement : 0
45+ readonly property int heightIncrement: sessionContainer.surface ? sessionContainer.surface.heightIncrement : 0
46+
4047 QtObject {
4148 id: d
4249
qml/Stages/DecoratedWindow.qml+7
@@ -39,6 +39,13 @@ FocusScope {
3939 property alias requestedWidth: applicationWindow.requestedWidth
4040 property real requestedHeight
4141
42+ property alias minimumWidth: applicationWindow.minimumWidth
43+ readonly property int minimumHeight: (root.decorationShown ? decoration.height : 0) + applicationWindow.minimumHeight
44+ property alias maximumWidth: applicationWindow.maximumWidth
45+ readonly property int maximumHeight: (root.decorationShown ? decoration.height : 0) + applicationWindow.maximumHeight
46+ property alias widthIncrement: applicationWindow.widthIncrement
47+ property alias heightIncrement: applicationWindow.heightIncrement
48+
4249 signal close()
4350 signal maximize()
4451 signal minimize()
qml/Stages/DesktopStage.qml+6
@@ -244,6 +244,12 @@ AbstractStage {
244244 height: decoratedWindow.height
245245 property alias requestedWidth: decoratedWindow.requestedWidth
246246 property alias requestedHeight: decoratedWindow.requestedHeight
247+ property alias minimumWidth: decoratedWindow.minimumWidth
248+ property alias minimumHeight: decoratedWindow.minimumHeight
249+ property alias maximumWidth: decoratedWindow.maximumWidth
250+ property alias maximumHeight: decoratedWindow.maximumHeight
251+ property alias widthIncrement: decoratedWindow.widthIncrement
252+ property alias heightIncrement: decoratedWindow.heightIncrement
247253
248254 QtObject {
249255 id: appDelegatePrivate
qml/Stages/WindowResizeArea.qml+95−16
@@ -72,8 +72,8 @@ MouseArea {
7272 var windowGeometry = windowStateStorage.getGeometry(root.windowId,
7373 Qt.rect(target.x, target.y, defaultWidth, defaultHeight));
7474
75− target.requestedWidth = Math.min(Math.max(windowGeometry.width, minWidth), screenWidth);
76− target.requestedHeight = Math.min(Math.max(windowGeometry.height, minHeight), root.screenHeight - PanelState.panelHeight);
75+ target.requestedWidth = Math.min(Math.max(windowGeometry.width, d.minimumWidth), screenWidth);
76+ target.requestedHeight = Math.min(Math.max(windowGeometry.height, d.minimumHeight), root.screenHeight - PanelState.panelHeight);
7777 target.x = Math.max(Math.min(windowGeometry.x, root.screenWidth - target.requestedWidth), 0)
7878 target.y = Math.max(Math.min(windowGeometry.y, root.screenHeight - target.requestedHeight), PanelState.panelHeight)
7979
@@ -91,6 +91,65 @@ MouseArea {
9191
9292 QtObject {
9393 id: d
94+
95+ readonly property int maxSafeInt: 2147483647
96+ readonly property int maxSizeIncrement: units.gu(40)
97+
98+ property int minimumWidth: root.target ? Math.max(root.minWidth, root.target.minimumWidth) : root.minWidth
99+ onMinimumWidthChanged: {
100+ if (target.requestedWidth < minimumWidth) {
101+ target.requestedWidth = minimumWidth;
102+ }
103+ }
104+ property int minimumHeight: root.target ? Math.max(root.minHeight, root.target.minimumHeight) : root.minHeight
105+ onMinimumHeightChanged: {
106+ if (target.requestedHeight < minimumHeight) {
107+ target.requestedHeight = minimumHeight;
108+ }
109+ }
110+ property int maximumWidth: root.target && root.target.maximumWidth >= minimumWidth && root.target.maximumWidth > 0
111+ ? root.target.maximumWidth : maxSafeInt
112+ onMaximumWidthChanged: {
113+ if (target.requestedWidth > maximumWidth) {
114+ target.requestedWidth = maximumWidth;
115+ }
116+ }
117+ property int maximumHeight: root.target && root.target.maximumHeight >= minimumHeight && root.target.maximumHeight > 0
118+ ? root.target.maximumHeight : maxSafeInt
119+ onMaximumHeightChanged: {
120+ if (target.requestedHeight > maximumHeight) {
121+ target.requestedHeight = maximumHeight;
122+ }
123+ }
124+ property int widthIncrement: {
125+ if (!root.target) {
126+ return 1;
127+ }
128+ if (root.target.widthIncrement > 0) {
129+ if (root.target.widthIncrement < maxSizeIncrement) {
130+ return root.target.widthIncrement;
131+ } else {
132+ return maxSizeIncrement;
133+ }
134+ } else {
135+ return 1;
136+ }
137+ }
138+ property int heightIncrement: {
139+ if (!root.target) {
140+ return 1;
141+ }
142+ if (root.target.heightIncrement > 0) {
143+ if (root.target.heightIncrement < maxSizeIncrement) {
144+ return root.target.heightIncrement;
145+ } else {
146+ return maxSizeIncrement;
147+ }
148+ } else {
149+ return 1;
150+ }
151+ }
152+
94153 property bool leftBorder: false
95154 property bool rightBorder: false
96155 property bool topBorder: false
@@ -209,38 +268,58 @@ MouseArea {
209268
210269 var pos = mapToItem(target.parent, mouse.x, mouse.y);
211270
212− var deltaX = pos.x - d.startMousePosX;
213− var deltaY = pos.y - d.startMousePosY;
271+ var deltaX = Math.floor((pos.x - d.startMousePosX) / d.widthIncrement) * d.widthIncrement;
272+ var deltaY = Math.floor((pos.y - d.startMousePosY) / d.heightIncrement) * d.heightIncrement;
214273
215274 if (d.leftBorder) {
216275 var newTargetX = d.startX + deltaX;
217− if (target.x + target.width > newTargetX + minWidth) {
218− target.requestedWidth = target.x + target.width - newTargetX;
276+ var rightBorderX = target.x + target.width;
277+ if (rightBorderX > newTargetX + d.minimumWidth) {
278+ if (rightBorderX < newTargetX + d.maximumWidth) {
279+ target.requestedWidth = rightBorderX - newTargetX;
280+ } else {
281+ target.requestedWidth = d.maximumWidth;
282+ }
219283 } else {
220− target.requestedWidth = minWidth;
284+ target.requestedWidth = d.minimumWidth;
221285 }
222286
223287 } else if (d.rightBorder) {
224− if (d.startWidth + deltaX >= minWidth) {
225− target.requestedWidth = d.startWidth + deltaX;
288+ var newWidth = d.startWidth + deltaX;
289+ if (newWidth > d.minimumWidth) {
290+ if (newWidth < d.maximumWidth) {
291+ target.requestedWidth = newWidth;
292+ } else {
293+ target.requestedWidth = d.maximumWidth;
294+ }
226295 } else {
227− target.requestedWidth = minWidth;
296+ target.requestedWidth = d.minimumWidth;
228297 }
229298 }
230299
231300 if (d.topBorder) {
232301 var newTargetY = d.startY + deltaY;
233− if (target.y + target.height > newTargetY + minHeight) {
234− target.requestedHeight = target.y + target.height - newTargetY;
302+ var bottomBorderY = target.y + target.height;
303+ if (bottomBorderY > newTargetY + d.minimumHeight) {
304+ if (bottomBorderY < newTargetY + d.maximumHeight) {
305+ target.requestedHeight = bottomBorderY - newTargetY;
306+ } else {
307+ target.requestedHeight = d.maximumHeight;
308+ }
235309 } else {
236− target.requestedHeight = minHeight;
310+ target.requestedHeight = d.minimumHeight;
237311 }
238312
239313 } else if (d.bottomBorder) {
240− if (d.startHeight + deltaY >= minHeight) {
241− target.requestedHeight = d.startHeight + deltaY;
314+ var newHeight = d.startHeight + deltaY;
315+ if (newHeight > d.minimumHeight) {
316+ if (newHeight < d.maximumHeight) {
317+ target.requestedHeight = newHeight;
318+ } else {
319+ target.requestedHeight = d.maximumHeight;
320+ }
242321 } else {
243− target.requestedHeight = minHeight;
322+ target.requestedHeight = d.minimumHeight;
244323 }
245324 }
246325 }
tests/mocks/Unity/Application/MirSurface.cpp+48
@@ -266,3 +266,51 @@ void MirSurface::setSlowToResize(bool value)
266266 }
267267 }
268268}
269+
270+void MirSurface::setMinimumWidth(int value)
271+{
272+ if (value != m_minimumWidth) {
273+ m_minimumWidth = value;
274+ Q_EMIT minimumWidthChanged(m_minimumWidth);
275+ }
276+}
277+
278+void MirSurface::setMaximumWidth(int value)
279+{
280+ if (value != m_maximumWidth) {
281+ m_maximumWidth = value;
282+ Q_EMIT maximumWidthChanged(m_maximumWidth);
283+ }
284+}
285+
286+void MirSurface::setMinimumHeight(int value)
287+{
288+ if (value != m_minimumHeight) {
289+ m_minimumHeight = value;
290+ Q_EMIT minimumHeightChanged(m_minimumHeight);
291+ }
292+}
293+
294+void MirSurface::setMaximumHeight(int value)
295+{
296+ if (value != m_maximumHeight) {
297+ m_maximumHeight = value;
298+ Q_EMIT maximumHeightChanged(m_maximumHeight);
299+ }
300+}
301+
302+void MirSurface::setWidthIncrement(int value)
303+{
304+ if (value != m_widthIncrement) {
305+ m_widthIncrement = value;
306+ Q_EMIT widthIncrementChanged(m_widthIncrement);
307+ }
308+}
309+
310+void MirSurface::setHeightIncrement(int value)
311+{
312+ if (value != m_heightIncrement) {
313+ m_heightIncrement = value;
314+ Q_EMIT heightIncrementChanged(m_heightIncrement);
315+ }
316+}
tests/mocks/Unity/Application/MirSurface.h+21
@@ -66,6 +66,13 @@ public:
6666 Mir::OrientationAngle orientationAngle() const override;
6767 void setOrientationAngle(Mir::OrientationAngle) override;
6868
69+ int minimumWidth() const override { return m_minimumWidth; }
70+ int minimumHeight() const override { return m_minimumHeight; }
71+ int maximumWidth() const override { return m_maximumWidth; }
72+ int maximumHeight() const override { return m_maximumHeight; }
73+ int widthIncrement() const override { return m_widthIncrement; }
74+ int heightIncrement() const override { return m_heightIncrement; }
75+
6976 ////
7077 // API for tests
7178
@@ -82,6 +89,13 @@ public:
8289 bool isSlowToResize() const;
8390 void setSlowToResize(bool value);
8491
92+ Q_INVOKABLE void setMinimumWidth(int);
93+ Q_INVOKABLE void setMaximumWidth(int);
94+ Q_INVOKABLE void setMinimumHeight(int);
95+ Q_INVOKABLE void setMaximumHeight(int);
96+ Q_INVOKABLE void setWidthIncrement(int);
97+ Q_INVOKABLE void setHeightIncrement(int);
98+
8599 /////
86100 // internal mock stuff
87101
@@ -125,6 +139,13 @@ private:
125139 int m_width;
126140 int m_height;
127141
142+ int m_minimumWidth{0};
143+ int m_minimumHeight{0};
144+ int m_maximumWidth{0};
145+ int m_maximumHeight{0};
146+ int m_widthIncrement{0};
147+ int m_heightIncrement{0};
148+
128149 bool m_slowToResize;
129150 QTimer m_delayedResizeTimer;
130151 QSize m_delayedResize;
tests/mocks/Unity/Application/SurfaceManager.cpp+56
@@ -46,6 +46,14 @@ MirSurface *SurfaceManager::createSurface(const QString& name,
4646 MirSurface* surface = qobject_cast<MirSurface*>(obj);
4747 Q_EMIT surfaceDestroyed(surface);
4848 });
49+
50+ surface->setMinimumWidth(m_newSurfaceMinimumWidth);
51+ surface->setMaximumWidth(m_newSurfaceMaximumWidth);
52+ surface->setMinimumHeight(m_newSurfaceMinimumHeight);
53+ surface->setMaximumHeight(m_newSurfaceMaximumHeight);
54+ surface->setWidthIncrement(m_newSurfaceWidthIncrement);
55+ surface->setHeightIncrement(m_newSurfaceHeightIncrement);
56+
4957 Q_EMIT surfaceCreated(surface);
5058 return surface;
5159}
@@ -62,3 +70,51 @@ MirSurface *SurfaceManager::inputMethodSurface()
6270 }
6371 return m_virtualKeyboard;
6472}
73+
74+void SurfaceManager::setNewSurfaceMinimumWidth(int value)
75+{
76+ if (m_newSurfaceMinimumWidth != value) {
77+ m_newSurfaceMinimumWidth = value;
78+ Q_EMIT newSurfaceMinimumWidthChanged(m_newSurfaceMinimumWidth);
79+ }
80+}
81+
82+void SurfaceManager::setNewSurfaceMaximumWidth(int value)
83+{
84+ if (m_newSurfaceMaximumWidth != value) {
85+ m_newSurfaceMaximumWidth = value;
86+ Q_EMIT newSurfaceMaximumWidthChanged(m_newSurfaceMaximumWidth);
87+ }
88+}
89+
90+void SurfaceManager::setNewSurfaceMinimumHeight(int value)
91+{
92+ if (m_newSurfaceMinimumHeight != value) {
93+ m_newSurfaceMinimumHeight = value;
94+ Q_EMIT newSurfaceMinimumHeightChanged(m_newSurfaceMinimumHeight);
95+ }
96+}
97+
98+void SurfaceManager::setNewSurfaceMaximumHeight(int value)
99+{
100+ if (m_newSurfaceMaximumHeight != value) {
101+ m_newSurfaceMaximumHeight = value;
102+ Q_EMIT newSurfaceMaximumHeightChanged(m_newSurfaceMaximumHeight);
103+ }
104+}
105+
106+void SurfaceManager::setNewSurfaceWidthIncrement(int value)
107+{
108+ if (m_newSurfaceWidthIncrement != value) {
109+ m_newSurfaceWidthIncrement = value;
110+ Q_EMIT newSurfaceWidthIncrementChanged(m_newSurfaceWidthIncrement);
111+ }
112+}
113+
114+void SurfaceManager::setNewSurfaceHeightIncrement(int value)
115+{
116+ if (m_newSurfaceHeightIncrement != value) {
117+ m_newSurfaceHeightIncrement = value;
118+ Q_EMIT newSurfaceHeightIncrementChanged(m_newSurfaceHeightIncrement);
119+ }
120+}
tests/mocks/Unity/Application/SurfaceManager.h+40
@@ -25,6 +25,14 @@
2525class SurfaceManager : public QObject
2626{
2727 Q_OBJECT
28+
29+ Q_PROPERTY(int newSurfaceMinimumWidth READ newSurfaceMinimumWidth WRITE setNewSurfaceMinimumWidth NOTIFY newSurfaceMinimumWidthChanged)
30+ Q_PROPERTY(int newSurfaceMaximumWidth READ newSurfaceMaximumWidth WRITE setNewSurfaceMaximumWidth NOTIFY newSurfaceMaximumWidthChanged)
31+ Q_PROPERTY(int newSurfaceMinimumHeight READ newSurfaceMinimumHeight WRITE setNewSurfaceMinimumHeight NOTIFY newSurfaceMinimumHeightChanged)
32+ Q_PROPERTY(int newSurfaceMaximumHeight READ newSurfaceMaximumHeight WRITE setNewSurfaceMaximumHeight NOTIFY newSurfaceMaximumHeightChanged)
33+ Q_PROPERTY(int newSurfaceWidthIncrement READ newSurfaceWidthIncrement WRITE setNewSurfaceWidthIncrement NOTIFY newSurfaceWidthIncrementChanged)
34+ Q_PROPERTY(int newSurfaceHeightIncrement READ newSurfaceHeightIncrement WRITE setNewSurfaceHeightIncrement NOTIFY newSurfaceHeightIncrementChanged)
35+
2836public:
2937 explicit SurfaceManager(QObject *parent = 0);
3038
@@ -38,14 +46,46 @@ public:
3846 // To be used in the tests
3947 Q_INVOKABLE MirSurface* inputMethodSurface();
4048
49+ int newSurfaceMinimumWidth() const { return m_newSurfaceMinimumWidth; }
50+ void setNewSurfaceMinimumWidth(int value);
51+
52+ int newSurfaceMaximumWidth() const { return m_newSurfaceMaximumWidth; }
53+ void setNewSurfaceMaximumWidth(int value);
54+
55+ int newSurfaceMinimumHeight() const { return m_newSurfaceMinimumHeight; }
56+ void setNewSurfaceMinimumHeight(int value);
57+
58+ int newSurfaceMaximumHeight() const { return m_newSurfaceMaximumHeight; }
59+ void setNewSurfaceMaximumHeight(int value);
60+
61+ int newSurfaceWidthIncrement() const { return m_newSurfaceWidthIncrement; }
62+ void setNewSurfaceWidthIncrement(int);
63+
64+ int newSurfaceHeightIncrement() const { return m_newSurfaceHeightIncrement; }
65+ void setNewSurfaceHeightIncrement(int);
66+
4167Q_SIGNALS:
4268 void countChanged();
4369 void surfaceCreated(MirSurface *surface);
4470 void surfaceDestroyed(MirSurface*surface);
4571
72+ void newSurfaceMinimumWidthChanged(int value);
73+ void newSurfaceMaximumWidthChanged(int value);
74+ void newSurfaceMinimumHeightChanged(int value);
75+ void newSurfaceMaximumHeightChanged(int value);
76+ void newSurfaceWidthIncrementChanged(int value);
77+ void newSurfaceHeightIncrementChanged(int value);
78+
4679private:
4780 static SurfaceManager *the_surface_manager;
4881 VirtualKeyboard *m_virtualKeyboard;
82+
83+ int m_newSurfaceMinimumWidth{0};
84+ int m_newSurfaceMaximumWidth{0};
85+ int m_newSurfaceMinimumHeight{0};
86+ int m_newSurfaceMaximumHeight{0};
87+ int m_newSurfaceWidthIncrement{1};
88+ int m_newSurfaceHeightIncrement{1};
4989};
5090
5191#endif // SURFACEMANAGER_H
tests/qmltests/Stages/SizeHintField.qmlnew file+33
@@ -0,0 +1,33 @@
1+/*
2+ * Copyright 2015 Canonical Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.4
18+import QtQuick.Layouts 1.1
19+import Ubuntu.Components 1.3
20+
21+Row {
22+ property alias text: label.text
23+ property alias value: field.text
24+ spacing: units.gu(1)
25+ Label {
26+ id: label
27+ color: "black"; anchors.verticalCenter: parent.verticalCenter
28+ }
29+ TextField {
30+ id: field
31+ text: ""; width: units.gu(8); hasClearButton: false; maximumLength: 6; inputMask: "d00000"
32+ }
33+}
tests/qmltests/Stages/SurfaceManagerControls.qmlnew file+33
@@ -0,0 +1,33 @@
1+/*
2+ * Copyright (C) 2015 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.4
18+import Ubuntu.Components 1.3
19+import Unity.Application 0.1
20+
21+Column {
22+ id: root
23+ property color textColor: "black"
24+
25+ Label {text: "Size hints for new surface:"; color: root.textColor; font.bold: true}
26+
27+ SurfaceManagerField { text: "min width"; propertyName: "newSurfaceMinimumWidth"; textColor: root.textColor }
28+ SurfaceManagerField { text: "max width"; propertyName: "newSurfaceMaximumWidth"; textColor: root.textColor }
29+ SurfaceManagerField { text: "min height"; propertyName: "newSurfaceMinimumHeight"; textColor: root.textColor }
30+ SurfaceManagerField { text: "max height"; propertyName: "newSurfaceMaximumHeight"; textColor: root.textColor }
31+ SurfaceManagerField { text: "width increment"; propertyName: "newSurfaceWidthIncrement"; textColor: root.textColor }
32+ SurfaceManagerField { text: "height increment"; propertyName: "newSurfaceHeightIncrement"; textColor: root.textColor }
33+}
tests/qmltests/Stages/SurfaceManagerField.qmlnew file+40
@@ -0,0 +1,40 @@
1+/*
2+ * Copyright (C) 2015 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.4
18+import Ubuntu.Components 1.3
19+import Unity.Application 0.1
20+
21+Row {
22+ id: root
23+ property alias textColor: label.color
24+ property alias text: label.text
25+ property string propertyName
26+
27+ Label {id: label; anchors.verticalCenter: parent.verticalCenter}
28+ TextField {
29+ width: units.gu(10); hasClearButton: false; maximumLength: 6
30+ inputMask: "d00000"
31+ text: ""
32+ onTextChanged: {
33+ if (text.length > 0) {
34+ SurfaceManager[root.propertyName] = parseInt(text);
35+ } else {
36+ SurfaceManager[root.propertyName] = 0;
37+ }
38+ }
39+ }
40+}
tests/qmltests/Stages/tst_DesktopStage.qml+30−24
@@ -88,36 +88,42 @@ Item {
8888 right: parent.right
8989 }
9090
91− Column {
92− anchors { left: parent.left; right: parent.right; top: parent.top; margins: units.gu(1) }
93− spacing: units.gu(1)
94−
95− Button {
96− color: "white"
97− text: "Make surface slow to resize"
98− activeFocusOnPress: false
99− onClicked: {
100− if (ApplicationManager.focusedApplicationId) {
101− var surface = ApplicationManager.findApplication(ApplicationManager.focusedApplicationId).session.surface;
102− surface.slowToResize = true;
91+ Flickable {
92+ anchors.fill: parent
93+ contentHeight: controlsColumn.height
94+ Column {
95+ id: controlsColumn
96+ spacing: units.gu(1)
97+
98+ Button {
99+ color: "white"
100+ text: "Make surface slow to resize"
101+ activeFocusOnPress: false
102+ onClicked: {
103+ if (ApplicationManager.focusedApplicationId) {
104+ var surface = ApplicationManager.findApplication(ApplicationManager.focusedApplicationId).session.surface;
105+ surface.slowToResize = true;
106+ }
103107 }
104108 }
105− }
106109
107− EdgeBarrierControls {
108− id: edgeBarrierControls
109− text: "Drag here to pull out spread"
110− backgroundColor: "blue"
111− onDragged: { desktopStageLoader.item.pushRightEdge(amount); }
112− }
110+ EdgeBarrierControls {
111+ id: edgeBarrierControls
112+ text: "Drag here to pull out spread"
113+ backgroundColor: "blue"
114+ onDragged: { desktopStageLoader.item.pushRightEdge(amount); }
115+ }
113116
114− Divider {}
117+ Divider {}
115118
116− Repeater {
117− model: ApplicationManager.availableApplications
118− ApplicationCheckBox {
119− appId: modelData
119+ Repeater {
120+ model: ApplicationManager.availableApplications
121+ ApplicationCheckBox {
122+ appId: modelData
123+ }
120124 }
125+
126+ SurfaceManagerControls { textColor: "white" }
121127 }
122128 }
123129 }
tests/qmltests/Stages/tst_WindowResizeArea.qml+225−30
@@ -28,7 +28,7 @@ import Unity.Application 0.1
2828Item {
2929 id: root
3030 height: units.gu(60)
31− width: units.gu(60)
31+ width: units.gu(85)
3232
3333 Binding {
3434 target: PanelState
@@ -41,14 +41,20 @@ Item {
4141
4242 Item {
4343 id: fakeWindow
44− property alias minWidth: windowResizeArea.minWidth
45− property alias minHeight: windowResizeArea.minHeight
44+ property alias resizeAreaMinWidth: windowResizeArea.minWidth
45+ property alias resizeAreaMinHeight: windowResizeArea.minHeight
4646 x: units.gu(20)
4747 y: units.gu(20)
4848 width: requestedWidth
4949 height: requestedHeight
5050 property real requestedWidth
5151 property real requestedHeight
52+ property real minimumWidth: 0
53+ property real minimumHeight: 0
54+ property real maximumWidth: 0
55+ property real maximumHeight: 0
56+ property real widthIncrement: 0
57+ property real heightIncrement: 0
5258 state: "normal"
5359
5460 function maximize() {
@@ -80,6 +86,10 @@ Item {
8086 anchors.fill: parent
8187 hoverEnabled: true
8288 }
89+ Text {
90+ text: parent.width + "x" + parent.height
91+ color: "white"
92+ }
8393 }
8494 }
8595 }
@@ -90,27 +100,107 @@ Item {
90100 active: windowLoaderCheckbox.checked
91101 }
92102
93− Column {
94− MouseTouchEmulationCheckbox {
95− checked: false
96− color: "black"
97− }
98− RowLayout {
99− Layout.fillWidth: true
100− CheckBox {
101− id: windowLoaderCheckbox
102− checked: true
103− activeFocusOnPress: false
103+ Rectangle {
104+ anchors.right: parent.right
105+ anchors.top: parent.top
106+ anchors.bottom: parent.bottom
107+ width: units.gu(25)
108+ color: "lightgrey"
109+ Column {
110+ width: parent.width
111+ spacing: units.gu(1)
112+ MouseTouchEmulationCheckbox {
113+ checked: false
114+ color: "black"
115+ }
116+ RowLayout {
117+ Layout.fillWidth: true
118+ CheckBox {
119+ id: windowLoaderCheckbox
120+ checked: true
121+ activeFocusOnPress: false
122+ }
123+ Label {
124+ color: "black"
125+ text: "Window loader active"
126+ anchors.verticalCenter: parent.verticalCenter
127+ }
104128 }
105129 Label {
106− id: label
130+ color: "black"; font.bold: true
131+ text: "Size Hints:"
132+ }
133+ SizeHintField { id: minWidthText; text: "min width" }
134+ SizeHintField { id: maxWidthText; text: "max width" }
135+ SizeHintField { id: minHeightText; text: "min height" }
136+ SizeHintField { id: maxHeightText; text: "max height" }
137+ SizeHintField { id: widthIncrText; text: "width incr" }
138+ SizeHintField { id: heightIncrText; text: "height incr" }
139+ Button {
107140 color: "black"
108− text: "Window loader active"
109− anchors.verticalCenter: parent.verticalCenter
141+ anchors.horizontalCenter: parent.horizontalCenter
142+ text: "Apply"
143+ onClicked: {
144+ var value = parseInt(minWidthText.value);
145+ if (isNaN(value)) {
146+ windowLoader.item.minimumWidth = 0;
147+ } else {
148+ windowLoader.item.resizeAreaMinWidth = 1; // get it out of the way
149+ windowLoader.item.minimumWidth = value;
150+ }
151+
152+ value = parseInt(maxWidthText.value);
153+ if (isNaN(value)) {
154+ windowLoader.item.maximumWidth = 0;
155+ } else {
156+ windowLoader.item.maximumWidth = value;
157+ }
158+
159+ value = parseInt(minHeightText.value);
160+ if (isNaN(value)) {
161+ windowLoader.item.minimumHeight = 0;
162+ } else {
163+ windowLoader.item.resizeAreaMinHeight = 1; // get it out of the way
164+ windowLoader.item.minimumHeight = value;
165+ }
166+
167+ value = parseInt(maxHeightText.value);
168+ if (isNaN(value)) {
169+ windowLoader.item.maximumHeight = 0;
170+ } else {
171+ windowLoader.item.maximumHeight = value;
172+ }
173+
174+ value = parseInt(widthIncrText.value);
175+ if (isNaN(value)) {
176+ windowLoader.item.widthIncrement = 0;
177+ } else {
178+ windowLoader.item.widthIncrement = value;
179+ }
180+
181+ value = parseInt(heightIncrText.value);
182+ if (isNaN(value)) {
183+ windowLoader.item.heightIncrement = 0;
184+ } else {
185+ windowLoader.item.heightIncrement = value;
186+ }
187+ }
110188 }
111189 }
112190 }
113191
192+ SignalSpy {
193+ id: windowRequestedWidthSpy
194+ target: windowLoader.item
195+ signalName: "onRequestedWidthChanged"
196+ }
197+
198+ SignalSpy {
199+ id: windowRequestedHeightSpy
200+ target: windowLoader.item
201+ signalName: "onRequestedHeightChanged"
202+ }
203+
114204 UnityTestCase {
115205 name: "WindowResizeArea"
116206 when: windowShown
@@ -122,6 +212,18 @@ Item {
122212 fakeWindow.y = units.gu(20)
123213 fakeWindow.requestedWidth = units.gu(20)
124214 fakeWindow.requestedHeight = units.gu(20)
215+ fakeWindow.resizeAreaMinWidth = units.gu(15);
216+ fakeWindow.resizeAreaMinHeight = units.gu(10);
217+ fakeWindow.minimumWidth = 0;
218+ fakeWindow.minimumHeight = 0;
219+ fakeWindow.maximumWidth = 0;
220+ fakeWindow.maximumHeight = 0;
221+ fakeWindow.widthIncrement = 0;
222+ fakeWindow.heightIncrement = 0;
223+
224+ // Our test window resizes instantly
225+ compare(fakeWindow.width, fakeWindow.requestedWidth);
226+ compare(fakeWindow.height, fakeWindow.requestedHeight);
125227 }
126228
127229 function test_resizeWindowRightBottom_data() {
@@ -143,8 +245,8 @@ Item {
143245 var startDragY = initialWindowY + initialWindowHeight + 1
144246 mouseFlick(root, startDragX, startDragY, startDragX + data.dx, startDragY + data.dy, true, true, units.gu(.5), 10);
145247
146− tryCompare(fakeWindow, "width", Math.max(initialWindowWidth + data.dx, fakeWindow.minWidth));
147− tryCompare(fakeWindow, "height", Math.max(initialWindowHeight + data.dy, fakeWindow.minHeight));
248+ tryCompare(fakeWindow, "width", Math.max(initialWindowWidth + data.dx, fakeWindow.resizeAreaMinWidth));
249+ tryCompare(fakeWindow, "height", Math.max(initialWindowHeight + data.dy, fakeWindow.resizeAreaMinHeight));
148250
149251 compare(fakeWindow.x, initialWindowX);
150252 compare(fakeWindow.y, initialWindowY);
@@ -169,11 +271,11 @@ Item {
169271 var startDragY = initialWindowY - 1
170272 mouseFlick(root, startDragX, startDragY, startDragX + data.dx, startDragY + data.dy, true, true, units.gu(.5), 10);
171273
172− tryCompare(fakeWindow, "width", Math.max(initialWindowWidth - data.dx, fakeWindow.minWidth));
173− tryCompare(fakeWindow, "height", Math.max(initialWindowHeight - data.dy, fakeWindow.minHeight));
274+ tryCompare(fakeWindow, "width", Math.max(initialWindowWidth - data.dx, fakeWindow.resizeAreaMinWidth));
275+ tryCompare(fakeWindow, "height", Math.max(initialWindowHeight - data.dy, fakeWindow.resizeAreaMinHeight));
174276
175− var maxMoveX = initialWindowWidth - fakeWindow.minWidth;
176− var maxMoveY = initialWindowHeight - fakeWindow.minHeight;
277+ var maxMoveX = initialWindowWidth - fakeWindow.resizeAreaMinWidth;
278+ var maxMoveY = initialWindowHeight - fakeWindow.resizeAreaMinHeight;
177279 compare(fakeWindow.x, Math.min(initialWindowX + data.dx, initialWindowX + maxMoveX));
178280 compare(fakeWindow.y, Math.min(initialWindowY + data.dy, initialWindowY + maxMoveY));
179281 }
@@ -189,8 +291,8 @@ Item {
189291 var startDragY = initialWindowY + initialWindowHeight + 1
190292 mouseFlick(root, startDragX, startDragY, startDragX + resizeDelta, startDragY + resizeDelta, true, true, units.gu(.5), 10);
191293
192− tryCompare(fakeWindow, "width", Math.max(initialWindowWidth + resizeDelta, fakeWindow.minWidth));
193− tryCompare(fakeWindow, "height", Math.max(initialWindowHeight + resizeDelta, fakeWindow.minHeight));
294+ tryCompare(fakeWindow, "width", Math.max(initialWindowWidth + resizeDelta, fakeWindow.resizeAreaMinWidth));
295+ tryCompare(fakeWindow, "height", Math.max(initialWindowHeight + resizeDelta, fakeWindow.resizeAreaMinHeight));
194296
195297 // This will destroy the window and recreate it
196298 windowLoader.active = false;
@@ -198,8 +300,8 @@ Item {
198300 windowLoader.active = true;
199301
200302 // Make sure its size is again the same as before
201− tryCompare(fakeWindow, "width", Math.max(initialWindowWidth + resizeDelta, fakeWindow.minWidth));
202− tryCompare(fakeWindow, "height", Math.max(initialWindowHeight + resizeDelta, fakeWindow.minHeight));
303+ tryCompare(fakeWindow, "width", Math.max(initialWindowWidth + resizeDelta, fakeWindow.resizeAreaMinWidth));
304+ tryCompare(fakeWindow, "height", Math.max(initialWindowHeight + resizeDelta, fakeWindow.resizeAreaMinHeight));
203305 }
204306
205307 // This tests if dragging smaller than minSize and then larger again, will keep the edge sticking
@@ -220,8 +322,8 @@ Item {
220322 var startDragX = initialWindowX + data.startX
221323 var startDragY = initialWindowY + data.startY
222324 mouseFlick(root, startDragX, startDragY, startDragX + data.dx, startDragY + data.dy, true, false, units.gu(.05), 10);
223− tryCompare(fakeWindow, "width", Math.max(initialWindowWidth - Math.abs(data.dx), fakeWindow.minWidth));
224− tryCompare(fakeWindow, "height", Math.max(initialWindowHeight - Math.abs(data.dy), fakeWindow.minHeight));
325+ tryCompare(fakeWindow, "width", Math.max(initialWindowWidth - Math.abs(data.dx), fakeWindow.resizeAreaMinWidth));
326+ tryCompare(fakeWindow, "height", Math.max(initialWindowHeight - Math.abs(data.dy), fakeWindow.resizeAreaMinHeight));
225327 mouseFlick(root, startDragX + data.dx, startDragY + data.dy, startDragX, startDragY, false, true, units.gu(.05), 10);
226328 tryCompare(fakeWindow, "width", initialWindowWidth);
227329 tryCompare(fakeWindow, "height", initialWindowHeight);
@@ -257,7 +359,6 @@ Item {
257359 fakeWindow.state = "normal"
258360 }
259361
260−
261362 function test_restoreMovesIntoBounds_data() {
262363 return [
263364 {tag: "left off", x: -units.gu(5), y: units.gu(5), w: units.gu(10), h: units.gu(10)},
@@ -290,5 +391,99 @@ Item {
290391
291392 waitForRendering(root)
292393 }
394+
395+ /*
396+ Tests that even though you dragged the window bottom right corner continously (ie,
397+ through multiple intermediate steps), its (requested) width and height changed only
398+ once. And, furthermore, its dimensions increased by a multiple of its size (width
399+ and height) increment value.
400+ */
401+ function test_sizeIncrement() {
402+ var initialWindowX = fakeWindow.x;
403+ var initialWindowY = fakeWindow.y;
404+ var initialWindowWidth = fakeWindow.width
405+ var initialWindowHeight = fakeWindow.height
406+
407+ fakeWindow.widthIncrement = 70;
408+ fakeWindow.heightIncrement = 70;
409+
410+ var startDragX = initialWindowX + initialWindowWidth + 1
411+ var startDragY = initialWindowY + initialWindowHeight + 1
412+ var deltaX = 100;
413+ var deltaY = 100;
414+
415+ windowRequestedWidthSpy.clear();
416+ verify(windowRequestedWidthSpy.valid);
417+
418+ windowRequestedHeightSpy.clear();
419+ verify(windowRequestedHeightSpy.valid);
420+
421+ mouseFlick(root, startDragX, startDragY, startDragX + deltaX, startDragY + deltaY, true, true, units.gu(.5), 10);
422+
423+ compare(windowRequestedWidthSpy.count, 1);
424+ compare(fakeWindow.width, initialWindowWidth + fakeWindow.widthIncrement);
425+ compare(windowRequestedHeightSpy.count, 1);
426+ compare(fakeWindow.height, initialWindowHeight + fakeWindow.heightIncrement);
427+ }
428+
429+ /*
430+ Tests that when dragging a window border you cannot make it bigger than its maximum size
431+ */
432+ function test_maximumSize() {
433+ fakeWindow.x = units.gu(1);
434+ fakeWindow.y = units.gu(1);
435+ fakeWindow.resizeAreaMinWidth = 1; // so it does not interfere with anything
436+ fakeWindow.resizeAreaMinHeight = 1; // so it does not interfere with anything
437+ fakeWindow.requestedWidth = units.gu(10);
438+ fakeWindow.requestedHeight = units.gu(10);
439+
440+ fakeWindow.maximumWidth = units.gu(20);
441+ fakeWindow.maximumHeight = units.gu(20);
442+
443+ // Our test window resizes instantly
444+ compare(fakeWindow.width, fakeWindow.requestedWidth);
445+ compare(fakeWindow.height, fakeWindow.requestedHeight);
446+
447+ var startDragX = fakeWindow.width + 1
448+ var startDragY = fakeWindow.height + 1
449+ var endDragX = (fakeWindow.maximumWidth * 2) + 1;
450+ var endDragY = (fakeWindow.maximumHeight * 2) + 1;
451+
452+ mouseFlick(fakeWindow, startDragX, startDragY, endDragX, endDragY,
453+ true/*pressMouse*/, true/*releaseMouse*/, units.gu(.5)/*speed*/, 20/*iterations*/);
454+
455+ compare(fakeWindow.requestedWidth, fakeWindow.maximumWidth);
456+ compare(fakeWindow.requestedHeight, fakeWindow.maximumHeight);
457+ }
458+
459+ /*
460+ Tests that when dragging a window border you cannot make it smaller than its minimum size
461+ */
462+ function test_minimumSize() {
463+ fakeWindow.x = units.gu(1);
464+ fakeWindow.y = units.gu(1);
465+ fakeWindow.resizeAreaMinWidth = 1; // so it does not interfere with anything
466+ fakeWindow.resizeAreaMinHeight = 1; // so it does not interfere with anything
467+ fakeWindow.requestedWidth = units.gu(20);
468+ fakeWindow.requestedHeight = units.gu(20);
469+
470+ fakeWindow.minimumWidth = units.gu(10);
471+ fakeWindow.minimumHeight = units.gu(10);
472+
473+ // Our test window resizes instantly
474+ compare(fakeWindow.width, fakeWindow.requestedWidth);
475+ compare(fakeWindow.height, fakeWindow.requestedHeight);
476+
477+ var startDragX = fakeWindow.width + 1
478+ var startDragY = fakeWindow.height + 1
479+ var endDragX = (fakeWindow.minimumWidth * 0.5) + 1;
480+ var endDragY = (fakeWindow.minimumHeight * 0.5) + 1;
481+
482+ mouseFlick(fakeWindow, startDragX, startDragY, endDragX, endDragY,
483+ true/*pressMouse*/, true/*releaseMouse*/, units.gu(.5)/*speed*/, 20/*iterations*/);
484+
485+ compare(fakeWindow.requestedWidth, fakeWindow.minimumWidth);
486+ compare(fakeWindow.requestedHeight, fakeWindow.minimumHeight);
487+ }
293488 }
294489}