Merge lp:~faenil/ubuntu-ui-toolkit/addIgnoreSynthesizedEventsToMouseFilter into lp:ubuntu-ui-toolkit/staging

Proposed by Andrea Bernabei
Status: Merged
Approved by: Zsombor Egri
Approved revision: 1738
Merged at revision: 1742
Proposed branch: lp:~faenil/ubuntu-ui-toolkit/addIgnoreSynthesizedEventsToMouseFilter
Merge into: lp:ubuntu-ui-toolkit/staging
Diff against target: 274 lines (+166/-2)
6 files modified
components.api (+1/-0)
src/Ubuntu/Components/plugin/ucmouse.h (+6/-0)
src/Ubuntu/Components/plugin/ucmousefilters.cpp (+61/-1)
tests/unit_x11/tst_mousefilters/FilterSynthesizedEvents.qml (+34/-0)
tests/unit_x11/tst_mousefilters/tst_mousefilters.pro (+2/-1)
tests/unit_x11/tst_mousefilters/tst_mousefilterstest.cpp (+62/-0)
To merge this branch: bzr merge lp:~faenil/ubuntu-ui-toolkit/addIgnoreSynthesizedEventsToMouseFilter
Reviewer Review Type Date Requested Status
PS Jenkins bot continuous-integration Approve
Zsombor Egri Approve
Review via email: mp+279464@code.launchpad.net

Description of the change

add the ignoreSynthesizedEvents property.

When the property is enabled, the Mouse filter ignores any synthesized mouse event, such as those created by the touch-to-mouse events synthesis.

Enabling this property makes it possible to only trigger the hovering logic ONLY when using a mouse, and not when using a touchscreen (as it happens when using MouseArea).

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Zsombor Egri (zsombi) wrote :

Nais!!! ;)

