diff options
Diffstat (limited to 'src/plugins/platforms/xcb/qxcbconnection_xi2.cpp')
-rw-r--r-- | src/plugins/platforms/xcb/qxcbconnection_xi2.cpp | 132 |
1 files changed, 100 insertions, 32 deletions
diff --git a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp index e055ad1424..e94433dd4b 100644 --- a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp @@ -1,31 +1,37 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the plugins of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** @@ -38,6 +44,7 @@ #include "qtouchdevice.h" #include <qpa/qwindowsysteminterface.h> #include <QDebug> +#include <cmath> #ifdef XCB_USE_XINPUT2 @@ -48,6 +55,7 @@ struct XInput2TouchDeviceData { XInput2TouchDeviceData() : xiDeviceInfo(0) , qtTouchDevice(0) + , providesTouchOrientation(false) { } XIDeviceInfo *xiDeviceInfo; @@ -59,6 +67,7 @@ struct XInput2TouchDeviceData { QPointF firstPressedPosition; // in screen coordinates where the first point was pressed QPointF firstPressedNormalPosition; // device coordinates (0 to 1, 0 to 1) where the first point was pressed QSizeF size; // device size in mm + bool providesTouchOrientation; }; void QXcbConnection::initializeXInput2() @@ -293,6 +302,11 @@ void QXcbConnection::xi2Select(xcb_window_t window) bitMask |= XI_ButtonPressMask; bitMask |= XI_ButtonReleaseMask; bitMask |= XI_MotionMask; + + // There is a check for enter/leave events in plain xcb enter/leave event handler + bitMask |= XI_EnterMask; + bitMask |= XI_LeaveMask; + qCDebug(lcQpaXInput, "XInput 2.2: Selecting press/release/motion events in addition to touch"); } XIEventMask mask; @@ -307,9 +321,12 @@ void QXcbConnection::xi2Select(xcb_window_t window) if (result != Success) qCDebug(lcQpaXInput, "XInput 2.2: failed to select pointer/touch events, window %x, result %d", window, result); } -#endif // XCB_USE_XINPUT22 const bool pointerSelected = isAtLeastXI22() && xi2MouseEvents(); +#else + const bool pointerSelected = false; +#endif // XCB_USE_XINPUT22 + QSet<int> tabletDevices; #ifndef QT_NO_TABLETEVENT if (!m_tabletData.isEmpty()) { @@ -413,6 +430,8 @@ XInput2TouchDeviceData *QXcbConnection::touchDeviceForId(int id) caps |= QTouchDevice::Position | QTouchDevice::NormalizedPosition; else if (vci->label == atom(QXcbAtom::AbsMTTouchMajor)) caps |= QTouchDevice::Area; + else if (vci->label == atom(QXcbAtom::AbsMTOrientation)) + dev->providesTouchOrientation = true; else if (vci->label == atom(QXcbAtom::AbsMTPressure) || vci->label == atom(QXcbAtom::AbsPressure)) caps |= QTouchDevice::Pressure; else if (vci->label == atom(QXcbAtom::RelX)) { @@ -474,6 +493,7 @@ void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event) xXIGenericDeviceEvent *xiEvent = reinterpret_cast<xXIGenericDeviceEvent *>(event); int sourceDeviceId = xiEvent->deviceid; // may be the master id xXIDeviceEvent *xiDeviceEvent = 0; + xXIEnterEvent *xiEnterEvent = 0; QXcbWindowEventListener *eventListener = 0; switch (xiEvent->evtype) { @@ -488,14 +508,16 @@ void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event) { xiDeviceEvent = reinterpret_cast<xXIDeviceEvent *>(event); eventListener = windowEventListenerFromId(xiDeviceEvent->event); - if (eventListener) { - long result = 0; - if (eventListener->handleGenericEvent(reinterpret_cast<xcb_generic_event_t *>(event), &result)) - return; - } sourceDeviceId = xiDeviceEvent->sourceid; // use the actual device id instead of the master break; } + case XI_Enter: + case XI_Leave: { + xiEnterEvent = reinterpret_cast<xXIEnterEvent *>(event); + eventListener = windowEventListenerFromId(xiEnterEvent->event); + sourceDeviceId = xiEnterEvent->sourceid; // use the actual device id instead of the master + break; + } case XI_HierarchyChanged: xi2HandleHierachyEvent(xiEvent); return; @@ -506,11 +528,19 @@ void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event) break; } + if (eventListener) { + long result = 0; + if (eventListener->handleGenericEvent(reinterpret_cast<xcb_generic_event_t *>(event), &result)) + return; + } + #ifndef QT_NO_TABLETEVENT - for (int i = 0; i < m_tabletData.count(); ++i) { - if (m_tabletData.at(i).deviceId == sourceDeviceId) { - if (xi2HandleTabletEvent(xiEvent, &m_tabletData[i], eventListener)) - return; + if (!xiEnterEvent) { + for (int i = 0; i < m_tabletData.count(); ++i) { + if (m_tabletData.at(i).deviceId == sourceDeviceId) { + if (xi2HandleTabletEvent(xiEvent, &m_tabletData[i], eventListener)) + return; + } } } #endif // QT_NO_TABLETEVENT @@ -543,6 +573,13 @@ void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event) xi2ProcessTouch(xiDeviceEvent, platformWindow); break; } + } else if (xiEnterEvent && xi2MouseEvents() && eventListener) { + switch (xiEnterEvent->evtype) { + case XI_Enter: + case XI_Leave: + eventListener->handleXIEnterLeave(event); + break; + } } #endif // XCB_USE_XINPUT22 } @@ -574,7 +611,9 @@ void QXcbConnection::xi2ProcessTouch(void *xiDevEvent, QXcbWindow *platformWindo QXcbScreen* screen = platformWindow->xcbScreen(); qreal x = fixed1616ToReal(xiDeviceEvent->root_x); qreal y = fixed1616ToReal(xiDeviceEvent->root_y); - qreal nx = -1.0, ny = -1.0, d = 0.0; + qreal nx = -1.0, ny = -1.0; + qreal w = 0.0, h = 0.0; + bool majorAxisIsY = touchPoint.area.height() > touchPoint.area.width(); for (int i = 0; i < dev->xiDeviceInfo->num_classes; ++i) { XIAnyClassInfo *classinfo = dev->xiDeviceInfo->classes[i]; if (classinfo->type == XIValuatorClass) { @@ -599,7 +638,24 @@ void QXcbConnection::xi2ProcessTouch(void *xiDevEvent, QXcbWindow *platformWindo } else if (vci->label == atom(QXcbAtom::AbsMTPositionY)) { ny = valuatorNormalized(value, vci); } else if (vci->label == atom(QXcbAtom::AbsMTTouchMajor)) { - d = valuatorNormalized(value, vci) * screen->geometry().width(); + const qreal sw = screen->geometry().width(); + const qreal sh = screen->geometry().height(); + w = valuatorNormalized(value, vci) * std::sqrt(sw * sw + sh * sh); + } else if (vci->label == atom(QXcbAtom::AbsMTTouchMinor)) { + const qreal sw = screen->geometry().width(); + const qreal sh = screen->geometry().height(); + h = valuatorNormalized(value, vci) * std::sqrt(sw * sw + sh * sh); + } else if (vci->label == atom(QXcbAtom::AbsMTOrientation)) { + // Find the closest axis. + // 0 corresponds to the Y axis, vci->max to the X axis. + // Flipping over the Y axis and rotating by 180 degrees + // don't change the result, so normalize value to range + // [0, vci->max] first. + value = qAbs(value); + while (value > vci->max) + value -= 2 * vci->max; + value = qAbs(value); + majorAxisIsY = value < vci->max - value; } else if (vci->label == atom(QXcbAtom::AbsMTPressure) || vci->label == atom(QXcbAtom::AbsPressure)) { touchPoint.pressure = valuatorNormalized(value, vci); @@ -616,8 +672,18 @@ void QXcbConnection::xi2ProcessTouch(void *xiDevEvent, QXcbWindow *platformWindo ny = y / screen->geometry().height(); } if (xiDeviceEvent->evtype != XI_TouchEnd) { - if (d == 0.0) - d = touchPoint.area.width(); + if (!dev->providesTouchOrientation) { + if (w == 0.0) + w = touchPoint.area.width(); + h = w; + } else { + if (w == 0.0) + w = qMax(touchPoint.area.width(), touchPoint.area.height()); + if (h == 0.0) + h = qMin(touchPoint.area.width(), touchPoint.area.height()); + if (majorAxisIsY) + qSwap(w, h); + } } switch (xiDeviceEvent->evtype) { @@ -681,7 +747,7 @@ void QXcbConnection::xi2ProcessTouch(void *xiDevEvent, QXcbWindow *platformWindo } dev->pointPressedPosition.remove(touchPoint.id); } - touchPoint.area = QRectF(x - d/2, y - d/2, d, d); + touchPoint.area = QRectF(x - w/2, y - h/2, w, h); touchPoint.normalPosition = QPointF(nx, ny); if (Q_UNLIKELY(lcQpaXInput().isDebugEnabled())) @@ -718,6 +784,8 @@ bool QXcbConnection::xi2SetMouseGrabEnabled(xcb_window_t w, bool grab) XISetMask(mask, XI_ButtonPress); XISetMask(mask, XI_ButtonRelease); XISetMask(mask, XI_Motion); + XISetMask(mask, XI_Enter); + XISetMask(mask, XI_Leave); XISetMask(mask, XI_TouchBegin); XISetMask(mask, XI_TouchUpdate); XISetMask(mask, XI_TouchEnd); @@ -827,9 +895,9 @@ void QXcbConnection::updateScrollingDevice(ScrollingDevice &scrollingDevice, int #endif } -void QXcbConnection::handleEnterEvent(const xcb_enter_notify_event_t *) -{ #ifdef XCB_USE_XINPUT21 +void QXcbConnection::handleEnterEvent() +{ QHash<int, ScrollingDevice>::iterator it = m_scrollingDevices.begin(); const QHash<int, ScrollingDevice>::iterator end = m_scrollingDevices.end(); while (it != end) { @@ -845,8 +913,8 @@ void QXcbConnection::handleEnterEvent(const xcb_enter_notify_event_t *) XIFreeDeviceInfo(xiDeviceInfo); ++it; } -#endif } +#endif void QXcbConnection::xi2HandleScrollEvent(void *event, ScrollingDevice &scrollingDevice) { |