Merge lp:~oif-team/ubuntu/natty/qt4-x11/xi2.1 into lp:ubuntu/natty/qt4-x11

Proposed by Chase Douglas
Status: Needs review
Proposed branch: lp:~oif-team/ubuntu/natty/qt4-x11/xi2.1
Merge into: lp:ubuntu/natty/qt4-x11
Diff against target: 941 lines (+909/-1)
4 files modified
debian/changelog (+8/-0)
debian/control (+1/-1)
debian/patches/200_xi2.1.patch (+897/-0)
debian/patches/series (+3/-0)
To merge this branch: bzr merge lp:~oif-team/ubuntu/natty/qt4-x11/xi2.1
Reviewer Review Type Date Requested Status
Jonathan Riddell Pending
Review via email: mp+50952@code.launchpad.net

Description of the change

Add in multitouch support. The patch's origin is from Denis Dzyubenko from Nokia. I have refined it some more. Hopefully this will serve as the base for multitouch support in upstream Qt when XInput 2.1 is finalized and available.

To post a comment you must log in.

Unmerged revisions

142. By Chase Douglas

* Add multitouch support through preliminary XInput 2.1
  - Add debian/patches/200_xi2.1.patch
  - Add build dependency on new libxi-dev with XInput 2.1 support

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'debian/changelog'
--- debian/changelog 2011-02-07 12:11:02 +0000
+++ debian/changelog 2011-02-23 16:43:58 +0000
@@ -1,3 +1,11 @@
1qt4-x11 (4:4.7.1-0ubuntu10) UNRELEASED; urgency=low
2
3 * Add multitouch support through preliminary XInput 2.1
4 - Add debian/patches/200_xi2.1.patch
5 - Add build dependency on new libxi-dev with XInput 2.1 support
6
7 -- Chase Douglas <chase.douglas@ubuntu.com> Wed, 23 Feb 2011 10:59:05 -0500
8
1qt4-x11 (4:4.7.1-0ubuntu9) natty; urgency=high9qt4-x11 (4:4.7.1-0ubuntu9) natty; urgency=high
210
3 * Force Qt4 on ARM to build against gcc-4.4 due to compiler regression in11 * Force Qt4 on ARM to build against gcc-4.4 due to compiler regression in
412
=== modified file 'debian/control'
--- debian/control 2011-02-07 12:11:02 +0000
+++ debian/control 2011-02-23 16:43:58 +0000
@@ -13,7 +13,7 @@
13# libopenvg1-mesa-dev,13# libopenvg1-mesa-dev,
14 libpam0g-dev, libpng12-dev, libpq-dev, libreadline-dev, libsm-dev,14 libpam0g-dev, libpng12-dev, libpq-dev, libreadline-dev, libsm-dev,
15 libsqlite0-dev, libsqlite3-dev, libtiff4-dev, libx11-dev, libxcursor-dev,15 libsqlite0-dev, libsqlite3-dev, libtiff4-dev, libx11-dev, libxcursor-dev,
16 libxext-dev, libxft-dev, libxi-dev, libxinerama-dev, libxmu-dev,16 libxext-dev, libxft-dev, libxi-dev (>= 2:1.4.1-1ubuntu1), libxinerama-dev, libxmu-dev,
17 libxrandr-dev, libxrender-dev, libxslt1-dev, libxt-dev, libxtst-dev,17 libxrandr-dev, libxrender-dev, libxslt1-dev, libxt-dev, libxtst-dev,
18 libxv-dev, zlib1g-dev, freetds-dev, g++-4.4 [armel]18 libxv-dev, zlib1g-dev, freetds-dev, g++-4.4 [armel]
19Standards-Version: 3.9.119Standards-Version: 3.9.1
2020
=== added file 'debian/patches/200_xi2.1.patch'
--- debian/patches/200_xi2.1.patch 1970-01-01 00:00:00 +0000
+++ debian/patches/200_xi2.1.patch 2011-02-23 16:43:58 +0000
@@ -0,0 +1,897 @@
1--- /dev/null
2+++ b/config.tests/x11/xinput2/xinput2.cpp
3@@ -0,0 +1,75 @@
4+/****************************************************************************
5+**
6+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
7+** All rights reserved.
8+** Contact: Nokia Corporation (qt-info@nokia.com)
9+**
10+** This file is part of the config.tests of the Qt Toolkit.
11+**
12+** $QT_BEGIN_LICENSE:LGPL$
13+** No Commercial Usage
14+** This file contains pre-release code and may not be distributed.
15+** You may use this file in accordance with the terms and conditions
16+** contained in the Technology Preview License Agreement accompanying
17+** this package.
18+**
19+** GNU Lesser General Public License Usage
20+** Alternatively, this file may be used under the terms of the GNU Lesser
21+** General Public License version 2.1 as published by the Free Software
22+** Foundation and appearing in the file LICENSE.LGPL included in the
23+** packaging of this file. Please review the following information to
24+** ensure the GNU Lesser General Public License version 2.1 requirements
25+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
26+**
27+** In addition, as a special exception, Nokia gives you certain additional
28+** rights. These rights are described in the Nokia Qt LGPL Exception
29+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
30+**
31+** If you have questions regarding the use of this file, please contact
32+** Nokia at qt-info@nokia.com.
33+**
34+**
35+**
36+**
37+**
38+**
39+**
40+**
41+** $QT_END_LICENSE$
42+**
43+****************************************************************************/
44+
45+#include <X11/Xlib.h>
46+#include <X11/extensions/XInput2.h>
47+#include <X11/extensions/Xge.h>
48+
49+#ifndef XInput_2_1
50+# error "Missing XInput_2_1 #define"
51+#endif
52+
53+int main(int, char **)
54+{
55+ // need XGenericEventCookie for XInput2 to work
56+ Display *dpy = 0;
57+ XEvent xevent;
58+ if (XGetEventData(dpy, &xevent.xcookie)) {
59+ XFreeEventData(dpy, &xevent.xcookie);
60+ }
61+
62+ XIEvent *xievent;
63+ xievent = 0;
64+
65+ XIDeviceEvent *xideviceevent;
66+ xideviceevent = 0;
67+
68+ XIHierarchyEvent *xihierarchyevent;
69+ xihierarchyevent = 0;
70+
71+ int deviceid = 0;
72+ int len = 0;
73+ Atom *atoms = XIListProperties(dpy, deviceid, &len);
74+ if (atoms)
75+ XFree(atoms);
76+
77+ return 0;
78+}
79--- /dev/null
80+++ b/config.tests/x11/xinput2/xinput2.pro
81@@ -0,0 +1,4 @@
82+CONFIG += x11
83+CONFIG -= qt
84+LIBS += -lXi
85+SOURCES = xinput2.cpp
86--- a/configure
87+++ b/configure
88@@ -765,6 +765,7 @@ CFG_DECORATION_AVAILABLE="styled windows
89 CFG_DECORATION_ON="${CFG_DECORATION_AVAILABLE}" # all on by default
90 CFG_DECORATION_PLUGIN_AVAILABLE=
91 CFG_DECORATION_PLUGIN=
92+CFG_XINPUT2=auto
93 CFG_XINPUT=runtime
94 CFG_XKB=auto
95 CFG_NIS=auto
96@@ -991,7 +992,7 @@ while [ "$#" -gt 0 ]; do
97 VAL=no
98 ;;
99 #Qt style yes options
100- -incremental|-qvfb|-profile|-shared|-static|-sm|-xinerama|-xshape|-xsync|-xinput|-egl|-reduce-exports|-pch|-separate-debug-info|-stl|-freetype|-xcursor|-xfixes|-xrandr|-xrender|-mitshm|-fontconfig|-xkb|-nis|-qdbus|-dbus|-dbus-linked|-glib|-gstreamer|-gtkstyle|-cups|-iconv|-largefile|-h|-help|-v|-verbose|-debug|-release|-fast|-accessibility|-confirm-license|-gnumake|-framework|-qt3support|-debug-and-release|-exceptions|-cocoa|-carbon|-universal|-prefix-install|-silent|-armfpa|-optimized-qmake|-dwarf2|-reduce-relocations|-sse|-openssl|-openssl-linked|-ptmalloc|-xmlpatterns|-phonon|-phonon-backend|-multimedia|-audio-backend|-svg|-declarative|-webkit|-javascript-jit|-script|-scripttools|-rpath|-force-pkg-config|-s60|-usedeffiles)
101+ -incremental|-qvfb|-profile|-shared|-static|-sm|-xinerama|-xshape|-xsync|-xinput|-xinput2|-egl|-reduce-exports|-pch|-separate-debug-info|-stl|-freetype|-xcursor|-xfixes|-xrandr|-xrender|-mitshm|-fontconfig|-xkb|-nis|-qdbus|-dbus|-dbus-linked|-glib|-gstreamer|-gtkstyle|-cups|-iconv|-largefile|-h|-help|-v|-verbose|-debug|-release|-fast|-accessibility|-confirm-license|-gnumake|-framework|-qt3support|-debug-and-release|-exceptions|-cocoa|-carbon|-universal|-prefix-install|-silent|-armfpa|-optimized-qmake|-dwarf2|-reduce-relocations|-sse|-openssl|-openssl-linked|-ptmalloc|-xmlpatterns|-phonon|-phonon-backend|-multimedia|-audio-backend|-svg|-declarative|-webkit|-javascript-jit|-script|-scripttools|-rpath|-force-pkg-config|-s60|-usedeffiles)
102 VAR=`echo $1 | sed "s,^-\(.*\),\1,"`
103 VAL=yes
104 ;;
105@@ -1637,6 +1638,13 @@ while [ "$#" -gt 0 ]; do
106 UNKNOWN_OPT=yes
107 fi
108 ;;
109+ xinput2)
110+ if [ "$VAL" = "yes" ] || [ "$VAL" = "no" ]; then
111+ CFG_XINPUT2="$VAL"
112+ else
113+ UNKNOWN_OPT=yes
114+ fi
115+ ;;
116 xinput)
117 if [ "$VAL" = "yes" ] || [ "$VAL" = "no" ] || [ "$VAL" = "runtime" ]; then
118 CFG_XINPUT="$VAL"
119@@ -3982,6 +3990,13 @@ if [ "$PLATFORM_X11" = "yes" ]; then
120 XMY="*"
121 XMN=" "
122 fi
123+ if [ "$CFG_XINPUT2" = "no" ]; then
124+ X2Y=" "
125+ X2N="*"
126+ else
127+ X2Y="*"
128+ X2N=" "
129+ fi
130 if [ "$CFG_XINPUT" = "no" ]; then
131 XIY=" "
132 XIN="*"
133@@ -4086,7 +4101,10 @@ Qt/X11 only:
134 Requires fontconfig/fontconfig.h, libfontconfig,
135 freetype.h and libfreetype.
136
137- $XIN -no-xinput ......... Do not compile Xinput support.
138+ $X2N -no-xinput2......... Do not compile XInput2 support.
139+ $X2Y -xinput2............ Compile XInput2 support.
140+
141+ $XIN -no-xinput.......... Do not compile Xinput support.
142 $XIY -xinput ............ Compile Xinput support. This also enabled tablet support
143 which requires IRIX with wacom.h and libXi or
144 XFree86 with X11/extensions/XInput.h and libXi.
145@@ -5910,7 +5928,23 @@ if [ "$PLATFORM_X11" = "yes" ]; then
146 fi
147 fi
148
149- # auto-detect Xinput support
150+ # auto-detect XInput2/Xinput support
151+ if [ "$CFG_XINPUT2" != "no" ]; then
152+ if "$unixtests/compile.test" "$XQMAKESPEC" "$QMAKE_CONFIG" $OPT_VERBOSE "$relpath" "$outpath" config.tests/x11/xinput2 "XInput2" $L_FLAGS $I_FLAGS $l_FLAGS $X11TESTS_FLAGS; then
153+ CFG_XINPUT2=yes
154+ CFG_XINPUT=no
155+ else
156+ if [ "$CFG_XINPUT2" = "yes" ] && [ "$CFG_CONFIGURE_EXIT_ON_ERROR" = "yes" ]; then
157+ echo "XInput2 support cannot be enabled due to functionality tests!"
158+ echo " Turn on verbose messaging (-v) to $0 to see the final report."
159+ echo " If you believe this message is in error you may use the continue"
160+ echo " switch (-continue) to $0 to continue."
161+ exit 101
162+ else
163+ CFG_XINPUT2=no
164+ fi
165+ fi
166+ fi
167 if [ "$CFG_XINPUT" != "no" ]; then
168 if "$unixtests/compile.test" "$XQMAKESPEC" "$QMAKE_CONFIG" $OPT_VERBOSE "$relpath" "$outpath" config.tests/x11/xinput "XInput" $L_FLAGS $I_FLAGS $l_FLAGS $X11TESTS_FLAGS; then
169 if [ "$CFG_XINPUT" != "runtime" ]; then
170@@ -6971,9 +7005,12 @@ if [ "$PLATFORM_X11" = "yes" ]; then
171 if [ "$CFG_FONTCONFIG" = "yes" ]; then
172 QT_CONFIG="$QT_CONFIG fontconfig"
173 fi
174- if [ "$CFG_XINPUT" = "yes" ]; then
175+ if [ "$CFG_XINPUT2" = "yes" -o "$CFG_XINPUT" = "yes" ]; then
176 QMakeVar set QMAKE_LIBS_X11 '-lXi $$QMAKE_LIBS_X11'
177 fi
178+ if [ "$CFG_XINPUT2" = "yes" ]; then
179+ QT_CONFIG="$QT_CONFIG xinput2"
180+ fi
181 if [ "$CFG_XINPUT" = "yes" ]; then
182 QT_CONFIG="$QT_CONFIG xinput tablet"
183 fi
184@@ -7846,6 +7883,7 @@ fi
185 [ "$CFG_XSHAPE" = "no" ] && QCONFIG_FLAGS="$QCONFIG_FLAGS QT_NO_SHAPE"
186 [ "$CFG_XVIDEO" = "no" ] && QCONFIG_FLAGS="$QCONFIG_FLAGS QT_NO_XVIDEO"
187 [ "$CFG_XSYNC" = "no" ] && QCONFIG_FLAGS="$QCONFIG_FLAGS QT_NO_XSYNC"
188+[ "$CFG_XINPUT2" = "no" ] && QCONFIG_FLAGS="$QCONFIG_FLAGS QT_NO_XINPUT2"
189 [ "$CFG_XINPUT" = "no" ] && QCONFIG_FLAGS="$QCONFIG_FLAGS QT_NO_XINPUT QT_NO_TABLET"
190
191 [ "$CFG_XCURSOR" = "runtime" ] && QCONFIG_FLAGS="$QCONFIG_FLAGS QT_RUNTIME_XCURSOR"
192@@ -8376,6 +8414,7 @@ if [ "$PLATFORM_X11" = "yes" ]; then
193 echo "Xfixes support ......... $CFG_XFIXES"
194 echo "Xrandr support ......... $CFG_XRANDR"
195 echo "Xrender support ........ $CFG_XRENDER"
196+ echo "XInput2 support ........ $CFG_XINPUT2"
197 echo "Xi support ............. $CFG_XINPUT"
198 echo "MIT-SHM support ........ $CFG_MITSHM"
199 echo "FontConfig support ..... $CFG_FONTCONFIG"
200--- a/examples/touch/fingerpaint/scribblearea.cpp
201+++ b/examples/touch/fingerpaint/scribblearea.cpp
202@@ -186,7 +186,9 @@ bool ScribbleArea::event(QEvent *event)
203 QRectF rect = touchPoint.rect();
204 if (rect.isEmpty()) {
205 qreal diameter = qreal(50) * touchPoint.pressure();
206+ QPointF center = rect.center();
207 rect.setSize(QSizeF(diameter, diameter));
208+ rect.moveCenter(center);
209 }
210
211 QPainter painter(&image);
212--- a/src/gui/kernel/kernel.pri
213+++ b/src/gui/kernel/kernel.pri
214@@ -141,6 +141,7 @@ symbian {
215 unix:x11 {
216 INCLUDEPATH += ../3rdparty/xorg
217 HEADERS += \
218+ kernel/qt_x11_p.h \
219 kernel/qx11embed_x11.h \
220 kernel/qx11info_x11.h \
221 kernel/qkde_p.h
222--- a/src/gui/kernel/qapplication_p.h
223+++ b/src/gui/kernel/qapplication_p.h
224@@ -601,6 +601,35 @@ public:
225 QList<QTouchEvent::TouchPoint> appAllTouchPoints;
226 #endif
227
228+#if defined(Q_WS_X11) && !defined(QT_NO_XINPUT2)
229+ struct TouchDeviceInfo {
230+ int deviceid;
231+ int maxTouches;
232+ bool directTouch;
233+ int numValuators;
234+ struct Valuator {
235+ int number;
236+ unsigned long label; // Atom
237+ qreal min;
238+ qreal max;
239+ quint32 resolution;
240+ };
241+ Valuator xivPosX;
242+ Valuator xivPosY;
243+ Valuator xivTouchMajor;
244+ Valuator xivTouchMinor;
245+ Valuator xivOrientation;
246+ };
247+ QHash<int, TouchDeviceInfo> touchDevices;
248+ QList<QTouchEvent::TouchPoint> appTouchPoints;
249+ QTouchEvent::DeviceType activeDeviceType;
250+ QMap<int, QPointF> touchedPos; // initial value of X and Y valuators for indirect touch
251+ QMap<int, QSizeF> touchedSize; // major => height, minor => width
252+ QMap<int, qreal> touchedOrientation; // -1 => point to left, 0 => point up, 1 => point to right
253+ QTouchEvent::TouchPoint unsentAppTouchPoint; // sequence that was not delivered to a widget yet
254+ void x11GetTouchDeviceInfo();
255+#endif
256+
257 private:
258 #ifdef Q_WS_QWS
259 QMap<const QScreen*, QRect> maxWindowRects;
260--- a/src/gui/kernel/qapplication_x11.cpp
261+++ b/src/gui/kernel/qapplication_x11.cpp
262@@ -87,6 +87,7 @@
263 #include <private/qgraphicssystemfactory_p.h>
264 #include "qguiplatformplugin_p.h"
265 #include "qkde_p.h"
266+#include "qmath.h"
267
268 #if !defined (QT_NO_TABLET)
269 extern "C" {
270@@ -126,9 +127,6 @@ extern "C" {
271
272 #define XK_MISCELLANY
273 #include <X11/keysymdef.h>
274-#if !defined(QT_NO_XINPUT)
275-#include <X11/extensions/XI.h>
276-#endif
277
278 #include <stdlib.h>
279 #include <string.h>
280@@ -327,6 +325,13 @@ static const char * x11_atomnames = {
281 // Tablet
282 "STYLUS\0"
283 "ERASER\0"
284+
285+ // XInput 2.1 touch
286+ "Abs MT Touch Major\0"
287+ "Abs MT Touch Minor\0"
288+ "Abs MT Orientation\0"
289+ "Abs MT Position X\0"
290+ "Abs MT Position Y\0"
291 };
292
293 Q_GUI_EXPORT QX11Data *qt_x11Data = 0;
294@@ -578,6 +583,10 @@ public:
295 #endif
296 bool translatePropertyEvent(const XEvent *);
297
298+#if !defined(QT_NO_XINPUT2)
299+ bool translateXI2Event(const XIEvent *);
300+#endif
301+
302 void doDeferredMap()
303 {
304 Q_ASSERT(testAttribute(Qt::WA_WState_Created));
305@@ -699,7 +708,7 @@ static int qt_x_errhandler(Display *dpy,
306
307 default:
308 #if !defined(QT_NO_XINPUT)
309- if (err->request_code == X11->xinput_major
310+ if (err->request_code == X11->xinput_opcode
311 && err->error_code == (X11->xinput_errorbase + XI_BadDevice)
312 && err->minor_code == 3 /* X_OpenDevice */) {
313 return 0;
314@@ -730,7 +739,7 @@ static int qt_x_errhandler(Display *dpy,
315 extensionName = "RENDER";
316 else if (err->request_code == X11->xrandr_major)
317 extensionName = "RANDR";
318- else if (err->request_code == X11->xinput_major)
319+ else if (err->request_code == X11->xinput_opcode)
320 extensionName = "XInputExtension";
321 else if (err->request_code == X11->mitshm_major)
322 extensionName = "MIT-SHM";
323@@ -1628,6 +1637,16 @@ static void getXDefault(const char *grou
324 }
325 #endif
326
327+inline void copy(QApplicationPrivate::TouchDeviceInfo::Valuator &dst,
328+ const XITouchValuatorClassInfo &src)
329+{
330+ dst.number = src.number;
331+ dst.label = src.label;
332+ dst.min = src.min;
333+ dst.max = src.max;
334+ dst.resolution = src.resolution;
335+}
336+
337 // ### This should be static but it isn't because of the friend declaration
338 // ### in qpaintdevice.h which then should have a static too but can't have
339 // ### it because "storage class specifiers invalid in friend function
340@@ -1660,9 +1679,13 @@ void qt_init(QApplicationPrivate *priv,
341
342 // XInputExtension
343 X11->use_xinput = false;
344- X11->xinput_major = 0;
345+ X11->xinput_opcode = 0;
346 X11->xinput_eventbase = 0;
347 X11->xinput_errorbase = 0;
348+#if !defined(QT_NO_XINPUT2)
349+ X11->xideviceinfo = 0;
350+ X11->xitouchclassinfo = 0;
351+#endif
352
353 X11->use_xkb = false;
354 X11->xkb_major = 0;
355@@ -2124,14 +2147,25 @@ void qt_init(QApplicationPrivate *priv,
356 #endif // QT_RUNTIME_XINERAMA
357 #endif // QT_NO_XINERAMA
358
359-#ifndef QT_NO_XINPUT
360+#if !defined(QT_NO_XINPUT2)
361+ X11->use_xinput = XQueryExtension(X11->display, "XInputExtension", &X11->xinput_opcode,
362+ &X11->xinput_eventbase, &X11->xinput_errorbase);
363+ if (X11->use_xinput) {
364+ // we want XInput2
365+ int ximajor = 2, ximinor = 1;
366+ if (XIQueryVersion(X11->display, &ximajor, &ximinor) == BadRequest) {
367+ // XInput2 not available
368+ X11->use_xinput = false;
369+ }
370+ }
371+#elif !defined(QT_NO_XINPUT)
372 // See if Xinput is supported on the connected display
373 X11->ptrXCloseDevice = 0;
374 X11->ptrXListInputDevices = 0;
375 X11->ptrXOpenDevice = 0;
376 X11->ptrXFreeDeviceList = 0;
377 X11->ptrXSelectExtensionEvent = 0;
378- X11->use_xinput = XQueryExtension(X11->display, "XInputExtension", &X11->xinput_major,
379+ X11->use_xinput = XQueryExtension(X11->display, "XInputExtension", &X11->xinput_opcode,
380 &X11->xinput_eventbase, &X11->xinput_errorbase);
381 if (X11->use_xinput) {
382 X11->ptrXCloseDevice = XINPUT_LOAD(XCloseDevice);
383@@ -3149,6 +3183,8 @@ int QApplication::x11ProcessEvent(XEvent
384 Q_D(QApplication);
385 QScopedLoopLevelCounter loopLevelCounter(d->threadData);
386
387+ bool isXI2Event = false;
388+
389 #ifdef ALIEN_DEBUG
390 //qDebug() << "QApplication::x11ProcessEvent:" << event->type;
391 #endif
392@@ -3179,6 +3215,16 @@ int QApplication::x11ProcessEvent(XEvent
393 case SelectionClear:
394 X11->time = event->xselectionclear.time;
395 break;
396+#if !defined(QT_NO_XINPUT2)
397+ case GenericEvent:
398+ if (X11->use_xinput
399+ && XGetEventData(X11->display, &event->xcookie)
400+ && event->xcookie.extension == X11->xinput_opcode) {
401+ // remember for later
402+ isXI2Event = true;
403+ }
404+ break;
405+#endif
406 default:
407 break;
408 }
409@@ -3190,7 +3236,43 @@ int QApplication::x11ProcessEvent(XEvent
410 }
411 #endif
412
413- QETWidget *widget = (QETWidget*)QWidget::find((WId)event->xany.window);
414+ QETWidget *widget = 0;
415+#if !defined(QT_NO_XINPUT2)
416+ if (isXI2Event) {
417+ // event->xany.window is not usable for these events
418+ // look up widget based on the type of event we received
419+ switch (event->xcookie.evtype) {
420+ case XI_TouchBegin:
421+ case XI_TouchEnd:
422+ case XI_TouchUpdate:
423+ // all of these events send XIDeviceEvents
424+ widget = (QETWidget *) QWidget::find(((XIDeviceEvent *) event->xcookie.data)->event);
425+ break;
426+ default:
427+ break;
428+ }
429+ } else
430+#endif // !defined(QT_NO_XINPUT2)
431+ {
432+ widget = (QETWidget*)QWidget::find((WId)event->xany.window);
433+ }
434+
435+#if !defined(QT_NO_XINPUT2)
436+ // make sure XFreeEventData() is called at every return point
437+ class CallXFreeEventData
438+ {
439+ Display *display;
440+ XGenericEventCookie *cookie;
441+ public:
442+ CallXFreeEventData(Display *display, XGenericEventCookie *cookie)
443+ : display(display), cookie(cookie)
444+ { }
445+ ~CallXFreeEventData()
446+ {
447+ XFreeEventData(display, cookie);
448+ }
449+ } instance(X11->display, &event->xcookie);
450+#endif
451
452 if (wPRmapper) { // just did a widget reparent?
453 if (widget == 0) { // not in std widget mapper
454@@ -3202,6 +3284,15 @@ int QApplication::x11ProcessEvent(XEvent
455 case XKeyRelease:
456 widget = qPRFindWidget(event->xany.window);
457 break;
458+#if !defined(QT_NO_XINPUT2)
459+ case GenericEvent:
460+ // as above, event->xany.window is unusable for these events
461+ if (isXI2Event) {
462+ widget = qPRFindWidget(((XIDeviceEvent *) event->xcookie.data)->event);
463+ break;
464+ }
465+ break;
466+#endif
467 }
468 }
469 else if (widget->testAttribute(Qt::WA_WState_Reparented))
470@@ -3836,6 +3927,10 @@ int QApplication::x11ProcessEvent(XEvent
471 }
472 break;
473
474+ case GenericEvent:
475+ if (isXI2Event)
476+ widget->translateXI2Event((XIEvent *)event->xcookie.data);
477+ break;
478 default:
479 break;
480 }
481@@ -5058,6 +5153,184 @@ bool QETWidget::translatePropertyEvent(c
482 return true;
483 }
484
485+#if !defined(QT_NO_XINPUT2)
486+bool QETWidget::translateXI2Event(const XIEvent *event)
487+{
488+ const XIDeviceEvent *dev = (const XIDeviceEvent *)event;
489+ QApplicationPrivate *qAppPriv = QApplicationPrivate::instance();
490+ const QApplicationPrivate::TouchDeviceInfo &tdi = qAppPriv->touchDevices[dev->sourceid];
491+ const int trackingId = dev->detail;
492+ QTouchEvent::TouchPoint *tp = 0;
493+ Qt::TouchPointStates primary = Qt::TouchPointPrimary;
494+
495+ if (!(dev->flags & XIPointerEmulated))
496+ primary = (Qt::TouchPointStates)0;
497+
498+ switch (event->evtype) {
499+ case XI_TouchBegin: {
500+ Q_ASSERT(qAppPriv->touchDevices.contains(dev->sourceid));
501+
502+ QWidget *w = childAt(QPoint(dev->event_x, dev->event_y));
503+ if (!w)
504+ break;
505+
506+ if (tdi.directTouch) {
507+ qAppPriv->appTouchPoints.append(QTouchEvent::TouchPoint(trackingId));
508+ tp = &qAppPriv->appTouchPoints.last();
509+ } else {
510+ // touch pad
511+ if (qAppPriv->appTouchPoints.isEmpty()) {
512+ if (!w->testAttribute(Qt::WA_TouchPadAcceptSingleTouchEvents)) {
513+ if (qAppPriv->unsentAppTouchPoint.id() == -1) {
514+ // do not send first TouchBegin from touchpad to a widget
515+ qAppPriv->unsentAppTouchPoint = QTouchEvent::TouchPoint(trackingId);
516+ tp = &qAppPriv->unsentAppTouchPoint;
517+ } else {
518+ // second touch on a touchpad
519+ qAppPriv->unsentAppTouchPoint.setState(Qt::TouchPointPressed | primary);
520+ qAppPriv->appTouchPoints.append(qAppPriv->unsentAppTouchPoint);
521+ qAppPriv->unsentAppTouchPoint = QTouchEvent::TouchPoint();
522+ }
523+ }
524+ }
525+ }
526+ if (!tp) {
527+ qAppPriv->appTouchPoints.append(QTouchEvent::TouchPoint(trackingId));
528+ tp = &qAppPriv->appTouchPoints.last();
529+ }
530+ break;
531+ }
532+
533+ case XI_TouchEnd:
534+ case XI_TouchUpdate: {
535+ Q_ASSERT(qAppPriv->touchDevices.contains(dev->sourceid));
536+
537+ // find the touchpoint
538+ for (int i = 0; i < qAppPriv->appTouchPoints.size(); ++i) {
539+ QTouchEvent::TouchPoint &touchPoint = qAppPriv->appTouchPoints[i];
540+ if (touchPoint.id() == trackingId)
541+ tp = &touchPoint;
542+ else
543+ touchPoint.setState(Qt::TouchPointStationary | primary);
544+ }
545+ if (!tp && qAppPriv->unsentAppTouchPoint.id() == trackingId)
546+ tp = &qAppPriv->unsentAppTouchPoint;
547+ if (!tp) {
548+ qWarning("Got touch without getting TouchBegin for id %d", trackingId);
549+ return false;
550+ }
551+ break;
552+ }
553+ default:
554+ qWarning() << "translateXI2Event: unknown XI2 event:" << event->evtype;
555+ return false;
556+ }
557+
558+ qreal *values = dev->valuators.values;
559+ for (int i = 0; i < qMin(dev->valuators.mask_len * 8, tdi.numValuators); ++i) {
560+ if (XIMaskIsSet(dev->valuators.mask, i)) {
561+ if (tdi.xivPosX.number == i) {
562+ qreal value = (*values++ - tdi.xivPosX.min) / (tdi.xivPosX.max - tdi.xivPosX.min);
563+ qreal screenValue;
564+ if (tdi.directTouch) {
565+ screenValue = dev->root_x;
566+ } else {
567+ if (qAppPriv->appTouchPoints.size() > 1) {
568+ // non-first touch point, make it relative to the first one
569+ const int firstId = qAppPriv->appTouchPoints.first().id();
570+ screenValue = dev->root_x + (value - qAppPriv->touchedPos[firstId].x()) * 300;
571+ if (event->evtype == XI_TouchBegin)
572+ qAppPriv->touchedPos[trackingId].rx() = qAppPriv->touchedPos[firstId].x();
573+ } else {
574+ screenValue = dev->root_x;
575+ if (event->evtype == XI_TouchBegin)
576+ qAppPriv->touchedPos[trackingId].rx() = value;
577+ }
578+ }
579+ tp->d->screenRect.moveCenter(QPointF(screenValue, tp->d->screenRect.center().y()));
580+ tp->d->normalizedPos.setX(value);
581+ } else if (tdi.xivPosY.number == i) {
582+ qreal value = (*values++ - tdi.xivPosY.min) / (tdi.xivPosY.max - tdi.xivPosY.min);
583+ qreal screenValue;
584+ if (tdi.directTouch) {
585+ screenValue = dev->root_y;
586+ } else {
587+ if (qAppPriv->appTouchPoints.size() > 1) {
588+ // non-first touch point, make it relative to the first one
589+ const int firstId = qAppPriv->appTouchPoints.first().id();
590+ screenValue = dev->root_y + (value - qAppPriv->touchedPos[firstId].y()) * 300;
591+ if (event->evtype == XI_TouchBegin)
592+ qAppPriv->touchedPos[trackingId].ry() = qAppPriv->touchedPos[firstId].y();
593+ } else {
594+ screenValue = dev->root_y;
595+ if (event->evtype == XI_TouchBegin)
596+ qAppPriv->touchedPos[trackingId].ry() = value;
597+ }
598+ }
599+ tp->d->screenRect.moveCenter(QPointF(tp->d->screenRect.center().x(), screenValue));
600+ tp->d->normalizedPos.setY(value);
601+ } else if (tdi.xivTouchMajor.number == i) {
602+ qreal value = (*values++ - tdi.xivTouchMajor.min) / (tdi.xivTouchMajor.max - tdi.xivTouchMajor.min);
603+ qAppPriv->touchedSize[trackingId].rheight() = value;
604+ } else if (tdi.xivTouchMinor.number == i) {
605+ qreal value = (*values++ - tdi.xivTouchMinor.min) / (tdi.xivTouchMinor.max - tdi.xivTouchMinor.min);
606+ qAppPriv->touchedSize[trackingId].rwidth() = value;
607+ } else if (tdi.xivOrientation.number == i) {
608+ qreal value = (*values++ - tdi.xivOrientation.min) / (tdi.xivOrientation.max - tdi.xivOrientation.min);
609+ qAppPriv->touchedOrientation[trackingId] = value * M_PI_2;
610+ } else
611+ ++values;
612+ }
613+ }
614+
615+ qreal angle = qAppPriv->touchedOrientation[trackingId];
616+ qreal width = qAppPriv->touchedSize[trackingId].height() * qFabs(qFastSin(angle)) +
617+ qAppPriv->touchedSize[trackingId].width() * qFabs(qFastCos(angle));
618+ qreal height = qAppPriv->touchedSize[trackingId].width() * qFabs(qFastSin(angle)) +
619+ qAppPriv->touchedSize[trackingId].height() * qFabs(qFastCos(angle));
620+ width *= tdi.directTouch ? 500 : 25;
621+ height *= tdi.directTouch ? 500 : 25;
622+ QPointF center = tp->d->screenRect.center();
623+ tp->d->screenRect = QRectF(center.x() - width/2, center.y() - height/2, width, height);
624+
625+ bool send = true;
626+ if (event->evtype == XI_TouchBegin) {
627+ tp->setState(Qt::TouchPointPressed | primary);
628+ if (qAppPriv->appTouchPoints.isEmpty())
629+ send = false;
630+ } else if (event->evtype == XI_TouchUpdate) {
631+ tp->setState(Qt::TouchPointMoved | primary);
632+ QWidget *w = childAt(QPoint(dev->event_x, dev->event_y));
633+ if (!w || (!tdi.directTouch && qAppPriv->appTouchPoints.size() == 1 && !w->testAttribute(Qt::WA_TouchPadAcceptSingleTouchEvents)))
634+ send = false;
635+ } else if (event->evtype == XI_TouchEnd) {
636+ tp->setState(Qt::TouchPointReleased | primary);
637+ if (qAppPriv->appTouchPoints.isEmpty())
638+ send = false;
639+
640+ for (int i = 0; i < qAppPriv->appTouchPoints.size(); ++i) {
641+ if (qAppPriv->appTouchPoints[i].id() == trackingId) {
642+ qAppPriv->appTouchPoints.removeAt(i);
643+ break;
644+ }
645+ }
646+ if (qAppPriv->unsentAppTouchPoint.id() == trackingId)
647+ qAppPriv->unsentAppTouchPoint = QTouchEvent::TouchPoint();
648+ if (qAppPriv->appTouchPoints.isEmpty()) {
649+ qAppPriv->touchedPos.clear();
650+ qAppPriv->touchedSize.clear();
651+ qAppPriv->touchedOrientation.clear();
652+ }
653+ }
654+
655+ if (send) {
656+ qAppPriv->activeDeviceType = tdi.directTouch ? QTouchEvent::TouchScreen : QTouchEvent::TouchPad;
657+ QApplicationPrivate::translateRawTouchEvent(0, qAppPriv->activeDeviceType, qAppPriv->appTouchPoints);
658+ }
659+
660+ return true;
661+}
662+#endif
663
664 //
665 // Paint event translation
666@@ -6177,11 +6450,61 @@ void QApplicationPrivate::_q_readRX71Mul
667
668 #else // !QT_RX71_MULTITOUCH
669
670+#if !defined(QT_NO_XINPUT2)
671+void QApplicationPrivate::x11GetTouchDeviceInfo()
672+{
673+ int count = 0;
674+ XIDeviceInfo *devices = XIQueryDevice(X11->display, XIAllDevices, &count);
675+ if (devices) {
676+ for (int i = 0; i < count; ++i) {
677+ if (!devices[i].enabled)
678+ continue;
679+ for (int k = 0; k < devices[i].num_classes; ++k) {
680+ XIAnyClassInfo *xiclassinfo = devices[i].classes[k];
681+ if (xiclassinfo->type == XITouchClass) {
682+ XITouchClassInfo *t = (XITouchClassInfo *)xiclassinfo;
683+ QApplicationPrivate::TouchDeviceInfo& tdi = touchDevices[devices[i].deviceid];
684+ tdi.deviceid = devices[i].deviceid;
685+ tdi.directTouch = t->mode == XIDirectTouch;
686+ tdi.maxTouches = t->num_touches;
687+ } else if (xiclassinfo->type == XITouchValuatorClass) {
688+ XITouchValuatorClassInfo *v = (XITouchValuatorClassInfo *)xiclassinfo;
689+ QApplicationPrivate::TouchDeviceInfo &tdi = touchDevices[devices[i].deviceid];
690+ tdi.numValuators++;
691+ if (v->label == ATOM(XAbsMTTouchMajor))
692+ copy(tdi.xivTouchMajor, *v);
693+ else if (v->label == ATOM(XAbsMTTouchMinor))
694+ copy(tdi.xivTouchMinor, *v);
695+ else if (v->label == ATOM(XAbsMTOrientation))
696+ copy(tdi.xivOrientation, *v);
697+ else if (v->label == ATOM(XAbsMTPositionX))
698+ copy(tdi.xivPosX, *v);
699+ else if (v->label == ATOM(XAbsMTPositionY))
700+ copy(tdi.xivPosY, *v);
701+ }
702+ }
703+ }
704+ XIFreeDeviceInfo(devices);
705+ }
706+}
707+
708+void QApplicationPrivate::initializeMultitouch_sys()
709+{
710+ x11GetTouchDeviceInfo();
711+}
712+void QApplicationPrivate::cleanupMultitouch_sys()
713+{
714+}
715+
716+#else
717+
718 void QApplicationPrivate::initializeMultitouch_sys()
719 { }
720 void QApplicationPrivate::cleanupMultitouch_sys()
721 { }
722
723+#endif
724+
725 #endif // QT_RX71_MULTITOUCH
726
727 QT_END_NAMESPACE
728--- a/src/gui/kernel/qevent.h
729+++ b/src/gui/kernel/qevent.h
730@@ -791,6 +791,7 @@ public:
731 QTouchEventTouchPointPrivate *d;
732 friend class QApplication;
733 friend class QApplicationPrivate;
734+ friend class QETWidget;
735 };
736
737 enum DeviceType {
738--- a/src/gui/kernel/qt_x11_p.h
739+++ b/src/gui/kernel/qt_x11_p.h
740@@ -97,13 +97,14 @@
741 # include <X11/extensions/shape.h>
742 #endif // QT_NO_SHAPE
743
744-
745-#if !defined (QT_NO_TABLET)
746+#if !defined(QT_NO_XINPUT2)
747+# include <X11/extensions/XInput2.h>
748+#elif !defined (QT_NO_TABLET)
749 # include <X11/extensions/XInput.h>
750-#if defined (Q_OS_IRIX)
751-# include <X11/extensions/SGIMisc.h>
752-# include <wacom.h>
753-#endif
754+# if defined (Q_OS_IRIX)
755+# include <X11/extensions/SGIMisc.h>
756+# include <wacom.h>
757+# endif
758 #endif // QT_NO_TABLET
759
760
761@@ -433,11 +434,15 @@ struct QX11Data
762 bool use_mitshm_pixmaps;
763 int mitshm_major;
764
765- // true if Qt is compiled w/ Tablet support and we have a tablet.
766+ // true if Qt is compiled w/ XInput2 or Tablet support and we have a tablet.
767 bool use_xinput;
768- int xinput_major;
769+ int xinput_opcode;
770 int xinput_eventbase;
771 int xinput_errorbase;
772+#if !defined(QT_NO_XINPUT2)
773+ XIDeviceInfo *xideviceinfo;
774+ XITouchClassInfo *xitouchclassinfo;
775+#endif
776
777 // for XKEYBOARD support
778 bool use_xkb;
779@@ -683,6 +688,12 @@ struct QX11Data
780 XTabletStylus,
781 XTabletEraser,
782
783+ XAbsMTTouchMajor,
784+ XAbsMTTouchMinor,
785+ XAbsMTOrientation,
786+ XAbsMTPositionX,
787+ XAbsMTPositionY,
788+
789 NPredefinedAtoms,
790
791 _QT_SETTINGS_TIMESTAMP = NPredefinedAtoms,
792--- a/src/gui/kernel/qwidget.cpp
793+++ b/src/gui/kernel/qwidget.cpp
794@@ -10737,7 +10737,7 @@ void QWidget::setAttribute(Qt::WidgetAtt
795
796 break;
797 case Qt::WA_AcceptTouchEvents:
798-#if defined(Q_WS_WIN) || defined(Q_WS_MAC) || defined(Q_OS_SYMBIAN)
799+#if defined(Q_WS_WIN) || defined(Q_WS_MAC) || defined(Q_OS_SYMBIAN) || defined(Q_WS_X11)
800 if (on)
801 d->registerTouchWindow();
802 #endif
803--- a/src/gui/kernel/qwidget_p.h
804+++ b/src/gui/kernel/qwidget_p.h
805@@ -667,6 +667,8 @@ public:
806
807 inline QRect mapFromWS(const QRect &r) const
808 { QRect rr(r); rr.translate(data.wrect.topLeft()); return rr; }
809+
810+ void registerTouchWindow();
811 #endif
812
813 // Variables.
814@@ -776,7 +778,6 @@ public:
815 void unregisterOleDnd(QWidget *widget, QOleDropTarget *target);
816 #endif
817 void grabMouseWhileInWindow();
818- void registerTouchWindow();
819 void winSetupGestures();
820 #elif defined(Q_WS_MAC) // <--------------------------------------------------------- MAC
821 // This is new stuff
822@@ -852,7 +853,6 @@ public:
823 static OSStatus qt_window_event(EventHandlerCallRef er, EventRef event, void *);
824 static OSStatus qt_widget_event(EventHandlerCallRef er, EventRef event, void *);
825 static bool qt_widget_rgn(QWidget *, short, RgnHandle, bool);
826- void registerTouchWindow();
827 #elif defined(Q_WS_QWS) // <--------------------------------------------------------- QWS
828 void setMaxWindowState_helper();
829 void setFullScreenSize_helper();
830@@ -872,7 +872,6 @@ public:
831 static QWidget *keyboardGrabber;
832 void s60UpdateIsOpaque();
833 void reparentChildren();
834- void registerTouchWindow();
835 #endif
836
837 };
838--- a/src/gui/kernel/qwidget_x11.cpp
839+++ b/src/gui/kernel/qwidget_x11.cpp
840@@ -871,7 +871,13 @@ void QWidgetPrivate::create_sys(WId wind
841 // else
842 XSelectInput(dpy, id, stdDesktopEventMask);
843 } else if (q->internalWinId()) {
844- XSelectInput(dpy, id, stdWidgetEventMask);
845+ uint eventmask = stdWidgetEventMask;
846+
847+ if (q->testAttribute(Qt::WA_AcceptTouchEvents))
848+ registerTouchWindow();
849+
850+ XSelectInput(dpy, id, eventmask);
851+
852 #if !defined (QT_NO_TABLET)
853 QTabletDeviceDataList *tablet_list = qt_tablet_devices();
854 if (X11->ptrXSelectExtensionEvent) {
855@@ -938,6 +944,9 @@ void QWidgetPrivate::create_sys(WId wind
856 surface->flush(q, q->rect(), q->mapTo(surface->window(), QPoint()));
857 }
858
859+ if (q->testAttribute(Qt::WA_AcceptTouchEvents))
860+ registerTouchWindow();
861+
862 #ifdef ALIEN_DEBUG
863 qDebug() << "QWidgetPrivate::create_sys END:" << q;
864 #endif
865@@ -3099,4 +3108,32 @@ void QWidgetPrivate::updateX11AcceptFocu
866 XFree((char *)h);
867 }
868
869+void QWidgetPrivate::registerTouchWindow()
870+{
871+#if !defined(QT_NO_XINPUT2)
872+ Q_Q(QWidget);
873+
874+ if (!q->testAttribute(Qt::WA_WState_Created) || q->windowType() == Qt::Desktop)
875+ return;
876+
877+ if (X11->use_xinput) {
878+ XIEventMask xieventmask;
879+
880+ const int mask_len = XIMaskLen(XI_LASTEVENT);
881+ QVector<uchar> mask_vector(mask_len, 0);
882+ uchar *bitmask = mask_vector.data();
883+
884+ xieventmask.deviceid = XIAllDevices;
885+ xieventmask.mask = bitmask;
886+ xieventmask.mask_len = mask_len;
887+
888+ XISetMask(bitmask, XI_TouchBegin);
889+ XISetMask(bitmask, XI_TouchEnd);
890+ XISetMask(bitmask, XI_TouchUpdate);
891+
892+ XISelectEvents(X11->display, q->effectiveWinId(), &xieventmask, 1);
893+ }
894+#endif
895+}
896+
897 QT_END_NAMESPACE
0898
=== modified file 'debian/patches/series'
--- debian/patches/series 2011-01-18 20:37:32 +0000
+++ debian/patches/series 2011-02-23 16:43:58 +0000
@@ -48,3 +48,6 @@
48kubuntu_25_qsortfilterproxymodel.diff48kubuntu_25_qsortfilterproxymodel.diff
49kubuntu_26_dbusconnection_pointer.diff49kubuntu_26_dbusconnection_pointer.diff
50kubuntu_27_dbus_signal_filter_passes_not_handled.diff50kubuntu_27_dbus_signal_filter_passes_not_handled.diff
51
52# XI 2.1 multitouch support
53200_xi2.1.patch

Subscribers

People subscribed via source and target branches