Merge lp:~dandrader/unity8/noStretchOnResize into lp:unity8

Proposed by Daniel d'Andrada
Status: Merged
Approved by: Albert Astals Cid
Approved revision: 2012
Merged at revision: 2059
Proposed branch: lp:~dandrader/unity8/noStretchOnResize
Merge into: lp:unity8
Prerequisite: lp:~unity-team/unity8/externalMonitor
Diff against target: 705 lines (+304/-50)
10 files modified
qml/Stages/ApplicationWindow.qml (+27/-1)
qml/Stages/DecoratedWindow.qml (+7/-2)
qml/Stages/DesktopStage.qml (+9/-9)
qml/Stages/SessionContainer.qml (+25/-1)
qml/Stages/SurfaceContainer.qml (+56/-4)
qml/Stages/WindowResizeArea.qml (+65/-20)
tests/mocks/Unity/Application/MirSurface.cpp (+52/-0)
tests/mocks/Unity/Application/MirSurface.h (+16/-0)
tests/qmltests/Stages/tst_DesktopStage.qml (+16/-1)
tests/qmltests/Stages/tst_WindowResizeArea.qml (+31/-12)
To merge this branch: bzr merge lp:~dandrader/unity8/noStretchOnResize
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Needs Fixing
Albert Astals Cid (community) Abstain
Michael Zanetti (community) Approve
Review via email: mp+274752@code.launchpad.net

This proposal supersedes a proposal from 2015-10-14.

Commit message

Don't stretch application surfaces when resizing

Description of the change

* Are there any related MPs required for this MP to build/function as expected? Please list.

No.

* Did you perform an exploratory manual test run of your code change and any related functionality?

Yes

* Did you make sure that your branch does not contain spurious tags?

Yes

* If you changed the packaging (debian), did you subscribe the ubuntu-unity team to this MP?

Not applicable

* If you changed the UI, has there been a design review?

Not applicable

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
Michael Zanetti (mzanetti) wrote : Posted in a previous version of this proposal

When resizing I can see the panel and the dropshadow resizing faster than the content. I think it would be better to not resize those either until the surface has caught up.

Other than that, it seems to work fine.

review: Needs Fixing
Revision history for this message
Daniel d'Andrada (dandrader) wrote : Posted in a previous version of this proposal

On 23/09/2015 07:31, Michael Zanetti wrote:
> Review: Needs Fixing
>
> When resizing I can see the panel and the dropshadow resizing faster than the content. I think it would be better to not resize those either until the surface has caught up.
>
> Other than that, it seems to work fine.

