on xenial help sign in
merge lp:~lukas-kde/unity8/fix-window-buttons-touch
983cd37Lukáš Tinkl
qml/ApplicationMenus/MenuBar.qml+48−23
@@ -28,11 +28,19 @@ Item {
28 property alias unityMenuModel: rowRepeater.model
28 property alias unityMenuModel: rowRepeater.model
29 property bool enableKeyFilter: false
29 property bool enableKeyFilter: false
30 property real overflowWidth: width
30 property real overflowWidth: width
31+ property bool windowMoving: false
31
32
32 // read from outside
33 // read from outside
33 readonly property bool valid: rowRepeater.count > 0
34 readonly property bool valid: rowRepeater.count > 0
34 readonly property bool showRequested: d.longAltPressed || d.currentItem != null
35 readonly property bool showRequested: d.longAltPressed || d.currentItem != null
35
36
37+ // MoveHandler API for DecoratedWindow
38+ signal pressed(var mouse)
39+ signal pressedChangedEx(bool pressed, var pressedButtons, real mouseX, real mouseY)
40+ signal positionChanged(var mouse)
41+ signal released(var mouse)
42+ signal doubleClicked(var mouse)
43+
36 implicitWidth: row.width
44 implicitWidth: row.width
37 height: parent.height
45 height: parent.height
38
46
@@ -77,7 +85,7 @@ Item {
77 anchors.fill: parent
85 anchors.fill: parent
78 enabled: d.currentItem != null
86 enabled: d.currentItem != null
79 hoverEnabled: enabled && d.currentItem && d.currentItem.__popup != null
87 hoverEnabled: enabled && d.currentItem && d.currentItem.__popup != null
80− onPressed: d.dismissAll()
88+ onPressed: { mouse.accepted = false; d.dismissAll(); }
81 }
89 }
82
90
83 Row {
91 Row {
@@ -96,6 +104,11 @@ Item {
96 onModelReset: d.firstInvisibleIndex = undefined
104 onModelReset: d.firstInvisibleIndex = undefined
97 }
105 }
98
106
107+ Component {
108+ id: menuComponent
109+ MenuPopup { }
110+ }
111+
99 Repeater {
112 Repeater {
100 id: rowRepeater
113 id: rowRepeater
101
114
@@ -119,7 +132,14 @@ Item {
119
132
120 function show() {
133 function show() {
121 if (!__popup) {
134 if (!__popup) {
122− __popup = menuComponent.createObject(root, { objectName: visualItem.objectName + "-menu" });
135+ __popup = menuComponent.createObject(root,
136+ {
137+ objectName: visualItem.objectName + "-menu",
138+ desiredX: Qt.binding(function() { return visualItem.x - units.gu(1); }),
139+ desiredY: Qt.binding(function() { return root.height; }),
140+ unityMenuModel: Qt.binding(function() { return root.unityMenuModel.submenu(visualItem.__ownIndex); })
141+ });
142+ __popup.reset();
123 __popup.childActivated.connect(dismiss);
143 __popup.childActivated.connect(dismiss);
124 // force the current item to be the newly popped up menu
144 // force the current item to be the newly popped up menu
125 } else {
145 } else {
@@ -162,17 +182,6 @@ Item {
162 onDismissAll: visualItem.dismiss()
182 onDismissAll: visualItem.dismiss()
163 }
183 }
164
184
165− Component {
166− id: menuComponent
167− MenuPopup {
168− desiredX: visualItem.x - units.gu(1)
169− desiredY: parent.height
170− unityMenuModel: root.unityMenuModel.submenu(visualItem.__ownIndex)
171−
172− Component.onCompleted: reset();
173− }
174− }
175−
176 RowLayout {
185 RowLayout {
177 id: column
186 id: column
178 spacing: units.gu(1)
187 spacing: units.gu(1)
@@ -217,24 +226,40 @@ Item {
217 } // Row
226 } // Row
218
227
219 MouseArea {
228 MouseArea {
220− anchors.fill: row
229+ anchors.fill: parent
221 hoverEnabled: d.currentItem
230 hoverEnabled: d.currentItem
222
231
232+ property bool moved: false
233+
223 onEntered: {
234 onEntered: {
224 if (d.currentItem) {
235 if (d.currentItem) {
225 updateCurrentItemFromPosition(Qt.point(mouseX, mouseY))
236 updateCurrentItemFromPosition(Qt.point(mouseX, mouseY))
226 }
237 }
227 }
238 }
228− onPositionChanged: {
239+
229− if (d.currentItem) {
240+ onClicked: {
241+ if (!moved) {
242+ var prevItem = d.currentItem;
230− updateCurrentItemFromPosition(Qt.point(mouse.x, mouse.y))
243+ updateCurrentItemFromPosition(Qt.point(mouseX, mouseY));
244+ if (prevItem && d.currentItem == prevItem) {
245+ prevItem.hide();
246+ }
231 }
247 }
248+ moved = false;
232 }
249 }
233− onClicked: {
250+
234− var prevItem = d.currentItem;
251+ // for the MoveHandler
252+ onPressed: root.pressed(mouse)
253+ onPressedChanged: root.pressedChangedEx(pressed, pressedButtons, mouseX, mouseY)
254+ onReleased: root.released(mouse)
255+ onDoubleClicked: root.doubleClicked(mouse)
256+
257+ Mouse.ignoreSynthesizedEvents: true
258+ Mouse.onPositionChanged: {
259+ root.positionChanged(mouse);
260+ moved = root.windowMoving;
261+ if (d.currentItem) {
235− updateCurrentItemFromPosition(Qt.point(mouse.x, mouse.y))
262+ updateCurrentItemFromPosition(Qt.point(mouse.x, mouse.y))
236− if (prevItem && d.currentItem == prevItem) {
237− prevItem.hide();
238 }
263 }
239 }
264 }
240
265
@@ -259,7 +284,7 @@ Item {
259 hoverEnabled: d.currentItem
284 hoverEnabled: d.currentItem
260 onEntered: d.currentItem = this
285 onEntered: d.currentItem = this
261 onPositionChanged: d.currentItem = this
286 onPositionChanged: d.currentItem = this
262− onClicked: d.currentItem = this
287+ onPressed: d.currentItem = this
263
288
264 property Item __popup: null;
289 property Item __popup: null;
265 readonly property bool popupVisible: __popup && __popup.visible
290 readonly property bool popupVisible: __popup && __popup.visible
qml/ApplicationMenus/MenuItem.qml+6−6
@@ -34,7 +34,7 @@ ActionItem {
34 val += units.gu(1) + title.contentWidth;
34 val += units.gu(1) + title.contentWidth;
35 if (hasSubmenu) {
35 if (hasSubmenu) {
36 val += units.gu(1) + chevronIcon.width;
36 val += units.gu(1) + chevronIcon.width;
37− } else if (shortcut != undefined) {
37+ } else if (menuData && menuData.shortcut != undefined) {
38 val += units.gu(3) + shortcutLabel.contentWidth;
38 val += units.gu(3) + shortcutLabel.contentWidth;
39 }
39 }
40 return val + units.gu(1);
40 return val + units.gu(1);
@@ -49,9 +49,9 @@ ActionItem {
49 enabled: root.enabled
49 enabled: root.enabled
50
50
51 // FIXME - SDK Action:text modifies menu text with html underline for mnemonic
51 // FIXME - SDK Action:text modifies menu text with html underline for mnemonic
52− text: menuData.label.replace("_", "&").replace("<u>", "&").replace("</u>", "")
52+ text: menuData ? menuData.label.replace("_", "&").replace("<u>", "&").replace("</u>", "") : ""
53− checkable: menuData.isCheck || menuData.isRadio
53+ checkable: menuData && (menuData.isCheck || menuData.isRadio)
54− checked: menuData.isToggled
54+ checked: menuData && menuData.isToggled
55 }
55 }
56
56
57 width: {
57 width: {
@@ -127,8 +127,8 @@ ActionItem {
127 color: enabled ? theme.palette.normal.overlaySecondaryText :
127 color: enabled ? theme.palette.normal.overlaySecondaryText :
128 theme.palette.disabled.overlaySecondaryText
128 theme.palette.disabled.overlaySecondaryText
129
129
130− visible: menuData.shortcut != undefined && !root.hasSubmenu && QuickUtils.keyboardAttached
130+ visible: menuData && menuData.shortcut != undefined && !root.hasSubmenu && QuickUtils.keyboardAttached
131− text: menuData.shortcut ? menuData.shortcut : ""
131+ text: menuData && menuData.shortcut ? menuData.shortcut : ""
132 }
132 }
133 }
133 }
134
134
qml/ApplicationMenus/MenuPopup.qml+75−73
@@ -276,6 +276,79 @@ UbuntuShape {
276 }
276 }
277 }
277 }
278
278
279+ Component {
280+ id: separatorComponent
281+ ListItems.ThinDivider {
282+ // Parent will be loader
283+ objectName: parent.objectName + "-separator"
284+ implicitHeight: units.dp(2)
285+ }
286+ }
287+
288+ Component {
289+ id: menuItemComponent
290+ MenuItem {
291+ // Parent will be loader
292+ id: menuItem
293+ menuData: parent.__menuData
294+ objectName: parent.objectName + "-actionItem"
295+
296+ width: MathUtils.clamp(implicitWidth, d.__minimumWidth, d.__maximumWidth)
297+
298+ action.onTriggered: {
299+ submenuHoverTimer.stop();
300+
301+ d.currentItem = parent;
302+
303+ if (hasSubmenu) {
304+ if (!popup) {
305+ var model = root.unityMenuModel.submenu(__ownIndex);
306+ popup = submenuComponent.createObject(focusScope, {
307+ objectName: parent.objectName + "-",
308+ unityMenuModel: model,
309+ substractWidth: true,
310+ desiredX: Qt.binding(function() { return root.width }),
311+ desiredY: Qt.binding(function() {
312+ var dummy = listView.contentY; // force a recalc on contentY change.
313+ return mapToItem(container, 0, y).y;
314+ })
315+ });
316+ popup.retreat.connect(function() {
317+ popup.destroy();
318+ popup = null;
319+ menuItem.forceActiveFocus();
320+ });
321+ popup.childActivated.connect(function() {
322+ popup.destroy();
323+ popup = null;
324+ root.childActivated();
325+ });
326+ } else if (popup) {
327+ popup.visible = true;
328+ }
329+ } else {
330+ root.unityMenuModel.activate(__ownIndex);
331+ root.childActivated();
332+ }
333+ }
334+
335+ Connections {
336+ target: d
337+ onCurrentIndexChanged: {
338+ if (popup && d.currentIndex != __ownIndex) {
339+ popup.visible = false;
340+ }
341+ }
342+ onDismissAll: {
343+ if (popup) {
344+ popup.destroy();
345+ popup = null;
346+ }
347+ }
348+ }
349+ }
350+ }
351+
279 ColumnLayout {
352 ColumnLayout {
280 id: menuColumn
353 id: menuColumn
281 spacing: 0
354 spacing: 0
@@ -289,6 +362,8 @@ UbuntuShape {
289 id: loader
362 id: loader
290 objectName: root.objectName + "-item" + __ownIndex
363 objectName: root.objectName + "-item" + __ownIndex
291
364
365+ property Item popup: null
366+ property var __menuData: model
292 property int __ownIndex: index
367 property int __ownIndex: index
293 property bool __isSeparator: model.isSeparator
368 property bool __isSeparator: model.isSeparator
294
369
@@ -301,80 +376,7 @@ UbuntuShape {
301 return menuItemComponent;
376 return menuItemComponent;
302 }
377 }
303
378
304− property Item popup: null
305−
306 Layout.fillWidth: true
379 Layout.fillWidth: true
307−
308− Component {
309− id: menuItemComponent
310− MenuItem {
311− id: menuItem
312− menuData: model
313− objectName: loader.objectName + "-actionItem"
314−
315− width: MathUtils.clamp(implicitWidth, d.__minimumWidth, d.__maximumWidth)
316−
317− action.onTriggered: {
318− submenuHoverTimer.stop();
319−
320− d.currentItem = loader;
321−
322− if (hasSubmenu) {
323− if (!popup) {
324− var model = root.unityMenuModel.submenu(__ownIndex);
325− popup = submenuComponent.createObject(focusScope, {
326− objectName: loader.objectName + "-",
327− unityMenuModel: model,
328− substractWidth: true,
329− desiredX: Qt.binding(function() { return root.width }),
330− desiredY: Qt.binding(function() {
331− var dummy = listView.contentY; // force a recalc on contentY change.
332− return mapToItem(container, 0, y).y;
333− })
334− });
335− popup.retreat.connect(function() {
336− popup.destroy();
337− popup = null;
338− menuItem.forceActiveFocus();
339− });
340− popup.childActivated.connect(function() {
341− popup.destroy();
342− popup = null;
343− root.childActivated();
344− });
345− } else if (popup) {
346− popup.visible = true;
347− }
348− } else {
349− root.unityMenuModel.activate(__ownIndex);
350− root.childActivated();
351− }
352− }
353−
354− Connections {
355− target: d
356− onCurrentIndexChanged: {
357− if (popup && d.currentIndex != __ownIndex) {
358− popup.visible = false;
359− }
360− }
361− onDismissAll: {
362− if (popup) {
363− popup.destroy();
364− popup = null;
365− }
366− }
367− }
368− }
369− }
370−
371− Component {
372− id: separatorComponent
373− ListItems.ThinDivider {
374− objectName: loader.objectName + "-separator"
375− implicitHeight: units.dp(2)
376− }
377− }
378 }
380 }
379
381
380 }
382 }
qml/Components/WindowControlButtons.qml−21
@@ -47,13 +47,6 @@ Row {
47 onClicked: root.closeClicked()
47 onClicked: root.closeClicked()
48 visible: root.closeButtonShown
48 visible: root.closeButtonShown
49
49
50− // We dont want touch events to fall through to parent,
51− // otherwise the containsMouse will not work.
52− MouseArea {
53− anchors.fill: parent
54− propagateComposedEvents: true
55− }
56−
57 Rectangle {
50 Rectangle {
58 anchors.fill: parent
51 anchors.fill: parent
59 anchors.margins: windowIsMaximized ? units.dp(3) : 0
52 anchors.margins: windowIsMaximized ? units.dp(3) : 0
@@ -78,13 +71,6 @@ Row {
78 onClicked: root.minimizeClicked()
71 onClicked: root.minimizeClicked()
79 visible: root.minimizeButtonVisible
72 visible: root.minimizeButtonVisible
80
73
81− // We dont want touch events to fall through to parent,
82− // otherwise the containsMouse will not work.
83− MouseArea {
84− anchors.fill: parent
85− propagateComposedEvents: true
86− }
87−
88 Rectangle {
74 Rectangle {
89 anchors.fill: parent
75 anchors.fill: parent
90 anchors.margins: windowIsMaximized ? units.dp(3) : 0
76 anchors.margins: windowIsMaximized ? units.dp(3) : 0
@@ -118,13 +104,6 @@ Row {
118 }
104 }
119 }
105 }
120
106
121− // We dont want touch events to fall through to parent,
122− // otherwise the containsMouse will not work.
123− MouseArea {
124− anchors.fill: parent
125− propagateComposedEvents: true
126− }
127−
128 Rectangle {
107 Rectangle {
129 anchors.fill: parent
108 anchors.fill: parent
130 anchors.margins: windowIsMaximized ? units.dp(3) : 0
109 anchors.margins: windowIsMaximized ? units.dp(3) : 0
qml/Panel/Panel.qml+2
@@ -231,6 +231,8 @@ Item {
231 target: __indicators
231 target: __indicators
232 onShownChanged: bar.dismiss();
232 onShownChanged: bar.dismiss();
233 }
233 }
234+
235+ onDoubleClicked: PanelState.restoreClicked()
234 }
236 }
235 }
237 }
236 }
238 }
qml/Stage/DecoratedWindow.qml+3
@@ -204,12 +204,14 @@ FocusScope {
204 height: units.gu(3)
204 height: units.gu(3)
205
205
206 title: applicationWindow.title
206 title: applicationWindow.title
207+ windowMoving: moveHandler.moving && !altDragHandler.dragging
207
208
208 opacity: root.hasDecoration ? Math.min(1, root.showDecoration) : 0
209 opacity: root.hasDecoration ? Math.min(1, root.showDecoration) : 0
209 Behavior on opacity { UbuntuNumberAnimation { } }
210 Behavior on opacity { UbuntuNumberAnimation { } }
210
211
211 onPressed: root.decorationPressed();
212 onPressed: root.decorationPressed();
212 onPressedChanged: moveHandler.handlePressedChanged(pressed, pressedButtons, mouseX, mouseY)
213 onPressedChanged: moveHandler.handlePressedChanged(pressed, pressedButtons, mouseX, mouseY)
214+ onPressedChangedEx: moveHandler.handlePressedChanged(pressed, pressedButtons, mouseX, mouseY)
213 onPositionChanged: moveHandler.handlePositionChanged(mouse)
215 onPositionChanged: moveHandler.handlePositionChanged(mouse)
214 onReleased: {
216 onReleased: {
215 root.decorationReleased();
217 root.decorationReleased();
@@ -255,6 +257,7 @@ FocusScope {
255 }
257 }
256
258
257 MouseArea {
259 MouseArea {
260+ id: altDragHandler
258 anchors.fill: applicationWindow
261 anchors.fill: applicationWindow
259 acceptedButtons: Qt.LeftButton
262 acceptedButtons: Qt.LeftButton
260 property bool dragging: false
263 property bool dragging: false
qml/Stage/MoveHandler.qml+4
@@ -29,6 +29,7 @@ QtObject {
29 property real boundsTopMargin: 0
29 property real boundsTopMargin: 0
30
30
31 readonly property bool dragging: priv.dragging
31 readonly property bool dragging: priv.dragging
32+ readonly property bool moving: priv.moving
32
33
33 signal fakeMaximizeAnimationRequested(real amount)
34 signal fakeMaximizeAnimationRequested(real amount)
34 signal fakeMaximizeLeftAnimationRequested(real amount)
35 signal fakeMaximizeLeftAnimationRequested(real amount)
@@ -43,6 +44,7 @@ QtObject {
43 property real distanceX
44 property real distanceX
44 property real distanceY
45 property real distanceY
45 property bool dragging
46 property bool dragging
47+ property bool moving
46
48
47 readonly property int triggerArea: units.gu(8)
49 readonly property int triggerArea: units.gu(8)
48 property bool nearLeftEdge: target.maximizedLeft
50 property bool nearLeftEdge: target.maximizedLeft
@@ -110,6 +112,7 @@ QtObject {
110
112
111 function handlePositionChanged(mouse, sensingPoints) {
113 function handlePositionChanged(mouse, sensingPoints) {
112 if (priv.dragging) {
114 if (priv.dragging) {
115+ priv.moving = true;
113 priv.mouseDownTimer.stop();
116 priv.mouseDownTimer.stop();
114 Mir.cursorName = "grabbing";
117 Mir.cursorName = "grabbing";
115
118
@@ -180,6 +183,7 @@ QtObject {
180 }
183 }
181
184
182 function handleReleased(touchMode) {
185 function handleReleased(touchMode) {
186+ priv.moving = false;
183 if (touchMode) {
187 if (touchMode) {
184 priv.progress = 0;
188 priv.progress = 0;
185 priv.resetEdges();
189 priv.resetEdges();
qml/Stage/WindowDecoration.qml+12−14
@@ -33,23 +33,21 @@ MouseArea {
33 property alias overlayShown: buttons.overlayShown
33 property alias overlayShown: buttons.overlayShown
34 property var menu: undefined
34 property var menu: undefined
35 property bool enableMenus: true
35 property bool enableMenus: true
36+ property bool windowMoving: false
36
37
37 readonly property real buttonsWidth: buttons.width + row.spacing
38 readonly property real buttonsWidth: buttons.width + row.spacing
38
39
39 acceptedButtons: Qt.AllButtons // prevent leaking unhandled mouse events
40 acceptedButtons: Qt.AllButtons // prevent leaking unhandled mouse events
40 hoverEnabled: true
41 hoverEnabled: true
41
42
42− drag.target: Item {}
43− drag.filterChildren: true
44− drag.threshold: 0
45−
46 signal closeClicked()
43 signal closeClicked()
47 signal minimizeClicked()
44 signal minimizeClicked()
48 signal maximizeClicked()
45 signal maximizeClicked()
49 signal maximizeHorizontallyClicked()
46 signal maximizeHorizontallyClicked()
50 signal maximizeVerticallyClicked()
47 signal maximizeVerticallyClicked()
51
48
52− onClicked: mouse.accepted = true // propogated event
49+ signal pressedChangedEx(bool pressed, var pressedButtons, real mouseX, real mouseY)
50+
53 onDoubleClicked: {
51 onDoubleClicked: {
54 if (mouse.button == Qt.LeftButton) {
52 if (mouse.button == Qt.LeftButton) {
55 root.maximizeClicked();
53 root.maximizeClicked();
@@ -69,13 +67,6 @@ MouseArea {
69 (menuBar.showRequested || root.containsMouse)
67 (menuBar.showRequested || root.containsMouse)
70 }
68 }
71
69
72− // We dont want touch events to fall through to parent as it expect some child MouseArea to have them
73− // If not some MouseArea in the menu bar, it will be this one.
74− MouseArea {
75− anchors.fill: parent
76− propagateComposedEvents: true
77− }
78−
79 Rectangle {
70 Rectangle {
80 id: background
71 id: background
81 anchors.fill: parent
72 anchors.fill: parent
@@ -136,7 +127,7 @@ MouseArea {
136 fontSize: "medium"
127 fontSize: "medium"
137 font.weight: root.active ? Font.Light : Font.Medium
128 font.weight: root.active ? Font.Light : Font.Medium
138 elide: Text.ElideRight
129 elide: Text.ElideRight
139− opacity: overlayShown || priv.shouldShowMenus ? 0 : 1
130+ opacity: overlayShown || menuBarLoader.visible ? 0 : 1
140 visible: opacity != 0
131 visible: opacity != 0
141 Behavior on opacity { UbuntuNumberAnimation {} }
132 Behavior on opacity { UbuntuNumberAnimation {} }
142 }
133 }
@@ -154,9 +145,16 @@ MouseArea {
154 height: menuBarLoader.height
145 height: menuBarLoader.height
155 enableKeyFilter: valid && root.active && root.enableMenus
146 enableKeyFilter: valid && root.active && root.enableMenus
156 unityMenuModel: root.menu
147 unityMenuModel: root.menu
148+ windowMoving: root.windowMoving
149+
150+ onPressed: root.onPressed(mouse)
151+ onPressedChangedEx: root.pressedChangedEx(pressed, pressedButtons, mouseX, mouseY)
152+ onPositionChanged: root.onPositionChanged(mouse)
153+ onReleased: root.onReleased(mouse)
154+ onDoubleClicked: root.onDoubleClicked(mouse)
157 }
155 }
158
156
159− opacity: !overlayShown && priv.shouldShowMenus ? 1 : 0
157+ opacity: (!overlayShown && priv.shouldShowMenus) || (active && priv.menuBar.valid && root.windowMoving) ? 1 : 0
160 visible: opacity == 1
158 visible: opacity == 1
161 Behavior on opacity { UbuntuNumberAnimation {} }
159 Behavior on opacity { UbuntuNumberAnimation {} }
162 }
160 }
tests/qmltests/ApplicationMenus/tst_MenuBar.qml+3
@@ -85,6 +85,7 @@ Item {
85 menuBar.dismiss();
85 menuBar.dismiss();
86 menuBackend.modelData = appMenuData.generateTestData(5,5,2,3, "menu")
86 menuBackend.modelData = appMenuData.generateTestData(5,5,2,3, "menu")
87 activatedSpy.clear();
87 activatedSpy.clear();
88+ waitForRendering(menuBar);
88 }
89 }
89
90
90 function test_mouseNavigation() {
91 function test_mouseNavigation() {
@@ -97,6 +98,7 @@ Item {
97 var menuItem2 = findChild(menuBar, "menuBar-item2"); verify(menuItem2);
98 var menuItem2 = findChild(menuBar, "menuBar-item2"); verify(menuItem2);
98
99
99 menuItem0.show();
100 menuItem0.show();
101+ mouseMove(menuItem0, menuItem0.width/2, menuItem0.height/2);
100 compare(priv.currentItem, menuItem0, "CurrentItem should be set to item 0");
102 compare(priv.currentItem, menuItem0, "CurrentItem should be set to item 0");
101 compare(priv.currentItem.popupVisible, true, "Popup should be visible");
103 compare(priv.currentItem.popupVisible, true, "Popup should be visible");
102
104
@@ -178,6 +180,7 @@ Item {
178
180
179 keyPress(data.tag, Qt.AltModifier, 100);
181 keyPress(data.tag, Qt.AltModifier, 100);
180 tryCompare(priv, "currentItem", menuItem);
182 tryCompare(priv, "currentItem", menuItem);
183+ keyRelease(data.tag, Qt.AltModifier, 100);
181 }
184 }
182
185
183 function test_menuActivateClosesMenu() {
186 function test_menuActivateClosesMenu() {
tests/qmltests/Stage/tst_DesktopStage.qml+18
@@ -1013,5 +1013,23 @@ Item {
1013 expectFail("", "Hovering the window controls should be ignored when the menu is open");
1013 expectFail("", "Hovering the window controls should be ignored when the menu is open");
1014 tryCompare(closeButton, "containsMouse", true);
1014 tryCompare(closeButton, "containsMouse", true);
1015 }
1015 }
1016+
1017+ function test_windowControlsTouchInteractionWithMenu() {
1018+ var appDelegate = startApplication("gmail-webapp");
1019+
1020+ var wd = findChild(appDelegate, "appWindowDecoration");
1021+ var maxButton = findChild(wd, "maximizeWindowButton");
1022+ var menuBarLoader = findChild(wd, "menuBarLoader");
1023+ var menuNav = findInvisibleChild(menuBarLoader, "d");
1024+
1025+ // make the menubar active and visible, select first item
1026+ menuBarLoader.active = true;
1027+ menuNav.select(0);
1028+ tryCompare(menuBarLoader.item, "visible", true);
1029+
1030+ // verify the maximized button can still be tapped
1031+ tap(maxButton);
1032+ tryCompare(appDelegate, "state", "maximized");
1033+ }
1016 }
1034 }
1017}
1035}
tests/qmltests/tst_Shell.qml+24
@@ -2910,5 +2910,29 @@ Rectangle {
2910 tryCompare(topLevelSurfaceList.focusedWindow, "surface", appDelegate.surface);
2910 tryCompare(topLevelSurfaceList.focusedWindow, "surface", appDelegate.surface);
2911 tryCompare(topLevelSurfaceList.applicationAt(0), "appId", "dialer-app");
2911 tryCompare(topLevelSurfaceList.applicationAt(0), "appId", "dialer-app");
2912 }
2912 }
2913+
2914+ function test_doubleClickPanelRestoresWindow() {
2915+ loadShell("desktop");
2916+ shell.usageScenario = "desktop";
2917+ waitForRendering(shell);
2918+ swipeAwayGreeter();
2919+
2920+ // start dialer
2921+ var appDelegate = startApplication("dialer-app")
2922+ verify(appDelegate);
2923+ tryCompare(appDelegate, "state", "normal");
2924+
2925+ // maximize dialer
2926+ var decoration = findChild(appDelegate, "appWindowDecoration");
2927+ verify(decoration);
2928+ mouseDoubleClickSequence(decoration);
2929+ tryCompare(appDelegate, "state", "maximized");
2930+
2931+ // double click the panel
2932+ var panel = findChild(shell, "panel");
2933+ verify(panel);
2934+ mouseDoubleClickSequence(panel, panel.width/2, PanelState.panelHeight/2, Qt.LeftButton, Qt.NoModifier, 300);
2935+ tryCompare(appDelegate, "state", "restored");
2936+ }
2913 }
2937 }
2914}
2938}