review: Approve
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) :
review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'components.api'
--- components.api 2015-11-30 12:43:00 +0000
+++ components.api 2015-12-03 15:50:37 +0000
@@ -631,6 +631,7 @@
631 property bool enabled631 property bool enabled
632 property list<Item> forwardTo632 property list<Item> forwardTo
633 readonly property bool hoverEnabled633 readonly property bool hoverEnabled
634 property bool ignoreSynthesizedEvents
634 signal pressed(QQuickMouseEvent mouse, Item host)635 signal pressed(QQuickMouseEvent mouse, Item host)
635 signal released(QQuickMouseEvent mouse, Item host)636 signal released(QQuickMouseEvent mouse, Item host)
636 signal clicked(QQuickMouseEvent mouse, Item host)637 signal clicked(QQuickMouseEvent mouse, Item host)
637638
=== modified file 'src/Ubuntu/Components/plugin/ucmouse.h'
--- src/Ubuntu/Components/plugin/ucmouse.h 2014-04-15 12:51:31 +0000
+++ src/Ubuntu/Components/plugin/ucmouse.h 2015-12-03 15:50:37 +0000
@@ -71,6 +71,10 @@
71 Q_PROPERTY(int clickAndHoldThreshold READ clickAndHoldThreshold WRITE setClickAndHoldThreshold NOTIFY clickAndHoldThresholdChanged)71 Q_PROPERTY(int clickAndHoldThreshold READ clickAndHoldThreshold WRITE setClickAndHoldThreshold NOTIFY clickAndHoldThresholdChanged)
72 Q_PROPERTY(QQmlListProperty<QQuickItem> forwardTo READ forwardTo)72 Q_PROPERTY(QQmlListProperty<QQuickItem> forwardTo READ forwardTo)
73 Q_PROPERTY(Priority priority READ priority WRITE setPriority NOTIFY priorityChanged)73 Q_PROPERTY(Priority priority READ priority WRITE setPriority NOTIFY priorityChanged)
74
75 //Added in 1.3, but we can't use REVISION because of QTBUG-40043
76 Q_PROPERTY(bool ignoreSynthesizedEvents MEMBER m_ignoreSynthesizedEvents NOTIFY ignoreSynthesizedEventsChanged)
77
74 Q_ENUMS(Priority)78 Q_ENUMS(Priority)
75public:79public:
76 enum Priority {80 enum Priority {
@@ -98,6 +102,7 @@
98 void hoverEnabledChanged();102 void hoverEnabledChanged();
99 void clickAndHoldThresholdChanged();103 void clickAndHoldThresholdChanged();
100 void priorityChanged();104 void priorityChanged();
105 void ignoreSynthesizedEventsChanged();
101106
102 void pressed(QQuickMouseEvent *mouse, QQuickItem *host);107 void pressed(QQuickMouseEvent *mouse, QQuickItem *host);
103 void released(QQuickMouseEvent *mouse, QQuickItem *host);108 void released(QQuickMouseEvent *mouse, QQuickItem *host);
@@ -151,6 +156,7 @@
151 bool m_longPress:1;156 bool m_longPress:1;
152 bool m_hovered:1;157 bool m_hovered:1;
153 bool m_doubleClicked:1;158 bool m_doubleClicked:1;
159 bool m_ignoreSynthesizedEvents:1;
154};160};
155QML_DECLARE_TYPEINFO(UCMouse, QML_HAS_ATTACHED_PROPERTIES)161QML_DECLARE_TYPEINFO(UCMouse, QML_HAS_ATTACHED_PROPERTIES)
156162
157163
=== modified file 'src/Ubuntu/Components/plugin/ucmousefilters.cpp'
--- src/Ubuntu/Components/plugin/ucmousefilters.cpp 2015-03-03 13:47:48 +0000
+++ src/Ubuntu/Components/plugin/ucmousefilters.cpp 2015-12-03 15:50:37 +0000
@@ -333,8 +333,48 @@
333333
334 Similar functionality for the case when the mouse event occurs outside of the334 Similar functionality for the case when the mouse event occurs outside of the
335 owner is brought by the \l InverseMouse attached property.335 owner is brought by the \l InverseMouse attached property.
336
337 \section1 Mouse events synthesis
338 QtQuick automatically creates artificial mouse events whenever a scene receives
339 touch events that are not consumed by any item (either by using MultiPointTouchArea
340 or a custom C++ item). The Mouse filter provides the possibility to ignore
341 synthesized mouse events by enabling the \l ignoreSynthesizedEvents
342 property.
343
344 This is really useful when, while developing a convergent application, the app developer
345 wants to avoid triggering the hovering logic using a touchscreen,
346 but still be able to handle the hover events when using a mouse, and at the same time
347 doesn't want to stop the mouse and touch events from propagating to items underneath the
348 MouseArea which handles the hovering.
349 The following is an example of how that functionaly can be implemented:
350 \qml
351 MouseArea {
352 id: proximityArea
353 anchors.fill: parent
354 propagateComposedEvents: true
355 hoverEnabled: true
356
357 //We use a separate variable to detect whether the area contains
358 //a mouse, because MouseArea's containsMouse is true even when
359 //tapping on it using a touchscreen (due to the touch events being
360 //converted to mouse events if no item consumes them).
361 property bool containsPointerDevice: false
362
363 //handle hover events using the Mouse filter instead of MouseArea, so that
364 //we can ignore synthesized mouse events and not trigger hover logic when the
365 //user is interacting with the app using a touch device.
366 Mouse.ignoreSynthesizedEvents: true
367 Mouse.onEntered: {
368 console.log("ONLY A MOUSE CAN TRIGGER THIS SLOT")
369 proximityArea.containsPointerDevice = true
370 }
371 Mouse.onExited: proximityArea.containsPointerDevice = false
372
373 //let mouse and touch events propagate underneath the mouse area
374 onPressed: mouse.accepted = false
375 }
376 \endqml
336 */377 */
337
338UCMouse::UCMouse(QObject *parent)378UCMouse::UCMouse(QObject *parent)
339 : QObject(parent)379 : QObject(parent)
340 , m_owner(qobject_cast<QQuickItem*>(parent))380 , m_owner(qobject_cast<QQuickItem*>(parent))
@@ -349,6 +389,7 @@
349 , m_longPress(false)389 , m_longPress(false)
350 , m_hovered(false)390 , m_hovered(false)
351 , m_doubleClicked(false)391 , m_doubleClicked(false)
392 , m_ignoreSynthesizedEvents(false)
352{393{
353 // if owner is MouseArea or InverseMouseArea, connect to the acceptedButtons394 // if owner is MouseArea or InverseMouseArea, connect to the acceptedButtons
354 // and hoverEnabled change signals395 // and hoverEnabled change signals
@@ -420,6 +461,11 @@
420{461{
421 bool result = false;462 bool result = false;
422 Q_UNUSED(target);463 Q_UNUSED(target);
464
465 if (m_ignoreSynthesizedEvents && event->source() == Qt::MouseEventSynthesizedByQt) {
466 return result;
467 }
468
423 switch (event->type()) {469 switch (event->type()) {
424 case QEvent::MouseButtonPress:470 case QEvent::MouseButtonPress:
425 {471 {
@@ -791,6 +837,20 @@
791}837}
792838
793/*!839/*!
840 \qmlproperty bool Mouse::ignoreSynthesizedEvents
841 This property controls how the filter handles the mouse events
842 synthesized by Qt (e.g. the artificial mouse events created when
843 an original touch event is not consumed by any Item in the scene).
844
845 If the value is true, the filter will ignore the synthesized mouse
846 events.
847
848 More info at \l{Mouse events synthesis}.
849
850 The default value is false.
851 */
852
853/*!
794 \qmlproperty Qt::MouseButtons Mouse::acceptedButtons854 \qmlproperty Qt::MouseButtons Mouse::acceptedButtons
795 \readonly855 \readonly
796 The property holds the accepted mouse buttons of the owner.856 The property holds the accepted mouse buttons of the owner.
797857
=== added file 'tests/unit_x11/tst_mousefilters/FilterSynthesizedEvents.qml'
--- tests/unit_x11/tst_mousefilters/FilterSynthesizedEvents.qml 1970-01-01 00:00:00 +0000
+++ tests/unit_x11/tst_mousefilters/FilterSynthesizedEvents.qml 2015-12-03 15:50:37 +0000
@@ -0,0 +1,34 @@
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 Lesser 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 Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17import QtQuick 2.4
18import Ubuntu.Components 1.3
19
20MouseArea {
21 width: units.gu(40)
22 height: units.gu(40)
23
24 objectName: "rootMouseArea"
25
26 MouseArea {
27 signal overlayPressed()
28 objectName: "overlayArea"
29 anchors.fill: parent
30
31 Mouse.enabled: true
32 Mouse.ignoreSynthesizedEvents: true
33 }
34}
035
=== modified file 'tests/unit_x11/tst_mousefilters/tst_mousefilters.pro'
--- tests/unit_x11/tst_mousefilters/tst_mousefilters.pro 2014-04-14 16:57:12 +0000
+++ tests/unit_x11/tst_mousefilters/tst_mousefilters.pro 2015-12-03 15:50:37 +0000
@@ -31,4 +31,5 @@
31 DoubleClicked.qml \31 DoubleClicked.qml \
32 HoverEvent.qml \32 HoverEvent.qml \
33 ForwardComposedEvents.qml \33 ForwardComposedEvents.qml \
34 ForwardEventChained.qml34 ForwardEventChained.qml \
35 FilterSynthesizedEvents.qml
3536
=== modified file 'tests/unit_x11/tst_mousefilters/tst_mousefilterstest.cpp'
--- tests/unit_x11/tst_mousefilters/tst_mousefilterstest.cpp 2014-11-25 09:58:33 +0000
+++ tests/unit_x11/tst_mousefilters/tst_mousefilterstest.cpp 2015-12-03 15:50:37 +0000
@@ -29,6 +29,7 @@
29#include "quickutils.h"29#include "quickutils.h"
30#include "inversemouseareatype.h"30#include "inversemouseareatype.h"
31#include "uctestcase.h"31#include "uctestcase.h"
32#include "uctestextras.h"
32#include <private/qquickevents_p_p.h>33#include <private/qquickevents_p_p.h>
33#include <private/qquickmousearea_p.h>34#include <private/qquickmousearea_p.h>
3435
@@ -116,6 +117,8 @@
116117
117 void initTestCase()118 void initTestCase()
118 {119 {
120 UCTestExtras::registerTouchDevice();
121
119 QString modules(UBUNTU_QML_IMPORT_PATH);122 QString modules(UBUNTU_QML_IMPORT_PATH);
120 QVERIFY(QDir(modules).exists());123 QVERIFY(QDir(modules).exists());
121124
@@ -1101,6 +1104,65 @@
1101 QTest::mouseRelease(test.data(), Qt::LeftButton, 0, guPoint(20, 30));1104 QTest::mouseRelease(test.data(), Qt::LeftButton, 0, guPoint(20, 30));
1102 QTest::waitForEvents();1105 QTest::waitForEvents();
1103 }1106 }
1107
1108 void testCase_ignoreSynthesizedEvents() {
1109 QScopedPointer<UbuntuTestCase> test(new UbuntuTestCase("FilterSynthesizedEvents.qml"));
1110 QQuickMouseArea *rootMouseArea = qobject_cast<QQuickMouseArea *>(test->rootObject());
1111 QQuickMouseArea* overlayArea = test->findItem<QQuickMouseArea *>("overlayArea");
1112 UCMouse *overlayFilter = attachedFilter<UCMouse>(test->rootObject(), "overlayArea");
1113
1114 QCOMPARE(rootMouseArea != Q_NULLPTR, true);
1115 QCOMPARE(overlayArea != Q_NULLPTR, true);
1116 QCOMPARE(overlayFilter != Q_NULLPTR, true);
1117
1118 QSignalSpy areaPressed(rootMouseArea, SIGNAL(pressed(QQuickMouseEvent *)));
1119 QSignalSpy overlayAreaPressed(overlayArea, SIGNAL(pressed(QQuickMouseEvent *)));
1120 QSignalSpy overlayFilterPressed(overlayFilter, SIGNAL(pressed(QQuickMouseEvent*, QQuickItem*)));
1121 QCOMPARE(overlayFilter->property("ignoreSynthesizedEvents").toBool(), true);
1122
1123 //we're assuming the priority is set to BeforeItem, the functionality is not priority-dependent anyway,
1124 //just the outcome is.
1125 QCOMPARE(overlayFilter->priority(), UCMouse::BeforeItem);
1126 QCOMPARE(overlayArea->isEnabled(), true);
1127
1128 //send a touch event, which will be converted to a synthesized mouse event, since
1129 //no item in this QML is handling touch events
1130 UCTestExtras::touchPress(0, overlayArea, guPoint(15, 15));
1131 QTest::waitForEvents();
1132
1133 QCOMPARE(areaPressed.count(), 0);
1134 QCOMPARE(overlayAreaPressed.count(), 1);
1135 QCOMPARE(overlayFilterPressed.count(), 0);
1136 UCTestExtras::touchRelease(0, overlayArea, guPoint(15, 15));
1137
1138 QTest::waitForEvents();
1139
1140 overlayFilter->setProperty("ignoreSynthesizedEvents", false);
1141 QCOMPARE(overlayFilter->property("ignoreSynthesizedEvents").toBool(), false);
1142 UCTestExtras::touchPress(1, overlayArea, guPoint(15, 15));
1143 QTest::waitForEvents();
1144
1145 QCOMPARE(areaPressed.count(), 0);
1146 //the filter doesn't accept the pressed event by default
1147 QCOMPARE(overlayAreaPressed.count(), 2);
1148 QCOMPARE(overlayFilterPressed.count(), 1);
1149 UCTestExtras::touchRelease(1, overlayArea, guPoint(15, 15));
1150 QTest::waitForEvents();
1151
1152 overlayArea->setEnabled(false);
1153 QCOMPARE(overlayArea->isEnabled(), false);
1154
1155 UCTestExtras::touchPress(2, overlayArea, guPoint(15, 15));
1156 QTest::waitForEvents();
1157
1158 //the filter gets the event but its owner is not enabled, so we expect it
1159 //to propagate to the area underneath
1160 QCOMPARE(areaPressed.count(), 1);
1161 QCOMPARE(overlayAreaPressed.count(), 2);
1162 QCOMPARE(overlayFilterPressed.count(), 2);
1163 UCTestExtras::touchRelease(2, overlayArea, guPoint(15, 15));
1164 QTest::waitForEvents();
1165 }
1104};1166};
11051167
1106QTEST_MAIN(tst_mouseFilterTest)1168QTEST_MAIN(tst_mouseFilterTest)

Subscribers

People subscribed via source and target branches