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/qxcbbackingstore.cpp18
-rw-r--r--src/plugins/platforms/xcb/qxcbbackingstore.h3
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.cpp65
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.h16
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection_xi2.cpp84
-rw-r--r--src/plugins/platforms/xcb/qxcbcursor.cpp5
-rw-r--r--src/plugins/platforms/xcb/qxcbdrag.cpp55
-rw-r--r--src/plugins/platforms/xcb/qxcbintegration.cpp30
-rw-r--r--src/plugins/platforms/xcb/qxcbkeyboard.cpp6
-rw-r--r--src/plugins/platforms/xcb/qxcbscreen.cpp30
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.cpp77
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 &region)
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)));