summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/xcb
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/platforms/xcb')
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.cpp9
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.h17
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection_xi2.cpp458
-rw-r--r--src/plugins/platforms/xcb/qxcbintegration.cpp5
-rw-r--r--src/plugins/platforms/xcb/qxcbkeyboard.cpp9
-rw-r--r--src/plugins/platforms/xcb/qxcbscreen.cpp6
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.cpp1
-rw-r--r--src/plugins/platforms/xcb/xcb-plugin.pro1
8 files changed, 315 insertions, 191 deletions
diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp
index 1b72bb0da1..7f23c84cb9 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection.cpp
@@ -1028,6 +1028,15 @@ void QXcbEventReader::registerForEvents()
connect(dispatcher, SIGNAL(awake()), m_connection, SLOT(processXcbEvents()));
}
+void QXcbEventReader::registerEventDispatcher(QAbstractEventDispatcher *dispatcher)
+{
+ // flush the xcb connection before the EventDispatcher is going to block
+ // In the non-threaded case processXcbEvents is called before going to block,
+ // which flushes the connection.
+ if (m_xcb_poll_for_queued_event)
+ connect(dispatcher, SIGNAL(aboutToBlock()), m_connection, SLOT(flush()));
+}
+
void QXcbEventReader::run()
{
xcb_generic_event_t *event;
diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h
index f96541318c..60a4efff4e 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.h
+++ b/src/plugins/platforms/xcb/qxcbconnection.h
@@ -311,6 +311,8 @@ public:
void start();
+ void registerEventDispatcher(QAbstractEventDispatcher *dispatcher);
+
signals:
void eventPending();
@@ -410,7 +412,6 @@ public:
void sync();
- void flush() { xcb_flush(m_connection); }
void handleXcbError(xcb_generic_error_t *error);
void handleXcbEvent(xcb_generic_event_t *event);
@@ -464,8 +465,11 @@ public:
void handleEnterEvent(const xcb_enter_notify_event_t *);
#endif
+ QXcbEventReader *eventReader() const { return m_reader; }
+
public slots:
void syncWindow(QXcbWindow *window);
+ void flush() { xcb_flush(m_connection); }
private slots:
void processXcbEvents();
@@ -496,27 +500,32 @@ private:
#ifdef XCB_USE_XINPUT2
void initializeXInput2();
void finalizeXInput2();
+ void xi2SetupDevices();
XInput2DeviceData *deviceForId(int id);
void xi2HandleEvent(xcb_ge_event_t *event);
+ void xi2HandleHierachyEvent(void *event);
int m_xiOpCode, m_xiEventBase, m_xiErrorBase;
#ifndef QT_NO_TABLETEVENT
struct TabletData {
- TabletData() : deviceId(0), down(false), serialId(0), inProximity(false) { }
+ TabletData() : deviceId(0), pointerType(QTabletEvent::UnknownPointer),
+ tool(QTabletEvent::Stylus), down(false), serialId(0), inProximity(false) { }
int deviceId;
QTabletEvent::PointerType pointerType;
+ QTabletEvent::TabletDevice tool;
bool down;
qint64 serialId;
bool inProximity;
struct ValuatorClassInfo {
- ValuatorClassInfo() : minVal(0), maxVal(0) { }
+ ValuatorClassInfo() : minVal(0.), maxVal(0.), curVal(0.) { }
double minVal;
double maxVal;
+ double curVal;
int number;
};
QHash<int, ValuatorClassInfo> valuatorInfo;
};
bool xi2HandleTabletEvent(void *event, TabletData *tabletData);
- void xi2ReportTabletEvent(const TabletData &tabletData, void *event);
+ void xi2ReportTabletEvent(TabletData &tabletData, void *event);
QVector<TabletData> m_tabletData;
#endif
struct ScrollingDevice {
diff --git a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
index eb7b220c43..e21db89a20 100644
--- a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
@@ -73,10 +73,6 @@ void QXcbConnection::initializeXInput2()
{
debug_xinput = qEnvironmentVariableIsSet("QT_XCB_DEBUG_XINPUT");
debug_xinput_devices = qEnvironmentVariableIsSet("QT_XCB_DEBUG_XINPUT_DEVICES");
-#ifndef QT_NO_TABLETEVENT
- m_tabletData.clear();
-#endif
- m_scrollingDevices.clear();
Display *xDisplay = static_cast<Display *>(m_xlib_display);
if (XQueryExtension(xDisplay, "XInputExtension", &m_xiOpCode, &m_xiEventBase, &m_xiErrorBase)) {
int xiMajor = 2;
@@ -97,126 +93,146 @@ void QXcbConnection::initializeXInput2()
#else
qDebug("XInput version %d.%d is available and Qt supports 2.0", xiMajor, m_xi2Minor);
#endif
- int deviceCount = 0;
- XIDeviceInfo *devices = XIQueryDevice(xDisplay, XIAllDevices, &deviceCount);
- for (int i = 0; i < deviceCount; ++i) {
- // Only non-master pointing devices are relevant here.
- if (devices[i].use != XISlavePointer)
- continue;
- if (Q_UNLIKELY(debug_xinput_devices))
- qDebug() << "input device "<< devices[i].name;
+ }
+
+ xi2SetupDevices();
+ }
+}
+
+void QXcbConnection::xi2SetupDevices()
+{
#ifndef QT_NO_TABLETEVENT
- TabletData tabletData;
+ m_tabletData.clear();
#endif
- ScrollingDevice scrollingDevice;
- for (int c = 0; c < devices[i].num_classes; ++c) {
- switch (devices[i].classes[c]->type) {
- case XIValuatorClass: {
- XIValuatorClassInfo *vci = reinterpret_cast<XIValuatorClassInfo *>(devices[i].classes[c]);
- const int valuatorAtom = qatom(vci->label);
- if (Q_UNLIKELY(debug_xinput_devices))
- qDebug() << " has valuator" << atomName(vci->label) << "recognized?" << (valuatorAtom < QXcbAtom::NAtoms);
+ m_scrollingDevices.clear();
+
+ if (!m_xi2Enabled)
+ return;
+
+ Display *xDisplay = static_cast<Display *>(m_xlib_display);
+ int deviceCount = 0;
+ XIDeviceInfo *devices = XIQueryDevice(xDisplay, XIAllDevices, &deviceCount);
+ for (int i = 0; i < deviceCount; ++i) {
+ // Only non-master pointing devices are relevant here.
+ if (devices[i].use != XISlavePointer)
+ continue;
+ if (Q_UNLIKELY(debug_xinput_devices))
+ qDebug() << "input device "<< devices[i].name;
#ifndef QT_NO_TABLETEVENT
- if (valuatorAtom < QXcbAtom::NAtoms) {
- TabletData::ValuatorClassInfo info;
- info.minVal = vci->min;
- info.maxVal = vci->max;
- info.number = vci->number;
- tabletData.valuatorInfo[valuatorAtom] = info;
- }
+ TabletData tabletData;
+#endif
+ ScrollingDevice scrollingDevice;
+ for (int c = 0; c < devices[i].num_classes; ++c) {
+ switch (devices[i].classes[c]->type) {
+ case XIValuatorClass: {
+ XIValuatorClassInfo *vci = reinterpret_cast<XIValuatorClassInfo *>(devices[i].classes[c]);
+ const int valuatorAtom = qatom(vci->label);
+ if (Q_UNLIKELY(debug_xinput_devices))
+ qDebug() << " has valuator" << atomName(vci->label) << "recognized?" << (valuatorAtom < QXcbAtom::NAtoms);
+#ifndef QT_NO_TABLETEVENT
+ if (valuatorAtom < QXcbAtom::NAtoms) {
+ TabletData::ValuatorClassInfo info;
+ info.minVal = vci->min;
+ info.maxVal = vci->max;
+ info.number = vci->number;
+ tabletData.valuatorInfo[valuatorAtom] = info;
+ }
#endif // QT_NO_TABLETEVENT
- if (valuatorAtom == QXcbAtom::RelHorizScroll || valuatorAtom == QXcbAtom::RelHorizWheel)
- scrollingDevice.lastScrollPosition.setX(vci->value);
- else if (valuatorAtom == QXcbAtom::RelVertScroll || valuatorAtom == QXcbAtom::RelVertWheel)
- scrollingDevice.lastScrollPosition.setY(vci->value);
- break;
- }
+ if (valuatorAtom == QXcbAtom::RelHorizScroll || valuatorAtom == QXcbAtom::RelHorizWheel)
+ scrollingDevice.lastScrollPosition.setX(vci->value);
+ else if (valuatorAtom == QXcbAtom::RelVertScroll || valuatorAtom == QXcbAtom::RelVertWheel)
+ scrollingDevice.lastScrollPosition.setY(vci->value);
+ break;
+ }
#ifdef XCB_USE_XINPUT21
- case XIScrollClass: {
- XIScrollClassInfo *sci = reinterpret_cast<XIScrollClassInfo *>(devices[i].classes[c]);
- if (sci->scroll_type == XIScrollTypeVertical) {
- scrollingDevice.orientations |= Qt::Vertical;
- scrollingDevice.verticalIndex = sci->number;
- scrollingDevice.verticalIncrement = sci->increment;
- }
- else if (sci->scroll_type == XIScrollTypeHorizontal) {
- scrollingDevice.orientations |= Qt::Horizontal;
- scrollingDevice.horizontalIndex = sci->number;
- scrollingDevice.horizontalIncrement = sci->increment;
- }
- break;
- }
- case XIButtonClass: {
- XIButtonClassInfo *bci = reinterpret_cast<XIButtonClassInfo *>(devices[i].classes[c]);
- if (bci->num_buttons >= 5) {
- Atom label4 = bci->labels[3];
- Atom label5 = bci->labels[4];
- if ((!label4 || qatom(label4) == QXcbAtom::ButtonWheelUp) && (!label5 || qatom(label5) == QXcbAtom::ButtonWheelDown))
- scrollingDevice.legacyOrientations |= Qt::Vertical;
- }
- if (bci->num_buttons >= 7) {
- Atom label6 = bci->labels[5];
- Atom label7 = bci->labels[6];
- if ((!label6 || qatom(label6) == QXcbAtom::ButtonHorizWheelLeft) && (!label7 || qatom(label7) == QXcbAtom::ButtonHorizWheelRight))
- scrollingDevice.legacyOrientations |= Qt::Horizontal;
- }
- break;
- }
-#endif
- default:
- break;
- }
+ case XIScrollClass: {
+ XIScrollClassInfo *sci = reinterpret_cast<XIScrollClassInfo *>(devices[i].classes[c]);
+ if (sci->scroll_type == XIScrollTypeVertical) {
+ scrollingDevice.orientations |= Qt::Vertical;
+ scrollingDevice.verticalIndex = sci->number;
+ scrollingDevice.verticalIncrement = sci->increment;
}
- bool isTablet = false;
-#ifndef QT_NO_TABLETEVENT
- // If we have found the valuators which we expect a tablet to have, assume it's a tablet.
- if (tabletData.valuatorInfo.contains(QXcbAtom::AbsX) &&
- tabletData.valuatorInfo.contains(QXcbAtom::AbsY) &&
- tabletData.valuatorInfo.contains(QXcbAtom::AbsPressure)) {
- tabletData.deviceId = devices[i].deviceid;
- tabletData.pointerType = QTabletEvent::Pen;
- if (QByteArray(devices[i].name).toLower().contains("eraser"))
- tabletData.pointerType = QTabletEvent::Eraser;
- m_tabletData.append(tabletData);
- isTablet = true;
- if (Q_UNLIKELY(debug_xinput_devices))
- qDebug() << " it's a tablet with pointer type" << tabletData.pointerType;
+ else if (sci->scroll_type == XIScrollTypeHorizontal) {
+ scrollingDevice.orientations |= Qt::Horizontal;
+ scrollingDevice.horizontalIndex = sci->number;
+ scrollingDevice.horizontalIncrement = sci->increment;
}
+ break;
+ }
+ case XIButtonClass: {
+ XIButtonClassInfo *bci = reinterpret_cast<XIButtonClassInfo *>(devices[i].classes[c]);
+ if (bci->num_buttons >= 5) {
+ Atom label4 = bci->labels[3];
+ Atom label5 = bci->labels[4];
+ if ((!label4 || qatom(label4) == QXcbAtom::ButtonWheelUp) && (!label5 || qatom(label5) == QXcbAtom::ButtonWheelDown))
+ scrollingDevice.legacyOrientations |= Qt::Vertical;
+ }
+ if (bci->num_buttons >= 7) {
+ Atom label6 = bci->labels[5];
+ Atom label7 = bci->labels[6];
+ if ((!label6 || qatom(label6) == QXcbAtom::ButtonHorizWheelLeft) && (!label7 || qatom(label7) == QXcbAtom::ButtonHorizWheelRight))
+ scrollingDevice.legacyOrientations |= Qt::Horizontal;
+ }
+ break;
+ }
+#endif
+ default:
+ break;
+ }
+ }
+ bool isTablet = false;
+#ifndef QT_NO_TABLETEVENT
+ // If we have found the valuators which we expect a tablet to have, assume it's a tablet.
+ if (tabletData.valuatorInfo.contains(QXcbAtom::AbsX) &&
+ tabletData.valuatorInfo.contains(QXcbAtom::AbsY) &&
+ tabletData.valuatorInfo.contains(QXcbAtom::AbsPressure)) {
+ tabletData.deviceId = devices[i].deviceid;
+ tabletData.pointerType = QTabletEvent::Pen;
+ if (QByteArray(devices[i].name).toLower().contains("eraser"))
+ tabletData.pointerType = QTabletEvent::Eraser;
+ m_tabletData.append(tabletData);
+ isTablet = true;
+ if (Q_UNLIKELY(debug_xinput_devices))
+ qDebug() << " it's a tablet with pointer type" << tabletData.pointerType;
+ }
#endif // QT_NO_TABLETEVENT
#ifdef XCB_USE_XINPUT21
- if (scrollingDevice.orientations || scrollingDevice.legacyOrientations) {
- scrollingDevice.deviceId = devices[i].deviceid;
- // Only use legacy wheel button events when we don't have real scroll valuators.
- scrollingDevice.legacyOrientations &= ~scrollingDevice.orientations;
- m_scrollingDevices.insert(scrollingDevice.deviceId, scrollingDevice);
- if (Q_UNLIKELY(debug_xinput_devices))
- qDebug() << " it's a scrolling device";
- }
+ if (scrollingDevice.orientations || scrollingDevice.legacyOrientations) {
+ scrollingDevice.deviceId = devices[i].deviceid;
+ // Only use legacy wheel button events when we don't have real scroll valuators.
+ scrollingDevice.legacyOrientations &= ~scrollingDevice.orientations;
+ m_scrollingDevices.insert(scrollingDevice.deviceId, scrollingDevice);
+ if (Q_UNLIKELY(debug_xinput_devices))
+ qDebug() << " it's a scrolling device";
+ }
#endif
- if (!isTablet) {
- XInput2DeviceData *dev = deviceForId(devices[i].deviceid);
- if (Q_UNLIKELY(debug_xinput_devices)) {
- if (dev && dev->qtTouchDevice->type() == QTouchDevice::TouchScreen)
- qDebug(" it's a touchscreen with type %d capabilities 0x%X max touch points %d",
- dev->qtTouchDevice->type(), (unsigned int)dev->qtTouchDevice->capabilities(),
- dev->qtTouchDevice->maximumTouchPoints());
- else if (dev && dev->qtTouchDevice->type() == QTouchDevice::TouchPad)
- qDebug(" it's a touchpad with type %d capabilities 0x%X max touch points %d size %f x %f",
- dev->qtTouchDevice->type(), (unsigned int)dev->qtTouchDevice->capabilities(),
- dev->qtTouchDevice->maximumTouchPoints(),
- dev->size.width(), dev->size.height());
- }
- }
+ if (!isTablet) {
+ XInput2DeviceData *dev = deviceForId(devices[i].deviceid);
+ if (Q_UNLIKELY(debug_xinput_devices)) {
+ if (dev && dev->qtTouchDevice->type() == QTouchDevice::TouchScreen)
+ qDebug(" it's a touchscreen with type %d capabilities 0x%X max touch points %d",
+ dev->qtTouchDevice->type(), (unsigned int)dev->qtTouchDevice->capabilities(),
+ dev->qtTouchDevice->maximumTouchPoints());
+ else if (dev && dev->qtTouchDevice->type() == QTouchDevice::TouchPad)
+ qDebug(" it's a touchpad with type %d capabilities 0x%X max touch points %d size %f x %f",
+ dev->qtTouchDevice->type(), (unsigned int)dev->qtTouchDevice->capabilities(),
+ dev->qtTouchDevice->maximumTouchPoints(),
+ dev->size.width(), dev->size.height());
}
- XIFreeDeviceInfo(devices);
}
}
+ XIFreeDeviceInfo(devices);
}
void QXcbConnection::finalizeXInput2()
{
+ foreach (XInput2DeviceData *dev, m_touchDevices) {
+ if (dev->xiDeviceInfo)
+ XIFreeDeviceInfo(dev->xiDeviceInfo);
+ delete dev;
+ }
}
void QXcbConnection::xi2Select(xcb_window_t window)
@@ -235,14 +251,13 @@ void QXcbConnection::xi2Select(xcb_window_t window)
XIEventMask mask;
mask.mask_len = sizeof(bitMask);
mask.mask = xiBitMask;
- // Enable each touchscreen
- foreach (XInput2DeviceData *dev, m_touchDevices) {
- mask.deviceid = dev->xiDeviceInfo->deviceid;
+ if (!m_touchDevices.isEmpty()) {
+ mask.deviceid = XIAllMasterDevices;
Status result = XISelectEvents(xDisplay, window, &mask, 1);
- // If we have XInput >= 2.2 and successfully enable a touchscreen, then
- // it will provide touch only. In most other cases, there will be
- // emulated mouse events from the driver. If not, then Qt must do its
- // own mouse emulation to enable interaction with mouse-oriented QWidgets.
+ // If we select for touch events on the master pointer, XInput2
+ // will not synthesize mouse events. This means Qt must do it,
+ // which is also preferable, since Qt can control better when
+ // to do so.
if (m_xi2Minor >= 2 && result == Success)
has_touch_without_mouse_emulation = true;
}
@@ -256,10 +271,10 @@ void QXcbConnection::xi2Select(xcb_window_t window)
// similar handlers useless and we have no intention to infect
// all the pure xcb code with Xlib-based XI2.
if (!m_tabletData.isEmpty()) {
- unsigned int tabletBitMask = bitMask;
+ unsigned int tabletBitMask;
unsigned char *xiTabletBitMask = reinterpret_cast<unsigned char *>(&tabletBitMask);
QVector<XIEventMask> xiEventMask(m_tabletData.count());
- tabletBitMask |= XI_ButtonPressMask;
+ tabletBitMask = XI_ButtonPressMask;
tabletBitMask |= XI_ButtonReleaseMask;
tabletBitMask |= XI_MotionMask;
tabletBitMask |= XI_PropertyEventMask;
@@ -278,24 +293,18 @@ void QXcbConnection::xi2Select(xcb_window_t window)
// Enable each scroll device
if (!m_scrollingDevices.isEmpty()) {
QVector<XIEventMask> xiEventMask(m_scrollingDevices.size());
- unsigned int scrollBitMask = 0;
+ unsigned int scrollBitMask;
unsigned char *xiScrollBitMask = reinterpret_cast<unsigned char *>(&scrollBitMask);
+
scrollBitMask = XI_MotionMask;
scrollBitMask |= XI_ButtonReleaseMask;
- bitMask |= XI_MotionMask;
- bitMask |= XI_ButtonReleaseMask;
int i=0;
Q_FOREACH (const ScrollingDevice& scrollingDevice, m_scrollingDevices) {
if (tabletDevices.contains(scrollingDevice.deviceId))
continue; // All necessary events are already captured.
xiEventMask[i].deviceid = scrollingDevice.deviceId;
- if (m_touchDevices.contains(scrollingDevice.deviceId)) {
- xiEventMask[i].mask_len = sizeof(bitMask);
- xiEventMask[i].mask = xiBitMask;
- } else {
- xiEventMask[i].mask_len = sizeof(scrollBitMask);
- xiEventMask[i].mask = xiScrollBitMask;
- }
+ xiEventMask[i].mask_len = sizeof(scrollBitMask);
+ xiEventMask[i].mask = xiScrollBitMask;
i++;
}
XISelectEvents(xDisplay, window, xiEventMask.data(), i);
@@ -303,6 +312,16 @@ void QXcbConnection::xi2Select(xcb_window_t window)
#else
Q_UNUSED(xiBitMask);
#endif
+
+ {
+ // Listen for hotplug events
+ XIEventMask xiEventMask;
+ bitMask = XI_HierarchyChangedMask;
+ xiEventMask.deviceid = XIAllDevices;
+ xiEventMask.mask_len = sizeof(bitMask);
+ xiEventMask.mask = xiBitMask;
+ XISelectEvents(xDisplay, window, &xiEventMask, 1);
+ }
}
XInput2DeviceData *QXcbConnection::deviceForId(int id)
@@ -326,10 +345,10 @@ XInput2DeviceData *QXcbConnection::deviceForId(int id)
if (Q_UNLIKELY(debug_xinput_devices))
qDebug(" has touch class with mode %d", tci->mode);
switch (tci->mode) {
- case XIModeRelative:
+ case XIDependentTouch:
type = QTouchDevice::TouchPad;
break;
- case XIModeAbsolute:
+ case XIDirectTouch:
type = QTouchDevice::TouchScreen;
break;
}
@@ -372,6 +391,7 @@ XInput2DeviceData *QXcbConnection::deviceForId(int id)
m_touchDevices[id] = dev;
} else {
m_touchDevices.remove(id);
+ XIFreeDeviceInfo(dev->xiDeviceInfo);
delete dev;
dev = 0;
}
@@ -402,6 +422,10 @@ void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event)
if (xi2PrepareXIGenericDeviceEvent(event, m_xiOpCode)) {
xXIGenericDeviceEvent *xiEvent = reinterpret_cast<xXIGenericDeviceEvent *>(event);
+ if (xiEvent->evtype == XI_HierarchyChanged) {
+ xi2HandleHierachyEvent(xiEvent);
+ return;
+ }
#ifndef QT_NO_TABLETEVENT
for (int i = 0; i < m_tabletData.count(); ++i) {
if (m_tabletData.at(i).deviceId == xiEvent->deviceid) {
@@ -427,7 +451,7 @@ void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event)
fixed1616ToReal(xiDeviceEvent->root_x), fixed1616ToReal(xiDeviceEvent->root_y) );
if (QXcbWindow *platformWindow = platformWindowFromId(xiDeviceEvent->event)) {
- XInput2DeviceData *dev = deviceForId(xiEvent->deviceid);
+ XInput2DeviceData *dev = deviceForId(xiDeviceEvent->sourceid);
Q_ASSERT(dev);
const bool firstTouch = m_touchPoints.isEmpty();
if (xiEvent->evtype == XI_TouchBegin) {
@@ -532,22 +556,6 @@ void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event)
qDebug() << " touchpoint " << touchPoint.id << " state " << touchPoint.state << " pos norm " << touchPoint.normalPosition <<
" area " << touchPoint.area << " pressure " << touchPoint.pressure;
QWindowSystemInterface::handleTouchEvent(platformWindow->window(), xiEvent->time, dev->qtTouchDevice, m_touchPoints.values());
- if (has_touch_without_mouse_emulation) {
- // We need to grab the touch event to prevent mouse emulation.
- if (xiEvent->evtype == XI_TouchBegin) {
- XIEventMask xieventmask;
- unsigned int bitMask = 0;
- unsigned char *xiBitMask = reinterpret_cast<unsigned char *>(&bitMask);
- xieventmask.deviceid = xiEvent->deviceid;
- xieventmask.mask = xiBitMask;
- xieventmask.mask_len = sizeof(bitMask);
- bitMask |= XI_TouchBeginMask;
- bitMask |= XI_TouchUpdateMask;
- bitMask |= XI_TouchEndMask;
- XIGrabDevice(static_cast<Display *>(m_xlib_display), xiEvent->deviceid, platformWindow->winId(), xiEvent->time, None, GrabModeAsync, GrabModeAsync, true, &xieventmask);
- } else if (xiEvent->evtype == XI_TouchEnd)
- XIUngrabDevice(static_cast<Display *>(m_xlib_display), xiEvent->deviceid, xiEvent->time);
- }
if (touchPoint.state == Qt::TouchPointReleased)
// If a touchpoint was released, we can forget it, because the ID won't be reused.
m_touchPoints.remove(touchPoint.id);
@@ -561,6 +569,19 @@ void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event)
}
}
+void QXcbConnection::xi2HandleHierachyEvent(void *event)
+{
+ xXIHierarchyEvent *xiEvent = reinterpret_cast<xXIHierarchyEvent *>(event);
+ // We only care about hotplugged devices
+ if (!(xiEvent->flags & (XISlaveRemoved | XISlaveAdded)))
+ return;
+ xi2SetupDevices();
+ // Reselect events for all event-listening windows.
+ Q_FOREACH (xcb_window_t window, m_mapper.keys()) {
+ xi2Select(window);
+ }
+}
+
void QXcbConnection::handleEnterEvent(const xcb_enter_notify_event_t *)
{
#ifdef XCB_USE_XINPUT21
@@ -664,6 +685,39 @@ void QXcbConnection::xi2HandleScrollEvent(void *event, ScrollingDevice &scrollin
#endif // XCB_USE_XINPUT21
}
+static QTabletEvent::TabletDevice toolIdToTabletDevice(quint32 toolId) {
+ // keep in sync with wacom_intuos_inout() in Linux kernel driver wacom_wac.c
+ switch (toolId) {
+ case 0xd12:
+ case 0x912:
+ case 0x112:
+ case 0x913: /* Intuos3 Airbrush */
+ case 0x91b: /* Intuos3 Airbrush Eraser */
+ case 0x902: /* Intuos4/5 13HD/24HD Airbrush */
+ case 0x90a: /* Intuos4/5 13HD/24HD Airbrush Eraser */
+ case 0x100902: /* Intuos4/5 13HD/24HD Airbrush */
+ case 0x10090a: /* Intuos4/5 13HD/24HD Airbrush Eraser */
+ return QTabletEvent::Airbrush;
+ case 0x007: /* Mouse 4D and 2D */
+ case 0x09c:
+ case 0x094:
+ return QTabletEvent::FourDMouse;
+ case 0x017: /* Intuos3 2D Mouse */
+ case 0x806: /* Intuos4 Mouse */
+ case 0x096: /* Lens cursor */
+ case 0x097: /* Intuos3 Lens cursor */
+ case 0x006: /* Intuos4 Lens cursor */
+ return QTabletEvent::Puck;
+ case 0x885: /* Intuos3 Art Pen (Marker Pen) */
+ case 0x100804: /* Intuos4/5 13HD/24HD Art Pen */
+ case 0x10080c: /* Intuos4/5 13HD/24HD Art Pen Eraser */
+ return QTabletEvent::RotationStylus;
+ case 0:
+ return QTabletEvent::NoDevice;
+ }
+ return QTabletEvent::Stylus; // Safe default assumption if nonzero
+}
+
#ifndef QT_NO_TABLETEVENT
bool QXcbConnection::xi2HandleTabletEvent(void *event, TabletData *tabletData)
{
@@ -692,9 +746,19 @@ bool QXcbConnection::xi2HandleTabletEvent(void *event, TabletData *tabletData)
xi2ReportTabletEvent(*tabletData, xiEvent);
break;
case XI_PropertyEvent: {
+ // This is the wacom driver's way of reporting tool proximity.
+ // The evdev driver doesn't do it this way.
xXIPropertyEvent *ev = reinterpret_cast<xXIPropertyEvent *>(event);
if (ev->what == XIPropertyModified) {
if (ev->property == atom(QXcbAtom::WacomSerialIDs)) {
+ enum WacomSerialIndex {
+ _WACSER_USB_ID = 0,
+ _WACSER_LAST_TOOL_SERIAL,
+ _WACSER_LAST_TOOL_ID,
+ _WACSER_TOOL_SERIAL,
+ _WACSER_TOOL_ID,
+ _WACSER_COUNT
+ };
Atom propType;
int propFormat;
unsigned long numItems, bytesAfter;
@@ -702,27 +766,44 @@ bool QXcbConnection::xi2HandleTabletEvent(void *event, TabletData *tabletData)
if (XIGetProperty(xDisplay, tabletData->deviceId, ev->property, 0, 100,
0, AnyPropertyType, &propType, &propFormat,
&numItems, &bytesAfter, &data) == Success) {
- if (propType == atom(QXcbAtom::INTEGER) && propFormat == 32) {
- int *ptr = reinterpret_cast<int *>(data);
- for (unsigned long i = 0; i < numItems; ++i)
- tabletData->serialId |= qint64(ptr[i]) << (i * 32);
+ if (propType == atom(QXcbAtom::INTEGER) && propFormat == 32 && numItems == _WACSER_COUNT) {
+ quint32 *ptr = reinterpret_cast<quint32 *>(data);
+ quint32 tool = ptr[_WACSER_TOOL_ID];
+ // Workaround for http://sourceforge.net/p/linuxwacom/bugs/246/
+ // e.g. on Thinkpad Helix, tool ID will be 0 and serial will be 1
+ if (!tool && ptr[_WACSER_TOOL_SERIAL])
+ tool = ptr[_WACSER_TOOL_SERIAL];
+
+ // The property change event informs us which tool is in proximity or which one left proximity.
+ if (tool) {
+ tabletData->inProximity = true;
+ tabletData->tool = toolIdToTabletDevice(tool);
+ tabletData->serialId = qint64(ptr[_WACSER_USB_ID]) << 32 | qint64(ptr[_WACSER_TOOL_SERIAL]);
+ QWindowSystemInterface::handleTabletEnterProximityEvent(tabletData->tool,
+ tabletData->pointerType,
+ tabletData->serialId);
+ } else {
+ tabletData->inProximity = false;
+ tabletData->tool = toolIdToTabletDevice(ptr[_WACSER_LAST_TOOL_ID]);
+ // Workaround for http://sourceforge.net/p/linuxwacom/bugs/246/
+ // e.g. on Thinkpad Helix, tool ID will be 0 and serial will be 1
+ if (!tabletData->tool)
+ tabletData->tool = toolIdToTabletDevice(ptr[_WACSER_LAST_TOOL_SERIAL]);
+ tabletData->serialId = qint64(ptr[_WACSER_USB_ID]) << 32 | qint64(ptr[_WACSER_LAST_TOOL_SERIAL]);
+ QWindowSystemInterface::handleTabletLeaveProximityEvent(tabletData->tool,
+ tabletData->pointerType,
+ tabletData->serialId);
+ }
+ if (Q_UNLIKELY(debug_xinput)) {
+ // TODO maybe have a hash of tabletData->deviceId to device data so we can
+ // look up the tablet name here, and distinguish multiple tablets
+ qDebug("XI2 proximity change on tablet %d (USB %x): last tool: %x id %x current tool: %x id %x TabletDevice %d",
+ ev->deviceid, ptr[_WACSER_USB_ID], ptr[_WACSER_LAST_TOOL_SERIAL], ptr[_WACSER_LAST_TOOL_ID],
+ ptr[_WACSER_TOOL_SERIAL], ptr[_WACSER_TOOL_ID], tabletData->tool);
+ }
}
XFree(data);
}
- // With recent-enough X drivers this property change event seems to come always
- // when entering and leaving proximity. Due to the lack of other options hook up
- // the enter/leave events to it.
- if (tabletData->inProximity) {
- tabletData->inProximity = false;
- QWindowSystemInterface::handleTabletLeaveProximityEvent(QTabletEvent::Stylus,
- tabletData->pointerType,
- tabletData->serialId);
- } else {
- tabletData->inProximity = true;
- QWindowSystemInterface::handleTabletEnterProximityEvent(QTabletEvent::Stylus,
- tabletData->pointerType,
- tabletData->serialId);
- }
}
}
break;
@@ -734,7 +815,7 @@ bool QXcbConnection::xi2HandleTabletEvent(void *event, TabletData *tabletData)
return handled;
}
-void QXcbConnection::xi2ReportTabletEvent(const TabletData &tabletData, void *event)
+void QXcbConnection::xi2ReportTabletEvent(TabletData &tabletData, void *event)
{
xXIDeviceEvent *ev = reinterpret_cast<xXIDeviceEvent *>(event);
QXcbWindow *xcbWindow = platformWindowFromId(ev->event);
@@ -744,45 +825,52 @@ void QXcbConnection::xi2ReportTabletEvent(const TabletData &tabletData, void *ev
const double scale = 65536.0;
QPointF local(ev->event_x / scale, ev->event_y / scale);
QPointF global(ev->root_x / scale, ev->root_y / scale);
- double pressure = 0, rotation = 0;
+ double pressure = 0, rotation = 0, tangentialPressure = 0;
int xTilt = 0, yTilt = 0;
- for (QHash<int, TabletData::ValuatorClassInfo>::const_iterator it = tabletData.valuatorInfo.constBegin(),
- ite = tabletData.valuatorInfo.constEnd(); it != ite; ++it) {
+ for (QHash<int, TabletData::ValuatorClassInfo>::iterator it = tabletData.valuatorInfo.begin(),
+ ite = tabletData.valuatorInfo.end(); it != ite; ++it) {
int valuator = it.key();
- const TabletData::ValuatorClassInfo &classInfo(it.value());
- double value;
- if (xi2GetValuatorValueIfSet(event, classInfo.number, &value)) {
- double normalizedValue = (value - classInfo.minVal) / double(classInfo.maxVal - classInfo.minVal);
- switch (valuator) {
- case QXcbAtom::AbsPressure:
- pressure = normalizedValue;
- break;
- case QXcbAtom::AbsTiltX:
- xTilt = value;
+ TabletData::ValuatorClassInfo &classInfo(it.value());
+ xi2GetValuatorValueIfSet(event, classInfo.number, &classInfo.curVal);
+ double normalizedValue = (classInfo.curVal - classInfo.minVal) / (classInfo.maxVal - classInfo.minVal);
+ switch (valuator) {
+ case QXcbAtom::AbsPressure:
+ pressure = normalizedValue;
+ break;
+ case QXcbAtom::AbsTiltX:
+ xTilt = classInfo.curVal;
+ break;
+ case QXcbAtom::AbsTiltY:
+ yTilt = classInfo.curVal;
+ break;
+ case QXcbAtom::AbsWheel:
+ switch (tabletData.tool) {
+ case QTabletEvent::Airbrush:
+ tangentialPressure = normalizedValue * 2.0 - 1.0; // Convert 0..1 range to -1..+1 range
break;
- case QXcbAtom::AbsTiltY:
- yTilt = value;
+ case QTabletEvent::RotationStylus:
+ rotation = normalizedValue * 360.0 - 180.0; // Convert 0..1 range to -180..+180 degrees
break;
- case QXcbAtom::AbsWheel:
- rotation = value / 64.0;
- break;
- default:
+ default: // Other types of styli do not use this valuator
break;
}
+ break;
+ default:
+ break;
}
}
if (Q_UNLIKELY(debug_xinput))
- qDebug("XI2 tablet event type %d seq %d detail %d pos %6.1f, %6.1f root pos %6.1f, %6.1f pressure %4.2lf tilt %d, %d rotation %6.2lf",
- ev->type, ev->sequenceNumber, ev->detail,
+ qDebug("XI2 event on tablet %d with tool %d type %d seq %d detail %d pos %6.1f, %6.1f root pos %6.1f, %6.1f pressure %4.2lf tilt %d, %d rotation %6.2lf",
+ ev->deviceid, tabletData.tool, ev->type, ev->sequenceNumber, ev->detail,
fixed1616ToReal(ev->event_x), fixed1616ToReal(ev->event_y),
fixed1616ToReal(ev->root_x), fixed1616ToReal(ev->root_y),
pressure, xTilt, yTilt, rotation);
QWindowSystemInterface::handleTabletEvent(window, tabletData.down, local, global,
- QTabletEvent::Stylus, tabletData.pointerType,
- pressure, xTilt, yTilt, 0,
+ tabletData.tool, tabletData.pointerType,
+ pressure, xTilt, yTilt, tangentialPressure,
rotation, 0, tabletData.serialId);
}
#endif // QT_NO_TABLETEVENT
diff --git a/src/plugins/platforms/xcb/qxcbintegration.cpp b/src/plugins/platforms/xcb/qxcbintegration.cpp
index ddb164bf07..1b1c20f02c 100644
--- a/src/plugins/platforms/xcb/qxcbintegration.cpp
+++ b/src/plugins/platforms/xcb/qxcbintegration.cpp
@@ -303,7 +303,10 @@ bool QXcbIntegration::hasCapability(QPlatformIntegration::Capability cap) const
QAbstractEventDispatcher *QXcbIntegration::createEventDispatcher() const
{
- return createUnixEventDispatcher();
+ QAbstractEventDispatcher *dispatcher = createUnixEventDispatcher();
+ for (int i = 0; i < m_connections.size(); i++)
+ m_connections[i]->eventReader()->registerEventDispatcher(dispatcher);
+ return dispatcher;
}
void QXcbIntegration::initialize()
diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.cpp b/src/plugins/platforms/xcb/qxcbkeyboard.cpp
index 69601f44d4..4c84b19f82 100644
--- a/src/plugins/platforms/xcb/qxcbkeyboard.cpp
+++ b/src/plugins/platforms/xcb/qxcbkeyboard.cpp
@@ -929,6 +929,15 @@ int QXcbKeyboard::keysymToQtKey(xcb_keysym_t key) const
i += 2;
}
+ if (rmod_masks.meta) {
+ // translate Super/Hyper keys to Meta if we're using them as the MetaModifier
+ if (rmod_masks.meta == rmod_masks.super && (code == Qt::Key_Super_L || code == Qt::Key_Super_R)) {
+ code = Qt::Key_Meta;
+ } else if (rmod_masks.meta == rmod_masks.hyper && (code == Qt::Key_Hyper_L || code == Qt::Key_Hyper_R)) {
+ code = Qt::Key_Meta;
+ }
+ }
+
return code;
}
diff --git a/src/plugins/platforms/xcb/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp
index 9f19841437..01e78465b6 100644
--- a/src/plugins/platforms/xcb/qxcbscreen.cpp
+++ b/src/plugins/platforms/xcb/qxcbscreen.cpp
@@ -106,6 +106,11 @@ QXcbScreen::QXcbScreen(QXcbConnection *connection, xcb_screen_t *scr,
qDebug(" root ID........: %x", screen()->root);
#endif
+ QScopedPointer<xcb_get_window_attributes_reply_t, QScopedPointerPodDeleter> rootAttribs(
+ xcb_get_window_attributes_reply(xcb_connection(),
+ xcb_get_window_attributes_unchecked(xcb_connection(), screen()->root), NULL));
+ const quint32 existingEventMask = rootAttribs.isNull() ? 0 : rootAttribs->your_event_mask;
+
const quint32 mask = XCB_CW_EVENT_MASK;
const quint32 values[] = {
// XCB_CW_EVENT_MASK
@@ -113,6 +118,7 @@ QXcbScreen::QXcbScreen(QXcbConnection *connection, xcb_screen_t *scr,
| XCB_EVENT_MASK_LEAVE_WINDOW
| XCB_EVENT_MASK_PROPERTY_CHANGE
| XCB_EVENT_MASK_STRUCTURE_NOTIFY // for the "MANAGER" atom (system tray notification).
+ | existingEventMask // don't overwrite the event mask on the root window
};
xcb_change_window_attributes(xcb_connection(), screen()->root, mask, values);
diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp
index 74d8b7c2c8..586068d8d9 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.cpp
+++ b/src/plugins/platforms/xcb/qxcbwindow.cpp
@@ -1342,6 +1342,7 @@ void QXcbWindow::setWindowTitle(const QString &title)
8,
ba.length(),
ba.constData()));
+ xcb_flush(xcb_connection());
}
void QXcbWindow::setWindowIcon(const QIcon &icon)
diff --git a/src/plugins/platforms/xcb/xcb-plugin.pro b/src/plugins/platforms/xcb/xcb-plugin.pro
index a52aaa4a2e..4d76e4d449 100644
--- a/src/plugins/platforms/xcb/xcb-plugin.pro
+++ b/src/plugins/platforms/xcb/xcb-plugin.pro
@@ -109,7 +109,6 @@ QMAKE_CXXFLAGS += $$QMAKE_CFLAGS_XCB
CONFIG += qpa/genericunixfontdatabase
contains(QT_CONFIG, dbus) {
-DEFINES += XCB_USE_IBUS
QT += dbus
LIBS += -ldbus-1
}