It's a design decision: should we show something like a translucent
orang rect that tightly follows the mouse pointer (therefore showing
shell's responsiveness and a smooth animation) or have the window stick
to the surface size (as you prefer, but risking showing a stuttering,
unresponsive, shell)?

I don't have a strong opinion on that, but I do prefer first option. But
I'm ok with your preference as well. Any of those are better than the
current state. We should get design input on that (not sure *how* to do
that)

Revision history for this message
kevin gunn (kgunn72) wrote : Posted in a previous version of this proposal

> On 23/09/2015 07:31, Michael Zanetti wrote:
> > Review: Needs Fixing
> >
> > When resizing I can see the panel and the dropshadow resizing faster than
> the content. I think it would be better to not resize those either until the
> surface has caught up.
> >
> > Other than that, it seems to work fine.
>
> It's a design decision: should we show something like a translucent
> orang rect that tightly follows the mouse pointer (therefore showing
> shell's responsiveness and a smooth animation) or have the window stick
> to the surface size (as you prefer, but risking showing a stuttering,
> unresponsive, shell)?
>
> I don't have a strong opinion on that, but I do prefer first option. But
> I'm ok with your preference as well. Any of those are better than the
> current state. We should get design input on that (not sure *how* to do
> that)

i would vote we land for the speedy soln now, and then log a bug subsequent to this landing outlining the choices between speed vs nice tight animation tween window/shadow

Revision history for this message
Albert Astals Cid (aacid) wrote : Posted in a previous version of this proposal

Text conflict in CMakeLists.txt
1 conflicts encountered.

Revision history for this message
Daniel d'Andrada (dandrader) wrote : Posted in a previous version of this proposal

> When resizing I can see the panel and the dropshadow resizing faster than the
> content. I think it would be better to not resize those either until the
> surface has caught up.
>
> Other than that, it seems to work fine.

Now it's exactly what you asked for.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Michael Zanetti (mzanetti) wrote :

looks mostly good. some leftovers in the code to clean up. see inline.

still need to test it on the real qtmir

review: Needs Fixing
Revision history for this message
Daniel d'Andrada (dandrader) wrote :

the ShellView changes are part of the prerequisite already[1]. I don't know why launchpad didn't update the web diff.

[1] - http://bazaar.launchpad.net/~unity-team/unity8/externalMonitor/view/head:/src/ShellView.cpp

Revision history for this message
Daniel d'Andrada (dandrader) wrote :

All comments addressed. Had to rebase to keep the commit stack plain and simple so that launchpad didn't get confused (new you no longer see ShellView changes in the web diff).

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Michael Zanetti (mzanetti) wrote :

Close, one issue:

When a window is slow to resize, resize it from the top-left corner towards the right (making the window smaller). Release the mouse before the actual resizing has happened. It will catch up resizing on the right edge instead of the left.

This can be reproduced with tryDesktopStage, but it's easiest/most notable when resizing the dash on top of QtMir (also reproducible with other apps tho).

review: Needs Fixing
Revision history for this message
Daniel d'Andrada (dandrader) wrote :

On 23/10/2015 11:18, Michael Zanetti wrote:
> When a window is slow to resize, resize it from the top-left corner towards the right (making the window smaller). Release the mouse before the actual resizing has happened. It will catch up resizing on the right edge instead of the left.

Knonw issue. Decided to leave it that way. Let's talk over IRC

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Michael Zanetti (mzanetti) wrote :

The last commit seems a okayish workaround to the problem. Let's go with this for now and refine it later.

One tiny issue where I'd like to hear your input:

Running on my laptop it sometimes happens that the dash doesn't start up properly (there's a bug for that, unrelated to this branch). With trunk, the window paints the background and then freezes. With this branch, the window doesn't even paint at all and we keep seeing the window decoration and shadow alone. What are your thoughts? Some potential issues?

review: Needs Information
Revision history for this message
Daniel d'Andrada (dandrader) wrote :

> The last commit seems a okayish workaround to the problem. Let's go with this
> for now and refine it later.
>
> One tiny issue where I'd like to hear your input:
>
> Running on my laptop it sometimes happens that the dash doesn't start up
> properly (there's a bug for that, unrelated to this branch). With trunk, the
> window paints the background and then freezes. With this branch, the window
> doesn't even paint at all and we keep seeing the window decoration and shadow
> alone. What are your thoughts? Some potential issues?

This is not related to this branch but to its prerequisites in qtmir.
It's a workaround for the situation where a mir surface doesn't have buffers to draw. So instead of crashing we just give a null/empty texture to Qt Scenegraph.

Revision history for this message
Michael Zanetti (mzanetti) wrote :

OK. Let's get this in then.

 * Did you perform an exploratory manual test run of the code change and any related functionality?

yes

 * Did CI run pass? If not, please explain why.

no, inter-project deps. I've ran related tests and they seem fine

 * Did you make sure that the branch does not contain spurious tags?

yes

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Albert Astals Cid (aacid) wrote :

Note: was already top approved

Text conflict in qml/Stages/DesktopStage.qml
Text conflict in qml/Stages/WindowResizeArea.qml
Text conflict in tests/mocks/Unity/Application/MirSurface.h
Text conflict in tests/qmltests/Stages/tst_DesktopStage.qml
Text conflict in tests/qmltests/Stages/tst_WindowResizeArea.qml
5 conflicts encountered.

review: Needs Fixing
2010. By Daniel d'Andrada

Merge trunk

2011. By Daniel d'Andrada

Fix typo

Revision history for this message
Daniel d'Andrada (dandrader) wrote :

> Note: was already top approved
>
> Text conflict in qml/Stages/DesktopStage.qml
> Text conflict in qml/Stages/WindowResizeArea.qml
> Text conflict in tests/mocks/Unity/Application/MirSurface.h
> Text conflict in tests/qmltests/Stages/tst_DesktopStage.qml
> Text conflict in tests/qmltests/Stages/tst_WindowResizeArea.qml
> 5 conflicts encountered.

Fixed, thanks.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Albert Astals Cid (aacid) wrote :

CI says

tests/mocks/Unity/Application/MirSurfaceItem.h:65:5: error: 'FillMode' does not name a type
     FillMode fillMode() const override;

Any idea what's wrong here?

review: Needs Information
Revision history for this message
Daniel d'Andrada (dandrader) wrote :

On 09/11/2015 08:04, Albert Astals Cid wrote:
> Review: Needs Information
>
> CI says
>
> tests/mocks/Unity/Application/MirSurfaceItem.h:65:5: error: 'FillMode' does not name a type
> FillMode fillMode() const override;
>
> Any idea what's wrong here?
>
>
It's the unity-api dependency

2012. By Daniel d'Andrada

Remove dependency on MirSurfaceItem.fillMode property

Revision history for this message
Daniel d'Andrada (dandrader) wrote :

Removed dependency on MirSurfaceItem.fillMode property as it's going to take forever for the qtmir branch that adds it to get merged.

This branch and the use of MirSurfaceItem.fillMode are independent of each other anyway. They are complementary

Revision history for this message
Daniel d'Andrada (dandrader) wrote :

> On 09/11/2015 08:04, Albert Astals Cid wrote:
> > Review: Needs Information
> >
> > CI says
> >
> > tests/mocks/Unity/Application/MirSurfaceItem.h:65:5: error: 'FillMode' does
> not name a type
> > FillMode fillMode() const override;
> >
> > Any idea what's wrong here?
> >
> >
> It's the unity-api dependency

Just removed the dependency btw, next CI build should no longer cough on it.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Francis Ginther (fginther) wrote :

I've restarted this MP to work around an issue triggering generic-deb-autopilot-vivid-touch on krillin hardware.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Continuous integration, rev:2012
http://jenkins.qa.ubuntu.com/job/unity8-ci/6691/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-vivid-touch/5099
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-xenial-touch/106/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity-phablet-qmluitests-vivid/1403
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-qmluitest-xenial-amd64/106
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-vivid-amd64-ci/1298
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-vivid-i386-ci/1299
    FAILURE: http://jenkins.qa.ubuntu.com/job/unity8-xenial-amd64-ci/105/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-xenial-i386-ci/105
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-vivid-touch/4081
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-vivid-armhf/5104
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-vivid-armhf/5104/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/25035
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-xenial-touch/10/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-xenial-armhf/106
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-xenial-armhf/106/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/25036

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/unity8-ci/6691/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Albert Astals Cid (aacid) wrote :

Merged and CI is "good" again, re-top approving based on Michael's top approve.

review: Abstain
2013. By Daniel d'Andrada

Merge trunk

[ Albert Astals Cid ]
* Make cardWidth and cardHeight real
* Reset instead of qFatal when removing things from the middle (LP:
  #1238979)
* Warn we're using only the cache when not connected to the interwebs
[ Andrea Cimitan ]
* Add sharing widget to zoomable image and video playback
[ Daniel d'Andrada ]
* Cursor: properly initialize hotspot position (LP: #1510407)
* Update GSettings mock in tst_OrientedShell
[ Lukáš Tinkl ]
* Restore windows when activating from the spread, maintain a focus
  stack
[ Michael Terry ]
* Make a few DBus calls asynchronous, for a smoother UX.
[ Michael Zanetti ]
* Add a warning dialog when disconnecting the external monitor.
* added icon for the dash (LP: #1488146)
* prevent windows to be moved under the panel (LP: #1438465)
* update inputinfo api to the latest upstream snapshot
* use UbuntuNumberAnimations instead of linear ones for window state
  transitions (LP: #1497097)

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Continuous integration, rev:2013
http://jenkins.qa.ubuntu.com/job/unity8-ci/6775/
Executed test runs:
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-vivid-touch/5324/console
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-xenial-touch/190/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity-phablet-qmluitests-vivid/1488
    FAILURE: http://jenkins.qa.ubuntu.com/job/unity8-qmluitest-xenial-amd64/190/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-vivid-amd64-ci/1382
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-vivid-i386-ci/1383
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-xenial-amd64-ci/189
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-xenial-i386-ci/189
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-vivid-touch/4224/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-vivid-armhf/5344
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-vivid-armhf/5344/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/25408
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-xenial-touch/56/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-xenial-armhf/190
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-xenial-armhf/190/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/25406

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/unity8-ci/6775/rebuild

review: Needs Fixing (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'qml/Stages/ApplicationWindow.qml'
2--- qml/Stages/ApplicationWindow.qml 2015-10-26 09:59:50 +0000
3+++ qml/Stages/ApplicationWindow.qml 2015-11-20 13:05:20 +0000
4@@ -34,6 +34,8 @@
5 property QtObject application
6 property int surfaceOrientationAngle
7 property alias resizeSurface: sessionContainer.resizeSurface
8+ property int requestedWidth: -1
9+ property int requestedHeight: -1
10
11 QtObject {
12 id: d
13@@ -135,7 +137,9 @@
14 id: sessionContainer
15 // A fake application might not even have a session property.
16 session: application && application.session ? application.session : null
17- anchors.fill: parent
18+
19+ requestedWidth: root.requestedWidth
20+ requestedHeight: root.requestedHeight
21
22 surfaceOrientationAngle: application && application.rotatesWindowContents ? root.surfaceOrientationAngle : 0
23
24@@ -150,6 +154,28 @@
25 focus: true
26 }
27
28+ // SessionContainer size drives ApplicationWindow size
29+ Binding {
30+ target: root; property: "width"
31+ value: stateGroup.state === "surface" ? sessionContainer.width : root.requestedWidth
32+ when: root.requestedWidth >= 0
33+ }
34+ Binding {
35+ target: root; property: "height"
36+ value: stateGroup.state === "surface" ? sessionContainer.height : root.requestedHeight
37+ when: root.requestedHeight >= 0
38+ }
39+
40+ // ApplicationWindow size drives SessionContainer size
41+ Binding {
42+ target: sessionContainer; property: "width"; value: root.width
43+ when: root.requestedWidth < 0
44+ }
45+ Binding {
46+ target: sessionContainer; property: "height"; value: root.height
47+ when: root.requestedHeight < 0
48+ }
49+
50 StateGroup {
51 id: stateGroup
52 objectName: "applicationWindowStateGroup"
53
54=== modified file 'qml/Stages/DecoratedWindow.qml'
55--- qml/Stages/DecoratedWindow.qml 2015-11-06 13:48:29 +0000
56+++ qml/Stages/DecoratedWindow.qml 2015-11-20 13:05:20 +0000
57@@ -23,6 +23,9 @@
58 FocusScope {
59 id: root
60
61+ width: applicationWindow.width
62+ height: (root.decorationShown ? decoration.height : 0) + applicationWindow.height
63+
64 property alias window: applicationWindow
65 property alias application: applicationWindow.application
66 property alias active: decoration.active
67@@ -32,6 +35,9 @@
68 property bool highlightShown: false
69 property real shadowOpacity: 1
70
71+ property alias requestedWidth: applicationWindow.requestedWidth
72+ property real requestedHeight
73+
74 signal close()
75 signal maximize()
76 signal minimize()
77@@ -82,8 +88,7 @@
78 anchors.top: parent.top
79 anchors.topMargin: decoration.height
80 anchors.left: parent.left
81- width: root.width
82- height: root.height - decoration.height
83+ requestedHeight: root.requestedHeight - (root.decorationShown ? decoration.height : 0)
84 interactive: true
85 focus: true
86 }
87
88=== modified file 'qml/Stages/DesktopStage.qml'
89--- qml/Stages/DesktopStage.qml 2015-11-12 20:40:49 +0000
90+++ qml/Stages/DesktopStage.qml 2015-11-20 13:05:20 +0000
91@@ -219,9 +219,11 @@
92 objectName: "appDelegate_" + appId
93 z: ApplicationManager.count - index
94 y: units.gu(3)
95- width: units.gu(60)
96- height: units.gu(50)
97- focus: appId === priv.focusedAppId
98+ width: decoratedWindow.width
99+ height: decoratedWindow.height
100+ property alias requestedWidth: decoratedWindow.requestedWidth
101+ property alias requestedHeight: decoratedWindow.requestedHeight
102+ focus: model.appId === priv.focusedAppId
103
104 QtObject {
105 id: appDelegatePrivate
106@@ -325,7 +327,7 @@
107 PropertyChanges {
108 target: appDelegate;
109 x: 0; y: 0;
110- width: root.width; height: root.height;
111+ requestedWidth: root.width; requestedHeight: root.height;
112 visuallyMinimized: false;
113 visuallyMaximized: true
114 }
115@@ -355,14 +357,14 @@
116 to: "normal"
117 enabled: appDelegate.animationsEnabled
118 PropertyAction { target: appDelegate; properties: "visuallyMinimized,visuallyMaximized" }
119- UbuntuNumberAnimation { target: appDelegate; properties: "x,y,opacity,width,height,scale"; duration: UbuntuAnimation.FastDuration }
120+ UbuntuNumberAnimation { target: appDelegate; properties: "x,y,opacity,requestedWidth,requestedHeight,scale"; duration: UbuntuAnimation.FastDuration }
121 },
122 Transition {
123 to: "maximized"
124 enabled: appDelegate.animationsEnabled
125 PropertyAction { target: appDelegate; property: "visuallyMinimized" }
126 SequentialAnimation {
127- UbuntuNumberAnimation { target: appDelegate; properties: "x,y,opacity,width,height,scale"; duration: UbuntuAnimation.FastDuration }
128+ UbuntuNumberAnimation { target: appDelegate; properties: "x,y,opacity,requestedWidth,requestedHeight,scale"; duration: UbuntuAnimation.FastDuration }
129 PropertyAction { target: appDelegate; property: "visuallyMaximized" }
130 }
131 },
132@@ -371,7 +373,7 @@
133 enabled: appDelegate.animationsEnabled
134 PropertyAction { target: appDelegate; property: "visuallyMaximized" }
135 SequentialAnimation {
136- UbuntuNumberAnimation { target: appDelegate; properties: "x,y,opacity,width,height,scale"; duration: UbuntuAnimation.FastDuration }
137+ UbuntuNumberAnimation { target: appDelegate; properties: "x,y,opacity,requestedWidth,requestedHeight,scale"; duration: UbuntuAnimation.FastDuration }
138 PropertyAction { target: appDelegate; property: "visuallyMinimized" }
139 ScriptAction {
140 script: {
141@@ -410,8 +412,6 @@
142 objectName: "decoratedWindow"
143 anchors.left: appDelegate.left
144 anchors.top: appDelegate.top
145- width: appDelegate.width
146- height: appDelegate.height
147 application: ApplicationManager.get(index)
148 active: ApplicationManager.focusedApplicationId === model.appId
149 focus: true
150
151=== modified file 'qml/Stages/SessionContainer.qml'
152--- qml/Stages/SessionContainer.qml 2015-09-29 12:28:10 +0000
153+++ qml/Stages/SessionContainer.qml 2015-11-20 13:05:20 +0000
154@@ -29,13 +29,37 @@
155 property alias surfaceOrientationAngle: _surfaceContainer.surfaceOrientationAngle
156 property alias resizeSurface: _surfaceContainer.resizeSurface
157
158+ property int requestedWidth: -1
159+ property int requestedHeight: -1
160+
161 readonly property alias surfaceContainer: _surfaceContainer
162 SurfaceContainer {
163 id: _surfaceContainer
164- anchors.fill: parent
165+ requestedWidth: root.requestedWidth
166+ requestedHeight: root.requestedHeight
167 surface: session ? session.surface : null
168 }
169
170+ // SurfaceContainer size drives SessionContainer size
171+ Binding {
172+ target: root; property: "width"; value: _surfaceContainer.width
173+ when: root.requestedWidth >= 0
174+ }
175+ Binding {
176+ target: root; property: "height"; value: _surfaceContainer.height
177+ when: root.requestedHeight >= 0
178+ }
179+
180+ // SessionContainer size drives SurfaceContainer size
181+ Binding {
182+ target: _surfaceContainer; property: "width"; value: root.width
183+ when: root.requestedWidth < 0
184+ }
185+ Binding {
186+ target: _surfaceContainer; property: "height"; value: root.height
187+ when: root.requestedHeight < 0
188+ }
189+
190 Repeater {
191 id: childSessionsRepeater
192 model: root.childSessions
193
194=== modified file 'qml/Stages/SurfaceContainer.qml'
195--- qml/Stages/SurfaceContainer.qml 2015-10-26 09:59:50 +0000
196+++ qml/Stages/SurfaceContainer.qml 2015-11-20 13:05:20 +0000
197@@ -31,6 +31,9 @@
198 property string name: surface ? surface.name : ""
199 property bool resizeSurface: true
200
201+ property int requestedWidth: -1
202+ property int requestedHeight: -1
203+
204 onSurfaceChanged: {
205 if (surface) {
206 surfaceItem.surface = surface;
207@@ -54,16 +57,65 @@
208
209 consumesInput: true
210
211- surfaceWidth: root.resizeSurface ? width : -1
212- surfaceHeight: root.resizeSurface ? height : -1
213-
214- anchors.fill: root
215+ surfaceWidth: {
216+ if (root.resizeSurface) {
217+ if (root.requestedWidth >= 0) {
218+ return root.requestedWidth;
219+ } else {
220+ return width;
221+ }
222+ } else {
223+ return -1;
224+ }
225+ }
226+
227+ surfaceHeight: {
228+ if (root.resizeSurface) {
229+ if (root.requestedHeight >= 0) {
230+ return root.requestedHeight;
231+ } else {
232+ return height;
233+ }
234+ } else {
235+ return -1;
236+ }
237+ }
238+
239 enabled: root.interactive
240 focus: true
241 antialiasing: !root.interactive
242 orientationAngle: root.surfaceOrientationAngle
243 }
244
245+ // MirSurface size drives SurfaceContainer size
246+ Binding {
247+ target: surfaceItem; property: "width"; value: root.surface ? root.surface.size.width : 0
248+ when: root.requestedWidth >= 0 && root.surface
249+ }
250+ Binding {
251+ target: surfaceItem; property: "height"; value: root.surface ? root.surface.size.height : 0
252+ when: root.requestedHeight >= 0 && root.surface
253+ }
254+ Binding {
255+ target: root; property: "width"; value: surfaceItem.width
256+ when: root.requestedWidth >= 0
257+ }
258+ Binding {
259+ target: root; property: "height"; value: surfaceItem.height
260+ when: root.requestedHeight >= 0
261+ }
262+
263+ // SurfaceContainer size drives MirSurface size
264+ Binding {
265+ target: surfaceItem; property: "width"; value: root.width
266+ when: root.requestedWidth < 0
267+ }
268+ Binding {
269+ target: surfaceItem; property: "height"; value: root.height
270+ when: root.requestedHeight < 0
271+ }
272+
273+
274 TouchGate {
275 targetItem: surfaceItem
276 anchors.fill: root
277
278=== modified file 'qml/Stages/WindowResizeArea.qml'
279--- qml/Stages/WindowResizeArea.qml 2015-11-09 10:52:53 +0000
280+++ qml/Stages/WindowResizeArea.qml 2015-11-20 13:05:20 +0000
281@@ -36,6 +36,8 @@
282 property int borderThickness: 0
283 property int minWidth: 0
284 property int minHeight: 0
285+ property int defaultWidth: units.gu(60)
286+ property int defaultHeight: units.gu(50)
287 property int screenWidth: 0
288 property int screenHeight: 0
289
290@@ -67,13 +69,14 @@
291 }
292
293 Component.onCompleted: {
294- var windowGeometry = windowStateStorage.getGeometry(root.windowId, Qt.rect(target.x, target.y, target.width, target.height))
295- if (windowGeometry !== undefined) {
296- target.width = Math.min(windowGeometry.width, root.screenWidth)
297- target.height = Math.min(windowGeometry.height, root.screenHeight - PanelState.panelHeight)
298- target.x = Math.max(Math.min(windowGeometry.x, root.screenWidth - target.width), 0)
299- target.y = Math.max(Math.min(windowGeometry.y, root.screenHeight - target.height), PanelState.panelHeight)
300- }
301+ var windowGeometry = windowStateStorage.getGeometry(root.windowId,
302+ Qt.rect(target.x, target.y, defaultWidth, defaultHeight));
303+
304+ target.requestedWidth = Math.min(Math.max(windowGeometry.width, minWidth), screenWidth);
305+ target.requestedHeight = Math.min(Math.max(windowGeometry.height, minHeight), root.screenHeight - PanelState.panelHeight);
306+ target.x = Math.max(Math.min(windowGeometry.x, root.screenWidth - target.requestedWidth), 0)
307+ target.y = Math.max(Math.min(windowGeometry.y, root.screenHeight - target.requestedHeight), PanelState.panelHeight)
308+
309 var windowState = windowStateStorage.getState(root.windowId, WindowStateStorage.WindowStateNormal)
310 if (windowState === WindowStateStorage.WindowStateMaximized) {
311 target.maximize(false)
312@@ -93,6 +96,18 @@
313 property bool topBorder: false
314 property bool bottomBorder: false
315
316+ // true - A change in surface size will cause the left border of the window to move accordingly.
317+ // The window's right border will stay in the same position.
318+ // false - a change in surface size will cause the right border of the window to move accordingly.
319+ // The window's left border will stay in the same position.
320+ property bool moveLeftBorder: false
321+
322+ // true - A change in surface size will cause the top border of the window to move accordingly.
323+ // The window's bottom border will stay in the same position.
324+ // false - a change in surface size will cause the bottom border of the window to move accordingly.
325+ // The window's top border will stay in the same position.
326+ property bool moveTopBorder: false
327+
328 property bool dragging: false
329 property real startMousePosX
330 property real startMousePosY
331@@ -100,6 +115,8 @@
332 property real startY
333 property real startWidth
334 property real startHeight
335+ property real currentWidth
336+ property real currentHeight
337
338 property string cursorName: {
339 if (root.containsMouse || root.pressed) {
340@@ -138,11 +155,24 @@
341 }
342 }
343
344+ Timer {
345+ id: resetBordersToMoveTimer
346+ interval: 2000
347+ onTriggered: {
348+ d.moveLeftBorder = false;
349+ d.moveTopBorder = false;
350+ }
351+ }
352+
353 onPressedChanged: {
354 var pos = mapToItem(target.parent, mouseX, mouseY);
355
356 if (pressed) {
357 d.updateBorders();
358+ resetBordersToMoveTimer.stop();
359+ d.moveLeftBorder = d.leftBorder;
360+ d.moveTopBorder = d.topBorder;
361+
362 var pos = mapToItem(root.target.parent, mouseX, mouseY);
363 d.startMousePosX = pos.x;
364 d.startMousePosY = pos.y;
365@@ -150,8 +180,11 @@
366 d.startY = target.y;
367 d.startWidth = target.width;
368 d.startHeight = target.height;
369+ d.currentWidth = target.width;
370+ d.currentHeight = target.height;
371 d.dragging = true;
372 } else {
373+ resetBordersToMoveTimer.start();
374 d.dragging = false;
375 if (containsMouse) {
376 d.updateBorders();
377@@ -182,37 +215,49 @@
378 if (d.leftBorder) {
379 var newTargetX = d.startX + deltaX;
380 if (target.x + target.width > newTargetX + minWidth) {
381- target.width = target.x + target.width - newTargetX;
382- target.x = newTargetX;
383+ target.requestedWidth = target.x + target.width - newTargetX;
384 } else {
385- target.x = target.x + target.width - minWidth;
386- target.width = minWidth;
387+ target.requestedWidth = minWidth;
388 }
389
390 } else if (d.rightBorder) {
391 if (d.startWidth + deltaX >= minWidth) {
392- target.width = d.startWidth + deltaX;
393+ target.requestedWidth = d.startWidth + deltaX;
394 } else {
395- target.width = minWidth;
396+ target.requestedWidth = minWidth;
397 }
398 }
399
400 if (d.topBorder) {
401 var newTargetY = d.startY + deltaY;
402 if (target.y + target.height > newTargetY + minHeight) {
403- target.height = target.y + target.height - newTargetY;
404- target.y = newTargetY;
405+ target.requestedHeight = target.y + target.height - newTargetY;
406 } else {
407- target.y = target.y + target.height - minHeight;
408- target.height = minHeight;
409+ target.requestedHeight = minHeight;
410 }
411
412 } else if (d.bottomBorder) {
413 if (d.startHeight + deltaY >= minHeight) {
414- target.height = d.startHeight + deltaY;
415+ target.requestedHeight = d.startHeight + deltaY;
416 } else {
417- target.height = minHeight;
418- }
419+ target.requestedHeight = minHeight;
420+ }
421+ }
422+ }
423+
424+ Connections {
425+ target: root.target
426+ onWidthChanged: {
427+ if (d.moveLeftBorder) {
428+ target.x += d.currentWidth - target.width;
429+ }
430+ d.currentWidth = target.width;
431+ }
432+ onHeightChanged: {
433+ if (d.moveTopBorder) {
434+ target.y += d.currentHeight - target.height;
435+ }
436+ d.currentHeight = target.height;
437 }
438 }
439 }
440
441=== modified file 'tests/mocks/Unity/Application/MirSurface.cpp'
442--- tests/mocks/Unity/Application/MirSurface.cpp 2015-10-27 21:55:10 +0000
443+++ tests/mocks/Unity/Application/MirSurface.cpp 2015-11-20 13:05:20 +0000
444@@ -35,8 +35,12 @@
445 , m_activeFocus(false)
446 , m_width(-1)
447 , m_height(-1)
448+ , m_slowToResize(false)
449 {
450 // qDebug() << "MirSurface::MirSurface() " << name;
451+ m_delayedResizeTimer.setInterval(600);
452+ m_delayedResizeTimer.setSingleShot(true);
453+ connect(&m_delayedResizeTimer, &QTimer::timeout, this, &MirSurface::applyDelayedResize);
454 }
455
456 MirSurface::~MirSurface()
457@@ -197,7 +201,38 @@
458
459 void MirSurface::resize(int width, int height)
460 {
461+ if (m_slowToResize) {
462+ if (!m_delayedResizeTimer.isActive()) {
463+ m_delayedResize.setWidth(width);
464+ m_delayedResize.setHeight(height);
465+ m_delayedResizeTimer.start();
466+ } else {
467+ m_pendingResize.setWidth(width);
468+ m_pendingResize.setHeight(height);
469+ }
470+ } else {
471+ doResize(width, height);
472+ }
473+}
474+
475+void MirSurface::applyDelayedResize()
476+{
477+ doResize(m_delayedResize.width(), m_delayedResize.height());
478+ m_delayedResize.setWidth(-1);
479+ m_delayedResize.setHeight(-1);
480+
481+ if (m_pendingResize.isValid()) {
482+ QSize size = m_pendingResize;
483+ m_pendingResize.setWidth(-1);
484+ m_pendingResize.setHeight(-1);
485+ resize(size.width(), size.height());
486+ }
487+}
488+
489+void MirSurface::doResize(int width, int height)
490+{
491 bool changed = false;
492+
493 if (width != m_width) {
494 m_width = width;
495 Q_EMIT widthChanged();
496@@ -214,3 +249,20 @@
497 Q_EMIT sizeChanged(QSize(width, height));
498 }
499 }
500+
501+bool MirSurface::isSlowToResize() const
502+{
503+ return m_slowToResize;
504+}
505+
506+void MirSurface::setSlowToResize(bool value)
507+{
508+ if (m_slowToResize != value) {
509+ m_slowToResize = value;
510+ Q_EMIT slowToResizeChanged();
511+ if (!m_slowToResize && m_delayedResizeTimer.isActive()) {
512+ m_delayedResizeTimer.stop();
513+ applyDelayedResize();
514+ }
515+ }
516+}
517
518=== modified file 'tests/mocks/Unity/Application/MirSurface.h'
519--- tests/mocks/Unity/Application/MirSurface.h 2015-10-20 16:48:06 +0000
520+++ tests/mocks/Unity/Application/MirSurface.h 2015-11-20 13:05:20 +0000
521@@ -18,6 +18,7 @@
522 #define MOCK_MIR_SURFACE_H
523
524 #include <QObject>
525+#include <QTimer>
526 #include <QUrl>
527 #include <QHash>
528
529@@ -33,6 +34,7 @@
530 Q_PROPERTY(int width READ width NOTIFY widthChanged)
531 Q_PROPERTY(int height READ height NOTIFY heightChanged)
532 Q_PROPERTY(bool activeFocus READ activeFocus NOTIFY activeFocusChanged)
533+ Q_PROPERTY(bool slowToResize READ isSlowToResize WRITE setSlowToResize NOTIFY slowToResizeChanged)
534
535 public:
536 MirSurface(const QString& name,
537@@ -77,6 +79,9 @@
538 int width() const;
539 int height() const;
540
541+ bool isSlowToResize() const;
542+ void setSlowToResize(bool value);
543+
544 /////
545 // internal mock stuff
546
547@@ -94,13 +99,18 @@
548 void orientationAngleChanged(Mir::OrientationAngle angle);
549 void widthChanged();
550 void heightChanged();
551+ void slowToResizeChanged();
552
553 ////
554 // internal mock stuff
555 void screenshotUrlChanged(QUrl);
556 void activeFocusChanged(bool);
557
558+private Q_SLOTS:
559+ void applyDelayedResize();
560+
561 private:
562+ void doResize(int width, int height);
563 void updateVisibility();
564
565 const QString m_name;
566@@ -114,6 +124,12 @@
567 bool m_activeFocus;
568 int m_width;
569 int m_height;
570+
571+ bool m_slowToResize;
572+ QTimer m_delayedResizeTimer;
573+ QSize m_delayedResize;
574+ QSize m_pendingResize;
575+
576 struct View {
577 bool visible;
578 };
579
580=== modified file 'tests/qmltests/Stages/tst_DesktopStage.qml'
581--- tests/qmltests/Stages/tst_DesktopStage.qml 2015-11-06 13:48:29 +0000
582+++ tests/qmltests/Stages/tst_DesktopStage.qml 2015-11-20 13:05:20 +0000
583@@ -17,7 +17,7 @@
584 import QtQuick 2.4
585 import QtTest 1.0
586 import Ubuntu.Components 1.3
587-import Ubuntu.Components.ListItems 1.3 as ListItem
588+import Ubuntu.Components.ListItems 1.3
589 import Unity.Application 0.1
590 import Unity.Test 0.1
591 import Utils 0.1
592@@ -82,6 +82,21 @@
593 Column {
594 anchors { left: parent.left; right: parent.right; top: parent.top; margins: units.gu(1) }
595 spacing: units.gu(1)
596+
597+ Button {
598+ color: "white"
599+ text: "Make surface slow to resize"
600+ activeFocusOnPress: false
601+ onClicked: {
602+ if (ApplicationManager.focusedApplicationId) {
603+ var surface = ApplicationManager.findApplication(ApplicationManager.focusedApplicationId).session.surface;
604+ surface.slowToResize = true;
605+ }
606+ }
607+ }
608+
609+ Divider {}
610+
611 Repeater {
612 model: ApplicationManager.availableApplications
613 ApplicationCheckBox {
614
615=== modified file 'tests/qmltests/Stages/tst_WindowResizeArea.qml'
616--- tests/qmltests/Stages/tst_WindowResizeArea.qml 2015-11-09 10:16:18 +0000
617+++ tests/qmltests/Stages/tst_WindowResizeArea.qml 2015-11-20 13:05:20 +0000
618@@ -30,8 +30,6 @@
619 height: units.gu(60)
620 width: units.gu(60)
621
622- property var fakeWindow: windowLoader.item
623-
624 Binding {
625 target: PanelState
626 property: "panelHeight"
627@@ -47,10 +45,10 @@
628 property alias minHeight: windowResizeArea.minHeight
629 x: units.gu(20)
630 y: units.gu(20)
631- height: units.gu(20)
632- width: units.gu(20)
633- property int windowHeight: height
634- property int windowWidth: width
635+ width: requestedWidth
636+ height: requestedHeight
637+ property real requestedWidth
638+ property real requestedHeight
639 state: "normal"
640
641 function maximize() {
642@@ -63,6 +61,8 @@
643 borderThickness: units.gu(2)
644 minWidth: units.gu(15)
645 minHeight: units.gu(10)
646+ defaultWidth: units.gu(20)
647+ defaultHeight: units.gu(20)
648 windowId: "test-window-id"
649 screenWidth: root.width
650 screenHeight: root.height
651@@ -87,22 +87,41 @@
652 Loader {
653 id: windowLoader
654 sourceComponent: fakeWindowComponent
655+ active: windowLoaderCheckbox.checked
656 }
657
658- MouseTouchEmulationCheckbox {
659- checked: false
660- color: "black"
661+ Column {
662+ MouseTouchEmulationCheckbox {
663+ checked: false
664+ color: "black"
665+ }
666+ RowLayout {
667+ Layout.fillWidth: true
668+ CheckBox {
669+ id: windowLoaderCheckbox
670+ checked: true
671+ activeFocusOnPress: false
672+ }
673+ Label {
674+ id: label
675+ color: "black"
676+ text: "Window loader active"
677+ anchors.verticalCenter: parent.verticalCenter
678+ }
679+ }
680 }
681
682 UnityTestCase {
683 name: "WindowResizeArea"
684 when: windowShown
685
686+ property var fakeWindow: windowLoader.item
687+
688 function init() {
689 fakeWindow.x = units.gu(20)
690 fakeWindow.y = units.gu(20)
691- fakeWindow.width = units.gu(20)
692- fakeWindow.height = units.gu(20)
693+ fakeWindow.requestedWidth = units.gu(20)
694+ fakeWindow.requestedHeight = units.gu(20)
695 }
696
697 function test_resizeWindowRightBottom_data() {
698@@ -188,7 +207,7 @@
699 function test_resizeSmallerAndLarger_data() {
700 return [
701 { tag: "topLeft", startX: -1, startY: -1, dx: units.gu(15), dy: units.gu(15) },
702- { tag: "bottomRight", startX: fakeWindow.width + 1, startY: fakeWindow.height + 1, dx: -units.gu(15), dy: -units.gu(15) }
703+ { tag: "bottomRight", startX: units.gu(20) + 1, startY: units.gu(20) + 1, dx: -units.gu(15), dy: -units.gu(15) }
704 ]
705 }
706

Subscribers

People subscribed via source and target branches