on xenial help sign in
displace application windows when the OSK would cover them
4dd864fMichael Zanetti
qml/Stages/DesktopStage.qml+17−2
@@ -263,8 +263,23 @@ AbstractStage {
263 }
263 }
264 }
264 }
265 z: normalZ
265 z: normalZ
266+ x: requestedX // may be overridden in some states. Do not directly write to this.
267+ y: requestedY // may be overridden in some states. Do not directly write to this.
266− x: priv.focusedAppDelegate ? priv.focusedAppDelegate.x + units.gu(3) : (normalZ - 1) * units.gu(3)
268+ property real requestedX: priv.focusedAppDelegate ? priv.focusedAppDelegate.x + units.gu(3) : (normalZ - 1) * units.gu(3)
267− y: priv.focusedAppDelegate ? priv.focusedAppDelegate.y + units.gu(3) : normalZ * units.gu(3)
269+ property real requestedY: priv.focusedAppDelegate ? priv.focusedAppDelegate.y + units.gu(3) : normalZ * units.gu(3)
270+
271+ Binding {
272+ target: appDelegate
273+ property: "y"
274+ value: appDelegate.requestedY -
275+ Math.min(appDelegate.requestedY - PanelState.panelHeight,
276+ Math.max(0, UbuntuKeyboardInfo.height - (appContainer.height - (appDelegate.requestedY + appDelegate.height))))
277+ when: appDelegate.focus && appDelegate.state == "normal"
278+ && SurfaceManager.inputMethodSurface
279+ && SurfaceManager.inputMethodSurface.state != Mir.HiddenState
280+ && SurfaceManager.inputMethodSurface.state != Mir.MinimizedState
281+
282+ }
268
283
269 width: decoratedWindow.width
284 width: decoratedWindow.width
270 height: decoratedWindow.height
285 height: decoratedWindow.height
qml/Stages/WindowControlsOverlay.qml+2−2
@@ -94,8 +94,8 @@ Item {
94 function handlePositionChanged(mouseX, mouseY) {
94 function handlePositionChanged(mouseX, mouseY) {
95 if (priv.dragging) {
95 if (priv.dragging) {
96 var pos = mapToItem(root.target.parent, mouseX, mouseY);
96 var pos = mapToItem(root.target.parent, mouseX, mouseY);
97− root.target.x = Math.round(pos.x - priv.distanceX);
97+ root.target.requestedX = Math.round(pos.x - priv.distanceX);
98− root.target.y = Math.round(Math.max(pos.y - priv.distanceY, PanelState.panelHeight));
98+ root.target.requestedY = Math.round(Math.max(pos.y - priv.distanceY, PanelState.panelHeight));
99 }
99 }
100 }
100 }
101 }
101 }
qml/Stages/WindowDecoration.qml+2−2
@@ -69,8 +69,8 @@ MouseArea {
69 // Use integer coordinate values to ensure that target is left in a pixel-aligned
69 // Use integer coordinate values to ensure that target is left in a pixel-aligned
70 // position. Mouse movement could have subpixel precision, yielding a fractional
70 // position. Mouse movement could have subpixel precision, yielding a fractional
71 // mouse position.
71 // mouse position.
72− root.target.x = Math.round(pos.x - priv.distanceX);
72+ root.target.requestedX = Math.round(pos.x - priv.distanceX);
73− root.target.y = Math.round(Math.max(pos.y - priv.distanceY, PanelState.panelHeight));
73+ root.target.requestedY = Math.round(Math.max(pos.y - priv.distanceY, PanelState.panelHeight));
74 }
74 }
75 }
75 }
76
76
qml/Stages/WindowResizeArea.qml+11−11
@@ -55,8 +55,8 @@ MouseArea {
55
55
56 function updateNormalGeometry() {
56 function updateNormalGeometry() {
57 if (root.target.state == "normal") {
57 if (root.target.state == "normal") {
58− normalX = root.target.x
58+ normalX = root.target.requestedX
59− normalY = root.target.y
59+ normalY = root.target.requestedY
60 normalWidth = root.target.width
60 normalWidth = root.target.width
61 normalHeight = root.target.height
61 normalHeight = root.target.height
62 }
62 }
@@ -73,14 +73,14 @@ MouseArea {
73
73
74 function loadWindowState() {
74 function loadWindowState() {
75 var windowGeometry = windowStateStorage.getGeometry(root.windowId,
75 var windowGeometry = windowStateStorage.getGeometry(root.windowId,
76− Qt.rect(target.x, target.y, defaultWidth, defaultHeight));
76+ Qt.rect(target.requestedX, target.requestedY, defaultWidth, defaultHeight));
77
77
78 target.requestedWidth = Qt.binding(function() { return Math.min(Math.max(windowGeometry.width, d.minimumWidth), screenWidth - root.leftMargin); });
78 target.requestedWidth = Qt.binding(function() { return Math.min(Math.max(windowGeometry.width, d.minimumWidth), screenWidth - root.leftMargin); });
79 target.requestedHeight = Qt.binding(function() { return Math.min(Math.max(windowGeometry.height, d.minimumHeight),
79 target.requestedHeight = Qt.binding(function() { return Math.min(Math.max(windowGeometry.height, d.minimumHeight),
80 root.screenHeight - (target.fullscreen ? 0 : PanelState.panelHeight)); });
80 root.screenHeight - (target.fullscreen ? 0 : PanelState.panelHeight)); });
81− target.x = Qt.binding(function() { return Math.max(Math.min(windowGeometry.x, root.screenWidth - root.leftMargin - target.requestedWidth),
81+ target.requestedX = Qt.binding(function() { return Math.max(Math.min(windowGeometry.x, root.screenWidth - root.leftMargin - target.requestedWidth),
82 (target.fullscreen ? 0 : root.leftMargin)); });
82 (target.fullscreen ? 0 : root.leftMargin)); });
83− target.y = Qt.binding(function() { return Math.max(Math.min(windowGeometry.y, root.screenHeight - target.requestedHeight), PanelState.panelHeight); });
83+ target.requestedY = Qt.binding(function() { return Math.max(Math.min(windowGeometry.y, root.screenHeight - target.requestedHeight), PanelState.panelHeight); });
84
84
85 var windowState = windowStateStorage.getState(root.windowId, WindowStateStorage.WindowStateNormal)
85 var windowState = windowStateStorage.getState(root.windowId, WindowStateStorage.WindowStateNormal)
86 switch (windowState) {
86 switch (windowState) {
@@ -258,8 +258,8 @@ MouseArea {
258 var pos = mapToItem(root.target.parent, mouseX, mouseY);
258 var pos = mapToItem(root.target.parent, mouseX, mouseY);
259 d.startMousePosX = pos.x;
259 d.startMousePosX = pos.x;
260 d.startMousePosY = pos.y;
260 d.startMousePosY = pos.y;
261− d.startX = target.x;
261+ d.startX = target.requestedX;
262− d.startY = target.y;
262+ d.startY = target.requestedY;
263 d.startWidth = target.width;
263 d.startWidth = target.width;
264 d.startHeight = target.height;
264 d.startHeight = target.height;
265 d.currentWidth = target.width;
265 d.currentWidth = target.width;
@@ -296,7 +296,7 @@ MouseArea {
296
296
297 if (d.leftBorder) {
297 if (d.leftBorder) {
298 var newTargetX = d.startX + deltaX;
298 var newTargetX = d.startX + deltaX;
299− var rightBorderX = target.x + target.width;
299+ var rightBorderX = target.requestedX + target.width;
300 if (rightBorderX > newTargetX + d.minimumWidth) {
300 if (rightBorderX > newTargetX + d.minimumWidth) {
301 if (rightBorderX < newTargetX + d.maximumWidth) {
301 if (rightBorderX < newTargetX + d.maximumWidth) {
302 target.requestedWidth = rightBorderX - newTargetX;
302 target.requestedWidth = rightBorderX - newTargetX;
@@ -322,7 +322,7 @@ MouseArea {
322
322
323 if (d.topBorder) {
323 if (d.topBorder) {
324 var newTargetY = Math.max(d.startY + deltaY, PanelState.panelHeight); // disallow resizing up past Panel
324 var newTargetY = Math.max(d.startY + deltaY, PanelState.panelHeight); // disallow resizing up past Panel
325− var bottomBorderY = target.y + target.height;
325+ var bottomBorderY = target.requestedY + target.height;
326 if (bottomBorderY > newTargetY + d.minimumHeight) {
326 if (bottomBorderY > newTargetY + d.minimumHeight) {
327 if (bottomBorderY < newTargetY + d.maximumHeight) {
327 if (bottomBorderY < newTargetY + d.maximumHeight) {
328 target.requestedHeight = bottomBorderY - newTargetY;
328 target.requestedHeight = bottomBorderY - newTargetY;
@@ -351,13 +351,13 @@ MouseArea {
351 target: root.target
351 target: root.target
352 onWidthChanged: {
352 onWidthChanged: {
353 if (d.moveLeftBorder) {
353 if (d.moveLeftBorder) {
354− target.x += d.currentWidth - target.width;
354+ target.requestedX += d.currentWidth - target.width;
355 }
355 }
356 d.currentWidth = target.width;
356 d.currentWidth = target.width;
357 }
357 }
358 onHeightChanged: {
358 onHeightChanged: {
359 if (d.moveTopBorder) {
359 if (d.moveTopBorder) {
360− target.y += d.currentHeight - target.height;
360+ target.requestedY += d.currentHeight - target.height;
361 }
361 }
362 d.currentHeight = target.height;
362 d.currentHeight = target.height;
363 }
363 }
tests/mocks/Unity/Application/UbuntuKeyboardInfo.cpp+1−1
@@ -21,7 +21,7 @@ UbuntuKeyboardInfo::UbuntuKeyboardInfo(QObject *parent)
21 m_x(0),
21 m_x(0),
22 m_y(0),
22 m_y(0),
23 m_width(200),
23 m_width(200),
24− m_height(200)
24+ m_height(0)
25{
25{
26}
26}
27
27
tests/qmltests/Stages/tst_DesktopStage.qml+27
@@ -517,6 +517,33 @@ Item {
517 tryCompare(MirFocusController, "focusedSurface", null); // verify still no surface is focused
517 tryCompare(MirFocusController, "focusedSurface", null); // verify still no surface is focused
518 }
518 }
519
519
520+ function test_oskDisplacesWindow_data() {
521+ return [
522+ {tag: "no need to displace", windowHeight: units.gu(10), windowY: units.gu(5), targetDisplacement: units.gu(5)},
523+ {tag: "displace to top", windowHeight: units.gu(50), windowY: units.gu(10), targetDisplacement: PanelState.panelHeight},
524+ {tag: "displace a bit", windowHeight: units.gu(40), windowY: units.gu(10), targetDisplacement: (root.height / 2) - units.gu(40)},
525+ ]
526+ }
527+
528+ function test_oskDisplacesWindow(data) {
529+ var dashAppDelegate = startApplication("unity8-dash");
530+ var oldOSKState = SurfaceManager.inputMethodSurface.state;
531+ SurfaceManager.inputMethodSurface.state = Mir.RestoredState;
532+ verify(dashAppDelegate);
533+ dashAppDelegate.requestedHeight = data.windowHeight;
534+ dashAppDelegate.requestedY = data.windowY;
535+ UbuntuKeyboardInfo.height = 0;
536+ var initialY = dashAppDelegate.y;
537+ verify(initialY > PanelState.panelHeight);
538+
539+ UbuntuKeyboardInfo.height = root.height / 2;
540+ tryCompare(dashAppDelegate, "y", data.targetDisplacement);
541+
542+ UbuntuKeyboardInfo.height = 0;
543+ tryCompare(dashAppDelegate, "y", initialY);
544+ SurfaceManager.inputMethodSurface.state = oldOSKState;
545+ }
546+
520 function test_minimizeApplicationHidesSurface() {
547 function test_minimizeApplicationHidesSurface() {
521 compare(topSurfaceList.applicationAt(0).appId, "unity8-dash");
548 compare(topSurfaceList.applicationAt(0).appId, "unity8-dash");
522 var dashSurface = topSurfaceList.surfaceAt(0);
549 var dashSurface = topSurfaceList.surfaceAt(0);
tests/qmltests/Stages/tst_WindowResizeArea.qml+36−34
@@ -44,8 +44,10 @@ Item {
44 id: fakeWindow
44 id: fakeWindow
45 property alias resizeAreaMinWidth: windowResizeArea.minWidth
45 property alias resizeAreaMinWidth: windowResizeArea.minWidth
46 property alias resizeAreaMinHeight: windowResizeArea.minHeight
46 property alias resizeAreaMinHeight: windowResizeArea.minHeight
47− x: units.gu(20)
47+ x: requestedX
48+ y: requestedY
49+ property real requestedX: units.gu(20)
48− y: units.gu(20)
50+ property real requestedY: units.gu(20)
49 width: requestedWidth
51 width: requestedWidth
50 height: requestedHeight
52 height: requestedHeight
51 property real requestedWidth
53 property real requestedWidth
@@ -226,8 +228,8 @@ Item {
226 property var fakeWindow: windowLoader.item
228 property var fakeWindow: windowLoader.item
227
229
228 function init() {
230 function init() {
229− fakeWindow.x = units.gu(20)
231+ fakeWindow.requestedX = units.gu(20)
230− fakeWindow.y = units.gu(20)
232+ fakeWindow.requestedY = units.gu(20)
231 fakeWindow.requestedWidth = units.gu(20)
233 fakeWindow.requestedWidth = units.gu(20)
232 fakeWindow.requestedHeight = units.gu(20)
234 fakeWindow.requestedHeight = units.gu(20)
233 fakeWindow.resizeAreaMinWidth = units.gu(15);
235 fakeWindow.resizeAreaMinWidth = units.gu(15);
@@ -254,8 +256,8 @@ Item {
254 }
256 }
255
257
256 function test_resizeWindowRightBottom(data) {
258 function test_resizeWindowRightBottom(data) {
257− var initialWindowX = fakeWindow.x;
259+ var initialWindowX = fakeWindow.requestedX;
258− var initialWindowY = fakeWindow.y;
260+ var initialWindowY = fakeWindow.requestedY;
259 var initialWindowWidth = fakeWindow.width
261 var initialWindowWidth = fakeWindow.width
260 var initialWindowHeight = fakeWindow.height
262 var initialWindowHeight = fakeWindow.height
261
263
@@ -266,8 +268,8 @@ Item {
266 tryCompare(fakeWindow, "width", Math.max(initialWindowWidth + data.dx, fakeWindow.resizeAreaMinWidth));
268 tryCompare(fakeWindow, "width", Math.max(initialWindowWidth + data.dx, fakeWindow.resizeAreaMinWidth));
267 tryCompare(fakeWindow, "height", Math.max(initialWindowHeight + data.dy, fakeWindow.resizeAreaMinHeight));
269 tryCompare(fakeWindow, "height", Math.max(initialWindowHeight + data.dy, fakeWindow.resizeAreaMinHeight));
268
270
269− compare(fakeWindow.x, initialWindowX);
271+ compare(fakeWindow.requestedX, initialWindowX);
270− compare(fakeWindow.y, initialWindowY);
272+ compare(fakeWindow.requestedY, initialWindowY);
271 }
273 }
272
274
273 function test_resizeWindowLeftTop_data() {
275 function test_resizeWindowLeftTop_data() {
@@ -280,8 +282,8 @@ Item {
280 }
282 }
281
283
282 function test_resizeWindowLeftTop(data) {
284 function test_resizeWindowLeftTop(data) {
283− var initialWindowX = fakeWindow.x;
285+ var initialWindowX = fakeWindow.requestedX;
284− var initialWindowY = fakeWindow.y;
286+ var initialWindowY = fakeWindow.requestedY;
285 var initialWindowWidth = fakeWindow.width
287 var initialWindowWidth = fakeWindow.width
286 var initialWindowHeight = fakeWindow.height
288 var initialWindowHeight = fakeWindow.height
287
289
@@ -294,13 +296,13 @@ Item {
294
296
295 var maxMoveX = initialWindowWidth - fakeWindow.resizeAreaMinWidth;
297 var maxMoveX = initialWindowWidth - fakeWindow.resizeAreaMinWidth;
296 var maxMoveY = initialWindowHeight - fakeWindow.resizeAreaMinHeight;
298 var maxMoveY = initialWindowHeight - fakeWindow.resizeAreaMinHeight;
297− compare(fakeWindow.x, Math.min(initialWindowX + data.dx, initialWindowX + maxMoveX));
299+ compare(fakeWindow.requestedX, Math.min(initialWindowX + data.dx, initialWindowX + maxMoveX));
298− compare(fakeWindow.y, Math.min(initialWindowY + data.dy, initialWindowY + maxMoveY));
300+ compare(fakeWindow.requestedY, Math.min(initialWindowY + data.dy, initialWindowY + maxMoveY));
299 }
301 }
300
302
301 function test_saveRestoreSize() {
303 function test_saveRestoreSize() {
302− var initialWindowX = fakeWindow.x;
304+ var initialWindowX = fakeWindow.requestedX;
303− var initialWindowY = fakeWindow.y;
305+ var initialWindowY = fakeWindow.requestedY;
304 var initialWindowWidth = fakeWindow.width
306 var initialWindowWidth = fakeWindow.width
305 var initialWindowHeight = fakeWindow.height
307 var initialWindowHeight = fakeWindow.height
306
308
@@ -332,8 +334,8 @@ Item {
332 }
334 }
333
335
334 function test_resizeSmallerAndLarger(data) {
336 function test_resizeSmallerAndLarger(data) {
335− var initialWindowX = fakeWindow.x;
337+ var initialWindowX = fakeWindow.requestedX;
336− var initialWindowY = fakeWindow.y;
338+ var initialWindowY = fakeWindow.requestedY;
337 var initialWindowWidth = fakeWindow.width
339 var initialWindowWidth = fakeWindow.width
338 var initialWindowHeight = fakeWindow.height
340 var initialWindowHeight = fakeWindow.height
339
341
@@ -348,18 +350,18 @@ Item {
348 }
350 }
349
351
350 function test_saveRestoreMaximized() {
352 function test_saveRestoreMaximized() {
351− var initialWindowX = fakeWindow.x;
353+ var initialWindowX = fakeWindow.requestedX;
352− var initialWindowY = fakeWindow.y;
354+ var initialWindowY = fakeWindow.requestedY;
353
355
354 var moveDelta = units.gu(5);
356 var moveDelta = units.gu(5);
355
357
356− fakeWindow.x = initialWindowX + moveDelta
358+ fakeWindow.requestedX = initialWindowX + moveDelta
357− fakeWindow.y = initialWindowY + moveDelta
359+ fakeWindow.requestedY = initialWindowY + moveDelta
358
360
359 // Now change the state to maximized. The window should not keep updating the stored values
361 // Now change the state to maximized. The window should not keep updating the stored values
360 fakeWindow.maximize()
362 fakeWindow.maximize()
361− fakeWindow.x = 31415 // 0 is too risky to pass the test even when broken
363+ fakeWindow.requestedX = 31415 // 0 is too risky to pass the test even when broken
362− fakeWindow.y = 31415
364+ fakeWindow.requestedY = 31415
363
365
364 // This will destroy the window and recreate it
366 // This will destroy the window and recreate it
365 windowLoader.active = false;
367 windowLoader.active = false;
@@ -389,8 +391,8 @@ Item {
389 }
391 }
390
392
391 function test_restoreMovesIntoBounds(data) {
393 function test_restoreMovesIntoBounds(data) {
392− fakeWindow.x = data.x;
394+ fakeWindow.requestedX = data.x;
393− fakeWindow.y = data.y;
395+ fakeWindow.requestedY = data.y;
394 fakeWindow.width = data.w;
396 fakeWindow.width = data.w;
395 fakeWindow.height = data.h;
397 fakeWindow.height = data.h;
396 waitForRendering(root);
398 waitForRendering(root);
@@ -402,10 +404,10 @@ Item {
402 waitForRendering(root)
404 waitForRendering(root)
403
405
404 // Make sure it's again where we left it in normal state before destroying
406 // Make sure it's again where we left it in normal state before destroying
405− compare(fakeWindow.x >= 0, true)
407+ compare(fakeWindow.requestedX >= 0, true)
406− compare(fakeWindow.y >= PanelState.panelHeight, true)
408+ compare(fakeWindow.requestedY >= PanelState.panelHeight, true)
407− compare(fakeWindow.x + fakeWindow.width <= root.width, true)
409+ compare(fakeWindow.requestedX + fakeWindow.width <= root.width, true)
408− compare(fakeWindow.y + fakeWindow.height <= root.height, true)
410+ compare(fakeWindow.requestedY + fakeWindow.height <= root.height, true)
409
411
410 waitForRendering(root)
412 waitForRendering(root)
411 }
413 }
@@ -417,8 +419,8 @@ Item {
417 and height) increment value.
419 and height) increment value.
418 */
420 */
419 function test_sizeIncrement() {
421 function test_sizeIncrement() {
420− var initialWindowX = fakeWindow.x;
422+ var initialWindowX = fakeWindow.requestedX;
421− var initialWindowY = fakeWindow.y;
423+ var initialWindowY = fakeWindow.requestedY;
422 var initialWindowWidth = fakeWindow.width
424 var initialWindowWidth = fakeWindow.width
423 var initialWindowHeight = fakeWindow.height
425 var initialWindowHeight = fakeWindow.height
424
426
@@ -448,8 +450,8 @@ Item {
448 Tests that when dragging a window border you cannot make it bigger than its maximum size
450 Tests that when dragging a window border you cannot make it bigger than its maximum size
449 */
451 */
450 function test_maximumSize() {
452 function test_maximumSize() {
451− fakeWindow.x = units.gu(1);
453+ fakeWindow.requestedX = units.gu(1);
452− fakeWindow.y = units.gu(1);
454+ fakeWindow.requestedY = units.gu(1);
453 fakeWindow.resizeAreaMinWidth = 1; // so it does not interfere with anything
455 fakeWindow.resizeAreaMinWidth = 1; // so it does not interfere with anything
454 fakeWindow.resizeAreaMinHeight = 1; // so it does not interfere with anything
456 fakeWindow.resizeAreaMinHeight = 1; // so it does not interfere with anything
455 fakeWindow.requestedWidth = units.gu(10);
457 fakeWindow.requestedWidth = units.gu(10);
@@ -478,8 +480,8 @@ Item {
478 Tests that when dragging a window border you cannot make it smaller than its minimum size
480 Tests that when dragging a window border you cannot make it smaller than its minimum size
479 */
481 */
480 function test_minimumSize() {
482 function test_minimumSize() {
481− fakeWindow.x = units.gu(1);
483+ fakeWindow.requestedX = units.gu(1);
482− fakeWindow.y = units.gu(1);
484+ fakeWindow.requestedY = units.gu(1);
483 fakeWindow.resizeAreaMinWidth = 1; // so it does not interfere with anything
485 fakeWindow.resizeAreaMinWidth = 1; // so it does not interfere with anything
484 fakeWindow.resizeAreaMinHeight = 1; // so it does not interfere with anything
486 fakeWindow.resizeAreaMinHeight = 1; // so it does not interfere with anything
485 fakeWindow.requestedWidth = units.gu(20);
487 fakeWindow.requestedWidth = units.gu(20);