Merge lp:~ci-train-bot/unity8/unity8-ubuntu-yakkety-landing-059 into lp:unity8

Proposed by Michał Sawicz
Status: Merged
Merged at revision: 2440
Proposed branch: lp:~ci-train-bot/unity8/unity8-ubuntu-yakkety-landing-059
Merge into: lp:unity8
Diff against target: 14480 lines (+2342/-7398)
240 files modified
CMakeLists.txt (+13/-2)
debian/changelog (+65/-0)
debian/control (+5/-3)
debian/unity8-private.install (+0/-1)
libs/CMakeLists.txt (+0/-1)
libs/UbuntuGestures/CMakeLists.txt (+0/-41)
libs/UbuntuGestures/CandidateInactivityTimer.cpp (+0/-46)
libs/UbuntuGestures/CandidateInactivityTimer.h (+0/-51)
libs/UbuntuGestures/DebugHelpers.cpp (+0/-95)
libs/UbuntuGestures/DebugHelpers.h (+0/-31)
libs/UbuntuGestures/Pool.h (+0/-124)
libs/UbuntuGestures/TimeSource.cpp (+0/-49)
libs/UbuntuGestures/TimeSource.h (+0/-64)
libs/UbuntuGestures/Timer.cpp (+0/-152)
libs/UbuntuGestures/Timer.h (+0/-122)
libs/UbuntuGestures/TouchOwnershipEvent.cpp (+0/-35)
libs/UbuntuGestures/TouchOwnershipEvent.h (+0/-50)
libs/UbuntuGestures/TouchRegistry.cpp (+0/-553)
libs/UbuntuGestures/TouchRegistry.h (+0/-201)
libs/UbuntuGestures/UbuntuGesturesGlobal.h (+0/-23)
libs/UbuntuGestures/UnownedTouchEvent.cpp (+0/-39)
libs/UbuntuGestures/UnownedTouchEvent.h (+0/-45)
plugins/Cursor/CMakeLists.txt (+2/-1)
plugins/Cursor/Cursor.qml (+21/-5)
plugins/Cursor/Cursor.qmltypes (+0/-78)
plugins/Cursor/CursorImageInfo.cpp (+106/-0)
plugins/Cursor/CursorImageInfo.h (+76/-0)
plugins/Cursor/CursorImageProvider.cpp (+52/-23)
plugins/Cursor/CursorImageProvider.h (+12/-4)
plugins/Cursor/MousePointer.cpp (+29/-24)
plugins/Cursor/MousePointer.h (+5/-6)
plugins/Cursor/plugin.cpp (+4/-2)
plugins/Cursor/qmldir (+1/-1)
plugins/Dash/AudioProgressBar.qml (+1/-1)
plugins/Dash/CardCreator.js (+64/-48)
plugins/Dash/CardCreatorCache.qml (+2/-2)
plugins/Dash/ScopeStyle.qml (+1/-1)
plugins/Dash/listviewwithpageheader.cpp (+14/-17)
plugins/Ubuntu/Gestures/AxisVelocityCalculator.h (+1/-1)
plugins/Ubuntu/Gestures/CMakeLists.txt (+5/-5)
plugins/Ubuntu/Gestures/Damper.cpp (+0/-24)
plugins/Ubuntu/Gestures/Damper.h (+0/-89)
plugins/Ubuntu/Gestures/Direction.h (+1/-0)
plugins/Ubuntu/Gestures/DirectionalDragArea.cpp (+0/-932)
plugins/Ubuntu/Gestures/DirectionalDragArea.h (+0/-143)
plugins/Ubuntu/Gestures/DirectionalDragArea_p.h (+0/-169)
plugins/Ubuntu/Gestures/Gestures.qmltypes (+0/-132)
plugins/Ubuntu/Gestures/MouseEventGenerator.cpp (+48/-134)
plugins/Ubuntu/Gestures/MouseEventGenerator.h (+23/-61)
plugins/Ubuntu/Gestures/PressedOutsideNotifier.h (+1/-1)
plugins/Ubuntu/Gestures/TouchGate.cpp (+2/-2)
plugins/Ubuntu/Gestures/TouchGestureArea.cpp (+9/-6)
plugins/Ubuntu/Gestures/TouchGestureArea.h (+2/-3)
plugins/Ubuntu/Gestures/plugin.cpp (+3/-5)
plugins/Unity/InputInfo/plugin.h (+1/-1)
plugins/Unity/InputInfo/qdeclarativeinputdevicemodel_p.h (+3/-3)
plugins/Unity/Session/dbusunitysessionservice.cpp (+7/-0)
plugins/Utils/WindowInputMonitor.cpp (+8/-8)
plugins/Utils/WindowInputMonitor.h (+8/-2)
plugins/Utils/windowstatestorage.h (+13/-3)
po/unity8.pot (+22/-22)
qml/Components/Dialogs.qml (+2/-2)
qml/Components/DragHandle.qml (+44/-26)
qml/Components/FloatingFlickable.qml (+59/-0)
qml/Components/Header.qml (+0/-28)
qml/Components/ModeSwitchWarningDialog.qml (+1/-1)
qml/Components/PanelState/PanelState.qml (+3/-3)
qml/Components/Rating.qml (+1/-0)
qml/Components/RatingStyle.qml (+3/-0)
qml/Components/WindowControlButtons.qml (+18/-7)
qml/Dash/CardCarousel.qml (+0/-1)
qml/Dash/CardGrid.qml (+0/-2)
qml/Dash/CardTool.qml (+6/-2)
qml/Dash/Dash.qml (+3/-3)
qml/Dash/DashApplication.qml (+0/-3)
qml/Dash/DashCategoryBase.qml (+3/-11)
qml/Dash/DashPageHeader.qml (+32/-37)
qml/Dash/Filters/FilterOptionSelector.qml (+4/-0)
qml/Dash/Filters/FilterWidgetFactory.qml (+8/-0)
qml/Dash/GenericScopeView.qml (+14/-4)
qml/Dash/PageHeaderExtraPanel.qml (+35/-11)
qml/Dash/Previews/PreviewActions.qml (+1/-1)
qml/Dash/Previews/PreviewPayments.qml (+1/-1)
qml/Dash/Previews/PreviewRatingInput.qml (+42/-43)
qml/Dash/ScopesList.qml (+1/-13)
qml/Launcher/Launcher.qml (+16/-24)
qml/Launcher/LauncherDelegate.qml (+2/-2)
qml/Notifications/Notification.qml (+20/-5)
qml/Notifications/NotificationMenuItemFactory.qml (+3/-0)
qml/Notifications/Notifications.qml (+18/-9)
qml/Panel/Indicators/MessageMenuItemFactory.qml (+1/-5)
qml/Panel/IndicatorsMenu.qml (+17/-13)
qml/Panel/Panel.qml (+15/-5)
qml/Shell.qml (+4/-3)
qml/Stages/DecoratedWindow.qml (+11/-7)
qml/Stages/DesktopSpread.qml (+1/-1)
qml/Stages/DesktopSpreadDelegate.qml (+1/-1)
qml/Stages/DesktopStage.qml (+57/-45)
qml/Stages/PhoneStage.qml (+4/-4)
qml/Stages/SideStage.qml (+1/-2)
qml/Stages/Splash.qml (+6/-17)
qml/Stages/SpreadDelegate.qml (+1/-1)
qml/Stages/TabletStage.qml (+4/-4)
qml/Stages/WindowDecoration.qml (+12/-8)
qml/Stages/WindowResizeArea.qml (+25/-5)
qml/Tutorial/TutorialBottom.qml (+3/-3)
qml/Wizard/Pages/50-timezone.qml (+5/-2)
src/CMakeLists.txt (+1/-4)
src/Dash/CMakeLists.txt (+1/-0)
src/Dash/main.cpp (+6/-0)
src/UnixSignalHandler.cpp (+1/-1)
src/main.cpp (+6/-0)
tests/CMakeLists.txt (+0/-1)
tests/autopilot/unity8/dash.py (+2/-3)
tests/libs/CMakeLists.txt (+0/-1)
tests/libs/UbuntuGestures/CMakeLists.txt (+0/-16)
tests/libs/UbuntuGestures/tst_TouchRegistry.cpp (+0/-974)
tests/mocks/Cursor/qmldir (+1/-1)
tests/mocks/GSettings.1.0/fake_gsettings.cpp (+1/-0)
tests/mocks/GSettings.1.0/fake_gsettings.h (+2/-2)
tests/mocks/IntegratedLightDM/liblightdm/GreeterPrivate.h (+0/-1)
tests/mocks/QtMultimedia/audio.cpp (+3/-3)
tests/mocks/QtMultimedia/audio.h (+12/-6)
tests/mocks/Ubuntu/Payments/MockPayments.cpp (+1/-0)
tests/mocks/Ubuntu/SystemSettings/TimeDate/CMakeLists.txt (+1/-1)
tests/mocks/Ubuntu/SystemSettings/TimeDate/MockTimeDate.qml (+16/-4)
tests/mocks/Ubuntu/SystemSettings/TimeDate/qmldir (+1/-1)
tests/mocks/Unity/Application/ApplicationInfo.h (+1/-1)
tests/mocks/Unity/Application/MirSurface.h (+2/-2)
tests/mocks/Unity/Application/MirSurfaceItem.cpp (+1/-0)
tests/mocks/Unity/InputInfo/plugin.h (+1/-1)
tests/mocks/Unity/Screens/plugin.h (+1/-1)
tests/mocks/Unity/fake_scope.cpp (+6/-3)
tests/mocks/Unity/fake_scope.h (+1/-1)
tests/mocks/Unity/fake_scopes.cpp (+11/-0)
tests/mocks/Utils/plugin.h (+1/-1)
tests/mocks/Utils/windowstatestorage.h (+14/-3)
tests/mocks/libusermetrics/UserMetrics.cpp (+1/-1)
tests/plugins/CMakeLists.txt (+2/-1)
tests/plugins/Cursor/CMakeLists.txt (+8/-0)
tests/plugins/Cursor/TextEntry.qml (+34/-0)
tests/plugins/Cursor/tst_Cursor.qml (+144/-0)
tests/plugins/Dash/cardcreator/1.res (+8/-26)
tests/plugins/Dash/cardcreator/1.res.cardcreator (+8/-26)
tests/plugins/Dash/cardcreator/1.tst (+1/-0)
tests/plugins/Dash/cardcreator/10.res (+0/-9)
tests/plugins/Dash/cardcreator/10.res.cardcreator (+0/-9)
tests/plugins/Dash/cardcreator/10.tst (+1/-0)
tests/plugins/Dash/cardcreator/11.res (+11/-29)
tests/plugins/Dash/cardcreator/11.res.cardcreator (+10/-28)
tests/plugins/Dash/cardcreator/11.tst (+1/-0)
tests/plugins/Dash/cardcreator/12.res (+8/-26)
tests/plugins/Dash/cardcreator/12.res.cardcreator (+10/-28)
tests/plugins/Dash/cardcreator/12.tst (+1/-0)
tests/plugins/Dash/cardcreator/2.res (+0/-9)
tests/plugins/Dash/cardcreator/2.res.cardcreator (+0/-9)
tests/plugins/Dash/cardcreator/2.tst (+1/-0)
tests/plugins/Dash/cardcreator/3.res (+5/-33)
tests/plugins/Dash/cardcreator/3.res.cardcreator (+5/-33)
tests/plugins/Dash/cardcreator/3.tst (+1/-0)
tests/plugins/Dash/cardcreator/4.res (+1/-2)
tests/plugins/Dash/cardcreator/4.res.cardcreator (+1/-2)
tests/plugins/Dash/cardcreator/4.tst (+1/-0)
tests/plugins/Dash/cardcreator/5.res (+2/-35)
tests/plugins/Dash/cardcreator/5.res.cardcreator (+2/-35)
tests/plugins/Dash/cardcreator/5.tst (+1/-0)
tests/plugins/Dash/cardcreator/6.res (+1/-2)
tests/plugins/Dash/cardcreator/6.res.cardcreator (+1/-2)
tests/plugins/Dash/cardcreator/6.tst (+1/-0)
tests/plugins/Dash/cardcreator/7.res (+0/-9)
tests/plugins/Dash/cardcreator/7.res.cardcreator (+0/-9)
tests/plugins/Dash/cardcreator/7.tst (+1/-0)
tests/plugins/Dash/cardcreator/8.res (+1/-2)
tests/plugins/Dash/cardcreator/8.res.cardcreator (+1/-2)
tests/plugins/Dash/cardcreator/8.tst (+1/-0)
tests/plugins/Dash/cardcreator/9.res (+1/-2)
tests/plugins/Dash/cardcreator/9.res.cardcreator (+1/-2)
tests/plugins/Dash/cardcreator/9.tst (+1/-0)
tests/plugins/Dash/cardcreatortest.cpp (+9/-6)
tests/plugins/Dash/cardcreatortest.qml (+4/-4)
tests/plugins/Dash/listviewwithpageheadersectionexternalmodeltest.cpp (+2/-2)
tests/plugins/Dash/listviewwithpageheadersectiontest.cpp (+2/-2)
tests/plugins/Dash/listviewwithpageheadertest.cpp (+5/-0)
tests/plugins/Dash/listviewwithpageheadertestsection.qml (+3/-2)
tests/plugins/Dash/listviewwithpageheadertestsectionexternalmodel.qml (+2/-1)
tests/plugins/Dash/tst_ListViewWithPageHeaderQML.qml (+4/-2)
tests/plugins/Dash/tst_ScopeStyle.qml (+1/-1)
tests/plugins/Ubuntu/Gestures/CMakeLists.txt (+4/-4)
tests/plugins/Ubuntu/Gestures/DownwardsLauncher.qml (+0/-72)
tests/plugins/Ubuntu/Gestures/GestureTest.cpp (+2/-2)
tests/plugins/Ubuntu/Gestures/LeftwardsLauncher.qml (+0/-76)
tests/plugins/Ubuntu/Gestures/RightwardsLauncher.qml (+0/-76)
tests/plugins/Ubuntu/Gestures/UpwardsLauncher.qml (+0/-76)
tests/plugins/Ubuntu/Gestures/tst_Damper.cpp (+0/-40)
tests/plugins/Ubuntu/Gestures/tst_DirectionalDragArea.cpp (+0/-1250)
tests/plugins/Ubuntu/Gestures/tst_DirectionalDragArea.qml (+0/-76)
tests/plugins/Ubuntu/Gestures/tst_FloatingFlickable.cpp (+26/-19)
tests/plugins/Ubuntu/Gestures/tst_FloatingFlickable.qml (+1/-0)
tests/plugins/Ubuntu/Gestures/tst_TouchGate.cpp (+1/-1)
tests/plugins/Unity/Indicators/MenuContentActivatorTest.cpp (+1/-0)
tests/plugins/Unity/Session/sessionbackendtest.cpp (+0/-15)
tests/plugins/Utils/WindowInputMonitorTest.cpp (+51/-10)
tests/qmltests/Components/CMakeLists.txt (+6/-3)
tests/qmltests/Components/tst_DragHandle.cpp (+28/-24)
tests/qmltests/Components/tst_DragHandle.qml (+27/-9)
tests/qmltests/Components/tst_DragHandle/BottomEdgeShowable.qml (+108/-0)
tests/qmltests/Components/tst_DragHandle/RightEdgeShowable.qml (+108/-0)
tests/qmltests/Components/tst_DragHandle/TopEdgeShowable.qml (+7/-7)
tests/qmltests/Components/tst_EdgeDragEvaluator.cpp (+1/-1)
tests/qmltests/Dash/Previews/tst_Preview.qml (+0/-1)
tests/qmltests/Dash/Previews/tst_PreviewRatingEdit.qml (+5/-1)
tests/qmltests/Dash/Previews/tst_PreviewRatingInput.qml (+18/-6)
tests/qmltests/Dash/Previews/tst_PreviewWidgetFactory.qml (+1/-1)
tests/qmltests/Dash/tst_Card.qml (+22/-10)
tests/qmltests/Dash/tst_CardTool.qml (+1/-1)
tests/qmltests/Dash/tst_Dash.qml (+76/-62)
tests/qmltests/Dash/tst_DashContent.qml (+65/-6)
tests/qmltests/Dash/tst_DashPageHeader.qml (+0/-24)
tests/qmltests/Dash/tst_DashShell.qml (+1/-1)
tests/qmltests/Dash/tst_GenericScopeView.qml (+2/-2)
tests/qmltests/Dash/tst_PreviewView.qml (+3/-3)
tests/qmltests/Greeter/tst_Greeter.qml (+1/-1)
tests/qmltests/Greeter/tst_NarrowView.qml (+1/-1)
tests/qmltests/Greeter/tst_WideView.qml (+1/-1)
tests/qmltests/Launcher/tst_Launcher.qml (+13/-1)
tests/qmltests/Notifications/tst_Notifications.qml (+89/-0)
tests/qmltests/Panel/Indicators/tst_MessageMenuItemFactory.qml (+1/-0)
tests/qmltests/Stages/tst_DesktopStage.qml (+31/-1)
tests/qmltests/Stages/tst_WindowResizeArea.qml (+16/-5)
tests/qmltests/Tutorial/tst_Tutorial.qml (+2/-2)
tests/qmltests/Wizard/tst_Wizard.qml (+4/-3)
tests/qmltests/tst_OrientedShell.qml (+1/-1)
tests/qmltests/tst_Shell.qml (+32/-5)
tests/qmltests/tst_ShellWithPin.qml (+1/-1)
tests/uqmlscene/main.cpp (+0/-1)
tests/utils/modules/Unity/Test/CMakeLists.txt (+4/-2)
tests/utils/modules/Unity/Test/UnityTestCase.qml (+34/-15)
tests/utils/modules/Unity/Test/testutil.cpp (+2/-2)
tools/CMakeLists.txt (+1/-1)
tools/scopetool.cpp (+1/-1)
To merge this branch: bzr merge lp:~ci-train-bot/unity8/unity8-ubuntu-yakkety-landing-059
Reviewer Review Type Date Requested Status
Unity Team Pending
Review via email: mp+296236@code.launchpad.net
To post a comment you must log in.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'CMakeLists.txt'
--- CMakeLists.txt 2016-05-18 11:17:20 +0000
+++ CMakeLists.txt 2016-06-01 16:58:47 +0000
@@ -57,12 +57,24 @@
57find_package(Qt5Concurrent 5.4 REQUIRED)57find_package(Qt5Concurrent 5.4 REQUIRED)
58find_package(Qt5Sql 5.4 REQUIRED)58find_package(Qt5Sql 5.4 REQUIRED)
5959
60pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=16)60pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=17)
61pkg_check_modules(GEONAMES REQUIRED geonames>=0.2)61pkg_check_modules(GEONAMES REQUIRED geonames>=0.2)
62pkg_check_modules(GIO REQUIRED gio-2.0>=2.32)62pkg_check_modules(GIO REQUIRED gio-2.0>=2.32)
63pkg_check_modules(GLIB REQUIRED glib-2.0>=2.32)63pkg_check_modules(GLIB REQUIRED glib-2.0>=2.32)
64pkg_check_modules(QMENUMODEL REQUIRED qmenumodel)64pkg_check_modules(QMENUMODEL REQUIRED qmenumodel)
6565
66pkg_check_modules(UBUNTUGESTURES REQUIRED UbuntuGestures)
67
68### Check UbuntuGestures private headers. No pkg-config (.pc) file is provided for them
69find_path(UBUNTUGESTUREPRIV
70 NAMES UbuntuGestures/private/damper_p.h UbuntuGestures/private/ucswipearea_p.h UbuntuGestures/private/ucswipearea_p_p.h
71 PATHS ${UBUNTUGESTURES_INCLUDEDIR}/UbuntuGestures/${UBUNTUGESTURES_VERSION}
72 NO_DEFAULT_PATH)
73if (${UBUNTUGESTUREPRIV} STREQUAL UBUNTUGESTUREPRIV-NOTFOUND)
74 message(FATAL_ERROR "UbuntuGestures private headers not found.")
75endif()
76# end of UbuntuGesture private headers check
77
66# Standard install paths78# Standard install paths
67include(GNUInstallDirs)79include(GNUInstallDirs)
6880
@@ -144,7 +156,6 @@
144156
145# add subdirectories to build157# add subdirectories to build
146add_subdirectory(include)158add_subdirectory(include)
147add_subdirectory(libs)
148add_subdirectory(src)159add_subdirectory(src)
149add_subdirectory(tools)160add_subdirectory(tools)
150add_subdirectory(qml)161add_subdirectory(qml)
151162
=== modified file 'debian/changelog'
--- debian/changelog 2016-05-20 08:44:19 +0000
+++ debian/changelog 2016-06-01 16:58:47 +0000
@@ -1,3 +1,68 @@
1unity8 (8.12+16.10.20160527-0ubuntu1) yakkety; urgency=medium
2
3 [ Albert Astals Cid ]
4 * Activate on click for SimpleMessages (LP: #1421696)
5 * Add override
6 * Change the art back to the cardData value if it changes from broken
7 to valid image (LP: #1533577)
8 * Concierge mode generated code optimization
9 * Don't use context properties but properties of the delegates
10 * Listen to contentItem::widthChanged instead of
11 Flickable::contentWidthChanged (LP: #1565763)
12 * Make some AP code faster
13 * Make tests a bit more stable
14 * Make unity8 and unity8-dash handle termination signals
15 * Remove workaround not needed anymore (LP: #1475643)
16 * Resolve cardArtStyle on compile time
17 * Set the theme earlier (LP: #1574048)
18
19 [ Albert Astals Cid, Daniel d'Andrada ]
20 * Remove DirectionalDragArea and libs/UbuntuGestures and port to SDK
21 equivalents
22
23 [ Andrea Cimitan ]
24 * Hide the preview review input field when a rating is required (LP:
25 #1541971)
26
27 [ CI Train Bot ]
28 * Resync trunk.
29
30 [ Daniel d'Andrada ]
31 * Fix DragHandle so it works in all directions
32 * Support animated cursors
33 * WindowInputMonitor - also map Qt::Key_HomePage to our home key
34 * plugins/Cursor: properly register to the screen's QPlatformCursor
35 when screen changes (LP: #1579742)
36
37 [ Josh Arenson ]
38 * Close the PageHeaderExtraPanel when a filter option is selected (LP:
39 #1569498)
40 * Wrap primaryFilter in a flickable to make it behave nicely. (LP:
41 #1569492)
42
43 [ Lukáš Tinkl ]
44 * First snap decision should always be expanded, unless user decides
45 otherwise (LP: #1580090, #1575045)
46 * Fullscreen notification bug fixes (LP: #1583944, #1581498, #1422711)
47 * Implement maximizing windows horizontally/vertically
48 * Lock the session when putting the laptop into sleep (LP: #1581063)
49
50 [ Lukáš Tinkl, Michael Terry ]
51 * With a maximized window, "dragging" the panel down should restore it
52
53 [ Michael Terry ]
54 * Change some dash button colors from orange to green. (LP: #1581047)
55 * Use PageHeader instead Ambiance's PageHeadStyle
56 * Use new setTimeZone method to set user-friendly timezone name in the
57 wizard. (LP: #1566295)
58
59 [ Michael Zanetti ]
60 * Remove the background dimming when the launcher is revealed by a
61 drag (LP: #1575137)
62 * reenable or drop disabled tests
63
64 -- Michael Terry <michael.terry@canonical.com> Fri, 27 May 2016 13:54:44 +0000
65
1unity8 (8.12+16.10.20160520.1-0ubuntu1) yakkety; urgency=medium66unity8 (8.12+16.10.20160520.1-0ubuntu1) yakkety; urgency=medium
267
3 [ Lukáš Tinkl ]68 [ Lukáš Tinkl ]
469
=== modified file 'debian/control'
--- debian/control 2016-05-17 19:42:10 +0000
+++ debian/control 2016-06-01 16:58:47 +0000
@@ -29,8 +29,10 @@
29 libqt5svg5-dev,29 libqt5svg5-dev,
30 libqt5xmlpatterns5-dev,30 libqt5xmlpatterns5-dev,
31 libsystemsettings-dev,31 libsystemsettings-dev,
32 libubuntugestures5-dev,
33 libubuntugestures5-private-dev,
32 libudev-dev,34 libudev-dev,
33 libunity-api-dev (>= 7.112),35 libunity-api-dev (>= 7.113),
34 libusermetricsoutput1-dev,36 libusermetricsoutput1-dev,
35# Need those X11 libs touch emulation from mouse events in manual QML tests on a X11 desktop37# Need those X11 libs touch emulation from mouse events in manual QML tests on a X11 desktop
36 libx11-dev[!armhf],38 libx11-dev[!armhf],
@@ -106,7 +108,7 @@
106 qtdeclarative5-qtmir-plugin (>= 0.4.8),108 qtdeclarative5-qtmir-plugin (>= 0.4.8),
107 qtdeclarative5-ubuntu-telephony0.1,109 qtdeclarative5-ubuntu-telephony0.1,
108 qtdeclarative5-ubuntu-web-plugin,110 qtdeclarative5-ubuntu-web-plugin,
109 ubuntu-system-settings,111 ubuntu-system-settings (>= 0.4),
110 unity-launcher-impl-7,112 unity-launcher-impl-7,
111 unity8-common (= ${source:Version}),113 unity8-common (= ${source:Version}),
112 unity8-private (= ${binary:Version}),114 unity8-private (= ${binary:Version}),
@@ -133,7 +135,7 @@
133 qtdeclarative5-ubuntu-ui-toolkit-plugin (>= 1.3.1845) | qtdeclarative5-ubuntu-ui-toolkit-plugin-gles (>= 1.3.1845),135 qtdeclarative5-ubuntu-ui-toolkit-plugin (>= 1.3.1845) | qtdeclarative5-ubuntu-ui-toolkit-plugin-gles (>= 1.3.1845),
134 qtdeclarative5-unity-notifications-plugin (>= 0.1.2) | unity-notifications-impl,136 qtdeclarative5-unity-notifications-plugin (>= 0.1.2) | unity-notifications-impl,
135 ubuntu-thumbnailer-impl-0,137 ubuntu-thumbnailer-impl-0,
136 unity-application-impl-16,138 unity-application-impl-17,
137 unity-notifications-impl-3,139 unity-notifications-impl-3,
138 unity-plugin-scopes | unity-scopes-impl,140 unity-plugin-scopes | unity-scopes-impl,
139 unity-scopes-impl-12,141 unity-scopes-impl-12,
140142
=== modified file 'debian/unity8-private.install'
--- debian/unity8-private.install 2016-04-28 12:06:22 +0000
+++ debian/unity8-private.install 2016-06-01 16:58:47 +0000
@@ -1,5 +1,4 @@
1usr/lib/*/libunity8-private.*1usr/lib/*/libunity8-private.*
2usr/lib/*/unity8/libUbuntuGestures*
3usr/lib/*/unity8/qml/AccountsService2usr/lib/*/unity8/qml/AccountsService
4usr/lib/*/unity8/qml/Cursor3usr/lib/*/unity8/qml/Cursor
5usr/lib/*/unity8/qml/Dash4usr/lib/*/unity8/qml/Dash
65
=== removed directory 'libs'
=== removed file 'libs/CMakeLists.txt'
--- libs/CMakeLists.txt 2014-10-01 13:20:32 +0000
+++ libs/CMakeLists.txt 1970-01-01 00:00:00 +0000
@@ -1,1 +0,0 @@
1add_subdirectory(UbuntuGestures)
20
=== removed directory 'libs/UbuntuGestures'
=== removed file 'libs/UbuntuGestures/CMakeLists.txt'
--- libs/UbuntuGestures/CMakeLists.txt 2015-04-10 21:16:37 +0000
+++ libs/UbuntuGestures/CMakeLists.txt 1970-01-01 00:00:00 +0000
@@ -1,41 +0,0 @@
1# in order to include Qt's private headers
2remove_definitions(-DQT_NO_KEYWORDS)
3
4set(UbuntuGestures_SOURCES
5 CandidateInactivityTimer.cpp
6 DebugHelpers.cpp
7 Timer.cpp
8 TimeSource.cpp
9 TouchOwnershipEvent.cpp
10 TouchRegistry.cpp
11 UnownedTouchEvent.cpp
12)
13
14add_definitions(-DUBUNTUGESTURES_LIBRARY)
15
16add_library(UbuntuGestures SHARED ${UbuntuGestures_SOURCES})
17
18qt5_use_modules(UbuntuGestures Core Quick)
19
20# So that Foo.cpp can #include "Foo.moc"
21include_directories(${CMAKE_CURRENT_BINARY_DIR})
22
23install(TARGETS UbuntuGestures
24 DESTINATION ${SHELL_PRIVATE_LIBDIR})
25
26
27# There's no cmake var for v8 include path :-/ so create one
28LIST(GET Qt5Core_INCLUDE_DIRS 0 QtCoreDir0)
29if(${Qt5Core_VERSION_STRING} VERSION_LESS "5.1.0")
30 SET(Qt5V8_PRIVATE_INCLUDE_DIR ${QtCoreDir0}/../QtV8/${Qt5Core_VERSION_STRING}/QtV8)
31else()
32 SET(Qt5V8_PRIVATE_INCLUDE_DIR ${QtCoreDir0}/QtV8/${Qt5Core_VERSION_STRING}/QtV8)
33endif()
34
35# DANGER! DANGER! Using Qt's private API!
36include_directories(
37 ${Qt5Qml_PRIVATE_INCLUDE_DIRS}
38 ${Qt5Quick_INCLUDE_DIRS}
39 ${Qt5Quick_PRIVATE_INCLUDE_DIRS}
40 ${Qt5V8_PRIVATE_INCLUDE_DIR}
41)
420
=== removed file 'libs/UbuntuGestures/CandidateInactivityTimer.cpp'
--- libs/UbuntuGestures/CandidateInactivityTimer.cpp 2015-04-17 18:31:12 +0000
+++ libs/UbuntuGestures/CandidateInactivityTimer.cpp 1970-01-01 00:00:00 +0000
@@ -1,46 +0,0 @@
1/*
2 * Copyright (C) 2014 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include "CandidateInactivityTimer.h"
18
19namespace UbuntuGestures {
20
21CandidateInactivityTimer::CandidateInactivityTimer(int touchId, QQuickItem *candidate,
22 AbstractTimer *timer, QObject *parent)
23 : QObject(parent)
24 , m_timer(timer)
25 , m_touchId(touchId)
26 , m_candidate(candidate)
27{
28 connect(m_timer, &AbstractTimer::timeout,
29 this, &CandidateInactivityTimer::onTimeout);
30 m_timer->setInterval(durationMs);
31 m_timer->setSingleShot(true);
32 m_timer->start();
33}
34
35CandidateInactivityTimer::~CandidateInactivityTimer()
36{
37 delete m_timer;
38}
39
40void CandidateInactivityTimer::onTimeout()
41{
42 qWarning("[TouchRegistry] Candidate for touch %d defaulted!", m_touchId);
43 Q_EMIT candidateDefaulted(m_touchId, m_candidate);
44}
45
46} // namespace UbuntuGestures
470
=== removed file 'libs/UbuntuGestures/CandidateInactivityTimer.h'
--- libs/UbuntuGestures/CandidateInactivityTimer.h 2015-04-17 18:31:12 +0000
+++ libs/UbuntuGestures/CandidateInactivityTimer.h 1970-01-01 00:00:00 +0000
@@ -1,51 +0,0 @@
1/*
2 * Copyright (C) 2014 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef UBUNTUGESTURES_CANDIDATE_INACTIVITY_TIMER_H
18#define UBUNTUGESTURES_CANDIDATE_INACTIVITY_TIMER_H
19
20#include <QObject>
21
22class QQuickItem;
23
24#include "Timer.h"
25
26namespace UbuntuGestures {
27
28class UBUNTUGESTURES_EXPORT CandidateInactivityTimer : public QObject {
29 Q_OBJECT
30public:
31 CandidateInactivityTimer(int touchId, QQuickItem *candidate,
32 AbstractTimer *timer,
33 QObject *parent = nullptr);
34
35 virtual ~CandidateInactivityTimer();
36
37 const int durationMs = 1000;
38
39Q_SIGNALS:
40 void candidateDefaulted(int touchId, QQuickItem *candidate);
41private Q_SLOTS:
42 void onTimeout();
43private:
44 AbstractTimer *m_timer;
45 int m_touchId;
46 QQuickItem *m_candidate;
47};
48
49} // namespace UbuntuGestures
50
51#endif // UBUNTUGESTURES_CANDIDATE_INACTIVITY_TIMER_H
520
=== removed file 'libs/UbuntuGestures/DebugHelpers.cpp'
--- libs/UbuntuGestures/DebugHelpers.cpp 2015-09-14 09:11:08 +0000
+++ libs/UbuntuGestures/DebugHelpers.cpp 1970-01-01 00:00:00 +0000
@@ -1,95 +0,0 @@
1/*
2 * Copyright (C) 2014 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include "DebugHelpers.h"
18#include <QTouchEvent>
19#include <QMouseEvent>
20
21QString touchPointStateToString(Qt::TouchPointState state)
22{
23 switch (state) {
24 case Qt::TouchPointPressed:
25 return QStringLiteral("pressed");
26 case Qt::TouchPointMoved:
27 return QStringLiteral("moved");
28 case Qt::TouchPointStationary:
29 return QStringLiteral("stationary");
30 case Qt::TouchPointReleased:
31 return QStringLiteral("released");
32 default:
33 return QStringLiteral("INVALID_STATE");
34 }
35}
36
37QString touchEventToString(const QTouchEvent *ev)
38{
39 QString message;
40
41 switch (ev->type()) {
42 case QEvent::TouchBegin:
43 message.append("TouchBegin ");
44 break;
45 case QEvent::TouchUpdate:
46 message.append("TouchUpdate ");
47 break;
48 case QEvent::TouchEnd:
49 message.append("TouchEnd ");
50 break;
51 case QEvent::TouchCancel:
52 message.append("TouchCancel ");
53 break;
54 default:
55 message.append("INVALID_TOUCH_EVENT_TYPE ");
56 }
57
58 foreach(const QTouchEvent::TouchPoint& touchPoint, ev->touchPoints()) {
59 message.append(
60 QStringLiteral("(id:%1, state:%2, scenePos:(%3,%4)) ")
61 .arg(touchPoint.id())
62 .arg(touchPointStateToString(touchPoint.state()))
63 .arg(touchPoint.scenePos().x())
64 .arg(touchPoint.scenePos().y())
65 );
66 }
67
68 return message;
69}
70
71QString mouseEventToString(const QMouseEvent *ev)
72{
73 QString message;
74
75 switch (ev->type()) {
76 case QEvent::MouseButtonPress:
77 message.append("MouseButtonPress ");
78 break;
79 case QEvent::MouseButtonRelease:
80 message.append("MouseButtonRelease ");
81 break;
82 case QEvent::MouseButtonDblClick:
83 message.append("MouseButtonDblClick ");
84 break;
85 case QEvent::MouseMove:
86 message.append("MouseMove ");
87 break;
88 default:
89 message.append("INVALID_MOUSE_EVENT_TYPE ");
90 }
91
92 message.append(QStringLiteral("pos(%1, %2)").arg(ev->x()).arg(ev->y()));
93
94 return message;
95}
960
=== removed file 'libs/UbuntuGestures/DebugHelpers.h'
--- libs/UbuntuGestures/DebugHelpers.h 2014-10-17 11:01:53 +0000
+++ libs/UbuntuGestures/DebugHelpers.h 1970-01-01 00:00:00 +0000
@@ -1,31 +0,0 @@
1/*
2 * Copyright (C) 2014 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef UBUNTUGESTURES_DEBUG_HELPER_H
18#define UBUNTUGESTURES_DEBUG_HELPER_H
19
20#include <QString>
21
22#include "UbuntuGesturesGlobal.h"
23
24class QMouseEvent;
25class QTouchEvent;
26
27UBUNTUGESTURES_EXPORT QString touchPointStateToString(Qt::TouchPointState state);
28UBUNTUGESTURES_EXPORT QString touchEventToString(const QTouchEvent *ev);
29UBUNTUGESTURES_EXPORT QString mouseEventToString(const QMouseEvent *ev);
30
31#endif // UBUNTUGESTURES_DEBUG_HELPER_H
320
=== removed file 'libs/UbuntuGestures/Pool.h'
--- libs/UbuntuGestures/Pool.h 2015-11-20 15:01:39 +0000
+++ libs/UbuntuGestures/Pool.h 1970-01-01 00:00:00 +0000
@@ -1,124 +0,0 @@
1/*
2 * Copyright (C) 2014 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef UBUNTUGESTURES_POOL_H
18#define UBUNTUGESTURES_POOL_H
19
20#include <QVector>
21
22#include "UbuntuGesturesGlobal.h"
23
24/*
25 An object pool.
26 Avoids unnecessary creations/initializations and deletions/destructions of items. Useful
27 in a scenario where items are created and destroyed very frequently but the total number
28 of items at any given time remains small. They're stored in a unordered fashion.
29
30 To be used in Pool, ItemType needs to have the following methods:
31
32 - ItemType();
33
34 A constructor that takes no parameters. An object contructed with it must return false if
35 isValid() is called.
36
37 - bool isValid() const;
38
39 Returns wheter the object holds a valid , "filled" state or is empty.
40 Used by Pool to check if the slot occupied by this object is actually available.
41
42 - void reset();
43
44 Resets the object to its initial, empty, state. After calling this method, isValid() must
45 return false.
46 */
47template <class ItemType> class Pool
48{
49public:
50 Pool() : m_lastUsedIndex(-1) {
51 }
52
53 class Iterator {
54 public:
55 Iterator() : index(-1), item(nullptr) {}
56 Iterator(int index, ItemType *item)
57 : index(index), item(item) {}
58
59 ItemType *operator->() const { return item; }
60 ItemType &operator*() const { return *item; }
61 ItemType &value() const { return *item; }
62
63 operator bool() const { return item != nullptr; }
64
65 int index;
66 ItemType *item;
67 };
68
69 ItemType &getEmptySlot() {
70 Q_ASSERT(m_lastUsedIndex < m_slots.size());
71
72 // Look for an in-between vacancy first
73 for (int i = 0; i < m_lastUsedIndex; ++i) {
74 ItemType &item = m_slots[i];
75 if (!item.isValid()) {
76 return item;
77 }
78 }
79
80 ++m_lastUsedIndex;
81 if (m_lastUsedIndex >= m_slots.size()) {
82 m_slots.resize(m_lastUsedIndex + 1);
83 }
84
85 return m_slots[m_lastUsedIndex];
86 }
87
88 void freeSlot(Iterator &iterator) {
89 m_slots[iterator.index].reset();
90 if (iterator.index == m_lastUsedIndex) {
91 do {
92 --m_lastUsedIndex;
93 } while (m_lastUsedIndex >= 0 && !m_slots.at(m_lastUsedIndex).isValid());
94 }
95 }
96
97 // Iterates through all valid items (i.e. the occupied slots)
98 // calling the given function, with the option of ending the loop early.
99 //
100 // bool Func(Iterator& item)
101 //
102 // Returning true means it wants to continue the "for" loop, false
103 // terminates the loop.
104 template<typename Func> void forEach(Func func) {
105 Iterator it;
106 for (it.index = 0; it.index <= m_lastUsedIndex; ++it.index) {
107 it.item = &m_slots[it.index];
108 if (!it.item->isValid())
109 continue;
110
111 if (!func(it))
112 break;
113 }
114 }
115
116 bool isEmpty() const { return m_lastUsedIndex == -1; }
117
118
119private:
120 QVector<ItemType> m_slots;
121 int m_lastUsedIndex;
122};
123
124#endif // UBUNTUGESTURES_POOL_H
1250
=== removed file 'libs/UbuntuGestures/TimeSource.cpp'
--- libs/UbuntuGestures/TimeSource.cpp 2015-04-10 21:16:37 +0000
+++ libs/UbuntuGestures/TimeSource.cpp 1970-01-01 00:00:00 +0000
@@ -1,49 +0,0 @@
1/*
2 * Copyright (C) 2013 - Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License, as
6 * published by the Free Software Foundation; either version 2.1 or 3.0
7 * of the License.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranties of
11 * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
12 * PURPOSE. See the applicable version of the GNU Lesser General Public
13 * License for more details.
14 *
15 * You should have received a copy of both the GNU Lesser General Public
16 * License along with this program. If not, see <http://www.gnu.org/licenses/>
17 *
18 * Authored by: Daniel d'Andrada <daniel.dandrada@canonical.com>
19 */
20
21#include "TimeSource.h"
22
23#include <QElapsedTimer>
24
25namespace UbuntuGestures {
26class RealTimeSourcePrivate {
27public:
28 QElapsedTimer timer;
29};
30}
31
32using namespace UbuntuGestures;
33
34RealTimeSource::RealTimeSource()
35 : UbuntuGestures::TimeSource()
36 , d(new RealTimeSourcePrivate)
37{
38 d->timer.start();
39}
40
41RealTimeSource::~RealTimeSource()
42{
43 delete d;
44}
45
46qint64 RealTimeSource::msecsSinceReference()
47{
48 return d->timer.elapsed();
49}
500
=== removed file 'libs/UbuntuGestures/TimeSource.h'
--- libs/UbuntuGestures/TimeSource.h 2015-04-10 21:16:37 +0000
+++ libs/UbuntuGestures/TimeSource.h 1970-01-01 00:00:00 +0000
@@ -1,64 +0,0 @@
1/*
2 * Copyright (C) 2013,2015 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License, as
6 * published by the Free Software Foundation; either version 2.1 or 3.0
7 * of the License.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranties of
11 * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
12 * PURPOSE. See the applicable version of the GNU Lesser General Public
13 * License for more details.
14 *
15 * You should have received a copy of both the GNU Lesser General Public
16 * License along with this program. If not, see <http://www.gnu.org/licenses/>
17 *
18 * Authored by: Daniel d'Andrada <daniel.dandrada@canonical.com>
19 */
20
21#ifndef UBUNTUGESTURES_TIMESOURCE_H
22#define UBUNTUGESTURES_TIMESOURCE_H
23
24#include "UbuntuGesturesGlobal.h"
25#include <QSharedPointer>
26
27namespace UbuntuGestures {
28/*
29 Interface for a time source.
30 */
31class UBUNTUGESTURES_EXPORT TimeSource {
32public:
33 virtual ~TimeSource() {}
34 /* Returns the current time in milliseconds since some reference time in the past. */
35 virtual qint64 msecsSinceReference() = 0;
36};
37typedef QSharedPointer<TimeSource> SharedTimeSource;
38
39/*
40 Implementation of a time source
41 */
42class RealTimeSourcePrivate;
43class UBUNTUGESTURES_EXPORT RealTimeSource : public TimeSource {
44public:
45 RealTimeSource();
46 virtual ~RealTimeSource();
47 qint64 msecsSinceReference() override;
48private:
49 RealTimeSourcePrivate *d;
50};
51
52/*
53 A fake time source, useful for tests
54 */
55class FakeTimeSource : public TimeSource {
56public:
57 FakeTimeSource() { m_msecsSinceReference = 0; }
58 qint64 msecsSinceReference() override { return m_msecsSinceReference; }
59 qint64 m_msecsSinceReference;
60};
61
62} // namespace UbuntuGestures
63
64#endif // UBUNTUGESTURES_TIMESOURCE_H
650
=== removed file 'libs/UbuntuGestures/Timer.cpp'
--- libs/UbuntuGestures/Timer.cpp 2015-04-24 13:19:24 +0000
+++ libs/UbuntuGestures/Timer.cpp 1970-01-01 00:00:00 +0000
@@ -1,152 +0,0 @@
1/*
2 * Copyright (C) 2014-2015 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include "Timer.h"
18
19namespace UbuntuGestures {
20
21Timer::Timer(QObject *parent) : AbstractTimer(parent)
22{
23 m_timer.setSingleShot(false);
24 connect(&m_timer, &QTimer::timeout, this, &AbstractTimer::timeout);
25}
26
27int Timer::interval() const
28{
29 return m_timer.interval();
30}
31
32void Timer::setInterval(int msecs)
33{
34 m_timer.setInterval(msecs);
35}
36
37void Timer::start()
38{
39 m_timer.start();
40 AbstractTimer::start();
41}
42
43void Timer::stop()
44{
45 m_timer.stop();
46 AbstractTimer::stop();
47}
48
49bool Timer::isSingleShot() const
50{
51 return m_timer.isSingleShot();
52}
53
54void Timer::setSingleShot(bool value)
55{
56 m_timer.setSingleShot(value);
57}
58
59/////////////////////////////////// FakeTimer //////////////////////////////////
60
61FakeTimer::FakeTimer(const SharedTimeSource &timeSource, QObject *parent)
62 : UbuntuGestures::AbstractTimer(parent)
63 , m_interval(0)
64 , m_singleShot(false)
65 , m_timeSource(timeSource)
66{
67}
68
69void FakeTimer::update()
70{
71 if (!isRunning()) {
72 return;
73 }
74
75 if (m_nextTimeoutTime <= m_timeSource->msecsSinceReference()) {
76 if (isSingleShot()) {
77 stop();
78 } else {
79 m_nextTimeoutTime += interval();
80 }
81 Q_EMIT timeout();
82 }
83}
84
85void FakeTimer::start()
86{
87 AbstractTimer::start();
88 m_nextTimeoutTime = m_timeSource->msecsSinceReference() + (qint64)interval();
89}
90
91int FakeTimer::interval() const
92{
93 return m_interval;
94}
95
96void FakeTimer::setInterval(int msecs)
97{
98 m_interval = msecs;
99}
100
101bool FakeTimer::isSingleShot() const
102{
103 return m_singleShot;
104}
105
106void FakeTimer::setSingleShot(bool value)
107{
108 m_singleShot = value;
109}
110
111/////////////////////////////////// FakeTimerFactory //////////////////////////////////
112
113FakeTimerFactory::FakeTimerFactory()
114{
115 m_timeSource.reset(new FakeTimeSource);
116}
117
118void FakeTimerFactory::updateTime(qint64 targetTime)
119{
120 qint64 minTimeoutTime = targetTime;
121
122 for (int i = 0; i < timers.count(); ++i) {
123 FakeTimer *timer = timers[i].data();
124 if (timer && timer->isRunning() && timer->nextTimeoutTime() < minTimeoutTime) {
125 minTimeoutTime = timer->nextTimeoutTime();
126 }
127 }
128
129 m_timeSource->m_msecsSinceReference = minTimeoutTime;
130
131 for (int i = 0; i < timers.count(); ++i) {
132 FakeTimer *timer = timers[i].data();
133 if (timer) {
134 timer->update();
135 }
136 }
137
138 if (m_timeSource->msecsSinceReference() < targetTime) {
139 updateTime(targetTime);
140 }
141}
142
143AbstractTimer *FakeTimerFactory::createTimer(QObject *parent)
144{
145 FakeTimer *fakeTimer = new FakeTimer(m_timeSource, parent);
146
147 timers.append(fakeTimer);
148
149 return fakeTimer;
150}
151
152} // namespace UbuntuGestures
1530
=== removed file 'libs/UbuntuGestures/Timer.h'
--- libs/UbuntuGestures/Timer.h 2016-03-29 03:47:39 +0000
+++ libs/UbuntuGestures/Timer.h 1970-01-01 00:00:00 +0000
@@ -1,122 +0,0 @@
1/*
2 * Copyright (C) 2014 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef UBUNTUGESTURES_TIMER_H
18#define UBUNTUGESTURES_TIMER_H
19
20#include "UbuntuGesturesGlobal.h"
21#include "TimeSource.h"
22
23#include <QObject>
24#include <QPointer>
25#include <QTimer>
26
27namespace UbuntuGestures {
28
29/* Defines an interface for a Timer. Useful for tests. */
30class UBUNTUGESTURES_EXPORT AbstractTimer : public QObject
31{
32 Q_OBJECT
33public:
34 AbstractTimer(QObject *parent) : QObject(parent), m_isRunning(false) {}
35 virtual int interval() const = 0;
36 virtual void setInterval(int msecs) = 0;
37 virtual void start() { m_isRunning = true; }
38 virtual void start(int msecs)
39 {
40 setInterval(msecs);
41 start();
42 }
43 virtual void stop() { m_isRunning = false; }
44 bool isRunning() const { return m_isRunning; }
45 virtual bool isSingleShot() const = 0;
46 virtual void setSingleShot(bool value) = 0;
47Q_SIGNALS:
48 void timeout();
49private:
50 bool m_isRunning;
51};
52
53/* Essentially a QTimer wrapper */
54class UBUNTUGESTURES_EXPORT Timer : public AbstractTimer
55{
56 Q_OBJECT
57public:
58 Timer(QObject *parent = nullptr);
59
60 int interval() const override;
61 void setInterval(int msecs) override;
62 void start() override;
63 void stop() override;
64 bool isSingleShot() const override;
65 void setSingleShot(bool value) override;
66private:
67 QTimer m_timer;
68};
69
70/* For tests */
71class UBUNTUGESTURES_EXPORT FakeTimer : public AbstractTimer
72{
73 Q_OBJECT
74public:
75 FakeTimer(const SharedTimeSource &timeSource, QObject *parent = nullptr);
76
77 void update();
78 qint64 nextTimeoutTime() const { return m_nextTimeoutTime; }
79
80 int interval() const override;
81 void setInterval(int msecs) override;
82 void start() override;
83 bool isSingleShot() const override;
84 void setSingleShot(bool value) override;
85private:
86 int m_interval;
87 bool m_singleShot;
88 SharedTimeSource m_timeSource;
89 qint64 m_nextTimeoutTime;
90};
91
92class UBUNTUGESTURES_EXPORT AbstractTimerFactory
93{
94public:
95 virtual ~AbstractTimerFactory() {}
96 virtual AbstractTimer *createTimer(QObject *parent = nullptr) = 0;
97};
98
99class UBUNTUGESTURES_EXPORT TimerFactory : public AbstractTimerFactory
100{
101public:
102 AbstractTimer *createTimer(QObject *parent = nullptr) override { return new Timer(parent); }
103};
104
105class UBUNTUGESTURES_EXPORT FakeTimerFactory : public AbstractTimerFactory
106{
107public:
108 FakeTimerFactory();
109 virtual ~FakeTimerFactory() {}
110
111 void updateTime(qint64 msecsSinceReference);
112 QSharedPointer<TimeSource> timeSource() { return m_timeSource; }
113
114 AbstractTimer *createTimer(QObject *parent = nullptr) override;
115 QList<QPointer<FakeTimer>> timers;
116private:
117 QSharedPointer<FakeTimeSource> m_timeSource;
118};
119
120} // namespace UbuntuGestures
121
122#endif // UBUNTUGESTURES_TIMER_H
1230
=== removed file 'libs/UbuntuGestures/TouchOwnershipEvent.cpp'
--- libs/UbuntuGestures/TouchOwnershipEvent.cpp 2014-10-01 13:20:32 +0000
+++ libs/UbuntuGestures/TouchOwnershipEvent.cpp 1970-01-01 00:00:00 +0000
@@ -1,35 +0,0 @@
1/*
2 * Copyright (C) 2014 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include "TouchOwnershipEvent.h"
18
19QEvent::Type TouchOwnershipEvent::m_touchOwnershipType = (QEvent::Type)-1;
20
21TouchOwnershipEvent::TouchOwnershipEvent(int touchId, bool gained)
22 : QEvent(touchOwnershipEventType())
23 , m_touchId(touchId)
24 , m_gained(gained)
25{
26}
27
28QEvent::Type TouchOwnershipEvent::touchOwnershipEventType()
29{
30 if (m_touchOwnershipType == (QEvent::Type)-1) {
31 m_touchOwnershipType = (QEvent::Type)registerEventType();
32 }
33
34 return m_touchOwnershipType;
35}
360
=== removed file 'libs/UbuntuGestures/TouchOwnershipEvent.h'
--- libs/UbuntuGestures/TouchOwnershipEvent.h 2014-10-01 13:20:32 +0000
+++ libs/UbuntuGestures/TouchOwnershipEvent.h 1970-01-01 00:00:00 +0000
@@ -1,50 +0,0 @@
1/*
2 * Copyright (C) 2014 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef UBUNTU_TOUCHOWNERSHIPEVENT_H
18#define UBUNTU_TOUCHOWNERSHIPEVENT_H
19
20#include <QEvent>
21#include "UbuntuGesturesGlobal.h"
22
23/*
24 When an item get an ownership event for a touch it can grab/steal that touch
25 with a clean conscience.
26 */
27class UBUNTUGESTURES_EXPORT TouchOwnershipEvent : public QEvent
28{
29public:
30 TouchOwnershipEvent(int touchId, bool gained);
31
32 static Type touchOwnershipEventType();
33
34 /*
35 Whether ownership was gained (true) or lost (false)
36 */
37 bool gained() const { return m_gained; }
38
39 /*
40 Id of the touch whose ownership was granted.
41 */
42 int touchId() const { return m_touchId; }
43
44private:
45 static Type m_touchOwnershipType;
46 int m_touchId;
47 bool m_gained;
48};
49
50#endif // UBUNTU_TOUCHOWNERSHIPEVENT_H
510
=== removed file 'libs/UbuntuGestures/TouchRegistry.cpp'
--- libs/UbuntuGestures/TouchRegistry.cpp 2016-03-29 03:47:39 +0000
+++ libs/UbuntuGestures/TouchRegistry.cpp 1970-01-01 00:00:00 +0000
@@ -1,553 +0,0 @@
1/*
2 * Copyright (C) 2014-2015 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include "TouchRegistry.h"
18
19#include <QCoreApplication>
20#include <QDebug>
21
22#pragma GCC diagnostic push
23#pragma GCC diagnostic ignored "-pedantic"
24#include <private/qquickitem_p.h>
25#pragma GCC diagnostic pop
26
27#include "CandidateInactivityTimer.h"
28#include "Timer.h"
29#include "TouchOwnershipEvent.h"
30#include "UnownedTouchEvent.h"
31
32#define TOUCHREGISTRY_DEBUG 0
33
34#if TOUCHREGISTRY_DEBUG
35 #include "DebugHelpers.h"
36 #define UG_DEBUG qDebug() << "[TouchRegistry]"
37#endif // TOUCHREGISTRY_DEBUG
38
39using namespace UbuntuGestures;
40
41TouchRegistry *TouchRegistry::m_instance = nullptr;
42
43TouchRegistry::TouchRegistry(QObject *parent)
44 : QObject(parent)
45 , m_inDispatchLoop(false)
46 , m_timerFactory(new TimerFactory)
47{
48}
49
50TouchRegistry::~TouchRegistry()
51{
52 Q_ASSERT(m_instance != nullptr);
53 m_instance = nullptr;
54 delete m_timerFactory;
55}
56
57TouchRegistry *TouchRegistry::instance()
58{
59 if (m_instance == nullptr) {
60 m_instance = new TouchRegistry;
61 }
62 return m_instance;
63}
64
65void TouchRegistry::setTimerFactory(AbstractTimerFactory *timerFactory)
66{
67 delete m_timerFactory;
68 m_timerFactory = timerFactory;
69}
70
71void TouchRegistry::update(const QTouchEvent *event)
72{
73 #if TOUCHREGISTRY_DEBUG
74 UG_DEBUG << "got" << qPrintable(touchEventToString(event));
75 #endif
76
77 const QList<QTouchEvent::TouchPoint> &touchPoints = event->touchPoints();
78 for (int i = 0; i < touchPoints.count(); ++i) {
79 const QTouchEvent::TouchPoint &touchPoint = touchPoints.at(i);
80 if (touchPoint.state() == Qt::TouchPointPressed) {
81 TouchInfo &touchInfo = m_touchInfoPool.getEmptySlot();
82 touchInfo.init(touchPoint.id());
83 } else if (touchPoint.state() == Qt::TouchPointReleased) {
84 Pool<TouchInfo>::Iterator touchInfo = findTouchInfo(touchPoint.id());
85
86 touchInfo->physicallyEnded = true;
87 }
88 }
89
90 deliverTouchUpdatesToUndecidedCandidatesAndWatchers(event);
91
92 freeEndedTouchInfos();
93}
94
95void TouchRegistry::deliverTouchUpdatesToUndecidedCandidatesAndWatchers(const QTouchEvent *event)
96{
97 // TODO: Look into how we could optimize this whole thing.
98 // Although it's not really a problem as we should have at most two candidates
99 // for each point and there should not be many active points at any given moment.
100 // But having three nested for-loops does scare.
101
102 const QList<QTouchEvent::TouchPoint> &updatedTouchPoints = event->touchPoints();
103
104 // Maps an item to the touches in this event he should be informed about.
105 // E.g.: a QTouchEvent might have three touches but a given item might be interested in only
106 // one of them. So he will get a UnownedTouchEvent from this QTouchEvent containing only that
107 // touch point.
108 QHash<QQuickItem*, QList<int>> touchIdsForItems;
109
110 // Build touchIdsForItems
111 m_touchInfoPool.forEach([&](Pool<TouchInfo>::Iterator &touchInfo) {
112 if (touchInfo->isOwned() && touchInfo->watchers.isEmpty())
113 return true;
114
115 for (int j = 0; j < updatedTouchPoints.count(); ++j) {
116 if (updatedTouchPoints[j].id() == touchInfo->id) {
117 if (!touchInfo->isOwned()) {
118 for (int i = 0; i < touchInfo->candidates.count(); ++i) {
119 CandidateInfo &candidate = touchInfo->candidates[i];
120 Q_ASSERT(!candidate.item.isNull());
121 if (candidate.state != CandidateInfo::InterimOwner) {
122 touchIdsForItems[candidate.item.data()].append(touchInfo->id);
123 }
124 }
125 }
126
127 const QList<QPointer<QQuickItem>> &watchers = touchInfo->watchers;
128 for (int i = 0; i < watchers.count(); ++i) {
129 if (!watchers[i].isNull()) {
130 touchIdsForItems[watchers[i].data()].append(touchInfo->id);
131 }
132 }
133
134 return true;
135 }
136 }
137
138 return true;
139 });
140
141 // TODO: Consider what happens if an item calls any of TouchRegistry's public methods
142 // from the event handler callback.
143 m_inDispatchLoop = true;
144 auto it = touchIdsForItems.constBegin();
145 while (it != touchIdsForItems.constEnd()) {
146 QQuickItem *item = it.key();
147 const QList<int> &touchIds = it.value();
148 dispatchPointsToItem(event, touchIds, item);
149 ++it;
150 };
151 m_inDispatchLoop = false;
152}
153
154void TouchRegistry::freeEndedTouchInfos()
155{
156 m_touchInfoPool.forEach([&](Pool<TouchInfo>::Iterator &touchInfo) {
157 if (touchInfo->ended()) {
158 m_touchInfoPool.freeSlot(touchInfo);
159 }
160 return true;
161 });
162}
163
164/*
165 Extracts the touches with the given touchIds from event and send them in a
166 UnownedTouchEvent to the given item
167 */
168void TouchRegistry::dispatchPointsToItem(const QTouchEvent *event, const QList<int> &touchIds,
169 QQuickItem *item)
170{
171 Qt::TouchPointStates touchPointStates = 0;
172 QList<QTouchEvent::TouchPoint> touchPoints;
173
174 const QList<QTouchEvent::TouchPoint> &allTouchPoints = event->touchPoints();
175
176 QTransform windowToCandidateTransform = QQuickItemPrivate::get(item)->windowToItemTransform();
177 QMatrix4x4 windowToCandidateMatrix(windowToCandidateTransform);
178
179 for (int i = 0; i < allTouchPoints.count(); ++i) {
180 const QTouchEvent::TouchPoint &originalTouchPoint = allTouchPoints[i];
181 if (touchIds.contains(originalTouchPoint.id())) {
182 QTouchEvent::TouchPoint touchPoint = originalTouchPoint;
183
184 translateTouchPointFromScreenToWindowCoords(touchPoint);
185
186 // Set the point's local coordinates to that of the item
187 touchPoint.setRect(windowToCandidateTransform.mapRect(touchPoint.sceneRect()));
188 touchPoint.setStartPos(windowToCandidateTransform.map(touchPoint.startScenePos()));
189 touchPoint.setLastPos(windowToCandidateTransform.map(touchPoint.lastScenePos()));
190 touchPoint.setVelocity(windowToCandidateMatrix.mapVector(touchPoint.velocity()).toVector2D());
191
192 touchPoints.append(touchPoint);
193 touchPointStates |= touchPoint.state();
194 }
195 }
196
197 QTouchEvent *eventForItem = new QTouchEvent(event->type(),
198 event->device(),
199 event->modifiers(),
200 touchPointStates,
201 touchPoints);
202 eventForItem->setWindow(event->window());
203 eventForItem->setTimestamp(event->timestamp());
204 eventForItem->setTarget(event->target());
205
206 UnownedTouchEvent unownedTouchEvent(eventForItem);
207
208 #if TOUCHREGISTRY_DEBUG
209 UG_DEBUG << "Sending unowned" << qPrintable(touchEventToString(eventForItem))
210 << "to" << item;
211 #endif
212
213 QCoreApplication::sendEvent(item, &unownedTouchEvent);
214}
215
216void TouchRegistry::translateTouchPointFromScreenToWindowCoords(QTouchEvent::TouchPoint &touchPoint)
217{
218 touchPoint.setScreenRect(touchPoint.sceneRect());
219 touchPoint.setStartScreenPos(touchPoint.startScenePos());
220 touchPoint.setLastScreenPos(touchPoint.lastScenePos());
221
222 touchPoint.setSceneRect(touchPoint.rect());
223 touchPoint.setStartScenePos(touchPoint.startPos());
224 touchPoint.setLastScenePos(touchPoint.lastPos());
225}
226
227bool TouchRegistry::eventFilter(QObject *watched, QEvent *event)
228{
229 Q_UNUSED(watched);
230
231 switch (event->type()) {
232 case QEvent::TouchBegin:
233 case QEvent::TouchUpdate:
234 case QEvent::TouchEnd:
235 case QEvent::TouchCancel:
236 update(static_cast<QTouchEvent*>(event));
237 break;
238 default:
239 // do nothing
240 break;
241 }
242
243 // Do not filter out the event. i.e., let it be handled further as
244 // we're just monitoring events
245 return false;
246}
247
248void TouchRegistry::addCandidateOwnerForTouch(int id, QQuickItem *candidate)
249{
250 #if TOUCHREGISTRY_DEBUG
251 UG_DEBUG << "addCandidateOwnerForTouch id" << id << "candidate" << candidate;
252 #endif
253
254 Pool<TouchInfo>::Iterator touchInfo = findTouchInfo(id);
255 if (!touchInfo) { qFatal("TouchRegistry: Failed to find TouchInfo"); }
256
257 if (touchInfo->isOwned()) {
258 qWarning("TouchRegistry: trying to add candidate owner for a touch that's already owned");
259 return;
260 }
261
262 // TODO: Check if candidate already exists
263
264 CandidateInfo candidateInfo;
265 candidateInfo.state = CandidateInfo::Undecided;
266 candidateInfo.item = candidate;
267 candidateInfo.inactivityTimer = new CandidateInactivityTimer(id, candidate,
268 m_timerFactory->createTimer(),
269 this);
270 connect(candidateInfo.inactivityTimer, &CandidateInactivityTimer::candidateDefaulted,
271 this, &TouchRegistry::rejectCandidateOwnerForTouch);
272
273 touchInfo->candidates.append(candidateInfo);
274
275 connect(candidate, &QObject::destroyed, this, [=](){ pruneNullCandidatesForTouch(id); });
276}
277
278void TouchRegistry::addTouchWatcher(int touchId, QQuickItem *watcher)
279{
280 #if TOUCHREGISTRY_DEBUG
281 UG_DEBUG << "addTouchWatcher id" << touchId << "watcher" << watcher;
282 #endif
283
284 Pool<TouchInfo>::Iterator touchInfo = findTouchInfo(touchId);
285 if (!touchInfo) { qFatal("TouchRegistry: Failed to find TouchInfo"); }
286
287 // TODO: Check if watcher already exists
288
289 touchInfo->watchers.append(watcher);
290}
291
292void TouchRegistry::removeCandidateOwnerForTouch(int id, QQuickItem *candidate)
293{
294 #if TOUCHREGISTRY_DEBUG
295 UG_DEBUG << "removeCandidateOwnerForTouch id" << id << "candidate" << candidate;
296 #endif
297
298 Pool<TouchInfo>::Iterator touchInfo = findTouchInfo(id);
299 if (!touchInfo) { qFatal("TouchRegistry: Failed to find TouchInfo"); }
300
301
302 // TODO: check if the candidate is in fact the owner of the touch
303
304 bool removed = false;
305 for (int i = 0; i < touchInfo->candidates.count() && !removed; ++i) {
306 if (touchInfo->candidates[i].item == candidate) {
307 removeCandidateOwnerForTouchByIndex(touchInfo, i);
308 removed = true;
309 }
310 }
311}
312
313void TouchRegistry::pruneNullCandidatesForTouch(int touchId)
314{
315 #if TOUCHREGISTRY_DEBUG
316 UG_DEBUG << "pruneNullCandidatesForTouch touchId" << touchId;
317 #endif
318
319 Pool<TouchInfo>::Iterator touchInfo = findTouchInfo(touchId);
320 if (!touchInfo) {
321 // doesn't matter as touch is already gone.
322 return;
323 }
324
325 int i = 0;
326 while (i < touchInfo->candidates.count()) {
327 if (touchInfo->candidates[i].item.isNull()) {
328 removeCandidateOwnerForTouchByIndex(touchInfo, i);
329 } else {
330 ++i;
331 }
332 }
333}
334
335void TouchRegistry::removeCandidateOwnerForTouchByIndex(Pool<TouchRegistry::TouchInfo>::Iterator &touchInfo,
336 int candidateIndex)
337{
338 // TODO: check if the candidate is in fact the owner of the touch
339
340 Q_ASSERT(candidateIndex < touchInfo->candidates.count());
341
342 if (candidateIndex == 0 && touchInfo->candidates[candidateIndex].state != CandidateInfo::Undecided) {
343 qCritical("TouchRegistry: touch owner is being removed.");
344 }
345 removeCandidateHelper(touchInfo, candidateIndex);
346
347 if (candidateIndex == 0) {
348 // the top candidate has been removed. if the new top candidate
349 // wants the touch let him know he's now the owner.
350 if (touchInfo->isOwned()) {
351 touchInfo->notifyCandidatesOfOwnershipResolution();
352 }
353 }
354
355 if (!m_inDispatchLoop && touchInfo->ended()) {
356 m_touchInfoPool.freeSlot(touchInfo);
357 }
358}
359
360void TouchRegistry::requestTouchOwnership(int id, QQuickItem *candidate)
361{
362 Pool<TouchInfo>::Iterator touchInfo = findTouchInfo(id);
363 if (!touchInfo) { qFatal("TouchRegistry: Failed to find TouchInfo"); }
364
365 Q_ASSERT(!touchInfo->isOwned());
366
367 int candidateIndex = -1;
368 for (int i = 0; i < touchInfo->candidates.count(); ++i) {
369 CandidateInfo &candidateInfo = touchInfo->candidates[i];
370 if (candidateInfo.item == candidate) {
371 candidateInfo.state = CandidateInfo::Requested;
372 delete candidateInfo.inactivityTimer;
373 candidateInfo.inactivityTimer = nullptr;
374 candidateIndex = i;
375 break;
376 }
377 }
378 #if TOUCHREGISTRY_DEBUG
379 UG_DEBUG << "requestTouchOwnership id " << id << "candidate" << candidate << "index: " << candidateIndex;
380 #endif
381
382 // add it as a candidate if not present yet
383 if (candidateIndex < 0) {
384 CandidateInfo candidateInfo;
385 candidateInfo.state = CandidateInfo::InterimOwner;
386 candidateInfo.item = candidate;
387 candidateInfo.inactivityTimer = nullptr;
388 touchInfo->candidates.append(candidateInfo);
389 // it's the last one
390 candidateIndex = touchInfo->candidates.count() - 1;
391 connect(candidate, &QObject::destroyed, this, [=](){ pruneNullCandidatesForTouch(id); });
392 }
393
394 // If it's the top candidate it means it's now the owner. Let
395 // it know about it.
396 if (candidateIndex == 0) {
397 touchInfo->notifyCandidatesOfOwnershipResolution();
398 }
399}
400
401Pool<TouchRegistry::TouchInfo>::Iterator TouchRegistry::findTouchInfo(int id)
402{
403 Pool<TouchInfo>::Iterator touchInfo;
404
405 m_touchInfoPool.forEach([&](Pool<TouchInfo>::Iterator &someTouchInfo) -> bool {
406 if (someTouchInfo->id == id) {
407 touchInfo = someTouchInfo;
408 return false;
409 } else {
410 return true;
411 }
412 });
413
414 return touchInfo;
415}
416
417
418void TouchRegistry::rejectCandidateOwnerForTouch(int id, QQuickItem *candidate)
419{
420 // NB: It's technically possible that candidate is a dangling pointer at this point.
421 // Although that would most likely be due to a bug in our code.
422 // In any case, only dereference it after it's confirmed that it indeed exists.
423
424 #if TOUCHREGISTRY_DEBUG
425 UG_DEBUG << "rejectCandidateOwnerForTouch id" << id << "candidate" << (void*)candidate;
426 #endif
427
428 Pool<TouchInfo>::Iterator touchInfo = findTouchInfo(id);
429 if (!touchInfo) {
430 #if TOUCHREGISTRY_DEBUG
431 UG_DEBUG << "Failed to find TouchInfo for id" << id;
432 #endif
433 return;
434 }
435
436 int rejectedCandidateIndex = -1;
437
438 // Check if the given candidate is valid and still undecided
439 for (int i = 0; i < touchInfo->candidates.count() && rejectedCandidateIndex == -1; ++i) {
440 CandidateInfo &candidateInfo = touchInfo->candidates[i];
441 if (candidateInfo.item == candidate) {
442 Q_ASSERT(i > 0 || candidateInfo.state == CandidateInfo::Undecided);
443 if (i == 0 && candidateInfo.state != CandidateInfo::Undecided) {
444 qCritical() << "TouchRegistry: Can't reject item (" << (void*)candidate
445 << ") as it already owns touch" << id;
446 return;
447 } else {
448 // we found the guy and it's all fine.
449 rejectedCandidateIndex = i;
450 }
451 }
452 }
453
454 // If we reached this point it's because the given candidate exists and is indeed undecided.
455
456 Q_ASSERT(rejectedCandidateIndex >= 0 && rejectedCandidateIndex < touchInfo->candidates.size());
457
458 {
459 TouchOwnershipEvent lostOwnershipEvent(id, false /*gained*/);
460 QCoreApplication::sendEvent(candidate, &lostOwnershipEvent);
461 }
462
463 removeCandidateHelper(touchInfo, rejectedCandidateIndex);
464
465 if (rejectedCandidateIndex == 0) {
466 // the top candidate has been removed. if the new top candidate
467 // wants the touch let him know he's now the owner.
468 if (touchInfo->isOwned()) {
469 touchInfo->notifyCandidatesOfOwnershipResolution();
470 }
471 }
472}
473
474void TouchRegistry::removeCandidateHelper(Pool<TouchInfo>::Iterator &touchInfo, int candidateIndex)
475{
476 {
477 CandidateInfo &candidateInfo = touchInfo->candidates[candidateIndex];
478
479 delete candidateInfo.inactivityTimer;
480 candidateInfo.inactivityTimer = nullptr;
481
482 if (candidateInfo.item) {
483 disconnect(candidateInfo.item.data(), nullptr, this, nullptr);
484 }
485 }
486 touchInfo->candidates.removeAt(candidateIndex);
487}
488
489////////////////////////////////////// TouchRegistry::TouchInfo ////////////////////////////////////
490
491TouchRegistry::TouchInfo::TouchInfo(int id)
492{
493 init(id);
494}
495
496void TouchRegistry::TouchInfo::reset()
497{
498 id = -1;
499
500 for (int i = 0; i < candidates.count(); ++i) {
501 CandidateInfo &candidate = candidates[i];
502 delete candidate.inactivityTimer;
503 candidate.inactivityTimer.clear(); // shoundn't be needed but anyway...
504 }
505}
506
507void TouchRegistry::TouchInfo::init(int id)
508{
509 this->id = id;
510 physicallyEnded = false;
511 candidates.clear();
512 watchers.clear();
513}
514
515bool TouchRegistry::TouchInfo::isOwned() const
516{
517 return !candidates.isEmpty() && candidates.first().state != CandidateInfo::Undecided;
518}
519
520bool TouchRegistry::TouchInfo::ended() const
521{
522 Q_ASSERT(isValid());
523 return physicallyEnded && (isOwned() || candidates.isEmpty());
524}
525
526void TouchRegistry::TouchInfo::notifyCandidatesOfOwnershipResolution()
527{
528 Q_ASSERT(isOwned());
529
530 #if TOUCHREGISTRY_DEBUG
531 UG_DEBUG << "sending TouchOwnershipEvent(id =" << id
532 << " gained) to candidate" << candidates[0].item;
533 #endif
534
535 // need to take a copy of the item list in case
536 // we call back in to remove candidate during the lost ownership event.
537 QList<QPointer<QQuickItem>> items;
538 Q_FOREACH(const CandidateInfo& info, candidates) {
539 items << info.item;
540 }
541
542 TouchOwnershipEvent gainedOwnershipEvent(id, true /*gained*/);
543 QCoreApplication::sendEvent(items[0], &gainedOwnershipEvent);
544
545 TouchOwnershipEvent lostOwnershipEvent(id, false /*gained*/);
546 for (int i = 1; i < items.count(); ++i) {
547 #if TOUCHREGISTRY_DEBUG
548 UG_DEBUG << "sending TouchOwnershipEvent(id =" << id << " lost) to candidate"
549 << items[i];
550 #endif
551 QCoreApplication::sendEvent(items[i], &lostOwnershipEvent);
552 }
553}
5540
=== removed file 'libs/UbuntuGestures/TouchRegistry.h'
--- libs/UbuntuGestures/TouchRegistry.h 2015-07-20 16:30:40 +0000
+++ libs/UbuntuGestures/TouchRegistry.h 1970-01-01 00:00:00 +0000
@@ -1,201 +0,0 @@
1/*
2 * Copyright (C) 2014 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef UNITY_TOUCHREGISTRY_H
18#define UNITY_TOUCHREGISTRY_H
19
20#include <QQuickItem>
21#include <QObject>
22#include <QPointer>
23#include <QTouchEvent>
24#include <QVector>
25
26#include "UbuntuGesturesGlobal.h"
27#include "CandidateInactivityTimer.h"
28#include "Timer.h"
29#include "Pool.h"
30
31namespace UbuntuGestures {
32 class AbstractTimerFactory;
33}
34
35/*
36 Where the ownership of touches is registered.
37
38 Singleton used for adding a touch point ownership model analogous to the one
39 described in the XInput 2.2 protocol[1] on top of the existing input dispatch logic in QQuickWindow.
40
41 It provides a much more flexible and powerful way of dealing with pointer ownership than the existing
42 mechanisms in Qt. Namely QQuickItem::grabTouchPoints, QuickItem::keepTouchGrab,
43 QQuickItem::setFiltersChildMouseEvents, QQuickItem::ungrabTouchPoints and QQuickItem::touchUngrabEvent.
44
45 Usage:
46
47 1- An item receives a a new touch point. If he's not sure whether he wants it yet, he calls:
48 TouchRegistry::instance()->addCandidateOwnerForTouch(touchId, this);
49 touchEvent->ignore();
50 Ignoring the event is crucial so that it can be seen by other interested parties, which will
51 behave similarly.
52
53 2- That item will then start receiving UnownedTouchEvents for that touch from step 1. Once he's
54 made a decision he calls either:
55 TouchRegistry::instance()->requestTouchOwnership(touchId, this);
56 If he wants the touch point or:
57 TouchRegistry::instance()->removeCandidateOwnerForTouch(touchId, this);
58  if he does not want it.
59
60 Candidates are put in a priority queue. The first one to call addCandidateOwnerForTouch() will
61 take precedence over the others for receiving ownership over the touch point (from now on called
62 simply top-candidate).
63
64 If the top-candidate calls requestTouchOwnership() he will immediately receive a
65 TouchOwnershipEvent(gained=true) for that touch point. He can then safely call
66 QQuickItem::grabTouchPoints to actually get the owned touch points. The other candidates
67 will receive TouchOwnershipEvent(gained=false) and will no longer receive UnownedTouchEvents
68 for that touch point. They will have to undo whatever action they were performing with that
69 touch point.
70
71 But if the top-candidate calls removeCandidateOwnerForTouch() instead, he's popped from the
72 candidacy queue and ownership is given to the new top-most candidate if he has already
73 made his decision, that is.
74
75 The TouchRegistry cannot enforce the results of this pointer ownership negotiation (i.e.,
76 who gets to grab the touch points) as that would clash with QQuickWindow's input event
77 dispatching logic. The candidates have to respect the decision and grab the touch points
78 themselves.
79
80 If an item wants ownership over touches as soon as he receives the TouchBegin for them, his step 1
81 would be instead:
82 TouchRegistry::instance()->requestTouchOwnership(touchId, this);
83 touchEvent->accept();
84 He won't get any UnownedTouchEvent for that touch as he is already the interim owner (ie, QQuickWindow
85 will keep sending touch updates to him already). Eventually he will be notified once ownership has
86 been granted to him (from TouchRegistry perspective), from which point onwards he could safely assume
87 other TouchRegistry users wouldn't snatch this touch away from him.
88
89 Items oblivious to TouchRegistry will lose their touch points without warning, just like in plain Qt.
90
91 [1] - http://www.x.org/releases/X11R7.7/doc/inputproto/XI2proto.txt (see multitouch-ownership)
92 */
93class UBUNTUGESTURES_EXPORT TouchRegistry : public QObject
94{
95 Q_OBJECT
96public:
97 virtual ~TouchRegistry();
98
99 // Returns a pointer to the application's TouchRegistry instance.
100 static TouchRegistry *instance();
101
102 void update(const QTouchEvent *event);
103
104 // Calls update() if the given event is a QTouchEvent
105 bool eventFilter(QObject *watched, QEvent *event) override;
106
107 // An item that might later request ownership over the given touch point.
108 // He will be kept informed about that touch point through UnownedTouchEvents
109 // All candidates must eventually decide whether they want to own the touch point
110 // or not. That decision is informed through requestTouchOwnership() or
111 // removeCandidateOwnerForTouch()
112 void addCandidateOwnerForTouch(int id, QQuickItem *candidate);
113
114 // The same as rejecting ownership of a touch
115 void removeCandidateOwnerForTouch(int id, QQuickItem *candidate);
116
117 // The candidate object wants to be the owner of the touch with the given id.
118 // If he's currently the oldest/top-most candidate, he will get an ownership
119 // event immediately. If not, he will get ownership if (or once) he becomes the
120 // top-most candidate.
121 void requestTouchOwnership(int id, QQuickItem *candidate);
122
123 // An item that has no interest (effective or potential) in owning a touch point
124 // but would nonetheless like to be kept up-to-date on its state.
125 void addTouchWatcher(int touchId, QQuickItem *watcherItem);
126
127 // Useful for tests, where you should use fake timers
128 void setTimerFactory(UbuntuGestures::AbstractTimerFactory *timerFactory);
129
130private Q_SLOTS:
131 void rejectCandidateOwnerForTouch(int id, QQuickItem *candidate);
132
133private:
134 // Only instance() can cronstruct one
135 TouchRegistry(QObject *parent = nullptr);
136
137 class CandidateInfo {
138 public:
139 enum {
140 // A candidate owner that doesn't yet know for sure whether he wants the touch point
141 // (gesture recognition is stilll going on)
142 Undecided = 0,
143 // A candidate owner that wants the touch but hasn't been granted it yet,
144 // most likely because there's an undecided candidate with higher priority
145 Requested = 1,
146 // An item that is the interim owner of the touch, receiving QTouchEvents of it
147 // from QQuickWindow. Ie, it's the actual touch owner from Qt's point of view.
148 // It wants to keep its touch ownership but hasn't been granted it by TouchRegistry
149 // yet because of undecided candidates higher up.
150 InterimOwner = 2
151 } state;
152 QPointer<QQuickItem> item;
153 QPointer<UbuntuGestures::CandidateInactivityTimer> inactivityTimer;
154 };
155
156 class TouchInfo {
157 public:
158 TouchInfo() : id(-1) {}
159 TouchInfo(int id);
160 bool isValid() const { return id >= 0; }
161 void reset();
162 void init(int id);
163 int id;
164 bool physicallyEnded;
165 bool isOwned() const;
166 bool ended() const;
167 void notifyCandidatesOfOwnershipResolution();
168
169 // TODO optimize storage (s/QList/Pool)
170 QList<CandidateInfo> candidates;
171 QList<QPointer<QQuickItem>> watchers;
172 };
173
174 void pruneNullCandidatesForTouch(int touchId);
175 void removeCandidateOwnerForTouchByIndex(Pool<TouchInfo>::Iterator &touchInfo, int candidateIndex);
176 void removeCandidateHelper(Pool<TouchInfo>::Iterator &touchInfo, int candidateIndex);
177
178 Pool<TouchInfo>::Iterator findTouchInfo(int id);
179
180 void deliverTouchUpdatesToUndecidedCandidatesAndWatchers(const QTouchEvent *event);
181
182 static void translateTouchPointFromScreenToWindowCoords(QTouchEvent::TouchPoint &touchPoint);
183
184 static void dispatchPointsToItem(const QTouchEvent *event, const QList<int> &touchIds,
185 QQuickItem *item);
186 void freeEndedTouchInfos();
187
188 Pool<TouchInfo> m_touchInfoPool;
189
190 // the singleton instance
191 static TouchRegistry *m_instance;
192
193 bool m_inDispatchLoop;
194
195 UbuntuGestures::AbstractTimerFactory *m_timerFactory;
196
197 friend class tst_TouchRegistry;
198 friend class tst_DirectionalDragArea;
199};
200
201#endif // UNITY_TOUCHREGISTRY_H
2020
=== removed file 'libs/UbuntuGestures/UbuntuGesturesGlobal.h'
--- libs/UbuntuGestures/UbuntuGesturesGlobal.h 2014-10-01 13:20:32 +0000
+++ libs/UbuntuGestures/UbuntuGesturesGlobal.h 1970-01-01 00:00:00 +0000
@@ -1,23 +0,0 @@
1/*
2 * Copyright (C) 2014 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include <QtCore/QtGlobal>
18
19#if defined(UBUNTUGESTURES_LIBRARY)
20# define UBUNTUGESTURES_EXPORT Q_DECL_EXPORT
21#else
22# define UBUNTUGESTURES_EXPORT Q_DECL_IMPORT
23#endif
240
=== removed file 'libs/UbuntuGestures/UnownedTouchEvent.cpp'
--- libs/UbuntuGestures/UnownedTouchEvent.cpp 2014-10-01 13:20:32 +0000
+++ libs/UbuntuGestures/UnownedTouchEvent.cpp 1970-01-01 00:00:00 +0000
@@ -1,39 +0,0 @@
1/*
2 * Copyright (C) 2014 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include "UnownedTouchEvent.h"
18
19QEvent::Type UnownedTouchEvent::m_unownedTouchEventType = (QEvent::Type)-1;
20
21UnownedTouchEvent::UnownedTouchEvent(QTouchEvent *touchEvent)
22 : QEvent(unownedTouchEventType())
23 , m_touchEvent(touchEvent)
24{
25}
26
27QEvent::Type UnownedTouchEvent::unownedTouchEventType()
28{
29 if (m_unownedTouchEventType == (QEvent::Type)-1) {
30 m_unownedTouchEventType = (QEvent::Type)registerEventType();
31 }
32
33 return m_unownedTouchEventType;
34}
35
36QTouchEvent *UnownedTouchEvent::touchEvent()
37{
38 return m_touchEvent.data();
39}
400
=== removed file 'libs/UbuntuGestures/UnownedTouchEvent.h'
--- libs/UbuntuGestures/UnownedTouchEvent.h 2014-10-01 13:20:32 +0000
+++ libs/UbuntuGestures/UnownedTouchEvent.h 1970-01-01 00:00:00 +0000
@@ -1,45 +0,0 @@
1/*
2 * Copyright (C) 2014 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef UBUNTU_UNOWNEDTOUCHEVENT_H
18#define UBUNTU_UNOWNEDTOUCHEVENT_H
19
20#include <QTouchEvent>
21#include <QScopedPointer>
22#include "UbuntuGesturesGlobal.h"
23
24/*
25 A touch event with touch points that do not belong the item receiving it.
26
27 See TouchRegistry::addCandidateOwnerForTouch and TouchRegistry::addTouchWatcher
28 */
29class UBUNTUGESTURES_EXPORT UnownedTouchEvent : public QEvent
30{
31public:
32 UnownedTouchEvent(QTouchEvent *touchEvent);
33 static Type unownedTouchEventType();
34
35 // TODO: It might be cleaner to store the information directly in UnownedTouchEvent
36 // instead of carrying around a synthesized QTouchEvent. But the latter option
37 // is very convenient.
38 QTouchEvent *touchEvent();
39
40private:
41 static Type m_unownedTouchEventType;
42 QScopedPointer<QTouchEvent> m_touchEvent;
43};
44
45#endif // UBUNTU_UNOWNEDTOUCHEVENT_H
460
=== modified file 'plugins/Cursor/CMakeLists.txt'
--- plugins/Cursor/CMakeLists.txt 2015-09-29 13:45:05 +0000
+++ plugins/Cursor/CMakeLists.txt 2016-06-01 16:58:47 +0000
@@ -8,8 +8,9 @@
88
9set(QMLPLUGIN_SRC9set(QMLPLUGIN_SRC
10 plugin.cpp10 plugin.cpp
11 CursorImageInfo.cpp
12 CursorImageProvider.cpp
11 MousePointer.cpp13 MousePointer.cpp
12 CursorImageProvider.cpp
13 # We need to run moc on this header14 # We need to run moc on this header
14 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/MirMousePointerInterface.h15 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/MirMousePointerInterface.h
15 )16 )
1617
=== modified file 'plugins/Cursor/Cursor.qml'
--- plugins/Cursor/Cursor.qml 2015-12-03 15:00:04 +0000
+++ plugins/Cursor/Cursor.qml 2016-06-01 16:58:47 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright (C) 2015 Canonical, Ltd.2 * Copyright (C) 2015-2016 Canonical, Ltd.
3 *3 *
4 * This program is free software; you can redistribute it and/or modify4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by5 * it under the terms of the GNU General Public License as published by
@@ -15,14 +15,30 @@
15 */15 */
1616
17import QtQuick 2.417import QtQuick 2.4
18import Cursor 1.0 // For MousePointer18import Cursor 1.1
1919
20MousePointer {20MousePointer {
21 id: mousePointer21 id: mousePointer
2222
23 Image {23 CursorImageInfo {
24 x: -mousePointer.hotspotX24 id: imageInfo
25 y: -mousePointer.hotspotY25 themeName: mousePointer.themeName
26 cursorName: mousePointer.cursorName
27 }
28
29 AnimatedSprite {
30 x: -imageInfo.hotspot.x
31 y: -imageInfo.hotspot.y
26 source: "image://cursor/" + mousePointer.themeName + "/" + mousePointer.cursorName32 source: "image://cursor/" + mousePointer.themeName + "/" + mousePointer.cursorName
33
34 interpolate: false
35
36 width: imageInfo.frameWidth
37 height: imageInfo.frameHeight
38
39 frameCount: imageInfo.frameCount
40 frameDuration: imageInfo.frameDuration
41 frameWidth: imageInfo.frameWidth
42 frameHeight: imageInfo.frameHeight
27 }43 }
28}44}
2945
=== removed file 'plugins/Cursor/Cursor.qmltypes'
--- plugins/Cursor/Cursor.qmltypes 2016-03-11 20:18:12 +0000
+++ plugins/Cursor/Cursor.qmltypes 1970-01-01 00:00:00 +0000
@@ -1,78 +0,0 @@
1import QtQuick.tooling 1.1
2
3// This file describes the plugin-supplied types contained in the library.
4// It is used for QML tooling purposes only.
5//
6// This file was auto-generated by:
7// 'qmlplugindump -notrelocatable Cursor 1.0 plugins'
8
9Module {
10 Component {
11 name: "MirMousePointerInterface"
12 defaultProperty: "data"
13 prototype: "QQuickItem"
14 Property { name: "cursorName"; type: "string"; isReadonly: true }
15 Property { name: "themeName"; type: "string"; isReadonly: true }
16 Property { name: "hotspotX"; type: "double"; isReadonly: true }
17 Property { name: "hotspotY"; type: "double"; isReadonly: true }
18 Signal {
19 name: "cursorNameChanged"
20 Parameter { name: "name"; type: "string" }
21 }
22 Signal {
23 name: "themeNameChanged"
24 Parameter { name: "name"; type: "string" }
25 }
26 Signal {
27 name: "hotspotXChanged"
28 Parameter { name: "value"; type: "double" }
29 }
30 Signal {
31 name: "hotspotYChanged"
32 Parameter { name: "value"; type: "double" }
33 }
34 Method {
35 name: "handleMouseEvent"
36 Parameter { name: "timestamp"; type: "ulong" }
37 Parameter { name: "movement"; type: "QPointF" }
38 Parameter { name: "buttons"; type: "Qt::MouseButtons" }
39 Parameter { name: "modifiers"; type: "Qt::KeyboardModifiers" }
40 }
41 Method {
42 name: "handleWheelEvent"
43 Parameter { name: "timestamp"; type: "ulong" }
44 Parameter { name: "angleDelta"; type: "QPoint" }
45 Parameter { name: "modifiers"; type: "Qt::KeyboardModifiers" }
46 }
47 }
48 Component {
49 name: "MousePointer"
50 defaultProperty: "data"
51 prototype: "MirMousePointerInterface"
52 exports: ["Cursor/MousePointer 1.0"]
53 exportMetaObjectRevisions: [0]
54 Signal {
55 name: "pushedLeftBoundary"
56 Parameter { name: "amount"; type: "double" }
57 Parameter { name: "buttons"; type: "Qt::MouseButtons" }
58 }
59 Signal {
60 name: "pushedRightBoundary"
61 Parameter { name: "amount"; type: "double" }
62 Parameter { name: "buttons"; type: "Qt::MouseButtons" }
63 }
64 Method {
65 name: "handleMouseEvent"
66 Parameter { name: "timestamp"; type: "ulong" }
67 Parameter { name: "movement"; type: "QPointF" }
68 Parameter { name: "buttons"; type: "Qt::MouseButtons" }
69 Parameter { name: "modifiers"; type: "Qt::KeyboardModifiers" }
70 }
71 Method {
72 name: "handleWheelEvent"
73 Parameter { name: "timestamp"; type: "ulong" }
74 Parameter { name: "angleDelta"; type: "QPoint" }
75 Parameter { name: "modifiers"; type: "Qt::KeyboardModifiers" }
76 }
77 }
78}
790
=== added file 'plugins/Cursor/CursorImageInfo.cpp'
--- plugins/Cursor/CursorImageInfo.cpp 1970-01-01 00:00:00 +0000
+++ plugins/Cursor/CursorImageInfo.cpp 2016-06-01 16:58:47 +0000
@@ -0,0 +1,106 @@
1/*
2 * Copyright (C) 2016 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include "CursorImageInfo.h"
18
19CursorImageInfo::CursorImageInfo(QObject *parent)
20 : QObject(parent)
21{
22 m_updateTimer.setInterval(0);
23 m_updateTimer.setSingleShot(true);
24 connect(&m_updateTimer, &QTimer::timeout, this, &CursorImageInfo::update);
25}
26
27void CursorImageInfo::setCursorName(const QString &cursorName)
28{
29 if (cursorName != m_cursorName) {
30 m_cursorName = cursorName;
31 Q_EMIT cursorNameChanged();
32 scheduleUpdate();
33 }
34}
35
36void CursorImageInfo::setThemeName(const QString &themeName)
37{
38 if (m_themeName != themeName) {
39 m_themeName = themeName;
40 Q_EMIT themeNameChanged();
41 scheduleUpdate();
42 }
43}
44
45void CursorImageInfo::scheduleUpdate()
46{
47 if (!m_updateTimer.isActive()) {
48 m_updateTimer.start();
49 }
50}
51
52void CursorImageInfo::update()
53{
54 m_cursorImage = CursorImageProvider::instance()->fetchCursor(m_themeName, m_cursorName);
55
56 Q_EMIT hotspotChanged();
57 Q_EMIT frameWidthChanged();
58 Q_EMIT frameHeightChanged();
59 Q_EMIT frameCountChanged();
60 Q_EMIT frameDurationChanged();
61}
62
63QPoint CursorImageInfo::hotspot() const
64{
65 if (m_cursorImage) {
66 return m_cursorImage->hotspot;
67 } else {
68 return QPoint();
69 }
70}
71
72qreal CursorImageInfo::frameWidth() const
73{
74 if (m_cursorImage) {
75 return m_cursorImage->frameWidth;
76 } else {
77 return 0;
78 }
79}
80
81qreal CursorImageInfo::frameHeight() const
82{
83 if (m_cursorImage) {
84 return m_cursorImage->frameHeight;
85 } else {
86 return 0;
87 }
88}
89
90int CursorImageInfo::frameCount() const
91{
92 if (m_cursorImage) {
93 return m_cursorImage->frameCount;
94 } else {
95 return 0;
96 }
97}
98
99int CursorImageInfo::frameDuration() const
100{
101 if (m_cursorImage) {
102 return m_cursorImage->frameDuration;
103 } else {
104 return 0;
105 }
106}
0107
=== added file 'plugins/Cursor/CursorImageInfo.h'
--- plugins/Cursor/CursorImageInfo.h 1970-01-01 00:00:00 +0000
+++ plugins/Cursor/CursorImageInfo.h 2016-06-01 16:58:47 +0000
@@ -0,0 +1,76 @@
1/*
2 * Copyright (C) 2016 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef CURSOR_IMAGE_INFO_H
18#define CURSOR_IMAGE_INFO_H
19
20#include "CursorImageProvider.h"
21
22#include <QObject>
23#include <QString>
24#include <QTimer>
25
26class CursorImageInfo : public QObject
27{
28 Q_OBJECT
29
30 Q_PROPERTY(QString themeName READ themeName WRITE setThemeName NOTIFY themeNameChanged)
31 Q_PROPERTY(QString cursorName READ cursorName WRITE setCursorName NOTIFY cursorNameChanged)
32
33 Q_PROPERTY(QPoint hotspot READ hotspot NOTIFY hotspotChanged)
34 Q_PROPERTY(qreal frameWidth READ frameWidth NOTIFY frameWidthChanged)
35 Q_PROPERTY(qreal frameHeight READ frameHeight NOTIFY frameHeightChanged)
36 Q_PROPERTY(int frameCount READ frameCount NOTIFY frameCountChanged)
37 Q_PROPERTY(int frameDuration READ frameDuration NOTIFY frameDurationChanged)
38
39public:
40 CursorImageInfo(QObject *parent = nullptr);
41
42 QString themeName() const { return m_themeName; }
43 void setThemeName(const QString &);
44
45 QString cursorName() const { return m_cursorName; }
46 void setCursorName(const QString &);
47
48 QPoint hotspot() const;
49 qreal frameWidth() const;
50 qreal frameHeight() const;
51 int frameCount() const;
52 int frameDuration() const;
53
54Q_SIGNALS:
55 void themeNameChanged();
56 void cursorNameChanged();
57 void hotspotChanged();
58 void frameWidthChanged();
59 void frameHeightChanged();
60 void frameCountChanged();
61 void frameDurationChanged();
62
63private Q_SLOTS:
64 void update();
65
66private:
67 void scheduleUpdate();
68 QTimer m_updateTimer;
69
70 QString m_themeName;
71 QString m_cursorName;
72
73 CursorImage *m_cursorImage{nullptr};
74};
75
76#endif // CURSOR_IMAGE_INFO_H
077
=== modified file 'plugins/Cursor/CursorImageProvider.cpp'
--- plugins/Cursor/CursorImageProvider.cpp 2015-11-30 17:38:20 +0000
+++ plugins/Cursor/CursorImageProvider.cpp 2016-06-01 16:58:47 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright (C) 2015 Canonical, Ltd.2 * Copyright (C) 2015-2016 Canonical, Ltd.
3 *3 *
4 * This program is free software: you can redistribute it and/or modify it under4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by5 * the terms of the GNU Lesser General Public License version 3, as published by
@@ -46,6 +46,9 @@
46 qimage.fill(Qt::transparent);46 qimage.fill(Qt::transparent);
47 QPainter imagePainter(&qimage);47 QPainter imagePainter(&qimage);
4848
49 frameWidth = qimage.width();
50 frameHeight = qimage.height();
51
49 QSvgRenderer *svgRenderer = new QSvgRenderer(QByteArray(svgString));52 QSvgRenderer *svgRenderer = new QSvgRenderer(QByteArray(svgString));
50 svgRenderer->render(&imagePainter);53 svgRenderer->render(&imagePainter);
51 delete svgRenderer;54 delete svgRenderer;
@@ -59,6 +62,8 @@
59{62{
60 qimage = QImage(1, 1, QImage::Format_ARGB32);63 qimage = QImage(1, 1, QImage::Format_ARGB32);
61 qimage.fill(Qt::transparent);64 qimage.fill(Qt::transparent);
65 frameWidth = qimage.width();
66 frameHeight = qimage.height();
62}67}
6368
64/////69/////
@@ -69,40 +74,74 @@
69{74{
70 qimage = cursor.pixmap().toImage();75 qimage = cursor.pixmap().toImage();
71 hotspot = cursor.hotSpot();76 hotspot = cursor.hotSpot();
77 frameWidth = qimage.width();
78 frameHeight = qimage.height();
72}79}
7380
74/////81/////
75// XCursorImage82// XCursorImage
7683
77XCursorImage::XCursorImage(const QString &theme, const QString &file)84XCursorImage::XCursorImage(const QString &theme, const QString &file)
78 : xcursorImages(nullptr)
79{85{
80 // TODO: Consider grid unit value86 // TODO: Consider grid unit value
81 // Hardcoding to a medium size for now87 // Hardcoding to a medium size for now
82 int preferredCursorHeightPx = 32;88 int preferredCursorHeightPx = 32;
8389
84 xcursorImages = XcursorLibraryLoadImages(QFile::encodeName(file), QFile::encodeName(theme),90 XcursorImages *xcursorImages = XcursorLibraryLoadImages(QFile::encodeName(file), QFile::encodeName(theme),
85 preferredCursorHeightPx);91 preferredCursorHeightPx);
86 if (!xcursorImages) {92 if (!xcursorImages || xcursorImages->nimage == 0) {
87 return;93 return;
88 }94 }
8995
90 // Just take the first one. It will have multiple images in case of an animated cursor.96 frameCount = xcursorImages->nimage;
91 // TODO: Support animated cursors97
92 if ( xcursorImages->nimage > 0) {98 for (int i = 0; i < xcursorImages->nimage; ++i) {
93 XcursorImage *xcursorImage = xcursorImages->images[0];99 XcursorImage *xcursorImage = xcursorImages->images[0];
94100 if (frameWidth < (int)xcursorImage->width) {
95 qimage = QImage((uchar*)xcursorImage->pixels,101 frameWidth = xcursorImage->width;
96 xcursorImage->width, xcursorImage->height, QImage::Format_ARGB32);102 }
97103 if (frameHeight < (int)xcursorImage->height) {
104 frameHeight = xcursorImage->height;
105 }
106 if (i == 0) {
107 frameDuration = (int)xcursorImage->delay;
108 } else {
109 if (frameDuration != (int)xcursorImage->delay) {
110 qWarning().nospace() << "CursorImageProvider: XCursorImage("<<theme<<","<<file<<") has"
111 " varying delays in its animation. Animation won't look right.";
112 }
113 }
114 }
115
116 {
117 // Assume that the hotspot position does not animate
118 XcursorImage *xcursorImage = xcursorImages->images[0];
98 hotspot.setX(xcursorImage->xhot);119 hotspot.setX(xcursorImage->xhot);
99 hotspot.setY(xcursorImage->yhot);120 hotspot.setY(xcursorImage->yhot);
100 }121 }
122
123 // Build the sprite as a single row of frames
124 qimage = QImage(frameWidth*frameCount, frameHeight, QImage::Format_ARGB32);
125 qimage.fill(Qt::transparent);
126
127 {
128 QPainter painter(&qimage);
129
130 for (int i = 0; i < xcursorImages->nimage; ++i) {
131 XcursorImage *xcursorImage = xcursorImages->images[i];
132
133 auto frameImage = QImage((uchar*)xcursorImage->pixels,
134 xcursorImage->width, xcursorImage->height, QImage::Format_ARGB32);
135
136 painter.drawImage(QPoint(i*frameWidth, 0), frameImage);
137 }
138 }
139
140 XcursorImagesDestroy(xcursorImages);
101}141}
102142
103XCursorImage::~XCursorImage()143XCursorImage::~XCursorImage()
104{144{
105 XcursorImagesDestroy(xcursorImages);
106}145}
107146
108/////147/////
@@ -205,16 +244,6 @@
205 return cursorImage->qimage;244 return cursorImage->qimage;
206}245}
207246
208QPoint CursorImageProvider::hotspot(const QString &themeName, const QString &cursorName)
209{
210 CursorImage *cursorImage = fetchCursor(themeName, cursorName);
211 if (cursorImage) {
212 return cursorImage->hotspot;
213 } else {
214 return QPoint(0,0);
215 }
216}
217
218CursorImage *CursorImageProvider::fetchCursor(const QString &cursorThemeAndName)247CursorImage *CursorImageProvider::fetchCursor(const QString &cursorThemeAndName)
219{248{
220 QString themeName;249 QString themeName;
221250
=== modified file 'plugins/Cursor/CursorImageProvider.h'
--- plugins/Cursor/CursorImageProvider.h 2015-11-16 14:27:31 +0000
+++ plugins/Cursor/CursorImageProvider.h 2016-06-01 16:58:47 +0000
@@ -31,15 +31,23 @@
31 virtual ~CursorImage() {}31 virtual ~CursorImage() {}
3232
33 QImage qimage;33 QImage qimage;
34
35 // TODO: consider if there's a need to animate the hotspot
36 // ie, if there's a need to make it an array of points, one for each frame.
37 // Maybe no single xcursor (or at least the ones we know of or use)
38 // vary its hotspot position through its animation.
34 QPoint hotspot;39 QPoint hotspot;
40
41 int frameWidth{0};
42 int frameHeight{0};
43 int frameCount{1};
44 int frameDuration{40};
35};45};
3646
37class XCursorImage : public CursorImage {47class XCursorImage : public CursorImage {
38public:48public:
39 XCursorImage(const QString &theme, const QString &file);49 XCursorImage(const QString &theme, const QString &file);
40 virtual ~XCursorImage();50 virtual ~XCursorImage();
41
42 XcursorImages *xcursorImages;
43};51};
4452
45class BuiltInCursorImage : public CursorImage {53class BuiltInCursorImage : public CursorImage {
@@ -68,16 +76,16 @@
6876
69 QImage requestImage(const QString &cursorName, QSize *size, const QSize &requestedSize) override;77 QImage requestImage(const QString &cursorName, QSize *size, const QSize &requestedSize) override;
7078
71 QPoint hotspot(const QString &themeName, const QString &cursorName);79 CursorImage *fetchCursor(const QString &themeName, const QString &cursorName);
7280
73 void setCustomCursor(const QCursor &customCursor);81 void setCustomCursor(const QCursor &customCursor);
7482
75private:83private:
76 CursorImage *fetchCursor(const QString &cursorThemeAndName);84 CursorImage *fetchCursor(const QString &cursorThemeAndName);
77 CursorImage *fetchCursor(const QString &themeName, const QString &cursorName);
78 CursorImage *fetchCursorHelper(const QString &themeName, const QString &cursorName);85 CursorImage *fetchCursorHelper(const QString &themeName, const QString &cursorName);
7986
80 // themeName -> (cursorName -> cursorImage)87 // themeName -> (cursorName -> cursorImage)
88 // TODO: discard old, unused, cursors
81 QMap<QString, QMap<QString, CursorImage*> > m_cursors;89 QMap<QString, QMap<QString, CursorImage*> > m_cursors;
8290
83 QScopedPointer<CursorImage> m_builtInCursorImage;91 QScopedPointer<CursorImage> m_builtInCursorImage;
8492
=== modified file 'plugins/Cursor/MousePointer.cpp'
--- plugins/Cursor/MousePointer.cpp 2015-12-01 21:54:18 +0000
+++ plugins/Cursor/MousePointer.cpp 2016-06-01 16:58:47 +0000
@@ -29,10 +29,7 @@
29 : MirMousePointerInterface(parent)29 : MirMousePointerInterface(parent)
30 , m_cursorName(QStringLiteral("left_ptr"))30 , m_cursorName(QStringLiteral("left_ptr"))
31 , m_themeName(QStringLiteral("default"))31 , m_themeName(QStringLiteral("default"))
32 , m_hotspotX(0)
33 , m_hotspotY(0)
34{32{
35 updateHotspot();
36}33}
3734
38void MousePointer::handleMouseEvent(ulong timestamp, QPointF movement, Qt::MouseButtons buttons,35void MousePointer::handleMouseEvent(ulong timestamp, QPointF movement, Qt::MouseButtons buttons,
@@ -89,8 +86,32 @@
8986
90void MousePointer::registerWindow(QWindow *window)87void MousePointer::registerWindow(QWindow *window)
91{88{
92 if (m_registeredWindow && window != m_registeredWindow) {89 if (window == m_registeredWindow) {
93 auto previousCursor = dynamic_cast<MirPlatformCursor*>(m_registeredWindow->screen()->handle()->cursor());90 return;
91 }
92
93 if (m_registeredWindow) {
94 m_registeredWindow->disconnect(this);
95 }
96
97 m_registeredWindow = window;
98
99 if (m_registeredWindow) {
100 connect(window, &QWindow::screenChanged, this, &MousePointer::registerScreen);
101 registerScreen(window->screen());
102 } else {
103 registerScreen(nullptr);
104 }
105}
106
107void MousePointer::registerScreen(QScreen *screen)
108{
109 if (m_registeredScreen == screen) {
110 return;
111 }
112
113 if (m_registeredScreen) {
114 auto previousCursor = dynamic_cast<MirPlatformCursor*>(m_registeredScreen->handle()->cursor());
94 if (previousCursor) {115 if (previousCursor) {
95 previousCursor->setMousePointer(nullptr);116 previousCursor->setMousePointer(nullptr);
96 } else {117 } else {
@@ -98,10 +119,10 @@
98 }119 }
99 }120 }
100121
101 m_registeredWindow = window;122 m_registeredScreen = screen;
102123
103 if (m_registeredWindow) {124 if (m_registeredScreen) {
104 auto cursor = dynamic_cast<MirPlatformCursor*>(window->screen()->handle()->cursor());125 auto cursor = dynamic_cast<MirPlatformCursor*>(m_registeredScreen->handle()->cursor());
105 if (cursor) {126 if (cursor) {
106 cursor->setMousePointer(this);127 cursor->setMousePointer(this);
107 } else {128 } else {
@@ -115,22 +136,6 @@
115 if (cursorName != m_cursorName) {136 if (cursorName != m_cursorName) {
116 m_cursorName = cursorName;137 m_cursorName = cursorName;
117 Q_EMIT cursorNameChanged(m_cursorName);138 Q_EMIT cursorNameChanged(m_cursorName);
118 updateHotspot();
119 }
120}
121
122void MousePointer::updateHotspot()
123{
124 QPoint newHotspot = CursorImageProvider::instance()->hotspot(m_themeName, m_cursorName);
125
126 if (m_hotspotX != newHotspot.x()) {
127 m_hotspotX = newHotspot.x();
128 Q_EMIT hotspotXChanged(m_hotspotX);
129 }
130
131 if (m_hotspotY != newHotspot.y()) {
132 m_hotspotY = newHotspot.y();
133 Q_EMIT hotspotYChanged(m_hotspotY);
134 }139 }
135}140}
136141
137142
=== modified file 'plugins/Cursor/MousePointer.h'
--- plugins/Cursor/MousePointer.h 2015-12-01 21:40:13 +0000
+++ plugins/Cursor/MousePointer.h 2016-06-01 16:58:47 +0000
@@ -20,6 +20,7 @@
20// Qt20// Qt
21#include <QPointer>21#include <QPointer>
22#include <QWindow>22#include <QWindow>
23#include <QScreen>
2324
24// Unity API25// Unity API
25#include <unity/shell/application/MirMousePointerInterface.h>26#include <unity/shell/application/MirMousePointerInterface.h>
@@ -35,9 +36,6 @@
35 void setThemeName(const QString &themeName) override;36 void setThemeName(const QString &themeName) override;
36 QString themeName() const override { return m_themeName; }37 QString themeName() const override { return m_themeName; }
3738
38 qreal hotspotX() const override { return m_hotspotX; }
39 qreal hotspotY() const override { return m_hotspotY; }
40
41 void setCustomCursor(const QCursor &) override;39 void setCustomCursor(const QCursor &) override;
4240
43public Q_SLOTS:41public Q_SLOTS:
@@ -53,15 +51,16 @@
53protected:51protected:
54 void itemChange(ItemChange change, const ItemChangeData &value) override;52 void itemChange(ItemChange change, const ItemChangeData &value) override;
5553
54private Q_SLOTS:
55 void registerScreen(QScreen *screen);
56
56private:57private:
57 void registerWindow(QWindow *window);58 void registerWindow(QWindow *window);
58 void updateHotspot();
5959
60 QPointer<QWindow> m_registeredWindow;60 QPointer<QWindow> m_registeredWindow;
61 QPointer<QScreen> m_registeredScreen;
61 QString m_cursorName;62 QString m_cursorName;
62 QString m_themeName;63 QString m_themeName;
63 int m_hotspotX;
64 int m_hotspotY;
65};64};
6665
67#endif // MOUSEPOINTER_H66#endif // MOUSEPOINTER_H
6867
=== modified file 'plugins/Cursor/plugin.cpp'
--- plugins/Cursor/plugin.cpp 2015-11-20 15:01:39 +0000
+++ plugins/Cursor/plugin.cpp 2016-06-01 16:58:47 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright (C) 2015 Canonical, Ltd.2 * Copyright (C) 2015-2016 Canonical, Ltd.
3 *3 *
4 * This program is free software; you can redistribute it and/or modify4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by5 * it under the terms of the GNU General Public License as published by
@@ -22,13 +22,15 @@
22#include "plugin.h"22#include "plugin.h"
2323
24// local24// local
25#include "CursorImageInfo.h"
25#include "CursorImageProvider.h"26#include "CursorImageProvider.h"
26#include "MousePointer.h"27#include "MousePointer.h"
2728
28void CursorPlugin::registerTypes(const char *uri)29void CursorPlugin::registerTypes(const char *uri)
29{30{
30 Q_ASSERT(uri == QLatin1String("Cursor"));31 Q_ASSERT(uri == QLatin1String("Cursor"));
31 qmlRegisterType<MousePointer>(uri, 1, 0, "MousePointer");32 qmlRegisterType<CursorImageInfo>(uri, 1, 1, "CursorImageInfo");
33 qmlRegisterType<MousePointer>(uri, 1, 1, "MousePointer");
32}34}
3335
34void CursorPlugin::initializeEngine(QQmlEngine *engine, const char *uri)36void CursorPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
3537
=== modified file 'plugins/Cursor/qmldir'
--- plugins/Cursor/qmldir 2015-09-29 13:45:05 +0000
+++ plugins/Cursor/qmldir 2016-06-01 16:58:47 +0000
@@ -1,3 +1,3 @@
1module Cursor1module Cursor
2plugin Cursor-qml2plugin Cursor-qml
3Cursor 1.0 Cursor.qml3Cursor 1.1 Cursor.qml
44
=== modified file 'plugins/Dash/AudioProgressBar.qml'
--- plugins/Dash/AudioProgressBar.qml 2016-01-18 22:56:16 +0000
+++ plugins/Dash/AudioProgressBar.qml 2016-06-01 16:58:47 +0000
@@ -49,6 +49,6 @@
49 rightMargin: maxWidth - (maxWidth * root.progress)49 rightMargin: maxWidth - (maxWidth * root.progress)
50 }50 }
51 height: units.dp(2)51 height: units.dp(2)
52 backgroundColor: UbuntuColors.orange52 backgroundColor: theme.palette.normal.activity
53 }53 }
54}54}
5555
=== modified file 'plugins/Dash/CardCreator.js'
--- plugins/Dash/CardCreator.js 2016-05-04 14:09:00 +0000
+++ plugins/Dash/CardCreator.js 2016-06-01 16:58:47 +0000
@@ -59,14 +59,30 @@
59 } \n\59 } \n\
60 }\n';60 }\n';
6161
62// %1 is the aspect of the UbuntuShape
63var kArtUbuntuShapeCode = 'UbuntuShape { \n\
64 anchors.fill: parent; \n\
65 source: artImage; \n\
66 sourceFillMode: UbuntuShape.PreserveAspectCrop; \n\
67 radius: "medium"; \n\
68 aspect: %1; \n\
69 }';
70
71var kArtProportionalShapeCode = 'ProportionalShape { \n\
72 anchors.fill: parent; \n\
73 source: artImage; \n\
74 aspect: UbuntuShape.DropShadow; \n\
75 }';
76
62// %1 is used as anchors of artShapeHolder77// %1 is used as anchors of artShapeHolder
63// %2 is used as image width78// %2 is used as image width
64// %3 is used as image height79// %3 is used as image height
65// %4 is whether the image or the Loader with the UbuntuShape/ProportionalShape should be visible80// %4 is whether the image should be visible
66// %5 is used as aspect ratio fallback81// %5 is used as aspect ratio fallback
67// %6 is whether the loader should be asynchronous or not82// %6 is whether the loader should be asynchronous or not
68// %7 is injected as code to artImage83// %7 is the shape code we want to use
69// %8 is used as image fallback84// %8 is injected as code to artImage
85// %9 is used as image fallback
70var kArtShapeHolderCode = 'Item { \n\86var kArtShapeHolderCode = 'Item { \n\
71 id: artShapeHolder; \n\87 id: artShapeHolder; \n\
72 height: root.fixedArtShapeSize.height > 0 ? root.fixedArtShapeSize.height : artShapeLoader.height; \n\88 height: root.fixedArtShapeSize.height > 0 ? root.fixedArtShapeSize.height : artShapeLoader.height; \n\
@@ -75,7 +91,8 @@
75 Loader { \n\91 Loader { \n\
76 id: artShapeLoader; \n\92 id: artShapeLoader; \n\
77 objectName: "artShapeLoader"; \n\93 objectName: "artShapeLoader"; \n\
78 readonly property string cardArt: cardData && cardData["art"] || %8; \n\94 readonly property string cardArt: cardData && cardData["art"] || %9; \n\
95 onCardArtChanged: { if (item) { item.image.source = cardArt; } } \n\
79 active: cardArt != ""; \n\96 active: cardArt != ""; \n\
80 asynchronous: %6; \n\97 asynchronous: %6; \n\
81 visible: status == Loader.Ready; \n\98 visible: status == Loader.Ready; \n\
@@ -84,31 +101,7 @@
84 objectName: "artShape"; \n\101 objectName: "artShape"; \n\
85 visible: image.status == Image.Ready; \n\102 visible: image.status == Image.Ready; \n\
86 readonly property alias image: artImage; \n\103 readonly property alias image: artImage; \n\
87 Loader { \n\104 %7 \n\
88 anchors.fill: parent; \n\
89 visible: %4; \n\
90 sourceComponent: root.artShapeStyle === "icon" ? artShapeIconComponent : artShapeShapeComponent; \n\
91 Component { \n\
92 id: artShapeShapeComponent; \n\
93 UbuntuShape { \n\
94 source: artImage; \n\
95 sourceFillMode: UbuntuShape.PreserveAspectCrop; \n\
96 radius: "medium"; \n\
97 aspect: { \n\
98 switch (root.artShapeStyle) { \n\
99 case "inset": return UbuntuShape.Inset; \n\
100 case "shadow": return UbuntuShape.DropShadow; \n\
101 default: \n\
102 case "flat": return UbuntuShape.Flat; \n\
103 } \n\
104 } \n\
105 } \n\
106 } \n\
107 Component { \n\
108 id: artShapeIconComponent; \n\
109 ProportionalShape { source: artImage; aspect: UbuntuShape.DropShadow; } \n\
110 } \n\
111 } \n\
112 readonly property real fixedArtShapeSizeAspect: (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) ? root.fixedArtShapeSize.width / root.fixedArtShapeSize.height : -1; \n\105 readonly property real fixedArtShapeSizeAspect: (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) ? root.fixedArtShapeSize.width / root.fixedArtShapeSize.height : -1; \n\
113 readonly property real aspect: fixedArtShapeSizeAspect > 0 ? fixedArtShapeSizeAspect : %5; \n\106 readonly property real aspect: fixedArtShapeSizeAspect > 0 ? fixedArtShapeSizeAspect : %5; \n\
114 Component.onCompleted: { updateWidthHeightBindings(); } \n\107 Component.onCompleted: { updateWidthHeightBindings(); } \n\
@@ -127,10 +120,10 @@
127 objectName: "artImage"; \n\120 objectName: "artImage"; \n\
128 source: artShapeLoader.cardArt; \n\121 source: artShapeLoader.cardArt; \n\
129 asynchronous: %6; \n\122 asynchronous: %6; \n\
130 visible: !%4; \n\123 visible: %4; \n\
131 width: %2; \n\124 width: %2; \n\
132 height: %3; \n\125 height: %3; \n\
133 %7 \n\126 %8 \n\
134 } \n\127 } \n\
135 } \n\128 } \n\
136 } \n\129 } \n\
@@ -318,7 +311,7 @@
318 id: touchdown; \n\311 id: touchdown; \n\
319 objectName: "touchdown"; \n\312 objectName: "touchdown"; \n\
320 anchors { %1 } \n\313 anchors { %1 } \n\
321 visible: root.artShapeStyle != "shadow" && root.artShapeStyle != "icon" && root.pressed; \n\314 visible: root.pressed; \n\
322 radius: "medium"; \n\315 radius: "medium"; \n\
323 borderSource: "radius_pressed.sci" \n\316 borderSource: "radius_pressed.sci" \n\
324 }\n';317 }\n';
@@ -412,7 +405,7 @@
412 return colorString;405 return colorString;
413}406}
414407
415function cardString(template, components, isCardTool) {408function cardString(template, components, isCardTool, artShapeStyle) {
416 var code;409 var code;
417410
418 var templateInteractive = (template == null ? true : (template["non-interactive"] !== undefined ? !template["non-interactive"] : true)) ? "true" : "false";411 var templateInteractive = (template == null ? true : (template["non-interactive"] !== undefined ? !template["non-interactive"] : true)) ? "true" : "false";
@@ -420,7 +413,6 @@
420 code = 'AbstractButton { \n\413 code = 'AbstractButton { \n\
421 id: root; \n\414 id: root; \n\
422 property var cardData; \n\415 property var cardData; \n\
423 property string artShapeStyle: "inset"; \n\
424 property string backgroundShapeStyle: "inset"; \n\416 property string backgroundShapeStyle: "inset"; \n\
425 property real fontScale: 1.0; \n\417 property real fontScale: 1.0; \n\
426 property var scopeStyle: null; \n\418 property var scopeStyle: null; \n\
@@ -519,17 +511,35 @@
519 var fallbackStatusCode = "";511 var fallbackStatusCode = "";
520 var fallbackURICode = '""';512 var fallbackURICode = '""';
521 if (fallback !== "") {513 if (fallback !== "") {
522 // fallbackStatusCode has %6 in it because we want to substitute it for fallbackURICode514 // fallbackStatusCode has %9 in it because we want to substitute it for fallbackURICode
523 // which in kArtShapeHolderCode is %8515 // which in kArtShapeHolderCode is %9
524 fallbackStatusCode += 'onStatusChanged: if (status === Image.Error) source = %8;';516 fallbackStatusCode += 'onStatusChanged: if (status === Image.Error) source = %9;';
525 fallbackURICode = 'decodeURI("%1")'.arg(fallback);517 fallbackURICode = 'decodeURI("%1")'.arg(fallback);
526 }518 }
519 var artShapeHolderShapeCode;
520 if (!isConciergeMode) {
521 if (artShapeStyle === "icon") {
522 artShapeHolderShapeCode = kArtProportionalShapeCode;
523 } else {
524 var artShapeHolderShapeAspect;
525 switch (artShapeStyle) {
526 case "inset": artShapeHolderShapeAspect = "UbuntuShape.Inset"; break;
527 case "shadow": artShapeHolderShapeAspect = "UbuntuShape.DropShadow"; break;
528 default:
529 case "flat": artShapeHolderShapeAspect = "UbuntuShape.Flat"; break;
530 }
531 artShapeHolderShapeCode = kArtUbuntuShapeCode.arg(artShapeHolderShapeAspect);
532 }
533 } else {
534 artShapeHolderShapeCode = "";
535 }
527 code += kArtShapeHolderCode.arg(artAnchors)536 code += kArtShapeHolderCode.arg(artAnchors)
528 .arg(widthCode)537 .arg(widthCode)
529 .arg(heightCode)538 .arg(heightCode)
530 .arg(isConciergeMode ? "false" : "true")539 .arg(isConciergeMode ? "true" : "false")
531 .arg(aspectRatio)540 .arg(aspectRatio)
532 .arg(asynchronous)541 .arg(asynchronous)
542 .arg(artShapeHolderShapeCode)
533 .arg(fallbackStatusCode)543 .arg(fallbackStatusCode)
534 .arg(fallbackURICode);544 .arg(fallbackURICode);
535 } else {545 } else {
@@ -854,6 +864,10 @@
854 code += kSummaryLabelCode.arg(summaryTopAnchor).arg(summaryTopMargin).arg(summaryColor);864 code += kSummaryLabelCode.arg(summaryTopAnchor).arg(summaryTopMargin).arg(summaryColor);
855 }865 }
856866
867// <<<<<<< TREE
868// if (artShapeStyle != "shadow" && artShapeStyle != "icon") {
869// var touchdownAnchors;
870// =======
857 if (hasSocialActions) {871 if (hasSocialActions) {
858 var socialAnchors;872 var socialAnchors;
859 var socialTopAnchor;873 var socialTopAnchor;
@@ -882,15 +896,17 @@
882 code += kSocialActionsRowCode.arg(socialAnchors).arg(socialColor);896 code += kSocialActionsRowCode.arg(socialAnchors).arg(socialColor);
883 }897 }
884898
885 var touchdownAnchors;899 if (artShapeStyle != "shadow" && artShapeStyle != "icon") {
886 if (hasBackground) {900 var touchdownAnchors;
887 touchdownAnchors = 'fill: backgroundLoader';901 if (hasBackground) {
888 } else if (touchdownOnArtShape) {902 touchdownAnchors = 'fill: backgroundLoader';
889 touchdownAnchors = 'fill: artShapeHolder';903 } else if (touchdownOnArtShape) {
890 } else {904 touchdownAnchors = 'fill: artShapeHolder';
891 touchdownAnchors = 'fill: root'905 } else {
906 touchdownAnchors = 'fill: root'
907 }
908 code += kTouchdownCode.arg(touchdownAnchors);
892 }909 }
893 code += kTouchdownCode.arg(touchdownAnchors);
894910
895 var implicitHeight = 'implicitHeight: ';911 var implicitHeight = 'implicitHeight: ';
896 if (hasSocialActions) {912 if (hasSocialActions) {
@@ -925,13 +941,13 @@
925 return code;941 return code;
926}942}
927943
928function createCardComponent(parent, template, components, isCardTool, identifier) {944function createCardComponent(parent, template, components, isCardTool, artShapeStyle, identifier) {
929 var imports = 'import QtQuick 2.4; \n\945 var imports = 'import QtQuick 2.4; \n\
930 import Ubuntu.Components 1.3; \n\946 import Ubuntu.Components 1.3; \n\
931 import Ubuntu.Settings.Components 0.1; \n\947 import Ubuntu.Settings.Components 0.1; \n\
932 import Dash 0.1;\n\948 import Dash 0.1;\n\
933 import Utils 0.1;\n';949 import Utils 0.1;\n';
934 var card = cardString(template, components, isCardTool);950 var card = cardString(template, components, isCardTool, artShapeStyle);
935 var code = imports + 'Component {\n' + card + '}\n';951 var code = imports + 'Component {\n' + card + '}\n';
936952
937 try {953 try {
938954
=== modified file 'plugins/Dash/CardCreatorCache.qml'
--- plugins/Dash/CardCreatorCache.qml 2016-02-16 14:26:58 +0000
+++ plugins/Dash/CardCreatorCache.qml 2016-06-01 16:58:47 +0000
@@ -23,7 +23,7 @@
2323
24 property var cache: new Object();24 property var cache: new Object();
2525
26 function getCardComponent(template, components, isCardTool) {26 function getCardComponent(template, components, isCardTool, artShapeStyle) {
27 if (template === undefined || components === undefined)27 if (template === undefined || components === undefined)
28 return undefined;28 return undefined;
2929
@@ -32,7 +32,7 @@
32 var allString = tString + cString + isCardTool;32 var allString = tString + cString + isCardTool;
33 var component = cache[allString];33 var component = cache[allString];
34 if (component === undefined) {34 if (component === undefined) {
35 component = CardCreator.createCardComponent(root, template, components, isCardTool, allString);35 component = CardCreator.createCardComponent(root, template, components, isCardTool, artShapeStyle, allString);
36 cache[allString] = component;36 cache[allString] = component;
37 }37 }
38 return component;38 return component;
3939
=== modified file 'plugins/Dash/ScopeStyle.qml'
--- plugins/Dash/ScopeStyle.qml 2016-03-29 03:47:39 +0000
+++ plugins/Dash/ScopeStyle.qml 2016-06-01 16:58:47 +0000
@@ -70,7 +70,7 @@
70 readonly property url navigationBackground: "navigation-background" in d.headerStyle ? d.headerStyle["navigation-background"] : "color:///#f5f5f5"70 readonly property url navigationBackground: "navigation-background" in d.headerStyle ? d.headerStyle["navigation-background"] : "color:///#f5f5f5"
7171
72 /// Color of the primary preview button72 /// Color of the primary preview button
73 readonly property color previewButtonColor: "preview-button-color" in style ? style["preview-button-color"] : UbuntuColors.orange73 readonly property color previewButtonColor: "preview-button-color" in style ? style["preview-button-color"] : theme.palette.normal.positive
7474
75 //! @cond75 //! @cond
76 property var d: QtObject {76 property var d: QtObject {
7777
=== modified file 'plugins/Dash/listviewwithpageheader.cpp'
--- plugins/Dash/listviewwithpageheader.cpp 2016-04-27 14:59:24 +0000
+++ plugins/Dash/listviewwithpageheader.cpp 2016-06-01 16:58:47 +0000
@@ -97,6 +97,7 @@
97#include <qqmlengine.h>97#include <qqmlengine.h>
98#pragma GCC diagnostic push98#pragma GCC diagnostic push
99#pragma GCC diagnostic ignored "-pedantic"99#pragma GCC diagnostic ignored "-pedantic"
100#include <private/qqmlcontext_p.h>
100#include <private/qqmldelegatemodel_p.h>101#include <private/qqmldelegatemodel_p.h>
101#include <private/qqmlglobal_p.h>102#include <private/qqmlglobal_p.h>
102#include <private/qquickitem_p.h>103#include <private/qquickitem_p.h>
@@ -168,7 +169,7 @@
168 m_contentYAnimation->setDuration(200);169 m_contentYAnimation->setDuration(200);
169 m_contentYAnimation->setTargetObject(this);170 m_contentYAnimation->setTargetObject(this);
170171
171 connect(this, &ListViewWithPageHeader::contentWidthChanged, this, &ListViewWithPageHeader::onContentWidthChanged);172 connect(contentItem(), &QQuickItem::widthChanged, this, &ListViewWithPageHeader::onContentWidthChanged);
172 connect(this, &ListViewWithPageHeader::contentHeightChanged, this, &ListViewWithPageHeader::onContentHeightChanged);173 connect(this, &ListViewWithPageHeader::contentHeightChanged, this, &ListViewWithPageHeader::onContentHeightChanged);
173 connect(this, &ListViewWithPageHeader::heightChanged, this, &ListViewWithPageHeader::onHeightChanged);174 connect(this, &ListViewWithPageHeader::heightChanged, this, &ListViewWithPageHeader::onHeightChanged);
174 connect(m_contentYAnimation, &QQuickNumberAnimation::runningChanged, this, &ListViewWithPageHeader::contentYAnimationRunningChanged);175 connect(m_contentYAnimation, &QQuickNumberAnimation::runningChanged, this, &ListViewWithPageHeader::contentYAnimationRunningChanged);
@@ -757,8 +758,6 @@
757758
758 QQmlContext *creationContext = m_sectionDelegate->creationContext();759 QQmlContext *creationContext = m_sectionDelegate->creationContext();
759 QQmlContext *context = new QQmlContext(creationContext ? creationContext : qmlContext(this));760 QQmlContext *context = new QQmlContext(creationContext ? creationContext : qmlContext(this));
760 context->setContextProperty(QStringLiteral("section"), sectionText);
761 context->setContextProperty(QStringLiteral("delegateIndex"), -1);
762 QObject *nobj = m_sectionDelegate->beginCreate(context);761 QObject *nobj = m_sectionDelegate->beginCreate(context);
763 if (nobj) {762 if (nobj) {
764 QQml_setParent_noEvent(context, nobj);763 QQml_setParent_noEvent(context, nobj);
@@ -766,6 +765,8 @@
766 if (!sectionItem) {765 if (!sectionItem) {
767 delete nobj;766 delete nobj;
768 } else {767 } else {
768 sectionItem->setProperty("text", sectionText);
769 sectionItem->setProperty("delegateIndex", -1);
769 sectionItem->setZ(2);770 sectionItem->setZ(2);
770 QQml_setParent_noEvent(sectionItem, m_clipItem);771 QQml_setParent_noEvent(sectionItem, m_clipItem);
771 sectionItem->setParentItem(m_clipItem);772 sectionItem->setParentItem(m_clipItem);
@@ -801,8 +802,7 @@
801 if (!item->sectionItem()) {802 if (!item->sectionItem()) {
802 item->setSectionItem(getSectionItem(sectionText));803 item->setSectionItem(getSectionItem(sectionText));
803 } else {804 } else {
804 QQmlContext *context = QQmlEngine::contextForObject(item->sectionItem())->parentContext();805 item->sectionItem()->setProperty("text", sectionText);
805 context->setContextProperty(QStringLiteral("section"), sectionText);
806 }806 }
807 } else {807 } else {
808 if (item->sectionItem()) {808 if (item->sectionItem()) {
@@ -923,8 +923,7 @@
923 polish();923 polish();
924 }924 }
925 if (listItem->sectionItem()) {925 if (listItem->sectionItem()) {
926 QQmlContext *context = QQmlEngine::contextForObject(listItem->sectionItem())->parentContext();926 listItem->sectionItem()->setProperty("delegateIndex", modelIndex);
927 context->setContextProperty(QStringLiteral("delegateIndex"), modelIndex);
928 }927 }
929 adjustMinYExtent();928 adjustMinYExtent();
930 m_contentHeightDirty = true;929 m_contentHeightDirty = true;
@@ -948,9 +947,10 @@
948 return;947 return;
949948
950 item->setParentItem(m_clipItem);949 item->setParentItem(m_clipItem);
950 // FIXME Why do we need the refreshExpressions call?
951 QQmlContext *context = QQmlEngine::contextForObject(item)->parentContext();951 QQmlContext *context = QQmlEngine::contextForObject(item)->parentContext();
952 context->setContextProperty(QStringLiteral("ListViewWithPageHeader"), this);952 QQmlContextPrivate::get(context)->data->refreshExpressions();
953 context->setContextProperty(QStringLiteral("heightToClip"), QVariant::fromValue<int>(0));953 item->setProperty("heightToClip", QVariant::fromValue<int>(0));
954 if (modelIndex == m_asyncRequestedIndex) {954 if (modelIndex == m_asyncRequestedIndex) {
955 createItem(modelIndex, false);955 createItem(modelIndex, false);
956 refill();956 refill();
@@ -1116,8 +1116,7 @@
1116 for (int i = 0; i < m_visibleItems.count(); ++i) {1116 for (int i = 0; i < m_visibleItems.count(); ++i) {
1117 ListItem *item = m_visibleItems[i];1117 ListItem *item = m_visibleItems[i];
1118 if (item->sectionItem()) {1118 if (item->sectionItem()) {
1119 QQmlContext *context = QQmlEngine::contextForObject(item->sectionItem())->parentContext();1119 item->sectionItem()->setProperty("delegateIndex", m_firstVisibleIndex + i);
1120 context->setContextProperty(QStringLiteral("delegateIndex"), m_firstVisibleIndex + i);
1121 }1120 }
1122 }1121 }
11231122
@@ -1287,8 +1286,7 @@
1287 } else {1286 } else {
1288 // Update the top sticky section header1287 // Update the top sticky section header
1289 const QString section = m_delegateModel->stringValue(modelIndex, m_sectionProperty);1288 const QString section = m_delegateModel->stringValue(modelIndex, m_sectionProperty);
1290 QQmlContext *context = QQmlEngine::contextForObject(m_topSectionItem)->parentContext();1289 m_topSectionItem->setProperty("text", section);
1291 context->setContextProperty(QStringLiteral("section"), section);
12921290
1293 QQuickItemPrivate::get(m_topSectionItem)->setCulled(false);1291 QQuickItemPrivate::get(m_topSectionItem)->setCulled(false);
1294 m_topSectionItem->setY(topSectionStickPos);1292 m_topSectionItem->setY(topSectionStickPos);
@@ -1300,19 +1298,18 @@
1300 break;1298 break;
1301 delegateIndex--;1299 delegateIndex--;
1302 }1300 }
1303 context->setContextProperty(QStringLiteral("delegateIndex"), delegateIndex);1301 m_topSectionItem->setProperty("delegateIndex", delegateIndex);
1304 if (item->sectionItem()) {1302 if (item->sectionItem()) {
1305 QQuickItemPrivate::get(item->sectionItem())->setCulled(true);1303 QQuickItemPrivate::get(item->sectionItem())->setCulled(true);
1306 }1304 }
1307 }1305 }
1308 }1306 }
1309 }1307 }
1310 QQmlContext *context = QQmlEngine::contextForObject(item->m_item)->parentContext();
1311 const qreal clipFrom = visibleFrom + (!item->sectionItem() && m_topSectionItem && !QQuickItemPrivate::get(m_topSectionItem)->culled ? m_topSectionItem->height() : 0);1308 const qreal clipFrom = visibleFrom + (!item->sectionItem() && m_topSectionItem && !QQuickItemPrivate::get(m_topSectionItem)->culled ? m_topSectionItem->height() : 0);
1312 if (!cull && pos < clipFrom) {1309 if (!cull && pos < clipFrom) {
1313 context->setContextProperty(QStringLiteral("heightToClip"), clipFrom - pos);1310 item->m_item->setProperty("heightToClip", clipFrom - pos);
1314 } else {1311 } else {
1315 context->setContextProperty(QStringLiteral("heightToClip"), QVariant::fromValue<int>(0));1312 item->m_item->setProperty("heightToClip", QVariant::fromValue<int>(0));
1316 }1313 }
1317// qDebug() << "ListViewWithPageHeader::layout" << item->m_item;1314// qDebug() << "ListViewWithPageHeader::layout" << item->m_item;
1318 pos += item->height();1315 pos += item->height();
13191316
=== modified file 'plugins/Ubuntu/Gestures/AxisVelocityCalculator.h'
--- plugins/Ubuntu/Gestures/AxisVelocityCalculator.h 2014-10-01 13:20:32 +0000
+++ plugins/Ubuntu/Gestures/AxisVelocityCalculator.h 2016-06-01 16:58:47 +0000
@@ -24,7 +24,7 @@
24#include "UbuntuGesturesQmlGlobal.h"24#include "UbuntuGesturesQmlGlobal.h"
25#include <stdint.h>25#include <stdint.h>
26#include <QtCore/QObject>26#include <QtCore/QObject>
27#include "TimeSource.h"27#include <TimeSource>
2828
29/*29/*
30 Estimates the current velocity of a finger based on recent movement along an axis30 Estimates the current velocity of a finger based on recent movement along an axis
3131
=== modified file 'plugins/Ubuntu/Gestures/CMakeLists.txt'
--- plugins/Ubuntu/Gestures/CMakeLists.txt 2016-03-29 03:47:39 +0000
+++ plugins/Ubuntu/Gestures/CMakeLists.txt 2016-06-01 16:58:47 +0000
@@ -4,27 +4,27 @@
4set(UbuntuGesturesQml_SOURCES4set(UbuntuGesturesQml_SOURCES
5 plugin.cpp5 plugin.cpp
6 AxisVelocityCalculator.cpp6 AxisVelocityCalculator.cpp
7 Damper.cpp
8 Direction.cpp7 Direction.cpp
9 DirectionalDragArea.cpp8 MouseEventGenerator.cpp
10 FloatingFlickable.cpp
11 PressedOutsideNotifier.cpp9 PressedOutsideNotifier.cpp
12 TouchDispatcher.cpp10 TouchDispatcher.cpp
13 TouchGate.cpp11 TouchGate.cpp
14 TouchGestureArea.cpp12 TouchGestureArea.cpp
15)13)
1614
15pkg_check_modules(UBUNTUGESTURES REQUIRED UbuntuGestures)
16
17add_definitions(-DUBUNTUGESTURESQML_LIBRARY)17add_definitions(-DUBUNTUGESTURESQML_LIBRARY)
1818
19add_library(UbuntuGesturesQml MODULE ${UbuntuGesturesQml_SOURCES})19add_library(UbuntuGesturesQml MODULE ${UbuntuGesturesQml_SOURCES})
20target_link_libraries(UbuntuGesturesQml UbuntuGestures)20target_link_libraries(UbuntuGesturesQml ${UBUNTUGESTURES_LIBRARIES})
2121
22qt5_use_modules(UbuntuGesturesQml Core Quick)22qt5_use_modules(UbuntuGesturesQml Core Quick)
2323
24# So that Foo.cpp can #include "Foo.moc"24# So that Foo.cpp can #include "Foo.moc"
25include_directories(${CMAKE_CURRENT_BINARY_DIR})25include_directories(${CMAKE_CURRENT_BINARY_DIR})
2626
27include_directories(${CMAKE_SOURCE_DIR}/libs/UbuntuGestures)27include_directories(${UBUNTUGESTURES_INCLUDE_DIRS})
2828
29# There's no cmake var for v8 include path :-/ so create one29# There's no cmake var for v8 include path :-/ so create one
30LIST(GET Qt5Core_INCLUDE_DIRS 0 QtCoreDir0)30LIST(GET Qt5Core_INCLUDE_DIRS 0 QtCoreDir0)
3131
=== removed file 'plugins/Ubuntu/Gestures/Damper.cpp'
--- plugins/Ubuntu/Gestures/Damper.cpp 2015-04-10 21:16:37 +0000
+++ plugins/Ubuntu/Gestures/Damper.cpp 1970-01-01 00:00:00 +0000
@@ -1,24 +0,0 @@
1/*
2 * Copyright (C) 2015 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include "Damper.h"
18#include <QDebug>
19
20QDebug operator<<(QDebug dbg, const DampedPointF &p)
21{
22 dbg.nospace() << "(" << p.x() << ", " << p.y() << ")";
23 return dbg.space();
24}
250
=== removed file 'plugins/Ubuntu/Gestures/Damper.h'
--- plugins/Ubuntu/Gestures/Damper.h 2015-11-20 15:01:39 +0000
+++ plugins/Ubuntu/Gestures/Damper.h 1970-01-01 00:00:00 +0000
@@ -1,89 +0,0 @@
1/*
2 * Copyright (C) 2013 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef UBUNTU_GESTURES_DAMPER_H
18#define UBUNTU_GESTURES_DAMPER_H
19
20#include <QtCore/QPointF>
21
22/*
23 Decreases the oscillations of a value along an axis.
24 */
25template <class Type> class Damper {
26public:
27 Damper() : m_value(0), m_maxDelta(0) { }
28
29 // Maximum delta between the raw value and its dampened counterpart.
30 void setMaxDelta(Type maxDelta) {
31 if (maxDelta < 0) qFatal("Damper::maxDelta must be a positive number.");
32 m_maxDelta = maxDelta;
33 }
34 Type maxDelta() const { return m_maxDelta; }
35
36 void reset(Type value) {
37 m_value = value;
38 }
39
40 Type update(Type value) {
41 Type delta = value - m_value;
42 if (delta > 0 && delta > m_maxDelta) {
43 m_value += delta - m_maxDelta;
44 } else if (delta < 0 && delta < -m_maxDelta) {
45 m_value += delta + m_maxDelta;
46 }
47
48 return m_value;
49 }
50
51 Type value() const { return m_value; }
52
53private:
54 Type m_value;
55 Type m_maxDelta;
56};
57
58/*
59 A point that has its movement dampened.
60 */
61class DampedPointF {
62public:
63 void setMaxDelta(qreal maxDelta) {
64 m_x.setMaxDelta(maxDelta);
65 m_y.setMaxDelta(maxDelta);
66 }
67
68 qreal maxDelta() const { return m_x.maxDelta(); }
69
70 void reset(const QPointF point) {
71 m_x.reset(point.x());
72 m_y.reset(point.y());
73 }
74
75 void update(const QPointF point) {
76 m_x.update(point.x());
77 m_y.update(point.y());
78 }
79
80 qreal x() const { return m_x.value(); }
81 qreal y() const { return m_y.value(); }
82private:
83 Damper<qreal> m_x;
84 Damper<qreal> m_y;
85};
86
87QDebug operator<<(QDebug dbg, const DampedPointF &p);
88
89#endif // UBUNTU_GESTURES_DAMPER_H
900
=== modified file 'plugins/Ubuntu/Gestures/Direction.h'
--- plugins/Ubuntu/Gestures/Direction.h 2015-04-17 14:21:43 +0000
+++ plugins/Ubuntu/Gestures/Direction.h 2016-06-01 16:58:47 +0000
@@ -29,6 +29,7 @@
29 Q_ENUMS(Type)29 Q_ENUMS(Type)
3030
31public:31public:
32 // Make sure it is kept synchronized with SDK UCSwipeArea::Direction
32 enum Type {33 enum Type {
33 Rightwards, // Along the positive direction of the X axis34 Rightwards, // Along the positive direction of the X axis
34 Leftwards, // Along the negative direction of the X axis35 Leftwards, // Along the negative direction of the X axis
3536
=== removed file 'plugins/Ubuntu/Gestures/DirectionalDragArea.cpp'
--- plugins/Ubuntu/Gestures/DirectionalDragArea.cpp 2016-03-29 03:47:39 +0000
+++ plugins/Ubuntu/Gestures/DirectionalDragArea.cpp 1970-01-01 00:00:00 +0000
@@ -1,932 +0,0 @@
1/*
2 * Copyright (C) 2013-2015 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#define ACTIVETOUCHESINFO_DEBUG 0
18#define DIRECTIONALDRAGAREA_DEBUG 0
19
20#include "DirectionalDragArea.h"
21
22#include <QQuickWindow>
23#include <QtCore/qmath.h>
24#include <QScreen>
25#include <QDebug>
26
27#pragma GCC diagnostic push
28#pragma GCC diagnostic ignored "-pedantic"
29#include <private/qquickwindow_p.h>
30#pragma GCC diagnostic pop
31
32// local
33#include "TouchOwnershipEvent.h"
34#include "TouchRegistry.h"
35#include "UnownedTouchEvent.h"
36
37#include "DirectionalDragArea_p.h"
38
39using namespace UbuntuGestures;
40
41#if DIRECTIONALDRAGAREA_DEBUG
42#define ddaDebug(params) qDebug().nospace() << "[DDA(" << qPrintable(objectName()) << ")] " << params
43#include "DebugHelpers.h"
44
45namespace {
46const char *statusToString(DirectionalDragAreaPrivate::Status status)
47{
48 if (status == DirectionalDragAreaPrivate::WaitingForTouch) {
49 return "WaitingForTouch";
50 } else if (status == DirectionalDragAreaPrivate::Undecided) {
51 return "Undecided";
52 } else {
53 return "Recognized";
54 }
55}
56
57} // namespace {
58#else // DIRECTIONALDRAGAREA_DEBUG
59#define ddaDebug(params) ((void)0)
60#endif // DIRECTIONALDRAGAREA_DEBUG
61
62DirectionalDragArea::DirectionalDragArea(QQuickItem *parent)
63 : QQuickItem(parent)
64 , d(new DirectionalDragAreaPrivate(this))
65{
66 d->setRecognitionTimer(new Timer(this));
67 d->recognitionTimer->setInterval(d->maxTime);
68 d->recognitionTimer->setSingleShot(true);
69
70 connect(this, &QQuickItem::enabledChanged, d, &DirectionalDragAreaPrivate::giveUpIfDisabledOrInvisible);
71 connect(this, &QQuickItem::visibleChanged, d, &DirectionalDragAreaPrivate::giveUpIfDisabledOrInvisible);
72}
73
74Direction::Type DirectionalDragArea::direction() const
75{
76 return d->direction;
77}
78
79void DirectionalDragArea::setDirection(Direction::Type direction)
80{
81 if (direction != d->direction) {
82 d->direction = direction;
83 Q_EMIT directionChanged(d->direction);
84 }
85}
86
87void DirectionalDragAreaPrivate::setDistanceThreshold(qreal value)
88{
89 if (distanceThreshold != value) {
90 distanceThreshold = value;
91 distanceThresholdSquared = distanceThreshold * distanceThreshold;
92 }
93}
94
95void DirectionalDragAreaPrivate::setMaxTime(int value)
96{
97 if (maxTime != value) {
98 maxTime = value;
99 recognitionTimer->setInterval(maxTime);
100 }
101}
102
103void DirectionalDragAreaPrivate::setRecognitionTimer(UbuntuGestures::AbstractTimer *timer)
104{
105 int interval = 0;
106 bool timerWasRunning = false;
107 bool wasSingleShot = false;
108
109 // can be null when called from the constructor
110 if (recognitionTimer) {
111 interval = recognitionTimer->interval();
112 timerWasRunning = recognitionTimer->isRunning();
113 if (recognitionTimer->parent() == this) {
114 delete recognitionTimer;
115 }
116 }
117
118 recognitionTimer = timer;
119 timer->setInterval(interval);
120 timer->setSingleShot(wasSingleShot);
121 connect(timer, &UbuntuGestures::AbstractTimer::timeout,
122 this, &DirectionalDragAreaPrivate::rejectGesture);
123 if (timerWasRunning) {
124 recognitionTimer->start();
125 }
126}
127
128void DirectionalDragAreaPrivate::setTimeSource(const SharedTimeSource &timeSource)
129{
130 this->timeSource = timeSource;
131 activeTouches.m_timeSource = timeSource;
132}
133
134qreal DirectionalDragArea::distance() const
135{
136 if (Direction::isHorizontal(d->direction)) {
137 return d->publicPos.x() - d->startPos.x();
138 } else {
139 return d->publicPos.y() - d->startPos.y();
140 }
141}
142
143void DirectionalDragAreaPrivate::updateSceneDistance()
144{
145 QPointF totalMovement = publicScenePos - startScenePos;
146 sceneDistance = projectOntoDirectionVector(totalMovement);
147}
148
149qreal DirectionalDragArea::sceneDistance() const
150{
151 return d->sceneDistance;
152}
153
154qreal DirectionalDragArea::touchX() const
155{
156 return d->publicPos.x();
157}
158
159qreal DirectionalDragArea::touchY() const
160{
161 return d->publicPos.y();
162}
163
164qreal DirectionalDragArea::touchSceneX() const
165{
166 return d->publicScenePos.x();
167}
168
169qreal DirectionalDragArea::touchSceneY() const
170{
171 return d->publicScenePos.y();
172}
173
174bool DirectionalDragArea::dragging() const
175{
176 return d->status == DirectionalDragAreaPrivate::Recognized;
177}
178
179bool DirectionalDragArea::pressed() const
180{
181 return d->status != DirectionalDragAreaPrivate::WaitingForTouch;
182}
183
184bool DirectionalDragArea::immediateRecognition() const
185{
186 return d->immediateRecognition;
187}
188
189void DirectionalDragArea::setImmediateRecognition(bool enabled)
190{
191 if (d->immediateRecognition != enabled) {
192 d->immediateRecognition = enabled;
193 Q_EMIT immediateRecognitionChanged(enabled);
194 }
195}
196
197bool DirectionalDragArea::monitorOnly() const
198{
199 return d->monitorOnly;
200}
201
202void DirectionalDragArea::setMonitorOnly(bool monitorOnly)
203{
204 if (d->monitorOnly != monitorOnly) {
205 d->monitorOnly = monitorOnly;
206
207 if (monitorOnly && d->status == DirectionalDragAreaPrivate::Undecided) {
208 TouchRegistry::instance()->removeCandidateOwnerForTouch(d->touchId, this);
209 // We still wanna know when it ends for keeping the composition time window up-to-date
210 TouchRegistry::instance()->addTouchWatcher(d->touchId, this);
211 }
212
213 Q_EMIT monitorOnlyChanged(monitorOnly);
214 }
215}
216
217void DirectionalDragArea::removeTimeConstraints()
218{
219 d->setMaxTime(60 * 60 * 1000);
220 d->compositionTime = 0;
221 ddaDebug("removed time constraints");
222}
223
224bool DirectionalDragArea::event(QEvent *event)
225{
226 if (event->type() == TouchOwnershipEvent::touchOwnershipEventType()) {
227 d->touchOwnershipEvent(static_cast<TouchOwnershipEvent *>(event));
228 return true;
229 } else if (event->type() == UnownedTouchEvent::unownedTouchEventType()) {
230 d->unownedTouchEvent(static_cast<UnownedTouchEvent *>(event));
231 return true;
232 } else {
233 return QQuickItem::event(event);
234 }
235}
236
237void DirectionalDragAreaPrivate::touchOwnershipEvent(TouchOwnershipEvent *event)
238{
239 if (event->gained()) {
240 QVector<int> ids;
241 ids.append(event->touchId());
242 ddaDebug("grabbing touch");
243 q->grabTouchPoints(ids);
244
245 // Work around for Qt bug. If we grab a touch that is being used for mouse pointer
246 // emulation it will cause the emulation logic to go nuts.
247 // Thus we have to also grab the mouse in this case.
248 //
249 // The fix for this bug has landed in Qt 5.4 (https://codereview.qt-project.org/96887)
250 // TODO: Remove this workaround once we start using Qt 5.4
251 if (q->window()) {
252 QQuickWindowPrivate *windowPrivate = QQuickWindowPrivate::get(q->window());
253 if (windowPrivate->touchMouseId == event->touchId() && q->window()->mouseGrabberItem()) {
254 ddaDebug("removing mouse grabber");
255 q->window()->mouseGrabberItem()->ungrabMouse();
256 }
257 }
258 } else {
259 // We still wanna know when it ends for keeping the composition time window up-to-date
260 TouchRegistry::instance()->addTouchWatcher(touchId, q);
261
262 setStatus(WaitingForTouch);
263 }
264}
265
266void DirectionalDragAreaPrivate::unownedTouchEvent(UnownedTouchEvent *unownedTouchEvent)
267{
268 QTouchEvent *event = unownedTouchEvent->touchEvent();
269
270 Q_ASSERT(!event->touchPointStates().testFlag(Qt::TouchPointPressed));
271
272 ddaDebug("Unowned " << timeSource->msecsSinceReference() << " " << qPrintable(touchEventToString(event)));
273
274 switch (status) {
275 case WaitingForTouch:
276 // do nothing
277 break;
278 case Undecided:
279 Q_ASSERT(q->isEnabled() && q->isVisible());
280 unownedTouchEvent_undecided(unownedTouchEvent);
281 break;
282 default: // Recognized:
283 if (monitorOnly) {
284 // Treat unowned event as if we owned it, but we are really just watching it
285 touchEvent_recognized(event);
286 }
287 break;
288 }
289
290 activeTouches.update(event);
291}
292
293void DirectionalDragAreaPrivate::unownedTouchEvent_undecided(UnownedTouchEvent *unownedTouchEvent)
294{
295 const QTouchEvent::TouchPoint *touchPoint = fetchTargetTouchPoint(unownedTouchEvent->touchEvent());
296 if (!touchPoint) {
297 qCritical() << "DirectionalDragArea[status=Undecided]: touch " << touchId
298 << "missing from UnownedTouchEvent without first reaching state Qt::TouchPointReleased. "
299 "Considering it as released.";
300
301 TouchRegistry::instance()->removeCandidateOwnerForTouch(touchId, q);
302 setStatus(WaitingForTouch);
303 return;
304 }
305
306 const QPointF &touchScenePos = touchPoint->scenePos();
307
308 if (touchPoint->state() == Qt::TouchPointReleased) {
309 // touch has ended before recognition concluded
310 ddaDebug("Touch has ended before recognition concluded");
311 TouchRegistry::instance()->removeCandidateOwnerForTouch(touchId, q);
312 setStatus(WaitingForTouch);
313 return;
314 }
315
316 previousDampedScenePos.setX(dampedScenePos.x());
317 previousDampedScenePos.setY(dampedScenePos.y());
318 dampedScenePos.update(touchScenePos);
319
320 if (!movingInRightDirection()) {
321 ddaDebug("Rejecting gesture because touch point is moving in the wrong direction.");
322 TouchRegistry::instance()->removeCandidateOwnerForTouch(touchId, q);
323 // We still wanna know when it ends for keeping the composition time window up-to-date
324 TouchRegistry::instance()->addTouchWatcher(touchId, q);
325 setStatus(WaitingForTouch);
326 return;
327 }
328
329 if (isWithinTouchCompositionWindow()) {
330 // There's still time for some new touch to appear and ruin our party as it would be combined
331 // with our touchId one and therefore deny the possibility of a single-finger gesture.
332 ddaDebug("Sill within composition window. Let's wait more.");
333 return;
334 }
335
336 if (movedFarEnoughAlongGestureAxis()) {
337 if (!monitorOnly) {
338 TouchRegistry::instance()->requestTouchOwnership(touchId, q);
339 }
340 setStatus(Recognized);
341 setPublicPos(touchPoint->pos());
342 setPublicScenePos(touchScenePos);
343 } else if (isPastMaxDistance()) {
344 ddaDebug("Rejecting gesture because it went farther than maxDistance without getting recognized.");
345 TouchRegistry::instance()->removeCandidateOwnerForTouch(touchId, q);
346 // We still wanna know when it ends for keeping the composition time window up-to-date
347 TouchRegistry::instance()->addTouchWatcher(touchId, q);
348 setStatus(WaitingForTouch);
349 } else {
350 ddaDebug("Didn't move far enough yet. Let's wait more.");
351 }
352}
353
354void DirectionalDragArea::touchEvent(QTouchEvent *event)
355{
356 // TODO: Consider when more than one touch starts in the same event (although it's not possible
357 // with Mir's android-input). Have to track them all. Consider it a plus/bonus.
358
359 ddaDebug(d->timeSource->msecsSinceReference() << " " << qPrintable(touchEventToString(event)));
360
361 if (!isEnabled() || !isVisible()) {
362 QQuickItem::touchEvent(event);
363 return;
364 }
365
366 switch (d->status) {
367 case DirectionalDragAreaPrivate::WaitingForTouch:
368 d->touchEvent_absent(event);
369 break;
370 case DirectionalDragAreaPrivate::Undecided:
371 d->touchEvent_undecided(event);
372 break;
373 default: // Recognized:
374 d->touchEvent_recognized(event);
375 break;
376 }
377
378 d->activeTouches.update(event);
379}
380
381void DirectionalDragAreaPrivate::touchEvent_absent(QTouchEvent *event)
382{
383 // TODO: accept/reject is for the whole event, not per touch id. See how that affects us.
384
385 if (!event->touchPointStates().testFlag(Qt::TouchPointPressed)) {
386 // Nothing to see here. No touch starting in this event.
387 return;
388 }
389
390 // to be proven wrong, if that's the case
391 bool allGood = true;
392
393 if (isWithinTouchCompositionWindow()) {
394 // too close to the last touch start. So we consider them as starting roughly at the same time.
395 // Can't be a single-touch gesture.
396 ddaDebug("A new touch point came in but we're still within time composition window. Ignoring it.");
397 allGood = false;
398 }
399
400 const QList<QTouchEvent::TouchPoint> &touchPoints = event->touchPoints();
401
402 const QTouchEvent::TouchPoint *newTouchPoint = nullptr;
403 for (int i = 0; i < touchPoints.count() && allGood; ++i) {
404 const QTouchEvent::TouchPoint &touchPoint = touchPoints.at(i);
405 if (touchPoint.state() == Qt::TouchPointPressed) {
406 if (newTouchPoint) {
407 // more than one touch starting in this QTouchEvent. Can't be a single-touch gesture
408 allGood = false;
409 } else {
410 // that's our candidate
411 newTouchPoint = &touchPoint;
412 }
413 }
414 }
415
416 if (allGood) {
417 allGood = sanityCheckRecognitionProperties();
418 if (!allGood) {
419 qWarning("DirectionalDragArea: recognition properties are wrongly set. Gesture recognition"
420 " is impossible");
421 }
422 }
423
424 if (allGood) {
425 Q_ASSERT(newTouchPoint);
426
427 startPos = newTouchPoint->pos();
428 startScenePos = newTouchPoint->scenePos();
429 touchId = newTouchPoint->id();
430 dampedScenePos.reset(startScenePos);
431 setPublicPos(startPos);
432
433 setPublicScenePos(startScenePos);
434 updateSceneDirectionVector();
435
436 if (recognitionIsDisabled()) {
437 // Behave like a dumb TouchArea
438 ddaDebug("Gesture recognition is disabled. Requesting touch ownership immediately.");
439 setStatus(Recognized);
440 if (monitorOnly) {
441 watchPressedTouchPoints(touchPoints);
442 event->ignore();
443 } else {
444 TouchRegistry::instance()->requestTouchOwnership(touchId, q);
445 event->accept();
446 }
447 } else {
448 // just monitor the touch points for now.
449 if (monitorOnly) {
450 watchPressedTouchPoints(touchPoints);
451 } else {
452 TouchRegistry::instance()->addCandidateOwnerForTouch(touchId, q);
453 }
454
455 setStatus(Undecided);
456 // Let the item below have it. We will monitor it and grab it later if a gesture
457 // gets recognized.
458 event->ignore();
459 }
460 } else {
461 watchPressedTouchPoints(touchPoints);
462 event->ignore();
463 }
464}
465
466void DirectionalDragAreaPrivate::touchEvent_undecided(QTouchEvent *event)
467{
468 Q_ASSERT(fetchTargetTouchPoint(event) == nullptr);
469
470 // We're not interested in new touch points. We already have our candidate (touchId).
471 // But we do want to know when those new touches end for keeping the composition time
472 // window up-to-date
473 event->ignore();
474 watchPressedTouchPoints(event->touchPoints());
475
476 if (event->touchPointStates().testFlag(Qt::TouchPointPressed) && isWithinTouchCompositionWindow()) {
477 // multi-finger drags are not accepted
478 ddaDebug("Multi-finger drags are not accepted");
479
480 TouchRegistry::instance()->removeCandidateOwnerForTouch(touchId, q);
481 // We still wanna know when it ends for keeping the composition time window up-to-date
482 TouchRegistry::instance()->addTouchWatcher(touchId, q);
483
484 setStatus(WaitingForTouch);
485 }
486}
487
488void DirectionalDragAreaPrivate::touchEvent_recognized(QTouchEvent *event)
489{
490 const QTouchEvent::TouchPoint *touchPoint = fetchTargetTouchPoint(event);
491
492 if (!touchPoint) {
493 qCritical() << "DirectionalDragArea[status=Recognized]: touch " << touchId
494 << "missing from QTouchEvent without first reaching state Qt::TouchPointReleased. "
495 "Considering it as released.";
496 setStatus(WaitingForTouch);
497 } else {
498 setPublicPos(touchPoint->pos());
499 setPublicScenePos(touchPoint->scenePos());
500
501 if (touchPoint->state() == Qt::TouchPointReleased) {
502 setStatus(WaitingForTouch);
503 }
504 }
505}
506
507void DirectionalDragAreaPrivate::watchPressedTouchPoints(const QList<QTouchEvent::TouchPoint> &touchPoints)
508{
509 for (int i = 0; i < touchPoints.count(); ++i) {
510 const QTouchEvent::TouchPoint &touchPoint = touchPoints.at(i);
511 if (touchPoint.state() == Qt::TouchPointPressed) {
512 TouchRegistry::instance()->addTouchWatcher(touchPoint.id(), q);
513 }
514 }
515}
516
517bool DirectionalDragAreaPrivate::recognitionIsDisabled() const
518{
519 return immediateRecognition || (distanceThreshold <= 0 && compositionTime <= 0);
520}
521
522bool DirectionalDragAreaPrivate::sanityCheckRecognitionProperties()
523{
524 return recognitionIsDisabled()
525 || (distanceThreshold < maxDistance && compositionTime < maxTime);
526}
527
528const QTouchEvent::TouchPoint *DirectionalDragAreaPrivate::fetchTargetTouchPoint(QTouchEvent *event)
529{
530 const QList<QTouchEvent::TouchPoint> &touchPoints = event->touchPoints();
531 const QTouchEvent::TouchPoint *touchPoint = 0;
532 for (int i = 0; i < touchPoints.size(); ++i) {
533 if (touchPoints.at(i).id() == touchId) {
534 touchPoint = &touchPoints.at(i);
535 break;
536 }
537 }
538 return touchPoint;
539}
540
541bool DirectionalDragAreaPrivate::movingInRightDirection() const
542{
543 if (direction == Direction::Horizontal || direction == Direction::Vertical) {
544 return true;
545 } else {
546 QPointF movementVector(dampedScenePos.x() - previousDampedScenePos.x(),
547 dampedScenePos.y() - previousDampedScenePos.y());
548
549 qreal scalarProjection = projectOntoDirectionVector(movementVector);
550
551 return scalarProjection >= 0.;
552 }
553}
554
555bool DirectionalDragAreaPrivate::movedFarEnoughAlongGestureAxis() const
556{
557 if (distanceThreshold <= 0.) {
558 // distance threshold check is disabled
559 return true;
560 } else {
561 QPointF totalMovement(dampedScenePos.x() - startScenePos.x(),
562 dampedScenePos.y() - startScenePos.y());
563
564 qreal scalarProjection = projectOntoDirectionVector(totalMovement);
565
566 ddaDebug(" movedFarEnoughAlongGestureAxis: scalarProjection=" << scalarProjection
567 << ", distanceThreshold=" << distanceThreshold);
568
569 if (direction == Direction::Horizontal || direction == Direction::Vertical) {
570 return qAbs(scalarProjection) > distanceThreshold;
571 } else {
572 return scalarProjection > distanceThreshold;
573 }
574 }
575}
576
577bool DirectionalDragAreaPrivate::isPastMaxDistance() const
578{
579 QPointF totalMovement(dampedScenePos.x() - startScenePos.x(),
580 dampedScenePos.y() - startScenePos.y());
581
582 qreal squaredDistance = totalMovement.x()*totalMovement.x() + totalMovement.y()*totalMovement.y();
583 return squaredDistance > maxDistance*maxDistance;
584}
585
586void DirectionalDragAreaPrivate::giveUpIfDisabledOrInvisible()
587{
588 if (!q->isEnabled() || !q->isVisible()) {
589 if (status == Undecided) {
590 TouchRegistry::instance()->removeCandidateOwnerForTouch(touchId, q);
591 // We still wanna know when it ends for keeping the composition time window up-to-date
592 TouchRegistry::instance()->addTouchWatcher(touchId, q);
593 }
594
595 if (status != WaitingForTouch) {
596 ddaDebug("Resetting status because got disabled or made invisible");
597 setStatus(WaitingForTouch);
598 }
599 }
600}
601
602void DirectionalDragAreaPrivate::rejectGesture()
603{
604 if (status == Undecided) {
605 ddaDebug("Rejecting gesture because it's taking too long to drag beyond the threshold.");
606
607 TouchRegistry::instance()->removeCandidateOwnerForTouch(touchId, q);
608 // We still wanna know when it ends for keeping the composition time window up-to-date
609 TouchRegistry::instance()->addTouchWatcher(touchId, q);
610
611 setStatus(WaitingForTouch);
612 }
613}
614
615void DirectionalDragAreaPrivate::setStatus(Status newStatus)
616{
617 if (newStatus == status)
618 return;
619
620 Status oldStatus = status;
621
622 if (oldStatus == Undecided) {
623 recognitionTimer->stop();
624 }
625
626 status = newStatus;
627 Q_EMIT statusChanged(status);
628
629 ddaDebug(statusToString(oldStatus) << " -> " << statusToString(newStatus));
630
631 switch (newStatus) {
632 case WaitingForTouch:
633 if (oldStatus == Recognized) {
634 Q_EMIT q->draggingChanged(false);
635 }
636 Q_EMIT q->pressedChanged(false);
637 break;
638 case Undecided:
639 recognitionTimer->start();
640 Q_EMIT q->pressedChanged(true);
641 break;
642 case Recognized:
643 if (oldStatus == WaitingForTouch) { // for immediate recognition
644 Q_EMIT q->pressedChanged(true);
645 }
646 Q_EMIT q->draggingChanged(true);
647 break;
648 default:
649 // no-op
650 break;
651 }
652}
653
654void DirectionalDragAreaPrivate::setPublicPos(const QPointF point)
655{
656 bool xChanged = publicPos.x() != point.x();
657 bool yChanged = publicPos.y() != point.y();
658
659 // Public position should not get updated while the gesture is still being recognized
660 // (ie, Undecided status).
661 Q_ASSERT(status == WaitingForTouch || status == Recognized);
662
663 if (status == Recognized && !recognitionIsDisabled()) {
664 // When the gesture finally gets recognized, the finger will likely be
665 // reasonably far from the edge. If we made the contentX immediately
666 // follow the finger position it would be visually unpleasant as it
667 // would appear right next to the user's finger out of nowhere (ie,
668 // it would jump). Instead, we make contentX go towards the user's
669 // finger in several steps. ie., in an animated way.
670 QPointF delta = point - publicPos;
671 // the trick is not to go all the way (1.0) as it would cause a sudden jump
672 publicPos.rx() += 0.4 * delta.x();
673 publicPos.ry() += 0.4 * delta.y();
674 } else {
675 // no smoothing when initializing or if gesture recognition was immediate as there will
676 // be no jump.
677 publicPos = point;
678 }
679
680 if (xChanged) {
681 Q_EMIT q->touchXChanged(publicPos.x());
682 if (Direction::isHorizontal(direction))
683 Q_EMIT q->distanceChanged(q->distance());
684 }
685
686 if (yChanged) {
687 Q_EMIT q->touchYChanged(publicPos.y());
688 if (Direction::isVertical(direction))
689 Q_EMIT q->distanceChanged(q->distance());
690 }
691}
692
693void DirectionalDragAreaPrivate::setPublicScenePos(const QPointF point)
694{
695 bool xChanged = publicScenePos.x() != point.x();
696 bool yChanged = publicScenePos.y() != point.y();
697
698 if (!xChanged && !yChanged)
699 return;
700
701 // Public position should not get updated while the gesture is still being recognized
702 // (ie, Undecided status).
703 Q_ASSERT(status == WaitingForTouch || status == Recognized);
704
705 qreal oldSceneDistance = sceneDistance;
706
707 if (status == Recognized && !recognitionIsDisabled()) {
708 // When the gesture finally gets recognized, the finger will likely be
709 // reasonably far from the edge. If we made the contentX immediately
710 // follow the finger position it would be visually unpleasant as it
711 // would appear right next to the user's finger out of nowhere (ie,
712 // it would jump). Instead, we make contentX go towards the user's
713 // finger in several steps. ie., in an animated way.
714 QPointF delta = point - publicScenePos;
715 // the trick is not to go all the way (1.0) as it would cause a sudden jump
716 publicScenePos.rx() += 0.4 * delta.x();
717 publicScenePos.ry() += 0.4 * delta.y();
718 } else {
719 // no smoothing when initializing or if gesture recognition was immediate as there will
720 // be no jump.
721 publicScenePos = point;
722 }
723
724 updateSceneDistance();
725
726 if (oldSceneDistance != sceneDistance) {
727 Q_EMIT q->sceneDistanceChanged(sceneDistance);
728 }
729
730 if (xChanged) {
731 Q_EMIT q->touchSceneXChanged(publicScenePos.x());
732 }
733
734 if (yChanged) {
735 Q_EMIT q->touchSceneYChanged(publicScenePos.y());
736 }
737}
738
739bool DirectionalDragAreaPrivate::isWithinTouchCompositionWindow()
740{
741 return
742 compositionTime > 0 &&
743 !activeTouches.isEmpty() &&
744 timeSource->msecsSinceReference() <=
745 activeTouches.mostRecentStartTime() + (qint64)compositionTime;
746}
747
748void DirectionalDragArea::itemChange(ItemChange change, const ItemChangeData &value)
749{
750 if (change == QQuickItem::ItemSceneChange) {
751 if (value.window != nullptr) {
752 value.window->installEventFilter(TouchRegistry::instance());
753
754 // TODO: Handle window->screen() changes (ie window changing screens)
755
756 qreal pixelsPerInch = value.window->screen()->physicalDotsPerInch();
757 if (pixelsPerInch < 0) {
758 // It can return garbage when run in a XVFB server (Virtual Framebuffer 'fake' X server)
759 pixelsPerInch = 72;
760 }
761
762 d->setPixelsPerMm(pixelsPerInch / 25.4);
763 }
764 }
765}
766
767void DirectionalDragAreaPrivate::setPixelsPerMm(qreal pixelsPerMm)
768{
769 dampedScenePos.setMaxDelta(1. * pixelsPerMm);
770 setDistanceThreshold(4. * pixelsPerMm);
771 maxDistance = 10. * pixelsPerMm;
772}
773
774//************************** ActiveTouchesInfo **************************
775
776ActiveTouchesInfo::ActiveTouchesInfo(const SharedTimeSource &timeSource)
777 : m_timeSource(timeSource)
778{
779}
780
781void ActiveTouchesInfo::update(QTouchEvent *event)
782{
783 if (!(event->touchPointStates() & (Qt::TouchPointPressed | Qt::TouchPointReleased))) {
784 // nothing to update
785 #if ACTIVETOUCHESINFO_DEBUG
786 qDebug("[DDA::ActiveTouchesInfo] Nothing to Update");
787 #endif
788 return;
789 }
790
791 const QList<QTouchEvent::TouchPoint> &touchPoints = event->touchPoints();
792 for (int i = 0; i < touchPoints.count(); ++i) {
793 const QTouchEvent::TouchPoint &touchPoint = touchPoints.at(i);
794 if (touchPoint.state() == Qt::TouchPointPressed) {
795 addTouchPoint(touchPoint.id());
796 } else if (touchPoint.state() == Qt::TouchPointReleased) {
797 removeTouchPoint(touchPoint.id());
798 }
799 }
800}
801
802#if ACTIVETOUCHESINFO_DEBUG
803QString ActiveTouchesInfo::toString()
804{
805 QString string = "(";
806
807 {
808 QTextStream stream(&string);
809 m_touchInfoPool.forEach([&](Pool<ActiveTouchInfo>::Iterator &touchInfo) {
810 stream << "(id=" << touchInfo->id << ",startTime=" << touchInfo->startTime << ")";
811 return true;
812 });
813 }
814
815 string.append(")");
816
817 return string;
818}
819#endif // ACTIVETOUCHESINFO_DEBUG
820
821void ActiveTouchesInfo::addTouchPoint(int touchId)
822{
823 ActiveTouchInfo &activeTouchInfo = m_touchInfoPool.getEmptySlot();
824 activeTouchInfo.id = touchId;
825 activeTouchInfo.startTime = m_timeSource->msecsSinceReference();
826
827 #if ACTIVETOUCHESINFO_DEBUG
828 qDebug() << "[DDA::ActiveTouchesInfo]" << qPrintable(toString());
829 #endif
830}
831
832qint64 ActiveTouchesInfo::touchStartTime(int touchId)
833{
834 qint64 result = -1;
835
836 m_touchInfoPool.forEach([&](Pool<ActiveTouchInfo>::Iterator &touchInfo) {
837 if (touchId == touchInfo->id) {
838 result = touchInfo->startTime;
839 return false;
840 } else {
841 return true;
842 }
843 });
844
845 Q_ASSERT(result != -1);
846 return result;
847}
848
849void ActiveTouchesInfo::removeTouchPoint(int touchId)
850{
851 m_touchInfoPool.forEach([&](Pool<ActiveTouchInfo>::Iterator &touchInfo) {
852 if (touchId == touchInfo->id) {
853 m_touchInfoPool.freeSlot(touchInfo);
854 return false;
855 } else {
856 return true;
857 }
858 });
859
860 #if ACTIVETOUCHESINFO_DEBUG
861 qDebug() << "[DDA::ActiveTouchesInfo]" << qPrintable(toString());
862 #endif
863}
864
865qint64 ActiveTouchesInfo::mostRecentStartTime()
866{
867 Q_ASSERT(!m_touchInfoPool.isEmpty());
868
869 qint64 highestStartTime = -1;
870
871 m_touchInfoPool.forEach([&](Pool<ActiveTouchInfo>::Iterator &activeTouchInfo) {
872 if (activeTouchInfo->startTime > highestStartTime) {
873 highestStartTime = activeTouchInfo->startTime;
874 }
875 return true;
876 });
877
878 return highestStartTime;
879}
880
881void DirectionalDragAreaPrivate::updateSceneDirectionVector()
882{
883 QPointF localOrigin(0., 0.);
884 QPointF localDirection;
885 switch (direction) {
886 case Direction::Upwards:
887 localDirection.rx() = 0.;
888 localDirection.ry() = -1.;
889 break;
890 case Direction::Downwards:
891 case Direction::Vertical:
892 localDirection.rx() = 0.;
893 localDirection.ry() = 1;
894 break;
895 case Direction::Leftwards:
896 localDirection.rx() = -1.;
897 localDirection.ry() = 0.;
898 break;
899 default: // Direction::Rightwards || Direction.Horizontal
900 localDirection.rx() = 1.;
901 localDirection.ry() = 0.;
902 break;
903 }
904 QPointF sceneOrigin = q->mapToScene(localOrigin);
905 QPointF sceneDirection = q->mapToScene(localDirection);
906 sceneDirectionVector = sceneDirection - sceneOrigin;
907}
908
909qreal DirectionalDragAreaPrivate::projectOntoDirectionVector(const QPointF sceneVector) const
910{
911 // same as dot product as sceneDirectionVector is a unit vector
912 return sceneVector.x() * sceneDirectionVector.x() +
913 sceneVector.y() * sceneDirectionVector.y();
914}
915
916DirectionalDragAreaPrivate::DirectionalDragAreaPrivate(DirectionalDragArea *q)
917 : q(q)
918 , status(WaitingForTouch)
919 , sceneDistance(0)
920 , touchId(-1)
921 , direction(Direction::Rightwards)
922 , distanceThreshold(0)
923 , distanceThresholdSquared(0.)
924 , maxTime(400)
925 , compositionTime(60)
926 , immediateRecognition(false)
927 , recognitionTimer(nullptr)
928 , timeSource(new RealTimeSource)
929 , activeTouches(timeSource)
930 , monitorOnly(false)
931{
932}
9330
=== removed file 'plugins/Ubuntu/Gestures/DirectionalDragArea.h'
--- plugins/Ubuntu/Gestures/DirectionalDragArea.h 2016-03-29 03:47:39 +0000
+++ plugins/Ubuntu/Gestures/DirectionalDragArea.h 1970-01-01 00:00:00 +0000
@@ -1,143 +0,0 @@
1/*
2 * Copyright (C) 2013,2014 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef DIRECTIONAL_DRAG_AREA_H
18#define DIRECTIONAL_DRAG_AREA_H
19
20#include <QtQuick/QQuickItem>
21#include "UbuntuGesturesQmlGlobal.h"
22#include "Damper.h"
23#include "Direction.h"
24
25// lib UbuntuGestures
26#include <Pool.h>
27#include <Timer.h>
28
29class TouchOwnershipEvent;
30class UnownedTouchEvent;
31class DirectionalDragAreaPrivate;
32
33/*
34 An area that detects axis-aligned single-finger drag gestures
35
36 If a drag deviates too much from the components' direction recognition will
37 fail. It will also fail if the drag or flick is too short. E.g. a noisy or
38 fidgety click
39
40 See doc/DirectionalDragArea.svg
41 */
42class UBUNTUGESTURESQML_EXPORT DirectionalDragArea : public QQuickItem {
43 Q_OBJECT
44
45 // The direction in which the gesture should move in order to be recognized.
46 Q_PROPERTY(Direction::Type direction READ direction WRITE setDirection NOTIFY directionChanged)
47
48 // The distance travelled by the finger along the axis specified by
49 // DirectionalDragArea's direction.
50 Q_PROPERTY(qreal distance READ distance NOTIFY distanceChanged)
51
52 // The distance travelled by the finger along the axis specified by
53 // DirectionalDragArea's direction in scene coordinates
54 Q_PROPERTY(qreal sceneDistance READ sceneDistance NOTIFY sceneDistanceChanged)
55
56 // Position of the touch point performing the drag relative to this item.
57 Q_PROPERTY(qreal touchX READ touchX NOTIFY touchXChanged)
58 Q_PROPERTY(qreal touchY READ touchY NOTIFY touchYChanged)
59
60 // Position of the touch point performing the drag, in scene's coordinate system
61 Q_PROPERTY(qreal touchSceneX READ touchSceneX NOTIFY touchSceneXChanged)
62 Q_PROPERTY(qreal touchSceneY READ touchSceneY NOTIFY touchSceneYChanged)
63
64 // Whether a drag gesture is taking place
65 Q_PROPERTY(bool dragging READ dragging NOTIFY draggingChanged)
66
67 // Whether the drag area is pressed.
68 Q_PROPERTY(bool pressed READ pressed NOTIFY pressedChanged)
69
70 // Whether a gesture should be Recognized as soon a touch lands on the area.
71 // With this property enabled it will work pretty much like a MultiPointTouchArea,
72 // just with a different API.
73 //
74 // It's false by default. In most cases you will not want that enabled.
75 Q_PROPERTY(bool immediateRecognition
76 READ immediateRecognition
77 WRITE setImmediateRecognition
78 NOTIFY immediateRecognitionChanged)
79
80 // Whether we are merely monitoring touch events (in which case, we don't
81 // claim ownership of the touch).
82 Q_PROPERTY(bool monitorOnly READ monitorOnly WRITE setMonitorOnly NOTIFY monitorOnlyChanged)
83
84 Q_ENUMS(Direction)
85public:
86 DirectionalDragArea(QQuickItem *parent = 0);
87
88 Direction::Type direction() const;
89 void setDirection(Direction::Type);
90
91 qreal distance() const;
92 qreal sceneDistance() const;
93
94 qreal touchX() const;
95 qreal touchY() const;
96
97 qreal touchSceneX() const;
98 qreal touchSceneY() const;
99
100 bool dragging() const;
101
102 bool pressed() const;
103
104 bool immediateRecognition() const;
105 void setImmediateRecognition(bool enabled);
106
107 bool monitorOnly() const;
108 void setMonitorOnly(bool monitorOnly);
109
110 bool event(QEvent *e) override;
111
112 /*
113 In qmltests, sequences of touch events are sent all at once, unlike in "real life".
114 Also qmltests might run really slowly, e.g. when run from inside virtual machines.
115 Thus to remove a variable that qmltests cannot really control, namely time, this
116 function removes all constraints that are sensible to elapsed time.
117
118 This effectively makes the DirectionalDragArea easier to fool.
119 */
120 Q_INVOKABLE void removeTimeConstraints();
121
122Q_SIGNALS:
123 void directionChanged(Direction::Type direction);
124 void draggingChanged(bool value);
125 void pressedChanged(bool value);
126 void distanceChanged(qreal value);
127 void sceneDistanceChanged(qreal value);
128 void touchXChanged(qreal value);
129 void touchYChanged(qreal value);
130 void touchSceneXChanged(qreal value);
131 void touchSceneYChanged(qreal value);
132 void immediateRecognitionChanged(bool value);
133 void monitorOnlyChanged(bool value);
134
135protected:
136 void touchEvent(QTouchEvent *event) override;
137 void itemChange(ItemChange change, const ItemChangeData &value) override;
138
139public: // so tests can access it
140 DirectionalDragAreaPrivate *d;
141};
142
143#endif // DIRECTIONAL_DRAG_AREA_H
1440
=== removed file 'plugins/Ubuntu/Gestures/DirectionalDragArea_p.h'
--- plugins/Ubuntu/Gestures/DirectionalDragArea_p.h 2016-03-29 03:47:39 +0000
+++ plugins/Ubuntu/Gestures/DirectionalDragArea_p.h 1970-01-01 00:00:00 +0000
@@ -1,169 +0,0 @@
1/*
2 * Copyright (C) 2015 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef DIRECTIONAL_DRAG_AREA_PRIV_H
18#define DIRECTIONAL_DRAG_AREA_PRIV_H
19
20// Information about an active touch point
21struct UBUNTUGESTURESQML_EXPORT ActiveTouchInfo {
22 ActiveTouchInfo() : id(-1), startTime(-1) {}
23 bool isValid() const { return id != -1; }
24 void reset() { id = -1; }
25 int id;
26 qint64 startTime;
27};
28class UBUNTUGESTURESQML_EXPORT ActiveTouchesInfo {
29public:
30 ActiveTouchesInfo(const UbuntuGestures::SharedTimeSource &timeSource);
31 void update(QTouchEvent *event);
32 qint64 touchStartTime(int id);
33 bool isEmpty() const { return m_touchInfoPool.isEmpty(); }
34 qint64 mostRecentStartTime();
35 UbuntuGestures::SharedTimeSource m_timeSource;
36private:
37 void addTouchPoint(int touchId);
38 void removeTouchPoint(int touchId);
39 #if ACTIVETOUCHESINFO_DEBUG
40 QString toString();
41 #endif
42
43 Pool<ActiveTouchInfo> m_touchInfoPool;
44};
45
46class UBUNTUGESTURESQML_EXPORT DirectionalDragAreaPrivate : public QObject {
47 Q_OBJECT
48
49 Q_ENUMS(Status)
50public:
51 DirectionalDragAreaPrivate(DirectionalDragArea *q);
52
53public Q_SLOTS:
54 void giveUpIfDisabledOrInvisible();
55 void rejectGesture();
56
57public:
58 // Describes the state of the directional drag gesture.
59 enum Status {
60 // Waiting for a new touch point to land on this area. No gesture is being processed
61 // or tracked.
62 WaitingForTouch,
63
64 // A touch point has landed on this area but it's not know yet whether it is
65 // performing a drag in the correct direction.
66 // If it's decided that the touch point is not performing a directional drag gesture,
67 // it will be rejected/ignored and status will return to WaitingForTouch.
68 Undecided, //Recognizing,
69
70 // There's a touch point in this area and it performed a drag in the correct
71 // direction.
72 //
73 // Once recognized, the gesture state will move back to WaitingForTouch only once
74 // that touch point ends. The gesture will remain in the Recognized state even if
75 // the touch point starts moving in other directions or halts.
76 Recognized,
77 };
78
79 void touchEvent_absent(QTouchEvent *event);
80 void touchEvent_undecided(QTouchEvent *event);
81 void touchEvent_recognized(QTouchEvent *event);
82 bool movingInRightDirection() const;
83 bool movedFarEnoughAlongGestureAxis() const;
84 bool isPastMaxDistance() const;
85 const QTouchEvent::TouchPoint *fetchTargetTouchPoint(QTouchEvent *event);
86 void setStatus(Status newStatus);
87 void setPublicPos(const QPointF point);
88 void setPublicScenePos(const QPointF point);
89 bool isWithinTouchCompositionWindow();
90 void updateSceneDirectionVector();
91 // returns the scalar projection between the given vector (in scene coordinates)
92 // and m_sceneDirectionVector
93 qreal projectOntoDirectionVector(const QPointF sceneVector) const;
94 void touchOwnershipEvent(TouchOwnershipEvent *event);
95 void unownedTouchEvent(UnownedTouchEvent *event);
96 void unownedTouchEvent_undecided(UnownedTouchEvent *unownedTouchEvent);
97 void watchPressedTouchPoints(const QList<QTouchEvent::TouchPoint> &touchPoints);
98 bool recognitionIsDisabled() const;
99 bool sanityCheckRecognitionProperties();
100 void updateSceneDistance();
101 void setMaxTime(int value);
102 void setDistanceThreshold(qreal value);
103 void setPixelsPerMm(qreal pixelsPerMm);
104 QString objectName() const { return q->objectName(); }
105
106 // Replaces the existing Timer with the given one.
107 //
108 // Useful for providing a fake timer when testing.
109 void setRecognitionTimer(UbuntuGestures::AbstractTimer *timer);
110
111 // Useful for testing, where a fake time source can be supplied
112 void setTimeSource(const UbuntuGestures::SharedTimeSource &timeSource);
113
114 DirectionalDragArea *q;
115
116 // The current status of the directional drag gesture area.
117 Status status;
118
119 QPointF startPos;
120 QPointF startScenePos;
121 qreal sceneDistance;
122 int touchId;
123
124 // The touch position exposed in the public API.
125 // It only starts to move once the gesture gets recognized.
126 QPointF publicPos;
127 QPointF publicScenePos;
128
129 // A movement damper is used in some of the gesture recognition calculations
130 // to get rid of noise or small oscillations in the touch position.
131 DampedPointF dampedScenePos;
132 QPointF previousDampedScenePos;
133
134 // Unit vector in scene coordinates describing the direction of the gesture recognition
135 QPointF sceneDirectionVector;
136
137 Direction::Type direction;
138
139 // How far a touch point has to move from its initial position along the gesture axis in order
140 // for it to be recognized as a directional drag.
141 qreal distanceThreshold;
142 qreal distanceThresholdSquared; // it's pow(distanceThreshold, 2)
143
144 // Maximum time (in milliseconds) the gesture can take to go beyond the distance threshold
145 int maxTime;
146
147 // Maximum distance the gesture can go without crossing the axis-aligned distance threshold
148 qreal maxDistance;
149
150 // Maximum time (in milliseconds) after the start of a given touch point where
151 // subsequent touch starts are grouped with the first one into an N-touches gesture
152 // (e.g. a two-fingers tap or drag).
153 int compositionTime;
154
155 bool immediateRecognition;
156
157 UbuntuGestures::AbstractTimer *recognitionTimer;
158
159 UbuntuGestures::SharedTimeSource timeSource;
160
161 ActiveTouchesInfo activeTouches;
162
163 bool monitorOnly;
164
165Q_SIGNALS:
166 void statusChanged(Status value);
167};
168
169#endif // DIRECTIONAL_DRAG_AREA_PRIV_H
1700
=== modified file 'plugins/Ubuntu/Gestures/Gestures.qmltypes'
--- plugins/Ubuntu/Gestures/Gestures.qmltypes 2016-03-29 03:47:39 +0000
+++ plugins/Ubuntu/Gestures/Gestures.qmltypes 2016-06-01 16:58:47 +0000
@@ -55,88 +55,6 @@
55 }55 }
56 }56 }
57 Component {57 Component {
58 name: "DirectionalDragArea"
59 defaultProperty: "data"
60 prototype: "QQuickItem"
61 exports: ["Ubuntu.Gestures/DirectionalDragArea 0.1"]
62 exportMetaObjectRevisions: [0]
63 Property { name: "direction"; type: "Direction::Type" }
64 Property { name: "distance"; type: "double"; isReadonly: true }
65 Property { name: "sceneDistance"; type: "double"; isReadonly: true }
66 Property { name: "touchX"; type: "double"; isReadonly: true }
67 Property { name: "touchY"; type: "double"; isReadonly: true }
68 Property { name: "touchSceneX"; type: "double"; isReadonly: true }
69 Property { name: "touchSceneY"; type: "double"; isReadonly: true }
70 Property { name: "dragging"; type: "bool"; isReadonly: true }
71 Property { name: "pressed"; type: "bool"; isReadonly: true }
72 Property { name: "immediateRecognition"; type: "bool" }
73 Signal {
74 name: "directionChanged"
75 Parameter { name: "direction"; type: "Direction::Type" }
76 }
77 Signal {
78 name: "draggingChanged"
79 Parameter { name: "value"; type: "bool" }
80 }
81 Signal {
82 name: "pressedChanged"
83 Parameter { name: "value"; type: "bool" }
84 }
85 Signal {
86 name: "distanceChanged"
87 Parameter { name: "value"; type: "double" }
88 }
89 Signal {
90 name: "sceneDistanceChanged"
91 Parameter { name: "value"; type: "double" }
92 }
93 Signal {
94 name: "touchXChanged"
95 Parameter { name: "value"; type: "double" }
96 }
97 Signal {
98 name: "touchYChanged"
99 Parameter { name: "value"; type: "double" }
100 }
101 Signal {
102 name: "touchSceneXChanged"
103 Parameter { name: "value"; type: "double" }
104 }
105 Signal {
106 name: "touchSceneYChanged"
107 Parameter { name: "value"; type: "double" }
108 }
109 Signal {
110 name: "immediateRecognitionChanged"
111 Parameter { name: "value"; type: "bool" }
112 }
113 Method { name: "removeTimeConstraints" }
114 }
115 Component {
116 name: "FloatingFlickable"
117 defaultProperty: "data"
118 prototype: "QQuickItem"
119 exports: ["Ubuntu.Gestures/FloatingFlickable 0.1"]
120 exportMetaObjectRevisions: [0]
121 Property { name: "contentWidth"; type: "double" }
122 Property { name: "contentHeight"; type: "double" }
123 Property { name: "contentX"; type: "double" }
124 Property { name: "contentY"; type: "double" }
125 Property { name: "direction"; type: "Direction::Type" }
126 }
127 Component {
128 name: "GestureTouchPoint"
129 prototype: "QObject"
130 exports: ["Ubuntu.Gestures/GestureTouchPoint 0.1"]
131 isCreatable: false
132 exportMetaObjectRevisions: [0]
133 Property { name: "pointId"; type: "int"; isReadonly: true }
134 Property { name: "pressed"; type: "bool"; isReadonly: true }
135 Property { name: "x"; type: "double"; isReadonly: true }
136 Property { name: "y"; type: "double"; isReadonly: true }
137 Property { name: "dragging"; type: "bool"; isReadonly: true }
138 }
139 Component {
140 name: "PressedOutsideNotifier"58 name: "PressedOutsideNotifier"
141 defaultProperty: "data"59 defaultProperty: "data"
142 prototype: "QQuickItem"60 prototype: "QQuickItem"
@@ -156,54 +74,4 @@
156 Parameter { name: "item"; type: "QQuickItem"; isPointer: true }74 Parameter { name: "item"; type: "QQuickItem"; isPointer: true }
157 }75 }
158 }76 }
159 Component {
160 name: "TouchGestureArea"
161 defaultProperty: "data"
162 prototype: "QQuickItem"
163 exports: ["Ubuntu.Gestures/TouchGestureArea 0.1"]
164 exportMetaObjectRevisions: [0]
165 Enum {
166 name: "Status"
167 values: {
168 "WaitingForTouch": 0,
169 "Undecided": 1,
170 "Recognized": 2,
171 "Rejected": 3
172 }
173 }
174 Property { name: "touchPoints"; type: "GestureTouchPoint"; isList: true; isReadonly: true }
175 Property { name: "dragging"; type: "bool"; isReadonly: true }
176 Property { name: "minimumTouchPoints"; type: "int" }
177 Property { name: "maximumTouchPoints"; type: "int" }
178 Signal {
179 name: "statusChanged"
180 Parameter { name: "status"; type: "Status" }
181 }
182 Signal { name: "touchPointsUpdated" }
183 Signal {
184 name: "draggingChanged"
185 Parameter { name: "dragging"; type: "bool" }
186 }
187 Signal {
188 name: "minimumTouchPointsChanged"
189 Parameter { name: "value"; type: "bool" }
190 }
191 Signal {
192 name: "maximumTouchPointsChanged"
193 Parameter { name: "value"; type: "bool" }
194 }
195 Signal {
196 name: "pressed"
197 Parameter { name: "points"; type: "QList<QObject*>" }
198 }
199 Signal {
200 name: "released"
201 Parameter { name: "points"; type: "QList<QObject*>" }
202 }
203 Signal {
204 name: "updated"
205 Parameter { name: "points"; type: "QList<QObject*>" }
206 }
207 Signal { name: "clicked" }
208 }
209}77}
21078
=== renamed file 'plugins/Ubuntu/Gestures/FloatingFlickable.cpp' => 'plugins/Ubuntu/Gestures/MouseEventGenerator.cpp'
--- plugins/Ubuntu/Gestures/FloatingFlickable.cpp 2015-05-27 09:37:34 +0000
+++ plugins/Ubuntu/Gestures/MouseEventGenerator.cpp 2016-06-01 16:58:47 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright (C) 2015 Canonical, Ltd.2 * Copyright (C) 2015-2016 Canonical, Ltd.
3 *3 *
4 * This program is free software; you can redistribute it and/or modify4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by5 * it under the terms of the GNU General Public License as published by
@@ -14,137 +14,51 @@
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */15 */
1616
17#include "FloatingFlickable.h"17#include "MouseEventGenerator.h"
1818
19#include <private/qquickflickable_p.h>19#include <QCoreApplication>
20#include "DirectionalDragArea.h"20#include <QMouseEvent>
2121#include <QQuickItem>
22#include <QDebug>22
2323MouseEventGenerator::MouseEventGenerator(QObject *parent)
24FloatingFlickable::FloatingFlickable(QQuickItem *parent)24 : QObject(parent)
25 : QQuickItem(parent)25{
26 , m_mousePressed(false)26}
27{27
28 m_dragArea = new DirectionalDragArea(this);28void MouseEventGenerator::move(const QPointF position)
29 m_dragArea->setWidth(width());29{
30 m_dragArea->setHeight(height());30 if (!m_mousePressed || !m_targetItem) {
31 m_dragArea->setDirection(Direction::Horizontal);31 return;
32 connect(m_dragArea, &DirectionalDragArea::touchXChanged,32 }
33 this, &FloatingFlickable::onDragAreaTouchPosChanged);33
34 connect(m_dragArea, &DirectionalDragArea::touchYChanged,34 QMouseEvent mouseEvent(QEvent::MouseMove,
35 this, &FloatingFlickable::onDragAreaTouchPosChanged);35 QPointF(position.x(), position.y()), Qt::NoButton, Qt::LeftButton, Qt::NoModifier);
36 connect(m_dragArea, &DirectionalDragArea::draggingChanged,36
37 this, &FloatingFlickable::onDragAreaDraggingChanged);37 QCoreApplication::sendEvent(m_targetItem, &mouseEvent);
38 connect(m_dragArea, &DirectionalDragArea::directionChanged, this, &FloatingFlickable::directionChanged);38}
3939
40 m_flickable = new QQuickFlickable(this);40void MouseEventGenerator::press(const QPointF position)
41 m_flickable->setEnabled(false);41{
42 m_flickable->setWidth(width());42 if (m_mousePressed || !m_targetItem) {
43 m_flickable->setHeight(height());43 return;
44 connect(m_flickable, &QQuickFlickable::contentWidthChanged, this, &FloatingFlickable::contentWidthChanged);44 }
45 connect(m_flickable, &QQuickFlickable::contentHeightChanged, this, &FloatingFlickable::contentHeightChanged);45
46 connect(m_flickable, &QQuickFlickable::contentXChanged, this, &FloatingFlickable::contentXChanged);46 QMouseEvent mouseEvent(QEvent::MouseButtonPress,
47 connect(m_flickable, &QQuickFlickable::contentYChanged, this, &FloatingFlickable::contentYChanged);47 QPointF(position.x(), position.y()), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
4848
49 connect(this, &QQuickItem::widthChanged, this, &FloatingFlickable::updateChildrenWidth);49 QCoreApplication::sendEvent(m_targetItem, &mouseEvent);
50 connect(this, &QQuickItem::heightChanged, this, &FloatingFlickable::updateChildrenHeight);50 m_mousePressed = true;
51}51}
5252
53qreal FloatingFlickable::contentWidth() const53void MouseEventGenerator::release(const QPointF position)
54{54{
55 return m_flickable->contentWidth();55 if (!m_mousePressed || !m_targetItem) {
56}56 return;
5757 }
58void FloatingFlickable::setContentWidth(qreal contentWidth)58
59{59 QMouseEvent mouseEvent(QEvent::MouseButtonRelease,
60 m_flickable->setContentWidth(contentWidth);60 QPointF(position.x(), position.y()), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
61}61
6262 QCoreApplication::sendEvent(m_targetItem, &mouseEvent);
63qreal FloatingFlickable::contentHeight() const63 m_mousePressed = false;
64{
65 return m_flickable->contentHeight();
66}
67
68void FloatingFlickable::setContentHeight(qreal contentHeight)
69{
70 m_flickable->setContentHeight(contentHeight);
71}
72
73qreal FloatingFlickable::contentX() const
74{
75 return m_flickable->contentX();
76}
77
78void FloatingFlickable::setContentX(qreal contentX)
79{
80 m_flickable->setContentX(contentX);
81}
82
83qreal FloatingFlickable::contentY() const
84{
85 return m_flickable->contentY();
86}
87
88void FloatingFlickable::setContentY(qreal contentY)
89{
90 m_flickable->setContentY(contentY);
91}
92
93Direction::Type FloatingFlickable::direction() const
94{
95 return m_dragArea->direction();
96}
97
98void FloatingFlickable::setDirection(Direction::Type direction)
99{
100 m_dragArea->setDirection(direction);
101 if (Direction::isHorizontal(direction)) {
102 m_flickable->setFlickableDirection(QQuickFlickable::HorizontalFlick);
103 } else {
104 m_flickable->setFlickableDirection(QQuickFlickable::VerticalFlick);
105 }
106}
107
108void FloatingFlickable::updateChildrenWidth()
109{
110 m_dragArea->setWidth(width());
111 m_flickable->setWidth(width());
112}
113
114void FloatingFlickable::updateChildrenHeight()
115{
116 m_dragArea->setHeight(height());
117 m_flickable->setHeight(height());
118}
119
120void FloatingFlickable::onDragAreaTouchPosChanged(qreal)
121{
122 if (m_mousePressed) {
123 QMouseEvent mouseEvent(QEvent::MouseMove,
124 QPointF(m_dragArea->touchX(),m_dragArea->touchY()),
125 Qt::NoButton, Qt::LeftButton, Qt::NoModifier);
126
127 QCoreApplication::sendEvent(m_flickable, &mouseEvent);
128
129 }
130}
131
132void FloatingFlickable::onDragAreaDraggingChanged(bool dragging)
133{
134 if (dragging && !m_mousePressed) {
135 QMouseEvent mouseEvent(QEvent::MouseButtonPress,
136 QPointF(m_dragArea->touchX(),m_dragArea->touchY()),
137 Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
138
139 QCoreApplication::sendEvent(m_flickable, &mouseEvent);
140 m_mousePressed = true;
141
142 } else if (!dragging && m_mousePressed) {
143 QMouseEvent mouseEvent(QEvent::MouseButtonRelease,
144 QPointF(m_dragArea->touchX(),m_dragArea->touchY()),
145 Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
146
147 QCoreApplication::sendEvent(m_flickable, &mouseEvent);
148 m_mousePressed = false;
149 }
150}64}
15165
=== renamed file 'plugins/Ubuntu/Gestures/FloatingFlickable.h' => 'plugins/Ubuntu/Gestures/MouseEventGenerator.h'
--- plugins/Ubuntu/Gestures/FloatingFlickable.h 2015-05-27 09:37:34 +0000
+++ plugins/Ubuntu/Gestures/MouseEventGenerator.h 2016-06-01 16:58:47 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright (C) 2015 Canonical, Ltd.2 * Copyright (C) 2015-2016 Canonical, Ltd.
3 *3 *
4 * This program is free software; you can redistribute it and/or modify4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by5 * it under the terms of the GNU General Public License as published by
@@ -14,73 +14,35 @@
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */15 */
1616
17#ifndef FLOATING_FLICKABLE_H17#ifndef MOUSEEVENTGENERATOR_H
18#define FLOATING_FLICKABLE_H18#define MOUSEEVENTGENERATOR_H
1919
20#include <QQuickItem>20#include <QObject>
21#include <QPointF>
22
21#include "UbuntuGesturesQmlGlobal.h"23#include "UbuntuGesturesQmlGlobal.h"
22#include "Direction.h"24
2325class QQuickItem;
24class DirectionalDragArea;26
25class QQuickFlickable;27class UBUNTUGESTURESQML_EXPORT MouseEventGenerator : public QObject {
26
27/*
28 A Flickable that can be put in front of the item to be flicked and
29 still have the item-to-be-flicked receive input events that are not flicks.
30
31 Ie, it's a Flickable that, input-wise, is transparent to non-flick gestures.
32
33 With a regular Flickable you would have to make the item-to-be-flicked a child
34 of Flicakble to achieve the same result. FloatingFlickable has no such requirement
35 or limitation.
36 */
37class UBUNTUGESTURESQML_EXPORT FloatingFlickable : public QQuickItem {
38 Q_OBJECT28 Q_OBJECT
3929 Q_PROPERTY(QQuickItem* targetItem MEMBER m_targetItem NOTIFY targetItemChanged)
40 Q_PROPERTY(qreal contentWidth READ contentWidth WRITE setContentWidth NOTIFY contentWidthChanged)30
41 Q_PROPERTY(qreal contentHeight READ contentHeight WRITE setContentHeight NOTIFY contentHeightChanged)31public:
42 Q_PROPERTY(qreal contentX READ contentX WRITE setContentX NOTIFY contentXChanged)32 MouseEventGenerator(QObject *parent = nullptr);
43 Q_PROPERTY(qreal contentY READ contentY WRITE setContentY NOTIFY contentYChanged)33
4434 Q_INVOKABLE void move(const QPointF position);
45 Q_PROPERTY(Direction::Type direction READ direction WRITE setDirection NOTIFY directionChanged)35 Q_INVOKABLE void press(const QPointF position);
36 Q_INVOKABLE void release(const QPointF position);
4637
47Q_SIGNALS:38Q_SIGNALS:
48 void contentWidthChanged();39 void targetItemChanged(QQuickItem *);
49 void contentHeightChanged();
50 void contentXChanged();
51 void contentYChanged();
52 void directionChanged();
53
54public:
55 FloatingFlickable(QQuickItem *parent = nullptr);
56
57 qreal contentWidth() const;
58 void setContentWidth(qreal contentWidth);
59
60 qreal contentHeight() const;
61 void setContentHeight(qreal contentHeight);
62
63 qreal contentX() const;
64 void setContentX(qreal contentX);
65
66 qreal contentY() const;
67 void setContentY(qreal contentY);
68
69 Direction::Type direction() const;
70 void setDirection(Direction::Type);
71
72private Q_SLOTS:
73 void updateChildrenWidth();
74 void updateChildrenHeight();
75 void onDragAreaTouchPosChanged(qreal);
76 void onDragAreaDraggingChanged(bool value);
7740
78private:41private:
79 DirectionalDragArea *m_dragArea;42 bool m_mousePressed {false};
80 QQuickFlickable *m_flickable;43 QQuickItem *m_targetItem {nullptr};
81 bool m_mousePressed;
8244
83 friend class tst_FloatingFlickable;45 friend class tst_FloatingFlickable;
84};46};
8547
86#endif // FLOATING_FLICKABLE_H48#endif // MOUSEEVENTGENERATOR_H
8749
=== modified file 'plugins/Ubuntu/Gestures/PressedOutsideNotifier.h'
--- plugins/Ubuntu/Gestures/PressedOutsideNotifier.h 2013-11-22 13:43:40 +0000
+++ plugins/Ubuntu/Gestures/PressedOutsideNotifier.h 2016-06-01 16:58:47 +0000
@@ -23,7 +23,7 @@
23#include <QPointer>23#include <QPointer>
24#include <QTimer>24#include <QTimer>
2525
26#include "UbuntuGesturesGlobal.h"26#include <ubuntugesturesglobal.h>
2727
28/*28/*
29 Notifies when a point, mouse or touch, is pressed outside its area.29 Notifies when a point, mouse or touch, is pressed outside its area.
3030
=== modified file 'plugins/Ubuntu/Gestures/TouchGate.cpp'
--- plugins/Ubuntu/Gestures/TouchGate.cpp 2015-06-24 11:41:09 +0000
+++ plugins/Ubuntu/Gestures/TouchGate.cpp 2016-06-01 16:58:47 +0000
@@ -20,8 +20,8 @@
20#include <QDebug>20#include <QDebug>
21#include <QQuickWindow>21#include <QQuickWindow>
2222
23#include <TouchOwnershipEvent.h>23#include <TouchOwnershipEvent>
24#include <TouchRegistry.h>24#include <TouchRegistry>
2525
26#if TOUCHGATE_DEBUG26#if TOUCHGATE_DEBUG
27#define ugDebug(params) qDebug().nospace() << "[TouchGate(" << (void*)this << ")] " << params27#define ugDebug(params) qDebug().nospace() << "[TouchGate(" << (void*)this << ")] " << params
2828
=== modified file 'plugins/Ubuntu/Gestures/TouchGestureArea.cpp'
--- plugins/Ubuntu/Gestures/TouchGestureArea.cpp 2016-03-11 20:18:12 +0000
+++ plugins/Ubuntu/Gestures/TouchGestureArea.cpp 2016-06-01 16:58:47 +0000
@@ -16,10 +16,11 @@
1616
17#include "TouchGestureArea.h"17#include "TouchGestureArea.h"
1818
19// local19#include <UbuntuGestures/TouchOwnershipEvent>
20#include "TouchOwnershipEvent.h"20#include <UbuntuGestures/TouchRegistry>
21#include "TouchRegistry.h"21#include <UbuntuGestures/UnownedTouchEvent>
22#include "UnownedTouchEvent.h"22// #include "TouchRegistry.h"
23// #include "UnownedTouchEvent.h"
2324
24#include <QGuiApplication>25#include <QGuiApplication>
25#include <QStyleHints>26#include <QStyleHints>
@@ -588,13 +589,15 @@
588 resyncCachedTouchPoints();589 resyncCachedTouchPoints();
589 break;590 break;
590 case InternalStatus::WaitingForMoreTouches:591 case InternalStatus::WaitingForMoreTouches:
591 m_recognitionTimer->start(m_recognitionPeriod);592 m_recognitionTimer->setInterval(m_recognitionPeriod);
593 m_recognitionTimer->start();
592 break;594 break;
593 case InternalStatus::Recognized:595 case InternalStatus::Recognized:
594 resyncCachedTouchPoints();596 resyncCachedTouchPoints();
595 break;597 break;
596 case InternalStatus::WaitingForRejection:598 case InternalStatus::WaitingForRejection:
597 m_recognitionTimer->start(m_releaseRejectPeriod);599 m_recognitionTimer->setInterval(m_releaseRejectPeriod);
600 m_recognitionTimer->start();
598 break;601 break;
599 case InternalStatus::Rejected:602 case InternalStatus::Rejected:
600 resyncCachedTouchPoints();603 resyncCachedTouchPoints();
601604
=== modified file 'plugins/Ubuntu/Gestures/TouchGestureArea.h'
--- plugins/Ubuntu/Gestures/TouchGestureArea.h 2016-03-11 20:18:12 +0000
+++ plugins/Ubuntu/Gestures/TouchGestureArea.h 2016-06-01 16:58:47 +0000
@@ -21,8 +21,7 @@
2121
22#include <QQuickItem>22#include <QQuickItem>
2323
24// lib UbuntuGestures24#include <UbuntuGestures/Timer>
25#include <Timer.h>
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches