diff -Nru qtbase-opensource-src-5.5.1+dfsg/debian/changelog qtbase-opensource-src-5.5.1+dfsg/debian/changelog --- qtbase-opensource-src-5.5.1+dfsg/debian/changelog 2016-09-12 07:49:32.000000000 +0200 +++ qtbase-opensource-src-5.5.1+dfsg/debian/changelog 2017-03-20 16:35:35.000000000 +0100 @@ -1,3 +1,10 @@ +qtbase-opensource-src (5.5.1+dfsg-16ubuntu7.3) xenial; urgency=medium + + * debian/patches/xcb-compress-mouse-motion-and-touch-update-events.patch: + - Backport event compression fix from Qt 5.6 branch (LP: #1598173) + + -- Elvis Stansvik Mon, 20 Mar 2017 16:33:33 +0100 + qtbase-opensource-src (5.5.1+dfsg-16ubuntu7.2) xenial; urgency=medium * debian/patches/Fix-parsing-of-tzfile-5-POSIX-rule-zone-names-with-b.patch: diff -Nru qtbase-opensource-src-5.5.1+dfsg/debian/patches/series qtbase-opensource-src-5.5.1+dfsg/debian/patches/series --- qtbase-opensource-src-5.5.1+dfsg/debian/patches/series 2016-09-12 07:49:13.000000000 +0200 +++ qtbase-opensource-src-5.5.1+dfsg/debian/patches/series 2017-03-20 16:18:44.000000000 +0100 @@ -55,3 +55,4 @@ disable_overlay_scrollbars.diff xcb_fix_parent_screen_of_embedded_windows.patch fix-duplicate-qnam-finished.patch +xcb-compress-mouse-motion-and-touch-update-events.patch diff -Nru qtbase-opensource-src-5.5.1+dfsg/debian/patches/xcb-compress-mouse-motion-and-touch-update-events.patch qtbase-opensource-src-5.5.1+dfsg/debian/patches/xcb-compress-mouse-motion-and-touch-update-events.patch --- qtbase-opensource-src-5.5.1+dfsg/debian/patches/xcb-compress-mouse-motion-and-touch-update-events.patch 1970-01-01 01:00:00.000000000 +0100 +++ qtbase-opensource-src-5.5.1+dfsg/debian/patches/xcb-compress-mouse-motion-and-touch-update-events.patch 2017-03-20 16:24:43.000000000 +0100 @@ -0,0 +1,438 @@ +Index: qtbase-opensource-src-5.5.1+dfsg/src/plugins/platforms/xcb/qxcbconnection.cpp +=================================================================== +--- qtbase-opensource-src-5.5.1+dfsg.orig/src/plugins/platforms/xcb/qxcbconnection.cpp ++++ qtbase-opensource-src-5.5.1+dfsg/src/plugins/platforms/xcb/qxcbconnection.cpp +@@ -107,6 +107,24 @@ Q_LOGGING_CATEGORY(lcQpaScreen, "qt.qpa. + #define XCB_GE_GENERIC 35 + #endif + ++// Starting from the xcb version 1.9.3 struct xcb_ge_event_t has changed: ++// - "pad0" became "extension" ++// - "pad1" and "pad" became "pad0" ++// New and old version of this struct share the following fields: ++typedef struct qt_xcb_ge_event_t { ++ uint8_t response_type; ++ uint8_t extension; ++ uint16_t sequence; ++ uint32_t length; ++ uint16_t event_type; ++} qt_xcb_ge_event_t; ++ ++static inline bool isXIEvent(xcb_generic_event_t *event, int opCode) ++{ ++ qt_xcb_ge_event_t *e = (qt_xcb_ge_event_t *)event; ++ return e->extension == opCode; ++} ++ + #ifdef XCB_USE_XLIB + static const char * const xcbConnectionErrors[] = { + "No error", /* Error 0 */ +@@ -1139,7 +1157,7 @@ void QXcbConnection::handleXcbEvent(xcb_ + #if defined(XCB_USE_XINPUT2) + case XCB_GE_GENERIC: + // Here the windowEventListener is invoked from xi2HandleEvent() +- if (m_xi2Enabled) ++ if (m_xi2Enabled && isXIEvent(event, m_xiOpCode)) + xi2HandleEvent(reinterpret_cast(event)); + break; + #endif +@@ -1467,6 +1485,105 @@ void *QXcbConnection::createVisualInfoFo + + #endif + ++#if defined(XCB_USE_XINPUT2) ++// it is safe to cast XI_* events here as long as we are only touching the first 32 bytes, ++// after that position event needs memmove, see xi2PrepareXIGenericDeviceEvent ++static inline bool isXIType(xcb_generic_event_t *event, int opCode, uint16_t type) ++{ ++ if (!isXIEvent(event, opCode)) ++ return false; ++ ++ xXIGenericDeviceEvent *xiEvent = reinterpret_cast(event); ++ return xiEvent->evtype == type; ++} ++#endif ++static inline bool isValid(xcb_generic_event_t *event) ++{ ++ return event && (event->response_type & ~0x80); ++} ++ ++/*! \internal ++ ++ Compresses events of the same type to avoid swamping the event queue. ++ If event compression is not desired there are several options what developers can do: ++ ++ 1) Write responsive applications. We drop events that have been buffered in the event ++ queue while waiting on unresponsive GUI thread. ++ 2) Use QAbstractNativeEventFilter to get all events from X connection. This is not optimal ++ because it requires working with native event types. ++ 3) Or add public API to Qt for disabling event compression QTBUG-44964 ++ ++*/ ++bool QXcbConnection::compressEvent(xcb_generic_event_t *event, int currentIndex, QXcbEventArray *eventqueue) const ++{ ++ uint responseType = event->response_type & ~0x80; ++ int nextIndex = currentIndex + 1; ++ ++ if (responseType == XCB_MOTION_NOTIFY) { ++ // compress XCB_MOTION_NOTIFY notify events ++ for (int j = nextIndex; j < eventqueue->size(); ++j) { ++ xcb_generic_event_t *next = eventqueue->at(j); ++ if (!isValid(next)) ++ continue; ++ if (next->response_type == XCB_MOTION_NOTIFY) ++ return true; ++ } ++ return false; ++ } ++#if defined(XCB_USE_XINPUT2) ++ // compress XI_* events ++ if (responseType == XCB_GE_GENERIC) { ++ if (!m_xi2Enabled) ++ return false; ++ ++ // compress XI_Motion ++ if (isXIType(event, m_xiOpCode, XI_Motion)) { ++ for (int j = nextIndex; j < eventqueue->size(); ++j) { ++ xcb_generic_event_t *next = eventqueue->at(j); ++ if (!isValid(next)) ++ continue; ++ if (isXIType(next, m_xiOpCode, XI_Motion)) ++ return true; ++ } ++ return false; ++ } ++#ifdef XCB_USE_XINPUT22 ++ // compress XI_TouchUpdate for the same touch point id ++ if (isXIType(event, m_xiOpCode, XI_TouchUpdate)) { ++ xXIDeviceEvent *xiDeviceEvent = reinterpret_cast(event); ++ uint32_t id = xiDeviceEvent->detail % INT_MAX; ++ for (int j = nextIndex; j < eventqueue->size(); ++j) { ++ xcb_generic_event_t *next = eventqueue->at(j); ++ if (!isValid(next)) ++ continue; ++ if (isXIType(next, m_xiOpCode, XI_TouchUpdate)) { ++ xXIDeviceEvent *xiDeviceNextEvent = reinterpret_cast(next); ++ if (id == xiDeviceNextEvent->detail % INT_MAX) ++ return true; ++ } ++ } ++ return false; ++ } ++#endif ++ return false; ++ } ++#endif ++ if (responseType == XCB_CONFIGURE_NOTIFY) { ++ // compress multiple configure notify events for the same window ++ for (int j = nextIndex; j < eventqueue->size(); ++j) { ++ xcb_generic_event_t *next = eventqueue->at(j); ++ if (isValid(next) && next->response_type == XCB_CONFIGURE_NOTIFY ++ && ((xcb_configure_notify_event_t *)next)->event == ((xcb_configure_notify_event_t*)event)->event) ++ { ++ return true; ++ } ++ } ++ return false; ++ } ++ ++ return false; ++} ++ + void QXcbConnection::processXcbEvents() + { + int connection_error = xcb_connection_has_error(xcb_connection()); +@@ -1477,61 +1594,39 @@ void QXcbConnection::processXcbEvents() + + QXcbEventArray *eventqueue = m_reader->lock(); + +- for(int i = 0; i < eventqueue->size(); ++i) { ++ for (int i = 0; i < eventqueue->size(); ++i) { + xcb_generic_event_t *event = eventqueue->at(i); + if (!event) + continue; + QScopedPointer eventGuard(event); + (*eventqueue)[i] = 0; + +- uint response_type = event->response_type & ~0x80; +- +- if (!response_type) { ++ if (!(event->response_type & ~0x80)) { + handleXcbError((xcb_generic_error_t *)event); +- } else { +- if (response_type == XCB_MOTION_NOTIFY) { +- // compress multiple motion notify events in a row +- // to avoid swamping the event queue +- xcb_generic_event_t *next = eventqueue->value(i+1, 0); +- if (next && (next->response_type & ~0x80) == XCB_MOTION_NOTIFY) +- continue; +- } ++ continue; ++ } + +- if (response_type == XCB_CONFIGURE_NOTIFY) { +- // compress multiple configure notify events for the same window +- bool found = false; +- for (int j = i; j < eventqueue->size(); ++j) { +- xcb_generic_event_t *other = eventqueue->at(j); +- if (other && (other->response_type & ~0x80) == XCB_CONFIGURE_NOTIFY +- && ((xcb_configure_notify_event_t *)other)->event == ((xcb_configure_notify_event_t *)event)->event) +- { +- found = true; +- break; +- } +- } +- if (found) +- continue; +- } ++ if (compressEvent(event, i, eventqueue)) ++ continue; + +- bool accepted = false; +- if (clipboard()->processIncr()) +- clipboard()->incrTransactionPeeker(event, accepted); +- if (accepted) +- continue; ++ bool accepted = false; ++ if (clipboard()->processIncr()) ++ clipboard()->incrTransactionPeeker(event, accepted); ++ if (accepted) ++ continue; + +- QVector::iterator it = m_peekFuncs.begin(); +- while (it != m_peekFuncs.end()) { +- // These callbacks return true if the event is what they were +- // waiting for, remove them from the list in that case. +- if ((*it)(this, event)) +- it = m_peekFuncs.erase(it); +- else +- ++it; +- } +- m_reader->unlock(); +- handleXcbEvent(event); +- m_reader->lock(); ++ QVector::iterator it = m_peekFuncs.begin(); ++ while (it != m_peekFuncs.end()) { ++ // These callbacks return true if the event is what they were ++ // waiting for, remove them from the list in that case. ++ if ((*it)(this, event)) ++ it = m_peekFuncs.erase(it); ++ else ++ ++it; + } ++ m_reader->unlock(); ++ handleXcbEvent(event); ++ m_reader->lock(); + } + + eventqueue->clear(); +@@ -2073,34 +2168,13 @@ bool QXcbConnection::xi2GetValuatorValue + return true; + } + +-// Starting from the xcb version 1.9.3 struct xcb_ge_event_t has changed: +-// - "pad0" became "extension" +-// - "pad1" and "pad" became "pad0" +-// New and old version of this struct share the following fields: +-// NOTE: API might change again in the next release of xcb in which case this comment will +-// need to be updated to reflect the reality. +-typedef struct qt_xcb_ge_event_t { +- uint8_t response_type; +- uint8_t extension; +- uint16_t sequence; +- uint32_t length; +- uint16_t event_type; +-} qt_xcb_ge_event_t; +- +-bool QXcbConnection::xi2PrepareXIGenericDeviceEvent(xcb_ge_event_t *ev, int opCode) ++void QXcbConnection::xi2PrepareXIGenericDeviceEvent(xcb_ge_event_t *event) + { +- qt_xcb_ge_event_t *event = (qt_xcb_ge_event_t *)ev; +- // xGenericEvent has "extension" on the second byte, the same is true for xcb_ge_event_t starting from +- // the xcb version 1.9.3, prior to that it was called "pad0". +- if (event->extension == opCode) { +- // xcb event structs contain stuff that wasn't on the wire, the full_sequence field +- // adds an extra 4 bytes and generic events cookie data is on the wire right after the standard 32 bytes. +- // Move this data back to have the same layout in memory as it was on the wire +- // and allow casting, overwriting the full_sequence field. +- memmove((char*) event + 32, (char*) event + 36, event->length * 4); +- return true; +- } +- return false; ++ // xcb event structs contain stuff that wasn't on the wire, the full_sequence field ++ // adds an extra 4 bytes and generic events cookie data is on the wire right after the standard 32 bytes. ++ // Move this data back to have the same layout in memory as it was on the wire ++ // and allow casting, overwriting the full_sequence field. ++ memmove((char*) event + 32, (char*) event + 36, event->length * 4); + } + #endif // defined(XCB_USE_XINPUT2) + +Index: qtbase-opensource-src-5.5.1+dfsg/src/plugins/platforms/xcb/qxcbconnection.h +=================================================================== +--- qtbase-opensource-src-5.5.1+dfsg.orig/src/plugins/platforms/xcb/qxcbconnection.h ++++ qtbase-opensource-src-5.5.1+dfsg/src/plugins/platforms/xcb/qxcbconnection.h +@@ -517,6 +517,7 @@ private: + QXcbScreen* findScreenForOutput(xcb_window_t rootWindow, xcb_randr_output_t output); + QXcbVirtualDesktop* virtualDesktopForRootWindow(xcb_window_t rootWindow); + void updateScreens(const xcb_randr_notify_event_t *event); ++ bool compressEvent(xcb_generic_event_t *event, int currentIndex, QXcbEventArray *eventqueue) const; + bool checkOutputIsPrimary(xcb_window_t rootWindow, xcb_randr_output_t output); + void updateScreen(QXcbScreen *screen, const xcb_randr_output_change_t &outputChange); + QXcbScreen *createScreen(QXcbVirtualDesktop *virtualDesktop, +@@ -576,7 +577,7 @@ private: + QHash m_scrollingDevices; + + static bool xi2GetValuatorValueIfSet(void *event, int valuatorNum, double *value); +- static bool xi2PrepareXIGenericDeviceEvent(xcb_ge_event_t *event, int opCode); ++ static void xi2PrepareXIGenericDeviceEvent(xcb_ge_event_t *event); + #endif + + xcb_connection_t *m_connection; +Index: qtbase-opensource-src-5.5.1+dfsg/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp +=================================================================== +--- qtbase-opensource-src-5.5.1+dfsg.orig/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp ++++ qtbase-opensource-src-5.5.1+dfsg/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp +@@ -459,82 +459,81 @@ static inline qreal fixed1616ToReal(FP16 + + void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event) + { +- if (xi2PrepareXIGenericDeviceEvent(event, m_xiOpCode)) { +- xXIGenericDeviceEvent *xiEvent = reinterpret_cast(event); +- int sourceDeviceId = xiEvent->deviceid; // may be the master id +- xXIDeviceEvent *xiDeviceEvent = 0; +- QXcbWindowEventListener *eventListener = 0; +- +- switch (xiEvent->evtype) { +- case XI_ButtonPress: +- case XI_ButtonRelease: +- case XI_Motion: ++ xi2PrepareXIGenericDeviceEvent(event); ++ xXIGenericDeviceEvent *xiEvent = reinterpret_cast(event); ++ int sourceDeviceId = xiEvent->deviceid; // may be the master id ++ xXIDeviceEvent *xiDeviceEvent = 0; ++ QXcbWindowEventListener *eventListener = 0; ++ ++ switch (xiEvent->evtype) { ++ case XI_ButtonPress: ++ case XI_ButtonRelease: ++ case XI_Motion: + #ifdef XCB_USE_XINPUT22 +- case XI_TouchBegin: +- case XI_TouchUpdate: +- case XI_TouchEnd: ++ case XI_TouchBegin: ++ case XI_TouchUpdate: ++ case XI_TouchEnd: + #endif +- { +- xiDeviceEvent = reinterpret_cast(event); +- eventListener = windowEventListenerFromId(xiDeviceEvent->event); +- if (eventListener) { +- long result = 0; +- if (eventListener->handleGenericEvent(reinterpret_cast(event), &result)) +- return; +- } +- sourceDeviceId = xiDeviceEvent->sourceid; // use the actual device id instead of the master +- break; +- } +- case XI_HierarchyChanged: +- xi2HandleHierachyEvent(xiEvent); +- return; +- case XI_DeviceChanged: +- xi2HandleDeviceChangedEvent(xiEvent); +- return; +- default: +- break; ++ { ++ xiDeviceEvent = reinterpret_cast(event); ++ eventListener = windowEventListenerFromId(xiDeviceEvent->event); ++ if (eventListener) { ++ long result = 0; ++ if (eventListener->handleGenericEvent(reinterpret_cast(event), &result)) ++ return; + } ++ sourceDeviceId = xiDeviceEvent->sourceid; // use the actual device id instead of the master ++ break; ++ } ++ case XI_HierarchyChanged: ++ xi2HandleHierachyEvent(xiEvent); ++ return; ++ case XI_DeviceChanged: ++ xi2HandleDeviceChangedEvent(xiEvent); ++ return; ++ default: ++ break; ++ } + + #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; +- } ++ 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 + + #ifdef XCB_USE_XINPUT21 +- QHash::iterator device = m_scrollingDevices.find(sourceDeviceId); +- if (device != m_scrollingDevices.end()) +- xi2HandleScrollEvent(xiEvent, device.value()); ++ QHash::iterator device = m_scrollingDevices.find(sourceDeviceId); ++ if (device != m_scrollingDevices.end()) ++ xi2HandleScrollEvent(xiEvent, device.value()); + #endif // XCB_USE_XINPUT21 + + #ifdef XCB_USE_XINPUT22 +- if (xiDeviceEvent) { +- switch (xiDeviceEvent->evtype) { +- case XI_ButtonPress: +- case XI_ButtonRelease: +- case XI_Motion: +- if (xi2MouseEvents() && eventListener && !(xiDeviceEvent->flags & XIPointerEmulated)) +- eventListener->handleXIMouseEvent(event); +- break; +- +- case XI_TouchBegin: +- case XI_TouchUpdate: +- case XI_TouchEnd: +- if (Q_UNLIKELY(lcQpaXInput().isDebugEnabled())) +- qCDebug(lcQpaXInput, "XI2 touch event type %d seq %d detail %d pos %6.1f, %6.1f root pos %6.1f, %6.1f on window %x", +- event->event_type, xiDeviceEvent->sequenceNumber, xiDeviceEvent->detail, +- fixed1616ToReal(xiDeviceEvent->event_x), fixed1616ToReal(xiDeviceEvent->event_y), +- fixed1616ToReal(xiDeviceEvent->root_x), fixed1616ToReal(xiDeviceEvent->root_y),xiDeviceEvent->event); +- if (QXcbWindow *platformWindow = platformWindowFromId(xiDeviceEvent->event)) +- xi2ProcessTouch(xiDeviceEvent, platformWindow); +- break; +- } ++ if (xiDeviceEvent) { ++ switch (xiDeviceEvent->evtype) { ++ case XI_ButtonPress: ++ case XI_ButtonRelease: ++ case XI_Motion: ++ if (xi2MouseEvents() && eventListener && !(xiDeviceEvent->flags & XIPointerEmulated)) ++ eventListener->handleXIMouseEvent(event); ++ break; ++ ++ case XI_TouchBegin: ++ case XI_TouchUpdate: ++ case XI_TouchEnd: ++ if (Q_UNLIKELY(lcQpaXInput().isDebugEnabled())) ++ qCDebug(lcQpaXInput, "XI2 touch event type %d seq %d detail %d pos %6.1f, %6.1f root pos %6.1f, %6.1f on window %x", ++ event->event_type, xiDeviceEvent->sequenceNumber, xiDeviceEvent->detail, ++ fixed1616ToReal(xiDeviceEvent->event_x), fixed1616ToReal(xiDeviceEvent->event_y), ++ fixed1616ToReal(xiDeviceEvent->root_x), fixed1616ToReal(xiDeviceEvent->root_y),xiDeviceEvent->event); ++ if (QXcbWindow *platformWindow = platformWindowFromId(xiDeviceEvent->event)) ++ xi2ProcessTouch(xiDeviceEvent, platformWindow); ++ break; + } +-#endif // XCB_USE_XINPUT22 + } ++#endif // XCB_USE_XINPUT22 + } + + #ifdef XCB_USE_XINPUT22