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.cpp17
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.h13
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection_xi2.cpp97
-rw-r--r--src/plugins/platforms/xcb/qxcbintegration.cpp4
-rw-r--r--src/plugins/platforms/xcb/qxcbkeyboard.cpp8
-rw-r--r--src/plugins/platforms/xcb/qxcbkeyboard.h2
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.cpp205
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.h9
8 files changed, 250 insertions, 105 deletions
diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp
index 4d29cdc316..998f4884aa 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection.cpp
@@ -619,8 +619,8 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGra
initializeScreens();
initializeXRender();
- m_xi2Enabled = false;
#if defined(XCB_USE_XINPUT2)
+ m_xi2Enabled = false;
initializeXInput2();
#endif
initializeXShape();
@@ -1142,8 +1142,16 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event)
handleClientMessageEvent((xcb_client_message_event_t *)event);
break;
case XCB_ENTER_NOTIFY:
+#ifdef XCB_USE_XINPUT22
+ if (isAtLeastXI22() && xi2MouseEvents())
+ break;
+#endif
HANDLE_PLATFORM_WINDOW_EVENT(xcb_enter_notify_event_t, event, handleEnterNotifyEvent);
case XCB_LEAVE_NOTIFY:
+#ifdef XCB_USE_XINPUT22
+ if (isAtLeastXI22() && xi2MouseEvents())
+ break;
+#endif
m_keyboard->updateXKBStateFromCore(((xcb_leave_notify_event_t *)event)->state);
HANDLE_PLATFORM_WINDOW_EVENT(xcb_leave_notify_event_t, event, handleLeaveNotifyEvent);
case XCB_FOCUS_IN:
@@ -1930,6 +1938,7 @@ static const char * xcb_atomnames = {
"Abs MT Position Y\0"
"Abs MT Touch Major\0"
"Abs MT Touch Minor\0"
+ "Abs MT Orientation\0"
"Abs MT Pressure\0"
"Abs MT Tracking ID\0"
"Max Contacts\0"
@@ -2224,13 +2233,15 @@ void QXcbConnection::initializeXKB()
#endif
}
+#if defined(XCB_USE_XINPUT22)
bool QXcbConnection::xi2MouseEvents() const
{
static bool mouseViaXI2 = !qEnvironmentVariableIsSet("QT_XCB_NO_XI2_MOUSE");
- // Don't use XInput2 when Xinerama extension is enabled,
- // because it causes problems with multi-monitor setup.
+ // FIXME: Don't use XInput2 mouse events when Xinerama extension
+ // is enabled, because it causes problems with multi-monitor setup.
return mouseViaXI2 && !has_xinerama_extension;
}
+#endif
#if defined(XCB_USE_XINPUT2)
static int xi2ValuatorOffset(unsigned char *maskPtr, int maskLen, int number)
diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h
index 839b51fc49..6a2ecacd77 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.h
+++ b/src/plugins/platforms/xcb/qxcbconnection.h
@@ -267,6 +267,7 @@ namespace QXcbAtom {
AbsMTPositionY,
AbsMTTouchMajor,
AbsMTTouchMinor,
+ AbsMTOrientation,
AbsMTPressure,
AbsMTTrackingID,
MaxContacts,
@@ -353,8 +354,10 @@ public:
virtual void handleFocusInEvent(const xcb_focus_in_event_t *) {}
virtual void handleFocusOutEvent(const xcb_focus_out_event_t *) {}
virtual void handlePropertyNotifyEvent(const xcb_property_notify_event_t *) {}
+#ifdef XCB_USE_XINPUT22
virtual void handleXIMouseEvent(xcb_ge_event_t *) {}
-
+ virtual void handleXIEnterLeave(xcb_ge_event_t *) {}
+#endif
virtual QXcbWindow *toWindow() { return 0; }
};
@@ -491,8 +494,8 @@ public:
static bool xEmbedSystemTrayAvailable();
static bool xEmbedSystemTrayVisualHasAlphaChannel();
-#ifdef XCB_USE_XINPUT2
- void handleEnterEvent(const xcb_enter_notify_event_t *);
+#ifdef XCB_USE_XINPUT21
+ void handleEnterEvent();
#endif
#ifdef XCB_USE_XINPUT22
@@ -506,7 +509,9 @@ public:
QXcbGlIntegration *glIntegration() const { return m_glIntegration; }
+#ifdef XCB_USE_XINPUT22
bool xi2MouseEvents() const;
+#endif
protected:
bool event(QEvent *e) Q_DECL_OVERRIDE;
@@ -540,9 +545,9 @@ private:
void initializeScreens();
bool compressEvent(xcb_generic_event_t *event, int currentIndex, QXcbEventArray *eventqueue) const;
+#ifdef XCB_USE_XINPUT2
bool m_xi2Enabled;
int m_xi2Minor;
-#ifdef XCB_USE_XINPUT2
void initializeXInput2();
void finalizeXInput2();
void xi2SetupDevices();
diff --git a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
index e2bf6e8eb4..ca19c3dce8 100644
--- a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
@@ -54,6 +54,7 @@ struct XInput2TouchDeviceData {
XInput2TouchDeviceData()
: xiDeviceInfo(0)
, qtTouchDevice(0)
+ , providesTouchOrientation(false)
{
}
XIDeviceInfo *xiDeviceInfo;
@@ -65,6 +66,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()
@@ -299,6 +301,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;
@@ -313,9 +320,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()) {
@@ -419,6 +429,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)) {
@@ -480,6 +492,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) {
@@ -494,14 +507,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;
@@ -512,11 +527,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
@@ -549,6 +572,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
}
@@ -580,7 +610,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) {
@@ -605,7 +637,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);
@@ -622,8 +671,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) {
@@ -687,7 +746,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()))
@@ -724,6 +783,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);
@@ -833,9 +894,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) {
@@ -851,8 +912,8 @@ void QXcbConnection::handleEnterEvent(const xcb_enter_notify_event_t *)
XIFreeDeviceInfo(xiDeviceInfo);
++it;
}
-#endif
}
+#endif
void QXcbConnection::xi2HandleScrollEvent(void *event, ScrollingDevice &scrollingDevice)
{
diff --git a/src/plugins/platforms/xcb/qxcbintegration.cpp b/src/plugins/platforms/xcb/qxcbintegration.cpp
index 68a999d55f..6e8755a220 100644
--- a/src/plugins/platforms/xcb/qxcbintegration.cpp
+++ b/src/plugins/platforms/xcb/qxcbintegration.cpp
@@ -180,9 +180,11 @@ QXcbIntegration::QXcbIntegration(const QStringList &parameters, int &argc, char
if (canNotGrabEnv)
m_canGrab = false;
+ const int numParameters = parameters.size();
+ m_connections.reserve(1 + numParameters / 2);
m_connections << new QXcbConnection(m_nativeInterface.data(), m_canGrab, m_defaultVisualId, displayName);
- for (int i = 0; i < parameters.size() - 1; i += 2) {
+ for (int i = 0; i < numParameters - 1; i += 2) {
qCDebug(lcQpaScreen) << "connecting to additional display: " << parameters.at(i) << parameters.at(i+1);
QString display = parameters.at(i) + QLatin1Char(':') + parameters.at(i+1);
m_connections << new QXcbConnection(m_nativeInterface.data(), m_canGrab, m_defaultVisualId, display.toLatin1().constData());
diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.cpp b/src/plugins/platforms/xcb/qxcbkeyboard.cpp
index 457e58d6ef..4de7716703 100644
--- a/src/plugins/platforms/xcb/qxcbkeyboard.cpp
+++ b/src/plugins/platforms/xcb/qxcbkeyboard.cpp
@@ -803,9 +803,9 @@ void QXcbKeyboard::updateXKBStateFromCore(quint16 state)
}
}
+#ifdef XCB_USE_XINPUT22
void QXcbKeyboard::updateXKBStateFromXI(void *modInfo, void *groupInfo)
{
-#ifdef XCB_USE_XINPUT22
if (m_config && !connection()->hasXKB()) {
xXIModifierInfo *mods = static_cast<xXIModifierInfo *>(modInfo);
xXIGroupInfo *group = static_cast<xXIGroupInfo *>(groupInfo);
@@ -821,12 +821,8 @@ void QXcbKeyboard::updateXKBStateFromXI(void *modInfo, void *groupInfo)
//qWarning("TODO: Support KeyboardLayoutChange on QPA (QTBUG-27681)");
}
}
-#else
- Q_UNUSED(modInfo);
- Q_UNUSED(groupInfo);
- Q_ASSERT(false); // this can't be
-#endif
}
+#endif
quint32 QXcbKeyboard::xkbModMask(quint16 state)
{
diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.h b/src/plugins/platforms/xcb/qxcbkeyboard.h
index ed9ab09ed8..75e6d2ec82 100644
--- a/src/plugins/platforms/xcb/qxcbkeyboard.h
+++ b/src/plugins/platforms/xcb/qxcbkeyboard.h
@@ -74,7 +74,9 @@ public:
void updateXKBMods();
quint32 xkbModMask(quint16 state);
void updateXKBStateFromCore(quint16 state);
+#ifdef XCB_USE_XINPUT22
void updateXKBStateFromXI(void *modInfo, void *groupInfo);
+#endif
#ifndef QT_NO_XKB
// when XKEYBOARD is present on the X server
int coreDeviceId() const { return core_device_id; }
diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp
index 848cd85b03..240a1dbc74 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.cpp
+++ b/src/plugins/platforms/xcb/qxcbwindow.cpp
@@ -900,8 +900,13 @@ static bool focusInPeeker(QXcbConnection *connection, xcb_generic_event_t *event
return true;
}
uint response_type = event->response_type & ~0x80;
- if (response_type == XCB_FOCUS_IN)
- return true;
+ if (response_type == XCB_FOCUS_IN) {
+ // Ignore focus events that are being sent only because the pointer is over
+ // our window, even if the input focus is in a different window.
+ xcb_focus_in_event_t *e = (xcb_focus_in_event_t *) event;
+ if (e->detail != XCB_NOTIFY_DETAIL_POINTER)
+ return true;
+ }
/* We are also interested in XEMBED_FOCUS_IN events */
if (response_type == XCB_CLIENT_MESSAGE) {
@@ -2171,6 +2176,85 @@ void QXcbWindow::handleButtonReleaseEvent(int event_x, int event_y, int root_x,
handleMouseEvent(timestamp, local, global, modifiers);
}
+static bool ignoreLeaveEvent(quint8 mode, quint8 detail)
+{
+ return (mode == XCB_NOTIFY_MODE_GRAB && detail == XCB_NOTIFY_DETAIL_ANCESTOR) // Check for AwesomeWM
+ || detail == XCB_NOTIFY_DETAIL_VIRTUAL
+ || detail == XCB_NOTIFY_DETAIL_NONLINEAR_VIRTUAL;
+}
+
+static bool ignoreEnterEvent(quint8 mode, quint8 detail)
+{
+ return ((mode == XCB_NOTIFY_MODE_UNGRAB && detail == XCB_NOTIFY_DETAIL_ANCESTOR) // Check for AwesomeWM
+ || (mode != XCB_NOTIFY_MODE_NORMAL && mode != XCB_NOTIFY_MODE_UNGRAB)
+ || detail == XCB_NOTIFY_DETAIL_VIRTUAL
+ || detail == XCB_NOTIFY_DETAIL_NONLINEAR_VIRTUAL);
+}
+
+class EnterEventChecker
+{
+public:
+ bool checkEvent(xcb_generic_event_t *event)
+ {
+ if (!event)
+ return false;
+ if ((event->response_type & ~0x80) != XCB_ENTER_NOTIFY)
+ return false;
+
+ xcb_enter_notify_event_t *enter = (xcb_enter_notify_event_t *)event;
+ if (ignoreEnterEvent(enter->mode, enter->detail))
+ return false;
+
+ return true;
+ }
+};
+
+void QXcbWindow::handleEnterNotifyEvent(int event_x, int event_y, int root_x, int root_y,
+ quint8 mode, quint8 detail, xcb_timestamp_t timestamp)
+{
+ connection()->setTime(timestamp);
+#ifdef XCB_USE_XINPUT21
+ connection()->handleEnterEvent();
+#endif
+
+ const QPoint global = QPoint(root_x, root_y);
+
+ if (ignoreEnterEvent(mode, detail)
+ || (connection()->buttons() != Qt::NoButton
+ && QGuiApplicationPrivate::lastCursorPosition != global))
+ return;
+
+ const QPoint local(event_x, event_y);
+ QWindowSystemInterface::handleEnterEvent(window(), local, global);
+}
+
+void QXcbWindow::handleLeaveNotifyEvent(int root_x, int root_y,
+ quint8 mode, quint8 detail, xcb_timestamp_t timestamp)
+{
+ connection()->setTime(timestamp);
+
+ const QPoint global(root_x, root_y);
+
+ if (ignoreLeaveEvent(mode, detail)
+ || (connection()->buttons() != Qt::NoButton
+ && QGuiApplicationPrivate::lastCursorPosition != global))
+ return;
+
+ EnterEventChecker checker;
+ xcb_enter_notify_event_t *enter = (xcb_enter_notify_event_t *)connection()->checkEvent(checker);
+ QXcbWindow *enterWindow = enter ? connection()->platformWindowFromId(enter->event) : 0;
+
+ if (enterWindow) {
+ QPoint local(enter->event_x, enter->event_y);
+ QPoint global = QPoint(root_x, root_y);
+ QWindowSystemInterface::handleEnterLeaveEvent(enterWindow->window(), window(), local, global);
+ } else {
+ QWindowSystemInterface::handleLeaveEvent(window());
+ }
+
+ free(enter);
+}
+
void QXcbWindow::handleMotionNotifyEvent(int event_x, int event_y, int root_x, int root_y,
Qt::KeyboardModifiers modifiers, xcb_timestamp_t timestamp)
{
@@ -2205,12 +2289,10 @@ static inline int fixed1616ToInt(FP1616 val)
{
return int((qreal(val >> 16)) + (val & 0xFFFF) / (qreal)0xFFFF);
}
-#endif
// With XI 2.2+ press/release/motion comes here instead of the above handlers.
void QXcbWindow::handleXIMouseEvent(xcb_ge_event_t *event)
{
-#ifdef XCB_USE_XINPUT22
QXcbConnection *conn = connection();
xXIDeviceEvent *ev = reinterpret_cast<xXIDeviceEvent *>(event);
const Qt::KeyboardModifiers modifiers = conn->keyboard()->translateModifiers(ev->mods.effective_mods);
@@ -2248,12 +2330,41 @@ void QXcbWindow::handleXIMouseEvent(xcb_ge_event_t *event)
qWarning() << "Unrecognized XI2 mouse event" << ev->evtype;
break;
}
-#else
- Q_UNUSED(event);
- Q_ASSERT(false); // this can't be
-#endif
}
+// With XI 2.2+ enter/leave comes here and are blocked in plain xcb events
+void QXcbWindow::handleXIEnterLeave(xcb_ge_event_t *event)
+{
+ xXIEnterEvent *ev = reinterpret_cast<xXIEnterEvent *>(event);
+
+ // Compare the window with current mouse grabber to prevent deliver events to any other windows.
+ // If leave event occurs and the window is under mouse - allow to deliver the leave event.
+ QXcbWindow *mouseGrabber = connection()->mouseGrabber();
+ if (mouseGrabber && mouseGrabber != this
+ && (ev->evtype != XI_Leave || QGuiApplicationPrivate::currentMouseWindow != window())) {
+ return;
+ }
+
+ const int root_x = fixed1616ToInt(ev->root_x);
+ const int root_y = fixed1616ToInt(ev->root_y);
+
+ switch (ev->evtype) {
+ case XI_Enter: {
+ const int event_x = fixed1616ToInt(ev->event_x);
+ const int event_y = fixed1616ToInt(ev->event_y);
+ qCDebug(lcQpaXInput, "XI2 mouse enter %d,%d, mode %d, detail %d, time %d", event_x, event_y, ev->mode, ev->detail, ev->time);
+ handleEnterNotifyEvent(event_x, event_y, root_x, root_y, ev->mode, ev->detail, ev->time);
+ break;
+ }
+ case XI_Leave:
+ qCDebug(lcQpaXInput, "XI2 mouse leave, mode %d, detail %d, time %d", ev->mode, ev->detail, ev->time);
+ connection()->keyboard()->updateXKBStateFromXI(&ev->mods, &ev->group);
+ handleLeaveNotifyEvent(root_x, root_y, ev->mode, ev->detail, ev->time);
+ break;
+ }
+}
+#endif
+
QXcbWindow *QXcbWindow::toWindow() { return this; }
void QXcbWindow::handleMouseEvent(xcb_timestamp_t time, const QPoint &local, const QPoint &global, Qt::KeyboardModifiers modifiers)
@@ -2262,74 +2373,14 @@ void QXcbWindow::handleMouseEvent(xcb_timestamp_t time, const QPoint &local, con
QWindowSystemInterface::handleMouseEvent(window(), time, local, global, connection()->buttons(), modifiers);
}
-static bool ignoreLeaveEvent(const xcb_leave_notify_event_t *event)
-{
- return event->detail == XCB_NOTIFY_DETAIL_VIRTUAL
- || event->detail == XCB_NOTIFY_DETAIL_NONLINEAR_VIRTUAL
- || event->mode == XCB_NOTIFY_MODE_GRAB;
-}
-
-static bool ignoreEnterEvent(const xcb_enter_notify_event_t *event)
-{
- return (event->mode != XCB_NOTIFY_MODE_NORMAL
- || event->detail == XCB_NOTIFY_DETAIL_VIRTUAL
- || event->detail == XCB_NOTIFY_DETAIL_NONLINEAR_VIRTUAL);
-}
-
-class EnterEventChecker
-{
-public:
- bool checkEvent(xcb_generic_event_t *event)
- {
- if (!event)
- return false;
- if ((event->response_type & ~0x80) != XCB_ENTER_NOTIFY)
- return false;
-
- xcb_enter_notify_event_t *enter = (xcb_enter_notify_event_t *)event;
- if (ignoreEnterEvent(enter))
- return false;
-
- return true;
- }
-};
-
void QXcbWindow::handleEnterNotifyEvent(const xcb_enter_notify_event_t *event)
{
- connection()->setTime(event->time);
-#ifdef XCB_USE_XINPUT2
- connection()->handleEnterEvent(event);
-#endif
-
- if (ignoreEnterEvent(event))
- return;
-
- const QPoint local(event->event_x, event->event_y);
- QPoint global = QPoint(event->root_x, event->root_y);
- QWindowSystemInterface::handleEnterEvent(window(), local, global);
+ handleEnterNotifyEvent(event->event_x, event->event_y, event->root_x, event->root_y, event->mode, event->detail, event->time);
}
void QXcbWindow::handleLeaveNotifyEvent(const xcb_leave_notify_event_t *event)
{
- connection()->setTime(event->time);
-
- if (ignoreLeaveEvent(event))
- return;
-
- EnterEventChecker checker;
- xcb_enter_notify_event_t *enter = (xcb_enter_notify_event_t *)connection()->checkEvent(checker);
- QXcbWindow *enterWindow = enter ? connection()->platformWindowFromId(enter->event) : 0;
-
- if (enterWindow) {
- QPoint local(enter->event_x, enter->event_y);
- QPoint global = QPoint(event->root_x, event->root_y);
-
- QWindowSystemInterface::handleEnterLeaveEvent(enterWindow->window(), window(), local, global);
- } else {
- QWindowSystemInterface::handleLeaveEvent(window());
- }
-
- free(enter);
+ handleLeaveNotifyEvent(event->root_x, event->root_y, event->mode, event->detail, event->time);
}
void QXcbWindow::handlePropertyNotifyEvent(const xcb_property_notify_event_t *event)
@@ -2383,14 +2434,22 @@ void QXcbWindow::handlePropertyNotifyEvent(const xcb_property_notify_event_t *ev
}
}
-void QXcbWindow::handleFocusInEvent(const xcb_focus_in_event_t *)
+void QXcbWindow::handleFocusInEvent(const xcb_focus_in_event_t *event)
{
+ // Ignore focus events that are being sent only because the pointer is over
+ // our window, even if the input focus is in a different window.
+ if (event->detail == XCB_NOTIFY_DETAIL_POINTER)
+ return;
doFocusIn();
}
-void QXcbWindow::handleFocusOutEvent(const xcb_focus_out_event_t *)
+void QXcbWindow::handleFocusOutEvent(const xcb_focus_out_event_t *event)
{
+ // Ignore focus events that are being sent only because the pointer is over
+ // our window, even if the input focus is in a different window.
+ if (event->detail == XCB_NOTIFY_DETAIL_POINTER)
+ return;
doFocusOut();
}
@@ -2433,7 +2492,7 @@ bool QXcbWindow::setMouseGrabEnabled(bool grab)
if (!grab && connection()->mouseGrabber() == this)
connection()->setMouseGrabber(Q_NULLPTR);
#ifdef XCB_USE_XINPUT22
- if (connection()->xi2MouseEvents()) {
+ if (connection()->isAtLeastXI22() && connection()->xi2MouseEvents()) {
bool result = connection()->xi2SetMouseGrabEnabled(m_window, grab);
if (grab && result)
connection()->setMouseGrabber(this);
diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h
index 0efd78452c..72688cdf16 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.h
+++ b/src/plugins/platforms/xcb/qxcbwindow.h
@@ -138,7 +138,10 @@ public:
void handleFocusInEvent(const xcb_focus_in_event_t *event) Q_DECL_OVERRIDE;
void handleFocusOutEvent(const xcb_focus_out_event_t *event) Q_DECL_OVERRIDE;
void handlePropertyNotifyEvent(const xcb_property_notify_event_t *event) Q_DECL_OVERRIDE;
+#ifdef XCB_USE_XINPUT22
void handleXIMouseEvent(xcb_ge_event_t *) Q_DECL_OVERRIDE;
+ void handleXIEnterLeave(xcb_ge_event_t *) Q_DECL_OVERRIDE;
+#endif
QXcbWindow *toWindow() Q_DECL_OVERRIDE;
@@ -219,6 +222,12 @@ protected:
void handleMotionNotifyEvent(int event_x, int event_y, int root_x, int root_y,
Qt::KeyboardModifiers modifiers, xcb_timestamp_t timestamp);
+ void handleEnterNotifyEvent(int event_x, int event_y, int root_x, int root_y,
+ quint8 mode, quint8 detail, xcb_timestamp_t timestamp);
+
+ void handleLeaveNotifyEvent(int root_x, int root_y,
+ quint8 mode, quint8 detail, xcb_timestamp_t timestamp);
+
xcb_window_t m_window;
uint m_depth;