1 /****************************************************************************
3 ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
6 ** This file is part of the plugins of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
40 ****************************************************************************/
42 #include "qxcbconnection.h"
44 #ifdef XCB_USE_XINPUT2_MAEMO
46 #include "qxcbwindow.h"
47 #include <qpa/qwindowsysteminterface.h>
48 #include <X11/extensions/XInput2.h>
49 #include <X11/extensions/XI2proto.h>
50 #include <X11/Xatom.h>
54 // Define it here to work around XLib defining Bool and stuff.
55 // We can't declare those variables in the header without facing include order headaches.
56 struct XInput2MaemoData {
63 , xibuttonclassinfo(0)
68 // true if Qt is compiled w/ XInput2 or Tablet support and we have a tablet.
73 // device info for the master pointer Qt is using
74 XIDeviceInfo *xideviceinfo;
75 XIButtonClassInfo *xibuttonclassinfo;
77 QList<QWindowSystemInterface::TouchPoint> allTouchPoints;
78 QTouchDevice *qtTouchDevice;
81 bool QXcbConnection::isUsingXInput2Maemo()
83 return m_xinputData && m_xinputData->use_xinput && m_xinputData->xiMaxContacts != 0;
86 void QXcbConnection::initializeXInput2Maemo()
88 Q_ASSERT(!m_xinputData);
89 m_xinputData = new XInput2MaemoData;
90 m_xinputData->use_xinput = XQueryExtension((Display *)m_xlib_display, "XInputExtension", &m_xinputData->xinput_opcode,
91 &m_xinputData->xinput_eventbase, &m_xinputData->xinput_errorbase);
92 if (m_xinputData->use_xinput) {
94 int ximajor = 2, ximinor = 0;
95 if (XIQueryVersion((Display *)m_xlib_display, &ximajor, &ximinor) == BadRequest) {
96 // XInput2 not available
97 m_xinputData->use_xinput = false;
99 // find the first master pointer and use this throughout Qt
100 // when making XI2 calls that need a device id (rationale is that
101 // for the time being, most setups will only have one master
102 // pointer (despite having multiple slaves)
104 XIDeviceInfo *devices = XIQueryDevice((Display *)m_xlib_display, XIAllMasterDevices, &deviceCount);
106 for (int i = 0; i < deviceCount; ++i) {
107 if (devices[i].use == XIMasterPointer) {
109 m_xinputData->xideviceinfo = XIQueryDevice((Display *)m_xlib_display, devices[i].deviceid, &unused);
113 XIFreeDeviceInfo(devices);
115 if (!m_xinputData->xideviceinfo)
116 qFatal("Qt: Internal error, no XI2 master pointer found.");
118 // find the button info
119 m_xinputData->xibuttonclassinfo = 0;
120 for (int i = 0; i < m_xinputData->xideviceinfo->num_classes; ++i) {
121 if (m_xinputData->xideviceinfo->classes[i]->type == XIButtonClass) {
122 m_xinputData->xibuttonclassinfo = (XIButtonClassInfo *) m_xinputData->xideviceinfo->classes[i];
127 // find the "Max Contacts" property on the device
130 ulong countReturn, bytesReturn;
132 if (XIGetProperty((Display *)m_xlib_display,
133 m_xinputData->xibuttonclassinfo->sourceid,
134 atom(QXcbAtom::MaxContacts),
144 && typeReturn == XA_INTEGER
146 && countReturn == 1) {
147 // touch driver reported the max number of touch-points
148 m_xinputData->xiMaxContacts = data[0];
150 m_xinputData->xiMaxContacts = 0;
154 XFlush((Display *)m_xlib_display);
159 void QXcbConnection::finalizeXInput2Maemo()
161 if (m_xinputData && m_xinputData->xideviceinfo) {
162 XIFreeDeviceInfo(m_xinputData->xideviceinfo);
167 void QXcbConnection::handleGenericEventMaemo(xcb_ge_event_t *event)
169 if (m_xinputData->use_xinput && xi2PrepareXIGenericDeviceEvent(event, m_xinputData->xinput_opcode)) {
170 xXIGenericDeviceEvent* xievent = (xXIGenericDeviceEvent*)event;
172 // On Harmattan XInput2 is hacked to give touch points updates into standard mouse button press/motion events.
173 if (m_xinputData->xiMaxContacts != 0
174 && (xievent->evtype == XI_ButtonPress
175 || xievent->evtype == XI_ButtonRelease
176 || xievent->evtype == XI_Motion)) {
177 xXIDeviceEvent *xideviceevent = (xXIDeviceEvent *)xievent;
178 QList<QWindowSystemInterface::TouchPoint> touchPoints = m_xinputData->allTouchPoints;
179 if (touchPoints.count() != m_xinputData->xiMaxContacts) {
180 // initial event, allocate space for all (potential) touch points
181 touchPoints.reserve(m_xinputData->xiMaxContacts);
182 for (int i = 0; i < m_xinputData->xiMaxContacts; ++i) {
183 QWindowSystemInterface::TouchPoint tp;
185 tp.state = Qt::TouchPointReleased;
189 qreal x, y, nx, ny, w = 0.0, h = 0.0, p = -1.0;
192 for (int i = 0; i < m_xinputData->xideviceinfo->num_classes; ++i) {
193 XIAnyClassInfo *classinfo = m_xinputData->xideviceinfo->classes[i];
194 if (classinfo->type == XIValuatorClass) {
195 XIValuatorClassInfo *valuatorclassinfo = reinterpret_cast<XIValuatorClassInfo *>(classinfo);
196 int n = valuatorclassinfo->number;
198 if (!xi2GetValuatorValueIfSet(xideviceevent, n, &value))
201 if (valuatorclassinfo->label == atom(QXcbAtom::AbsMTPositionX)) {
203 nx = (x - valuatorclassinfo->min) / (valuatorclassinfo->max - valuatorclassinfo->min);
204 } else if (valuatorclassinfo->label == atom(QXcbAtom::AbsMTPositionY)) {
206 ny = (y - valuatorclassinfo->min) / (valuatorclassinfo->max - valuatorclassinfo->min);
207 } else if (valuatorclassinfo->label == atom(QXcbAtom::AbsMTTouchMajor)) {
209 } else if (valuatorclassinfo->label == atom(QXcbAtom::AbsMTTouchMinor)) {
211 } else if (valuatorclassinfo->label == atom(QXcbAtom::AbsMTPressure)) {
212 p = (value - valuatorclassinfo->min) / (valuatorclassinfo->max - valuatorclassinfo->min);
213 } else if (valuatorclassinfo->label == atom(QXcbAtom::AbsMTTrackingID)) {
216 QWindowSystemInterface::TouchPoint &touchPoint = touchPoints[id];
218 Qt::TouchPointState newstate;
219 if (touchPoint.state == Qt::TouchPointReleased) {
220 newstate = Qt::TouchPointPressed;
222 if (touchPoint.area.center() != QPoint(x, y))
223 newstate = Qt::TouchPointMoved;
225 newstate = Qt::TouchPointStationary;
228 touchPoint.state = newstate;
229 touchPoint.area = QRectF(x - w/2, y - h/2, w, h);
230 touchPoint.normalPosition = QPointF(nx, ny);
231 touchPoint.pressure = p;
236 // mark previously-active-but-now-inactive touch points as released
237 for (int i = 0; i < touchPoints.count(); ++i)
238 if (!(active & (1 << i)) && touchPoints.at(i).state != Qt::TouchPointReleased)
239 touchPoints[i].state = Qt::TouchPointReleased;
241 if (QXcbWindow *platformWindow = platformWindowFromId(xideviceevent->event)) {
242 QTouchDevice *dev = m_xinputData->qtTouchDevice;
244 dev = new QTouchDevice;
245 dev->setType(QTouchDevice::TouchScreen);
246 dev->setCapabilities(QTouchDevice::Position | QTouchDevice::Area | QTouchDevice::Pressure | QTouchDevice::NormalizedPosition);
247 QWindowSystemInterface::registerTouchDevice(dev);
248 m_xinputData->qtTouchDevice = dev;
250 QWindowSystemInterface::handleTouchEvent(platformWindow->window(), xideviceevent->time, dev, touchPoints);
253 if (xideviceevent->evtype == XI_ButtonRelease) {
254 // final event, forget touch state
255 m_xinputData->allTouchPoints.clear();
257 // save current state so that we have something to reuse later
258 m_xinputData->allTouchPoints = touchPoints;
267 #endif // XCB_USE_XINPUT2_MAEMO