diff options
author | Liang Qi <liang.qi@qt.io> | 2016-05-12 07:31:50 +0200 |
---|---|---|
committer | Liang Qi <liang.qi@qt.io> | 2016-05-12 08:33:08 +0200 |
commit | 990969655c5fb4d03682e96df9b12101f5ee9815 (patch) | |
tree | b8fb5c50285105c8bc5a938fb50f93ff9f24889d /src/plugins/platforms/xcb | |
parent | a213011a53f12f101d08a04afc8fdacd2d54a232 (diff) | |
parent | e64b2234e829cc47872225debcf80d6c06db18f0 (diff) |
Merge remote-tracking branch 'origin/5.7' into dev
Conflicts:
config_help.txt
configure
src/corelib/io/qprocess_wince.cpp
src/plugins/platforms/windows/qwindowstheme.cpp
src/plugins/platforms/xcb/qxcbbackingstore.cpp
tests/auto/corelib/tools/qtimezone/BLACKLIST
tests/auto/network/socket/qudpsocket/tst_qudpsocket.cpp
tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp
Change-Id: I26644d1cb3b78412c8ff285e2a55bea1bd641c01
Diffstat (limited to 'src/plugins/platforms/xcb')
-rw-r--r-- | src/plugins/platforms/xcb/qxcbbackingstore.cpp | 18 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbbackingstore.h | 3 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbconnection.cpp | 65 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbconnection.h | 16 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbconnection_xi2.cpp | 84 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbcursor.cpp | 5 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbdrag.cpp | 55 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbintegration.cpp | 30 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbkeyboard.cpp | 6 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbscreen.cpp | 30 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbwindow.cpp | 77 |
11 files changed, 248 insertions, 141 deletions
diff --git a/src/plugins/platforms/xcb/qxcbbackingstore.cpp b/src/plugins/platforms/xcb/qxcbbackingstore.cpp index 2925917562..130ae9be0c 100644 --- a/src/plugins/platforms/xcb/qxcbbackingstore.cpp +++ b/src/plugins/platforms/xcb/qxcbbackingstore.cpp @@ -525,28 +525,36 @@ void QXcbBackingStore::beginPaint(const QRegion ®ion) if (!m_image) return; - m_paintRegion = region; - m_image->preparePaint(m_paintRegion); + m_paintRegions.push(region); + m_image->preparePaint(region); if (m_image->hasAlpha()) { QPainter p(paintDevice()); p.setCompositionMode(QPainter::CompositionMode_Source); const QColor blank = Qt::transparent; - for (const QRect &rect : m_paintRegion) + for (const QRect &rect : region) p.fillRect(rect, blank); } } void QXcbBackingStore::endPaint() { + if (Q_UNLIKELY(m_paintRegions.isEmpty())) { + qWarning("%s: paint regions empty!", Q_FUNC_INFO); + return; + } + + const QRegion region = m_paintRegions.pop(); + m_image->preparePaint(region); + QXcbWindow *platformWindow = static_cast<QXcbWindow *>(window()->handle()); if (!platformWindow || !platformWindow->imageNeedsRgbSwap()) return; // Slow path: the paint device was m_rgbImage. Now copy with swapping red // and blue into m_image. - auto it = m_paintRegion.begin(); - const auto end = m_paintRegion.end(); + auto it = region.begin(); + const auto end = region.end(); if (it == end) return; QPainter p(m_image->image()); diff --git a/src/plugins/platforms/xcb/qxcbbackingstore.h b/src/plugins/platforms/xcb/qxcbbackingstore.h index 4b8c040729..6af679d28a 100644 --- a/src/plugins/platforms/xcb/qxcbbackingstore.h +++ b/src/plugins/platforms/xcb/qxcbbackingstore.h @@ -41,6 +41,7 @@ #define QXCBBACKINGSTORE_H #include <qpa/qplatformbackingstore.h> +#include <QtCore/QStack> #include <xcb/xcb.h> @@ -75,7 +76,7 @@ public: private: QXcbShmImage *m_image; - QRegion m_paintRegion; + QStack<QRegion> m_paintRegions; QImage m_rgbImage; }; diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index cb222842db..87b4c7b91f 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -166,9 +166,9 @@ static int ioErrorHandler(Display *dpy) } #endif -QXcbScreen* QXcbConnection::findScreenForCrtc(xcb_window_t rootWindow, xcb_randr_crtc_t crtc) +QXcbScreen* QXcbConnection::findScreenForCrtc(xcb_window_t rootWindow, xcb_randr_crtc_t crtc) const { - foreach (QXcbScreen *screen, m_screens) { + for (QXcbScreen *screen : m_screens) { if (screen->root() == rootWindow && screen->crtc() == crtc) return screen; } @@ -176,9 +176,9 @@ QXcbScreen* QXcbConnection::findScreenForCrtc(xcb_window_t rootWindow, xcb_randr return 0; } -QXcbScreen* QXcbConnection::findScreenForOutput(xcb_window_t rootWindow, xcb_randr_output_t output) +QXcbScreen* QXcbConnection::findScreenForOutput(xcb_window_t rootWindow, xcb_randr_output_t output) const { - foreach (QXcbScreen *screen, m_screens) { + for (QXcbScreen *screen : m_screens) { if (screen->root() == rootWindow && screen->output() == output) return screen; } @@ -186,9 +186,9 @@ QXcbScreen* QXcbConnection::findScreenForOutput(xcb_window_t rootWindow, xcb_ran return 0; } -QXcbVirtualDesktop* QXcbConnection::virtualDesktopForRootWindow(xcb_window_t rootWindow) +QXcbVirtualDesktop* QXcbConnection::virtualDesktopForRootWindow(xcb_window_t rootWindow) const { - foreach (QXcbVirtualDesktop *virtualDesktop, m_virtualDesktops) { + for (QXcbVirtualDesktop *virtualDesktop : m_virtualDesktops) { if (virtualDesktop->screen()->root == rootWindow) return virtualDesktop; } @@ -215,6 +215,9 @@ void QXcbConnection::updateScreens(const xcb_randr_notify_event_t *event) // CRTC with node mode could mean that output has been disabled, and we'll // get RRNotifyOutputChange notification for that. if (screen && crtc.mode) { + if (crtc.rotation == XCB_RANDR_ROTATION_ROTATE_90 || + crtc.rotation == XCB_RANDR_ROTATION_ROTATE_270) + std::swap(crtc.width, crtc.height); screen->updateGeometry(QRect(crtc.x, crtc.y, crtc.width, crtc.height), crtc.rotation); if (screen->mode() != crtc.mode) screen->updateRefreshRate(crtc.mode); @@ -242,7 +245,8 @@ void QXcbConnection::updateScreens(const xcb_randr_notify_event_t *event) xcb_randr_get_output_info_reply(xcb_connection(), outputInfoCookie, NULL)); // Find a fake screen - foreach (QPlatformScreen *scr, virtualDesktop->screens()) { + const auto scrs = virtualDesktop->screens(); + for (QPlatformScreen *scr : scrs) { QXcbScreen *xcbScreen = (QXcbScreen *)scr; if (xcbScreen->output() == XCB_NONE) { screen = xcbScreen; @@ -284,7 +288,7 @@ void QXcbConnection::updateScreens(const xcb_randr_notify_event_t *event) } } - qCDebug(lcQpaScreen) << "primary output is" << m_screens.first()->name(); + qCDebug(lcQpaScreen) << "primary output is" << qAsConst(m_screens).first()->name(); } } @@ -319,7 +323,7 @@ void QXcbConnection::updateScreen(QXcbScreen *screen, const xcb_randr_output_cha // If the screen became primary, reshuffle the order in QGuiApplicationPrivate const int idx = m_screens.indexOf(screen); if (idx > 0) { - m_screens.first()->setPrimary(false); + qAsConst(m_screens).first()->setPrimary(false); m_screens.swap(0, idx); } screen->virtualDesktop()->setPrimaryScreen(screen); @@ -339,7 +343,7 @@ QXcbScreen *QXcbConnection::createScreen(QXcbVirtualDesktop *virtualDesktop, if (screen->isPrimary()) { if (!m_screens.isEmpty()) - m_screens.first()->setPrimary(false); + qAsConst(m_screens).first()->setPrimary(false); m_screens.prepend(screen); } else { @@ -518,7 +522,7 @@ void QXcbConnection::initializeScreens() ++xcbScreenNumber; } // for each xcb screen - foreach (QXcbVirtualDesktop *virtualDesktop, m_virtualDesktops) + for (QXcbVirtualDesktop *virtualDesktop : qAsConst(m_virtualDesktops)) virtualDesktop->subscribeToXFixesSelectionNotify(); if (m_virtualDesktops.isEmpty()) { @@ -526,19 +530,19 @@ void QXcbConnection::initializeScreens() } else { // Ensure the primary screen is first on the list if (primaryScreen) { - if (m_screens.first() != primaryScreen) { + if (qAsConst(m_screens).first() != primaryScreen) { m_screens.removeOne(primaryScreen); m_screens.prepend(primaryScreen); } } // Push the screens to QGuiApplication - foreach (QXcbScreen *screen, m_screens) { + for (QXcbScreen *screen : qAsConst(m_screens)) { qCDebug(lcQpaScreen) << "adding" << screen << "(Primary:" << screen->isPrimary() << ")"; QXcbIntegration::instance()->screenAdded(screen, screen->isPrimary()); } - qCDebug(lcQpaScreen) << "primary output is" << m_screens.first()->name(); + qCDebug(lcQpaScreen) << "primary output is" << qAsConst(m_screens).first()->name(); } } @@ -563,6 +567,7 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGra , m_buttons(0) , m_focusWindow(0) , m_mouseGrabber(0) + , m_mousePressWindow(0) , m_clientLeader(0) , m_systemTrayTracker(0) , m_glIntegration(Q_NULLPTR) @@ -1010,8 +1015,8 @@ void QXcbConnection::handleXcbError(xcb_generic_error_t *error) } } if (i == m_callLog.size() && !m_callLog.isEmpty()) - qDebug("Caused some time after: %s:%d", m_callLog.first().file.constData(), - m_callLog.first().line); + qDebug("Caused some time after: %s:%d", qAsConst(m_callLog).first().file.constData(), + qAsConst(m_callLog).first().line); #endif } @@ -1231,7 +1236,7 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event) #ifndef QT_NO_CLIPBOARD m_clipboard->handleXFixesSelectionRequest(notify_event); #endif - foreach (QXcbVirtualDesktop *virtualDesktop, m_virtualDesktops) + for (QXcbVirtualDesktop *virtualDesktop : qAsConst(m_virtualDesktops)) virtualDesktop->handleXFixesSelectionNotify(notify_event); handled = true; @@ -1240,7 +1245,7 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event) handled = true; } else if (has_randr_extension && response_type == xrandr_first_event + XCB_RANDR_SCREEN_CHANGE_NOTIFY) { xcb_randr_screen_change_notify_event_t *change_event = (xcb_randr_screen_change_notify_event_t *)event; - foreach (QXcbScreen *s, m_screens) { + for (QXcbScreen *s : qAsConst(m_screens)) { if (s->root() == change_event->root ) s->handleScreenChange(change_event); } @@ -1375,6 +1380,11 @@ void QXcbConnection::setFocusWindow(QXcbWindow *w) void QXcbConnection::setMouseGrabber(QXcbWindow *w) { m_mouseGrabber = w; + m_mousePressWindow = Q_NULLPTR; +} +void QXcbConnection::setMousePressWindow(QXcbWindow *w) +{ + m_mousePressWindow = w; } void QXcbConnection::grabServer() @@ -1628,8 +1638,13 @@ bool QXcbConnection::compressEvent(xcb_generic_event_t *event, int currentIndex, if (!m_xi2Enabled) return false; - // compress XI_Motion + // compress XI_Motion, but not from tablet devices if (isXIType(event, m_xiOpCode, XI_Motion)) { +#ifndef QT_NO_TABLETEVENT + xXIDeviceEvent *xdev = reinterpret_cast<xXIDeviceEvent *>(event); + if (const_cast<QXcbConnection *>(this)->tabletDataForDevice(xdev->sourceid)) + return false; +#endif // QT_NO_TABLETEVENT for (int j = nextIndex; j < eventqueue->size(); ++j) { xcb_generic_event_t *next = eventqueue->at(j); if (!isValid(next)) @@ -1726,7 +1741,7 @@ void QXcbConnection::processXcbEvents() // Indicate with a null event that the event the callbacks are waiting for // is not in the queue currently. - Q_FOREACH (PeekFunc f, m_peekFuncs) + for (PeekFunc f : qAsConst(m_peekFuncs)) f(this, 0); m_peekFuncs.clear(); @@ -2248,7 +2263,7 @@ bool QXcbConnection::xi2MouseEvents() const #endif #if defined(XCB_USE_XINPUT2) -static int xi2ValuatorOffset(unsigned char *maskPtr, int maskLen, int number) +static int xi2ValuatorOffset(const unsigned char *maskPtr, int maskLen, int number) { int offset = 0; for (int i = 0; i < maskLen; i++) { @@ -2267,11 +2282,11 @@ static int xi2ValuatorOffset(unsigned char *maskPtr, int maskLen, int number) return -1; } -bool QXcbConnection::xi2GetValuatorValueIfSet(void *event, int valuatorNum, double *value) +bool QXcbConnection::xi2GetValuatorValueIfSet(const void *event, int valuatorNum, double *value) { - xXIDeviceEvent *xideviceevent = static_cast<xXIDeviceEvent *>(event); - unsigned char *buttonsMaskAddr = (unsigned char*)&xideviceevent[1]; - unsigned char *valuatorsMaskAddr = buttonsMaskAddr + xideviceevent->buttons_len * 4; + const xXIDeviceEvent *xideviceevent = static_cast<const xXIDeviceEvent *>(event); + const unsigned char *buttonsMaskAddr = (const unsigned char*)&xideviceevent[1]; + const unsigned char *valuatorsMaskAddr = buttonsMaskAddr + xideviceevent->buttons_len * 4; FP3232 *valuatorsValuesAddr = (FP3232*)(valuatorsMaskAddr + xideviceevent->valuators_len * 4); int valuatorOffset = xi2ValuatorOffset(valuatorsMaskAddr, xideviceevent->valuators_len, valuatorNum); diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h index 9fed7b52f1..891f0fbcb5 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.h +++ b/src/plugins/platforms/xcb/qxcbconnection.h @@ -481,6 +481,8 @@ public: void setFocusWindow(QXcbWindow *); QXcbWindow *mouseGrabber() const { return m_mouseGrabber; } void setMouseGrabber(QXcbWindow *); + QXcbWindow *mousePressWindow() const { return m_mousePressWindow; } + void setMousePressWindow(QXcbWindow *); QByteArray startupId() const { return m_startupId; } void setStartupId(const QByteArray &nextId) { m_startupId = nextId; } @@ -533,9 +535,9 @@ private: void initializeXShape(); void initializeXKB(); void handleClientMessageEvent(const xcb_client_message_event_t *event); - QXcbScreen* findScreenForCrtc(xcb_window_t rootWindow, xcb_randr_crtc_t crtc); - QXcbScreen* findScreenForOutput(xcb_window_t rootWindow, xcb_randr_output_t output); - QXcbVirtualDesktop* virtualDesktopForRootWindow(xcb_window_t rootWindow); + QXcbScreen* findScreenForCrtc(xcb_window_t rootWindow, xcb_randr_crtc_t crtc) const; + QXcbScreen* findScreenForOutput(xcb_window_t rootWindow, xcb_randr_output_t output) const; + QXcbVirtualDesktop* virtualDesktopForRootWindow(xcb_window_t rootWindow) const; void updateScreens(const xcb_randr_notify_event_t *event); bool checkOutputIsPrimary(xcb_window_t rootWindow, xcb_randr_output_t output); void updateScreen(QXcbScreen *screen, const xcb_randr_output_change_t &outputChange); @@ -579,9 +581,10 @@ private: }; QHash<int, ValuatorClassInfo> valuatorInfo; }; - bool xi2HandleTabletEvent(void *event, TabletData *tabletData, QXcbWindowEventListener *eventListener); - void xi2ReportTabletEvent(TabletData &tabletData, void *event); + bool xi2HandleTabletEvent(const void *event, TabletData *tabletData); + void xi2ReportTabletEvent(const void *event, TabletData *tabletData); QVector<TabletData> m_tabletData; + TabletData *tabletDataForDevice(int id); #endif // !QT_NO_TABLETEVENT struct ScrollingDevice { ScrollingDevice() : deviceId(0), verticalIndex(0), horizontalIndex(0), orientations(0), legacyOrientations(0) { } @@ -596,7 +599,7 @@ private: void xi2HandleScrollEvent(void *event, ScrollingDevice &scrollingDevice); QHash<int, ScrollingDevice> m_scrollingDevices; - static bool xi2GetValuatorValueIfSet(void *event, int valuatorNum, double *value); + static bool xi2GetValuatorValueIfSet(const void *event, int valuatorNum, double *value); static void xi2PrepareXIGenericDeviceEvent(xcb_ge_event_t *event); #endif @@ -668,6 +671,7 @@ private: QXcbWindow *m_focusWindow; QXcbWindow *m_mouseGrabber; + QXcbWindow *m_mousePressWindow; xcb_window_t m_clientLeader; QByteArray m_startupId; diff --git a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp index 63a650a514..5b7f45fb6c 100644 --- a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp @@ -42,7 +42,7 @@ #include "qxcbscreen.h" #include "qxcbwindow.h" #include "qtouchdevice.h" -#include <qpa/qwindowsysteminterface.h> +#include <qpa/qwindowsysteminterface_p.h> #include <QDebug> #include <cmath> @@ -119,7 +119,7 @@ void QXcbConnection::xi2SetupDevices() // Only non-master pointing devices are relevant here. if (devices[i].use != XISlavePointer) continue; - qCDebug(lcQpaXInputDevices) << "input device "<< devices[i].name; + qCDebug(lcQpaXInputDevices) << "input device " << devices[i].name << "ID" << devices[i].deviceid; #ifndef QT_NO_TABLETEVENT TabletData tabletData; #endif @@ -274,7 +274,7 @@ void QXcbConnection::xi2SetupDevices() void QXcbConnection::finalizeXInput2() { - foreach (XInput2TouchDeviceData *dev, m_touchDevices) { + for (XInput2TouchDeviceData *dev : qAsConst(m_touchDevices)) { if (dev->xiDeviceInfo) XIFreeDeviceInfo(dev->xiDeviceInfo); delete dev; @@ -313,12 +313,13 @@ void QXcbConnection::xi2Select(xcb_window_t window) mask.mask_len = sizeof(bitMask); mask.mask = xiBitMask; // When xi2MouseEvents() is true (the default), pointer emulation for touch and tablet - // events will get disabled. This is preferable for touch, as Qt Quick handles touch events - // directly while for others QtGui synthesizes mouse events, not so much for tablets. For - // the latter we will synthesize the events ourselves. + // events will get disabled. This is preferable, as Qt Quick handles touch events + // directly, while for other applications QtGui synthesizes mouse events. mask.deviceid = XIAllMasterDevices; Status result = XISelectEvents(xDisplay, window, &mask, 1); - if (result != Success) + if (result == Success) + QWindowSystemInterfacePrivate::TabletEvent::setPlatformSynthesizesMouse(false); + else qCDebug(lcQpaXInput, "XInput 2.2: failed to select pointer/touch events, window %x, result %d", window, result); } @@ -358,7 +359,7 @@ void QXcbConnection::xi2Select(xcb_window_t window) scrollBitMask = XI_MotionMask; scrollBitMask |= XI_ButtonReleaseMask; int i=0; - Q_FOREACH (const ScrollingDevice& scrollingDevice, m_scrollingDevices) { + for (const ScrollingDevice& scrollingDevice : qAsConst(m_scrollingDevices)) { if (tabletDevices.contains(scrollingDevice.deviceId)) continue; // All necessary events are already captured. xiEventMask[i].deviceid = scrollingDevice.deviceId; @@ -536,12 +537,9 @@ void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event) #ifndef QT_NO_TABLETEVENT 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; - } - } + QXcbConnection::TabletData *tablet = tabletDataForDevice(sourceDeviceId); + if (tablet && xi2HandleTabletEvent(xiEvent, tablet)) + return; } #endif // QT_NO_TABLETEVENT @@ -832,9 +830,8 @@ void QXcbConnection::xi2HandleHierachyEvent(void *event) return; xi2SetupDevices(); // Reselect events for all event-listening windows. - Q_FOREACH (xcb_window_t window, m_mapper.keys()) { - xi2Select(window); - } + for (auto it = m_mapper.cbegin(), end = m_mapper.cend(); it != end; ++it) + xi2Select(it.key()); } void QXcbConnection::xi2HandleDeviceChangedEvent(void *event) @@ -1042,36 +1039,36 @@ static QTabletEvent::TabletDevice toolIdToTabletDevice(quint32 toolId) { } #ifndef QT_NO_TABLETEVENT -bool QXcbConnection::xi2HandleTabletEvent(void *event, TabletData *tabletData, QXcbWindowEventListener *eventListener) +bool QXcbConnection::xi2HandleTabletEvent(const void *event, TabletData *tabletData) { bool handled = true; Display *xDisplay = static_cast<Display *>(m_xlib_display); - xXIGenericDeviceEvent *xiEvent = static_cast<xXIGenericDeviceEvent *>(event); - xXIDeviceEvent *xiDeviceEvent = reinterpret_cast<xXIDeviceEvent *>(xiEvent); + const xXIGenericDeviceEvent *xiEvent = static_cast<const xXIGenericDeviceEvent *>(event); + const xXIDeviceEvent *xiDeviceEvent = reinterpret_cast<const xXIDeviceEvent *>(xiEvent); switch (xiEvent->evtype) { case XI_ButtonPress: { Qt::MouseButton b = xiToQtMouseButton(xiDeviceEvent->detail); tabletData->buttons |= b; - xi2ReportTabletEvent(*tabletData, xiEvent); + xi2ReportTabletEvent(xiEvent, tabletData); break; } case XI_ButtonRelease: { Qt::MouseButton b = xiToQtMouseButton(xiDeviceEvent->detail); tabletData->buttons ^= b; - xi2ReportTabletEvent(*tabletData, xiEvent); + xi2ReportTabletEvent(xiEvent, tabletData); break; } case XI_Motion: // Report TabletMove only when the stylus is touching the tablet or any button is pressed. // TODO: report proximity (hover) motion (no suitable Qt event exists yet). if (tabletData->buttons != Qt::NoButton) - xi2ReportTabletEvent(*tabletData, xiEvent); + xi2ReportTabletEvent(xiEvent, tabletData); 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); + const xXIPropertyEvent *ev = reinterpret_cast<const xXIPropertyEvent *>(event); if (ev->what == XIPropertyModified) { if (ev->property == atom(QXcbAtom::WacomSerialIDs)) { enum WacomSerialIndex { @@ -1132,21 +1129,12 @@ bool QXcbConnection::xi2HandleTabletEvent(void *event, TabletData *tabletData, Q break; } -#ifdef XCB_USE_XINPUT22 - // Synthesize mouse events since otherwise there are no mouse events from - // the pen on the XI 2.2+ path. - if (xi2MouseEvents() && eventListener) - eventListener->handleXIMouseEvent(reinterpret_cast<xcb_ge_event_t *>(event), Qt::MouseEventSynthesizedByQt); -#else - Q_UNUSED(eventListener); -#endif - return handled; } -void QXcbConnection::xi2ReportTabletEvent(TabletData &tabletData, void *event) +void QXcbConnection::xi2ReportTabletEvent(const void *event, TabletData *tabletData) { - xXIDeviceEvent *ev = reinterpret_cast<xXIDeviceEvent *>(event); + const xXIDeviceEvent *ev = reinterpret_cast<const xXIDeviceEvent *>(event); QXcbWindow *xcbWindow = platformWindowFromId(ev->event); if (!xcbWindow) return; @@ -1157,8 +1145,8 @@ void QXcbConnection::xi2ReportTabletEvent(TabletData &tabletData, void *event) double pressure = 0, rotation = 0, tangentialPressure = 0; int xTilt = 0, yTilt = 0; - for (QHash<int, TabletData::ValuatorClassInfo>::iterator it = tabletData.valuatorInfo.begin(), - ite = tabletData.valuatorInfo.end(); it != ite; ++it) { + for (QHash<int, TabletData::ValuatorClassInfo>::iterator it = tabletData->valuatorInfo.begin(), + ite = tabletData->valuatorInfo.end(); it != ite; ++it) { int valuator = it.key(); TabletData::ValuatorClassInfo &classInfo(it.value()); xi2GetValuatorValueIfSet(event, classInfo.number, &classInfo.curVal); @@ -1174,7 +1162,7 @@ void QXcbConnection::xi2ReportTabletEvent(TabletData &tabletData, void *event) yTilt = classInfo.curVal; break; case QXcbAtom::AbsWheel: - switch (tabletData.tool) { + switch (tabletData->tool) { case QTabletEvent::Airbrush: tangentialPressure = normalizedValue * 2.0 - 1.0; // Convert 0..1 range to -1..+1 range break; @@ -1193,17 +1181,27 @@ void QXcbConnection::xi2ReportTabletEvent(TabletData &tabletData, void *event) if (Q_UNLIKELY(lcQpaXInput().isDebugEnabled())) qCDebug(lcQpaXInput, "XI2 event on tablet %d with tool %d type %d seq %d detail %d time %d " "pos %6.1f, %6.1f root pos %6.1f, %6.1f buttons 0x%x pressure %4.2lf tilt %d, %d rotation %6.2lf", - tabletData.deviceId, tabletData.tool, ev->evtype, ev->sequenceNumber, ev->detail, ev->time, + tabletData->deviceId, tabletData->tool, ev->evtype, ev->sequenceNumber, ev->detail, ev->time, fixed1616ToReal(ev->event_x), fixed1616ToReal(ev->event_y), fixed1616ToReal(ev->root_x), fixed1616ToReal(ev->root_y), - (int)tabletData.buttons, pressure, xTilt, yTilt, rotation); + (int)tabletData->buttons, pressure, xTilt, yTilt, rotation); QWindowSystemInterface::handleTabletEvent(window, ev->time, local, global, - tabletData.tool, tabletData.pointerType, - tabletData.buttons, pressure, + tabletData->tool, tabletData->pointerType, + tabletData->buttons, pressure, xTilt, yTilt, tangentialPressure, - rotation, 0, tabletData.serialId); + rotation, 0, tabletData->serialId); } + +QXcbConnection::TabletData *QXcbConnection::tabletDataForDevice(int id) +{ + for (int i = 0; i < m_tabletData.count(); ++i) { + if (m_tabletData.at(i).deviceId == id) + return &m_tabletData[i]; + } + return Q_NULLPTR; +} + #endif // QT_NO_TABLETEVENT #endif // XCB_USE_XINPUT2 diff --git a/src/plugins/platforms/xcb/qxcbcursor.cpp b/src/plugins/platforms/xcb/qxcbcursor.cpp index 0b539a2241..11e0c998b1 100644 --- a/src/plugins/platforms/xcb/qxcbcursor.cpp +++ b/src/plugins/platforms/xcb/qxcbcursor.cpp @@ -343,7 +343,7 @@ QXcbCursor::~QXcbCursor() xcb_close_font(conn, cursorFont); #ifndef QT_NO_CURSOR - foreach (xcb_cursor_t cursor, m_cursorHash) + for (xcb_cursor_t cursor : qAsConst(m_cursorHash)) xcb_free_cursor(conn, cursor); #endif } @@ -624,7 +624,8 @@ void QXcbCursor::queryPointer(QXcbConnection *c, QXcbVirtualDesktop **virtualDes xcb_query_pointer_reply_t *reply = xcb_query_pointer_reply(c->xcb_connection(), cookie, &err); if (!err && reply) { if (virtualDesktop) { - foreach (QXcbVirtualDesktop *vd, c->virtualDesktops()) { + const auto virtualDesktops = c->virtualDesktops(); + for (QXcbVirtualDesktop *vd : virtualDesktops) { if (vd->root() == reply->root) { *virtualDesktop = vd; break; diff --git a/src/plugins/platforms/xcb/qxcbdrag.cpp b/src/plugins/platforms/xcb/qxcbdrag.cpp index ea20ef7a04..b55fbd8f03 100644 --- a/src/plugins/platforms/xcb/qxcbdrag.cpp +++ b/src/plugins/platforms/xcb/qxcbdrag.cpp @@ -1078,6 +1078,40 @@ void QXcbDrag::cancel() send_leave(); } +// find an ancestor with XdndAware on it +static xcb_window_t findXdndAwareParent(QXcbConnection *c, xcb_window_t window) +{ + xcb_window_t target = 0; + forever { + // check if window has XdndAware + xcb_get_property_cookie_t gpCookie = Q_XCB_CALL( + xcb_get_property(c->xcb_connection(), false, window, + c->atom(QXcbAtom::XdndAware), XCB_GET_PROPERTY_TYPE_ANY, 0, 0)); + xcb_get_property_reply_t *gpReply = xcb_get_property_reply( + c->xcb_connection(), gpCookie, 0); + bool aware = gpReply && gpReply->type != XCB_NONE; + free(gpReply); + if (aware) { + target = window; + break; + } + + // try window's parent + xcb_query_tree_cookie_t qtCookie = Q_XCB_CALL( + xcb_query_tree_unchecked(c->xcb_connection(), window)); + xcb_query_tree_reply_t *qtReply = xcb_query_tree_reply( + c->xcb_connection(), qtCookie, NULL); + if (!qtReply) + break; + xcb_window_t root = qtReply->root; + xcb_window_t parent = qtReply->parent; + free(qtReply); + if (window == root) + break; + window = parent; + } + return target; +} void QXcbDrag::handleSelectionRequest(const xcb_selection_request_event_t *event) { @@ -1105,17 +1139,16 @@ void QXcbDrag::handleSelectionRequest(const xcb_selection_request_event_t *event // xcb_convert_selection() that we sent the XdndDrop event to. at = findTransactionByWindow(event->requestor); } -// if (at == -1 && event->time == XCB_CURRENT_TIME) { -// // previous Qt versions always requested the data on a child of the target window -// // using CurrentTime... but it could be asking for either drop data or the current drag's data -// Window target = findXdndAwareParent(event->requestor); -// if (target) { -// if (current_target && current_target == target) -// at = -2; -// else -// at = findXdndDropTransactionByWindow(target); -// } -// } + + if (at == -1) { + xcb_window_t target = findXdndAwareParent(connection(), event->requestor); + if (target) { + if (event->time == XCB_CURRENT_TIME && current_target == target) + at = -2; + else + at = findTransactionByWindow(target); + } + } } QDrag *transactionDrag = 0; diff --git a/src/plugins/platforms/xcb/qxcbintegration.cpp b/src/plugins/platforms/xcb/qxcbintegration.cpp index b5e03e68fe..703167c0cd 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.cpp +++ b/src/plugins/platforms/xcb/qxcbintegration.cpp @@ -250,17 +250,25 @@ QPlatformOffscreenSurface *QXcbIntegration::createPlatformOffscreenSurface(QOffs bool QXcbIntegration::hasCapability(QPlatformIntegration::Capability cap) const { switch (cap) { - case ThreadedPixmaps: return true; - case OpenGL: return m_connections.first()->glIntegration(); - case ThreadedOpenGL: return m_connections.at(0)->threadedEventHandling() - && m_connections.at(0)->glIntegration() - && m_connections.at(0)->glIntegration()->supportsThreadedOpenGL(); - case WindowMasks: return true; - case MultipleWindows: return true; - case ForeignWindows: return true; - case SyncState: return true; - case RasterGLSurface: return true; - case SwitchableWidgetComposition: return true; + case OpenGL: + case ThreadedOpenGL: + { + const auto *connection = qAsConst(m_connections).first(); + if (const auto *integration = connection->glIntegration()) + return cap != ThreadedOpenGL + || (connection->threadedEventHandling() && integration->supportsThreadedOpenGL()); + return false; + } + + case ThreadedPixmaps: + case WindowMasks: + case MultipleWindows: + case ForeignWindows: + case SyncState: + case RasterGLSurface: + case SwitchableWidgetComposition: + return true; + default: return QPlatformIntegration::hasCapability(cap); } } diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.cpp b/src/plugins/platforms/xcb/qxcbkeyboard.cpp index 48912e0520..7168e6e3bd 100644 --- a/src/plugins/platforms/xcb/qxcbkeyboard.cpp +++ b/src/plugins/platforms/xcb/qxcbkeyboard.cpp @@ -692,8 +692,8 @@ void QXcbKeyboard::updateKeymap() if (!xkb_context) { if (qEnvironmentVariableIsSet("QT_XKB_CONFIG_ROOT")) { xkb_context = xkb_context_new((xkb_context_flags)XKB_CONTEXT_NO_DEFAULT_INCLUDES); - QList<QByteArray> xkbRootList = QByteArray(qgetenv("QT_XKB_CONFIG_ROOT")).split(':'); - foreach (const QByteArray &xkbRoot, xkbRootList) + const QList<QByteArray> xkbRootList = QByteArray(qgetenv("QT_XKB_CONFIG_ROOT")).split(':'); + for (const QByteArray &xkbRoot : xkbRootList) xkb_context_include_path_append(xkb_context, xkbRoot.constData()); } else { xkb_context = xkb_context_new((xkb_context_flags)0); @@ -1038,7 +1038,7 @@ QList<int> QXcbKeyboard::possibleKeys(const QKeyEvent *event) const // catch only more specific shortcuts, i.e. Ctrl+Shift+= also generates Ctrl++ and +, // but Ctrl++ is more specific than +, so we should skip the last one bool ambiguous = false; - foreach (int shortcut, result) { + for (int shortcut : qAsConst(result)) { if (int(shortcut & ~Qt::KeyboardModifierMask) == qtKey && (shortcut & mods) == mods) { ambiguous = true; break; diff --git a/src/plugins/platforms/xcb/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp index 4cb1b29152..dc6846b20b 100644 --- a/src/plugins/platforms/xcb/qxcbscreen.cpp +++ b/src/plugins/platforms/xcb/qxcbscreen.cpp @@ -76,7 +76,8 @@ QXcbVirtualDesktop::~QXcbVirtualDesktop() QXcbScreen *QXcbVirtualDesktop::screenAt(const QPoint &pos) const { - foreach (QXcbScreen *screen, connection()->screens()) { + const auto screens = connection()->screens(); + for (QXcbScreen *screen : screens) { if (screen->virtualDesktop() == this && screen->geometry().contains(pos)) return screen; } @@ -157,7 +158,7 @@ void QXcbVirtualDesktop::updateWorkArea() QRect workArea = getWorkArea(); if (m_workArea != workArea) { m_workArea = workArea; - foreach (QPlatformScreen *screen, m_screens) + for (QPlatformScreen *screen : qAsConst(m_screens)) ((QXcbScreen *)screen)->updateAvailableGeometry(); } } @@ -386,10 +387,9 @@ QSurfaceFormat QXcbScreen::surfaceFormatFor(const QSurfaceFormat &format) const const xcb_visualtype_t *QXcbScreen::visualForFormat(const QSurfaceFormat &format) const { - QVector<const xcb_visualtype_t *> candidates; + const xcb_visualtype_t *candidate = nullptr; - for (auto ii = m_visuals.constBegin(); ii != m_visuals.constEnd(); ++ii) { - const xcb_visualtype_t &xcb_visualtype = ii.value(); + for (const xcb_visualtype_t &xcb_visualtype : m_visuals) { const int redSize = qPopulationCount(xcb_visualtype.red_mask); const int greenSize = qPopulationCount(xcb_visualtype.green_mask); @@ -408,19 +408,17 @@ const xcb_visualtype_t *QXcbScreen::visualForFormat(const QSurfaceFormat &format if (format.alphaBufferSize() != -1 && alphaSize != format.alphaBufferSize()) continue; - candidates.append(&xcb_visualtype); - } - - if (candidates.isEmpty()) - return nullptr; + // Try to find a RGB visual rather than e.g. BGR or GBR + if (qCountTrailingZeroBits(xcb_visualtype.blue_mask) == 0) + return &xcb_visualtype; - // Try to find a RGB visual rather than e.g. BGR or GBR - for (const xcb_visualtype_t *candidate : qAsConst(candidates)) - if (qCountTrailingZeroBits(candidate->blue_mask) == 0) - return candidate; + // In case we do not find anything we like, just remember the first one + // and hope for the best: + if (!candidate) + candidate = &xcb_visualtype; + } - // Did not find anything we like, just grab the first one and hope for the best - return candidates.first(); + return candidate; } void QXcbScreen::sendStartupMessage(const QByteArray &message) const diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index b0b21a5be4..17fafd5ef0 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -286,7 +286,7 @@ static inline XTextProperty* qstringToXTP(Display *dpy, const QString& s) // TODO move this into a utility function in QWindow or QGuiApplication static QWindow *childWindowAt(QWindow *win, const QPoint &p) { - foreach (QObject *obj, win->children()) { + for (QObject *obj : win->children()) { if (obj->isWindowType()) { QWindow *childWin = static_cast<QWindow *>(obj); if (childWin->isVisible()) { @@ -592,8 +592,12 @@ QXcbWindow::~QXcbWindow() { if (window()->type() != Qt::ForeignWindow) destroy(); - else if (connection()->mouseGrabber() == this) - connection()->setMouseGrabber(Q_NULLPTR); + else { + if (connection()->mouseGrabber() == this) + connection()->setMouseGrabber(Q_NULLPTR); + if (connection()->mousePressWindow() == this) + connection()->setMousePressWindow(Q_NULLPTR); + } } void QXcbWindow::destroy() @@ -851,6 +855,16 @@ void QXcbWindow::hide() if (connection()->mouseGrabber() == this) connection()->setMouseGrabber(Q_NULLPTR); + if (QPlatformWindow *w = connection()->mousePressWindow()) { + // Unset mousePressWindow when it (or one of its parents) is unmapped + while (w) { + if (w == this) { + connection()->setMousePressWindow(Q_NULLPTR); + break; + } + w = w->parent(); + } + } m_mapped = false; @@ -864,7 +878,8 @@ void QXcbWindow::hide() // Find the top level window at cursor position. // Don't use QGuiApplication::topLevelAt(): search only the virtual siblings of this window's screen QWindow *enterWindow = Q_NULLPTR; - foreach (QPlatformScreen *screen, xcbScreen()->virtualSiblings()) { + const auto screens = xcbScreen()->virtualSiblings(); + for (QPlatformScreen *screen : screens) { if (screen->geometry().contains(cursorPos)) { const QPoint devicePosition = QHighDpi::toNativePixels(cursorPos, screen->screen()); enterWindow = screen->topLevelAt(devicePosition); @@ -2198,6 +2213,8 @@ void QXcbWindow::handleButtonPressEvent(int event_x, int event_y, int root_x, in return; } + connection()->setMousePressWindow(this); + handleMouseEvent(timestamp, local, global, modifiers, source); } @@ -2212,19 +2229,44 @@ void QXcbWindow::handleButtonReleaseEvent(int event_x, int event_y, int root_x, return; } + if (connection()->buttons() == Qt::NoButton) + connection()->setMousePressWindow(Q_NULLPTR); + handleMouseEvent(timestamp, local, global, modifiers, source); } -static bool ignoreLeaveEvent(quint8 mode, quint8 detail) +static inline bool doCheckUnGrabAncestor(QXcbConnection *conn) +{ + /* Checking for XCB_NOTIFY_MODE_GRAB and XCB_NOTIFY_DETAIL_ANCESTOR prevents unwanted + * enter/leave events on AwesomeWM on mouse button press. It also ignores duplicated + * enter/leave events on Alt+Tab switching on some WMs with XInput2 events. + * Without XInput2 events the (Un)grabAncestor cannot be checked when mouse button is + * not pressed, otherwise (e.g. on Alt+Tab) it can igonre important enter/leave events. + */ + if (conn) { + const bool mouseButtonsPressed = (conn->buttons() != Qt::NoButton); +#ifdef XCB_USE_XINPUT22 + return mouseButtonsPressed || (conn->isAtLeastXI22() && conn->xi2MouseEvents()); +#else + return mouseButtonsPressed; +#endif + } + return true; +} + +static bool ignoreLeaveEvent(quint8 mode, quint8 detail, QXcbConnection *conn = Q_NULLPTR) { - return (mode == XCB_NOTIFY_MODE_GRAB && detail == XCB_NOTIFY_DETAIL_ANCESTOR) // Check for AwesomeWM + return ((doCheckUnGrabAncestor(conn) + && mode == XCB_NOTIFY_MODE_GRAB && detail == XCB_NOTIFY_DETAIL_ANCESTOR) + || (mode == XCB_NOTIFY_MODE_UNGRAB && detail == XCB_NOTIFY_DETAIL_INFERIOR) || detail == XCB_NOTIFY_DETAIL_VIRTUAL - || detail == XCB_NOTIFY_DETAIL_NONLINEAR_VIRTUAL; + || detail == XCB_NOTIFY_DETAIL_NONLINEAR_VIRTUAL); } -static bool ignoreEnterEvent(quint8 mode, quint8 detail) +static bool ignoreEnterEvent(quint8 mode, quint8 detail, QXcbConnection *conn = Q_NULLPTR) { - return ((mode == XCB_NOTIFY_MODE_UNGRAB && detail == XCB_NOTIFY_DETAIL_ANCESTOR) // Check for AwesomeWM + return ((doCheckUnGrabAncestor(conn) + && mode == XCB_NOTIFY_MODE_UNGRAB && detail == XCB_NOTIFY_DETAIL_ANCESTOR) || (mode != XCB_NOTIFY_MODE_NORMAL && mode != XCB_NOTIFY_MODE_UNGRAB) || detail == XCB_NOTIFY_DETAIL_VIRTUAL || detail == XCB_NOTIFY_DETAIL_NONLINEAR_VIRTUAL); @@ -2258,9 +2300,7 @@ void QXcbWindow::handleEnterNotifyEvent(int event_x, int event_y, int root_x, in const QPoint global = QPoint(root_x, root_y); - if (ignoreEnterEvent(mode, detail) - || (connection()->buttons() != Qt::NoButton - && QGuiApplicationPrivate::lastCursorPosition != global)) + if (ignoreEnterEvent(mode, detail, connection()) || connection()->mousePressWindow()) return; const QPoint local(event_x, event_y); @@ -2272,11 +2312,7 @@ void QXcbWindow::handleLeaveNotifyEvent(int root_x, int root_y, { connection()->setTime(timestamp); - const QPoint global(root_x, root_y); - - if (ignoreLeaveEvent(mode, detail) - || (connection()->buttons() != Qt::NoButton - && QGuiApplicationPrivate::lastCursorPosition != global)) + if (ignoreLeaveEvent(mode, detail, connection()) || connection()->mousePressWindow()) return; EnterEventChecker checker; @@ -2299,6 +2335,11 @@ void QXcbWindow::handleMotionNotifyEvent(int event_x, int event_y, int root_x, i { QPoint local(event_x, event_y); QPoint global(root_x, root_y); + + // "mousePressWindow" can be NULL i.e. if a window will be grabbed or umnapped, so set it again here + if (connection()->buttons() != Qt::NoButton && connection()->mousePressWindow() == Q_NULLPTR) + connection()->setMousePressWindow(this); + handleMouseEvent(timestamp, local, global, modifiers, source); } @@ -2350,7 +2391,7 @@ void QXcbWindow::handleXIMouseEvent(xcb_ge_event_t *event, Qt::MouseEventSource conn->setButton(conn->translateMouseButton(i), XIMaskIsSet(buttonMask, i)); } - const char *sourceName = nullptr; + const char *sourceName = 0; if (lcQpaXInput().isDebugEnabled()) { const QMetaObject *metaObject = qt_getEnumMetaObject(source); const QMetaEnum me = metaObject->enumerator(metaObject->indexOfEnumerator(qt_getEnumName(source))); |