summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/platforms')
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenu.mm34
-rw-r--r--src/plugins/platforms/cocoa/qcocoawindow.mm19
-rw-r--r--src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp22
-rw-r--r--src/plugins/platforms/direct2d/qwindowsdirect2dwindow.cpp2
-rw-r--r--src/plugins/platforms/eglfs/qeglfswindow.cpp2
-rw-r--r--src/plugins/platforms/windows/accessible/iaccessible2.cpp2
-rw-r--r--src/plugins/platforms/windows/qwindowseglcontext.cpp16
-rw-r--r--src/plugins/platforms/windows/qwindowseglcontext.h3
-rw-r--r--src/plugins/platforms/windows/qwindowsnativeinterface.cpp6
-rw-r--r--src/plugins/platforms/windows/qwindowsnativeinterface.h2
-rw-r--r--src/plugins/platforms/windows/qwindowswindow.cpp2
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.cpp79
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.h35
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection_xi2.cpp442
-rw-r--r--src/plugins/platforms/xcb/qxcbkeyboard.cpp31
-rw-r--r--src/plugins/platforms/xcb/qxcbkeyboard.h1
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.cpp126
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.h10
-rw-r--r--src/plugins/platforms/xcb/xcb_qpa_lib.pro5
19 files changed, 569 insertions, 270 deletions
diff --git a/src/plugins/platforms/cocoa/qcocoamenu.mm b/src/plugins/platforms/cocoa/qcocoamenu.mm
index 09a4c95469..dd2c37d914 100644
--- a/src/plugins/platforms/cocoa/qcocoamenu.mm
+++ b/src/plugins/platforms/cocoa/qcocoamenu.mm
@@ -81,7 +81,7 @@ QT_END_NAMESPACE
}
- (id) initWithMenu:(QCocoaMenu*) m;
-- (BOOL)hasShortcut:(NSMenu *)menu forKey:(NSString *)key forModifiers:(NSUInteger)modifier;
+- (NSMenuItem *)findItem:(NSMenu *)menu forKey:(NSString *)key forModifiers:(NSUInteger)modifier;
@end
@@ -152,11 +152,20 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QCocoaMenuDelegate);
// Change the private unicode keys to the ones used in setting the "Key Equivalents"
NSString *characters = qt_mac_removePrivateUnicode([event characters]);
- if ([self hasShortcut:menu
- forKey:characters
- // Interested only in Shift, Cmd, Ctrl & Alt Keys, so ignoring masks like, Caps lock, Num Lock ...
- forModifiers:([event modifierFlags] & (NSShiftKeyMask | NSControlKeyMask | NSCommandKeyMask | NSAlternateKeyMask))
- ]) {
+ // Interested only in Shift, Cmd, Ctrl & Alt Keys, so ignoring masks like, Caps lock, Num Lock ...
+ const NSUInteger mask = NSShiftKeyMask | NSControlKeyMask | NSCommandKeyMask | NSAlternateKeyMask;
+ if (NSMenuItem *menuItem = [self findItem:menu forKey:characters forModifiers:([event modifierFlags] & mask)]) {
+ if (!menuItem.target) {
+ // This item was modified by QCocoaMenuBar::redirectKnownMenuItemsToFirstResponder
+ // and it looks like we're running a modal session for NSOpenPanel/NSSavePanel.
+ // QCocoaFileDialogHelper is actually the only place we use this and we run NSOpenPanel modal
+ // (modal sheet, window modal, application modal).
+ // Whatever the current first responder is, let's give it a chance
+ // and do not touch the Qt's focusObject (which is different from some native view
+ // having a focus inside NSSave/OpenPanel.
+ return YES;
+ }
+
QObject *object = qApp->focusObject();
if (object) {
QChar ch;
@@ -194,22 +203,23 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QCocoaMenuDelegate);
return NO;
}
-- (BOOL)hasShortcut:(NSMenu *)menu forKey:(NSString *)key forModifiers:(NSUInteger)modifier
+- (NSMenuItem *)findItem:(NSMenu *)menu forKey:(NSString *)key forModifiers:(NSUInteger)modifier
{
for (NSMenuItem *item in [menu itemArray]) {
if (![item isEnabled] || [item isHidden] || [item isSeparatorItem])
continue;
- if ([item hasSubmenu]
- && [self hasShortcut:[item submenu] forKey:key forModifiers:modifier])
- return YES;
+ if ([item hasSubmenu]) {
+ if (NSMenuItem *nested = [self findItem:[item submenu] forKey:key forModifiers:modifier])
+ return nested;
+ }
NSString *menuKey = [item keyEquivalent];
if (menuKey
&& NSOrderedSame == [menuKey compare:key]
&& modifier == [item keyEquivalentModifierMask])
- return YES;
+ return item;
}
- return NO;
+ return nil;
}
@end
diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm
index cbe4227b63..86959869cc 100644
--- a/src/plugins/platforms/cocoa/qcocoawindow.mm
+++ b/src/plugins/platforms/cocoa/qcocoawindow.mm
@@ -799,9 +799,22 @@ NSUInteger QCocoaWindow::windowStyleMask(Qt::WindowFlags flags)
if (flags & Qt::FramelessWindowHint)
return styleMask;
if ((type & Qt::Popup) == Qt::Popup) {
- if (!windowIsPopupType(type))
- styleMask = (NSUtilityWindowMask | NSResizableWindowMask | NSClosableWindowMask |
- NSMiniaturizableWindowMask | NSTitledWindowMask);
+ if (!windowIsPopupType(type)) {
+ styleMask = NSUtilityWindowMask;
+ if (!(flags & Qt::CustomizeWindowHint)) {
+ styleMask |= NSResizableWindowMask | NSClosableWindowMask |
+ NSMiniaturizableWindowMask | NSTitledWindowMask;
+ } else {
+ if (flags & Qt::WindowMaximizeButtonHint)
+ styleMask |= NSResizableWindowMask;
+ if (flags & Qt::WindowTitleHint)
+ styleMask |= NSTitledWindowMask;
+ if (flags & Qt::WindowCloseButtonHint)
+ styleMask |= NSClosableWindowMask;
+ if (flags & Qt::WindowMinimizeButtonHint)
+ styleMask |= NSMiniaturizableWindowMask;
+ }
+ }
} else {
if (type == Qt::Window && !(flags & Qt::CustomizeWindowHint)) {
styleMask = (NSResizableWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSTitledWindowMask);
diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp
index d439196dc1..16c05329de 100644
--- a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp
+++ b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp
@@ -358,10 +358,10 @@ public:
} else if (path.isRect() && (q->state()->matrix.type() <= QTransform::TxScale)) {
const qreal * const points = path.points();
D2D_RECT_F rect = {
- points[0], // left
- points[1], // top
- points[2], // right,
- points[5] // bottom
+ FLOAT(points[0]), // left
+ FLOAT(points[1]), // top
+ FLOAT(points[2]), // right,
+ FLOAT(points[5]) // bottom
};
dc()->PushAxisAlignedClip(rect, antialiasMode());
@@ -918,13 +918,13 @@ public:
DWRITE_GLYPH_RUN glyphRun = {
fontFace, // IDWriteFontFace *fontFace;
- fontDef.pixelSize, // FLOAT fontEmSize;
- numGlyphs, // UINT32 glyphCount;
+ FLOAT(fontDef.pixelSize), // FLOAT fontEmSize;
+ UINT32(numGlyphs), // UINT32 glyphCount;
glyphIndices, // const UINT16 *glyphIndices;
glyphAdvances, // const FLOAT *glyphAdvances;
glyphOffsets, // const DWRITE_GLYPH_OFFSET *glyphOffsets;
FALSE, // BOOL isSideways;
- rtl ? 1 : 0 // UINT32 bidiLevel;
+ rtl ? 1u : 0u // UINT32 bidiLevel;
};
const bool antiAlias = bool((q->state()->renderHints & QPainter::TextAntialiasing)
@@ -1393,8 +1393,8 @@ void QWindowsDirect2DPaintEngine::drawEllipse(const QRectF &r)
D2D1_ELLIPSE ellipse = {
to_d2d_point_2f(p),
- r.width() / 2.0,
- r.height() / 2.0
+ FLOAT(r.width() / 2.0),
+ FLOAT(r.height() / 2.0)
};
if (d->brush.brush)
@@ -1421,8 +1421,8 @@ void QWindowsDirect2DPaintEngine::drawEllipse(const QRect &r)
D2D1_ELLIPSE ellipse = {
to_d2d_point_2f(p),
- r.width() / 2.0,
- r.height() / 2.0
+ FLOAT(r.width() / 2.0),
+ FLOAT(r.height() / 2.0)
};
if (d->brush.brush)
diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.cpp
index e762eab711..ba23526447 100644
--- a/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.cpp
+++ b/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.cpp
@@ -163,7 +163,7 @@ void QWindowsDirect2DWindow::present(const QRegion &region)
const SIZE size = { bounds.width(), bounds.height() };
const POINT ptDst = { bounds.x(), bounds.y() };
const POINT ptSrc = { 0, 0 };
- const BLENDFUNCTION blend = { AC_SRC_OVER, 0, 255.0 * opacity(), AC_SRC_ALPHA };
+ const BLENDFUNCTION blend = { AC_SRC_OVER, 0, BYTE(255.0 * opacity()), AC_SRC_ALPHA };
const QRect r = region.boundingRect();
const RECT dirty = { r.left(), r.top(), r.left() + r.width(), r.top() + r.height() };
UPDATELAYEREDWINDOWINFO info = { sizeof(UPDATELAYEREDWINDOWINFO), NULL,
diff --git a/src/plugins/platforms/eglfs/qeglfswindow.cpp b/src/plugins/platforms/eglfs/qeglfswindow.cpp
index 30fdce9fd3..c0d51c94a5 100644
--- a/src/plugins/platforms/eglfs/qeglfswindow.cpp
+++ b/src/plugins/platforms/eglfs/qeglfswindow.cpp
@@ -35,6 +35,7 @@
#include <qpa/qwindowsysteminterface.h>
#include <qpa/qplatformintegration.h>
#include <private/qguiapplication_p.h>
+#include <QtGui/private/qopenglcontext_p.h>
#include <QtGui/QOpenGLContext>
#include <QtPlatformSupport/private/qeglplatformcursor_p.h>
#include <QtPlatformSupport/private/qeglconvenience_p.h>
@@ -106,6 +107,7 @@ void QEglFSWindow::create()
if (isRaster()) {
QOpenGLContext *context = new QOpenGLContext(QGuiApplication::instance());
+ context->setShareContext(qt_gl_global_share_context());
context->setFormat(m_format);
context->setScreen(window()->screen());
if (!context->create())
diff --git a/src/plugins/platforms/windows/accessible/iaccessible2.cpp b/src/plugins/platforms/windows/accessible/iaccessible2.cpp
index 99c44c69ef..5ed8d30e67 100644
--- a/src/plugins/platforms/windows/accessible/iaccessible2.cpp
+++ b/src/plugins/platforms/windows/accessible/iaccessible2.cpp
@@ -102,7 +102,7 @@ HRESULT STDMETHODCALLTYPE AccessibleApplication::get_toolkitName(/* [retval][out
HRESULT STDMETHODCALLTYPE AccessibleApplication::get_toolkitVersion(/* [retval][out] */ BSTR *version)
{
- *version = ::SysAllocString(QT_UNICODE_LITERAL(QT_VERSION_STR));
+ *version = ::SysAllocString(TEXT(QT_VERSION_STR));
return S_OK;
}
diff --git a/src/plugins/platforms/windows/qwindowseglcontext.cpp b/src/plugins/platforms/windows/qwindowseglcontext.cpp
index 0184877fdd..06c9985cac 100644
--- a/src/plugins/platforms/windows/qwindowseglcontext.cpp
+++ b/src/plugins/platforms/windows/qwindowseglcontext.cpp
@@ -39,7 +39,6 @@
#include <QtGui/QOpenGLContext>
#if defined(QT_OPENGL_ES_2_ANGLE) || defined(QT_OPENGL_DYNAMIC)
-# define EGL_EGLEXT_PROTOTYPES
# include <QtANGLE/EGL/eglext.h>
#endif
@@ -137,7 +136,6 @@ bool QWindowsLibEGL::init()
eglGetError = RESOLVE((EGLint (EGLAPIENTRY *)(void)), eglGetError);
eglGetDisplay = RESOLVE((EGLDisplay (EGLAPIENTRY *)(EGLNativeDisplayType)), eglGetDisplay);
- eglGetPlatformDisplayEXT = RESOLVE((EGLDisplay (EGLAPIENTRY *)(EGLenum platform, void *native_display, const EGLint *attrib_list)), eglGetPlatformDisplayEXT);
eglInitialize = RESOLVE((EGLBoolean (EGLAPIENTRY *)(EGLDisplay, EGLint *, EGLint *)), eglInitialize);
eglTerminate = RESOLVE((EGLBoolean (EGLAPIENTRY *)(EGLDisplay)), eglTerminate);
eglChooseConfig = RESOLVE((EGLBoolean (EGLAPIENTRY *)(EGLDisplay, const EGLint *, EGLConfig *, EGLint, EGLint *)), eglChooseConfig);
@@ -156,7 +154,15 @@ bool QWindowsLibEGL::init()
eglSwapBuffers = RESOLVE((EGLBoolean (EGLAPIENTRY *)(EGLDisplay , EGLSurface)), eglSwapBuffers);
eglGetProcAddress = RESOLVE((__eglMustCastToProperFunctionPointerType (EGLAPIENTRY * )(const char *)), eglGetProcAddress);
- return eglGetError && eglGetDisplay && eglInitialize;
+ if (!eglGetError || !eglGetDisplay || !eglInitialize || !eglGetProcAddress)
+ return false;
+
+ eglGetPlatformDisplayEXT = 0;
+#ifdef EGL_ANGLE_platform_angle
+ eglGetPlatformDisplayEXT = reinterpret_cast<EGLDisplay (EGLAPIENTRY *)(EGLenum, void *, const EGLint *)>(eglGetProcAddress("eglGetPlatformDisplayEXT"));
+#endif
+
+ return true;
}
#if !defined(QT_STATIC) || defined(QT_OPENGL_DYNAMIC)
@@ -360,7 +366,7 @@ QWindowsEGLStaticContext *QWindowsEGLStaticContext::create(QWindowsOpenGLTester:
EGLDisplay display = EGL_NO_DISPLAY;
EGLint major = 0;
EGLint minor = 0;
-#ifdef EGL_ANGLE_platform_angle_opengl
+#ifdef EGL_ANGLE_platform_angle
if (libEGL.eglGetPlatformDisplayEXT
&& (preferredType & QWindowsOpenGLTester::AngleBackendMask)) {
const EGLint anglePlatformAttributes[][5] = {
@@ -384,7 +390,7 @@ QWindowsEGLStaticContext *QWindowsEGLStaticContext::create(QWindowsOpenGLTester:
}
}
}
-#else // EGL_ANGLE_platform_angle_opengl
+#else // EGL_ANGLE_platform_angle
Q_UNUSED(preferredType)
#endif
if (display == EGL_NO_DISPLAY)
diff --git a/src/plugins/platforms/windows/qwindowseglcontext.h b/src/plugins/platforms/windows/qwindowseglcontext.h
index 2b249348c3..d8302c97a7 100644
--- a/src/plugins/platforms/windows/qwindowseglcontext.h
+++ b/src/plugins/platforms/windows/qwindowseglcontext.h
@@ -46,7 +46,6 @@ struct QWindowsLibEGL
EGLint (EGLAPIENTRY * eglGetError)(void);
EGLDisplay (EGLAPIENTRY * eglGetDisplay)(EGLNativeDisplayType display_id);
- EGLDisplay (EGLAPIENTRY * eglGetPlatformDisplayEXT)(EGLenum platform, void *native_display, const EGLint *attrib_list);
EGLBoolean (EGLAPIENTRY * eglInitialize)(EGLDisplay dpy, EGLint *major, EGLint *minor);
EGLBoolean (EGLAPIENTRY * eglTerminate)(EGLDisplay dpy);
EGLBoolean (EGLAPIENTRY * eglChooseConfig)(EGLDisplay dpy, const EGLint *attrib_list,
@@ -74,6 +73,8 @@ struct QWindowsLibEGL
EGLBoolean (EGLAPIENTRY * eglSwapBuffers)(EGLDisplay dpy, EGLSurface surface);
__eglMustCastToProperFunctionPointerType (EGLAPIENTRY * eglGetProcAddress)(const char *procname);
+ EGLDisplay (EGLAPIENTRY * eglGetPlatformDisplayEXT)(EGLenum platform, void *native_display, const EGLint *attrib_list);
+
private:
#if !defined(QT_STATIC) || defined(QT_OPENGL_DYNAMIC)
void *resolve(const char *name);
diff --git a/src/plugins/platforms/windows/qwindowsnativeinterface.cpp b/src/plugins/platforms/windows/qwindowsnativeinterface.cpp
index 9691156403..6e58c55bbe 100644
--- a/src/plugins/platforms/windows/qwindowsnativeinterface.cpp
+++ b/src/plugins/platforms/windows/qwindowsnativeinterface.cpp
@@ -34,6 +34,7 @@
#include "qwindowsnativeinterface.h"
#include "qwindowswindow.h"
#include "qwindowscontext.h"
+#include "qwindowsfontdatabase.h"
#include "qwindowsopenglcontext.h"
#include "qwindowsopengltester.h"
#include "qwindowsintegration.h"
@@ -222,6 +223,11 @@ int QWindowsNativeInterface::registerMimeType(const QString &mimeType)
return QWindowsMime::registerMimeType(mimeType);
}
+QFont QWindowsNativeInterface::logFontToQFont(const void *logFont, int verticalDpi)
+{
+ return QWindowsFontDatabase::LOGFONT_to_QFont(*reinterpret_cast<const LOGFONT *>(logFont), verticalDpi);
+}
+
QFunctionPointer QWindowsNativeInterface::platformFunction(const QByteArray &function) const
{
if (function == QWindowsWindowFunctions::setTouchWindowTouchTypeIdentifier())
diff --git a/src/plugins/platforms/windows/qwindowsnativeinterface.h b/src/plugins/platforms/windows/qwindowsnativeinterface.h
index be8418b769..97839ae1ae 100644
--- a/src/plugins/platforms/windows/qwindowsnativeinterface.h
+++ b/src/plugins/platforms/windows/qwindowsnativeinterface.h
@@ -34,6 +34,7 @@
#ifndef QWINDOWSNATIVEINTERFACE_H
#define QWINDOWSNATIVEINTERFACE_H
+#include <QtGui/qfont.h>
#include <QtGui/qpa/qplatformnativeinterface.h>
QT_BEGIN_NAMESPACE
@@ -77,6 +78,7 @@ public:
Q_INVOKABLE void registerWindowsMime(void *mimeIn);
Q_INVOKABLE void unregisterWindowsMime(void *mime);
Q_INVOKABLE int registerMimeType(const QString &mimeType);
+ Q_INVOKABLE QFont logFontToQFont(const void *logFont, int verticalDpi);
bool asyncExpose() const;
void setAsyncExpose(bool value);
diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp
index 923040fd71..543c08135f 100644
--- a/src/plugins/platforms/windows/qwindowswindow.cpp
+++ b/src/plugins/platforms/windows/qwindowswindow.cpp
@@ -438,6 +438,8 @@ QDebug operator<<(QDebug debug, const WindowCreationData &d)
// Fix top level window flags in case only the type flags are passed.
static inline void fixTopLevelWindowFlags(Qt::WindowFlags &flags)
{
+ // Not supported on Windows, also do correction when it is set.
+ flags &= ~Qt::WindowFullscreenButtonHint;
switch (flags) {
case Qt::Window:
flags |= Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowMinimizeButtonHint
diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp
index 92d064df9b..80c844e658 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection.cpp
@@ -70,7 +70,6 @@
#endif
#if defined(XCB_USE_XINPUT2)
-#include <X11/extensions/XInput2.h>
#include <X11/extensions/XI2proto.h>
#endif
@@ -457,6 +456,7 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGra
, m_focusWindow(0)
, m_systemTrayTracker(0)
, m_glIntegration(Q_NULLPTR)
+ , m_xiGrab(false)
{
#ifdef XCB_USE_XLIB
Display *dpy = XOpenDisplay(m_displayName.constData());
@@ -909,7 +909,7 @@ static Qt::MouseButtons translateMouseButtons(int s)
return ret;
}
-static Qt::MouseButton translateMouseButton(xcb_button_t s)
+Qt::MouseButton QXcbConnection::translateMouseButton(xcb_button_t s)
{
switch (s) {
case 1: return Qt::LeftButton;
@@ -944,39 +944,6 @@ static Qt::MouseButton translateMouseButton(xcb_button_t s)
}
}
-void QXcbConnection::handleButtonPress(xcb_generic_event_t *ev)
-{
- xcb_button_press_event_t *event = (xcb_button_press_event_t *)ev;
-
- // the event explicitly contains the state of the three first buttons,
- // the rest we need to manage ourselves
- m_buttons = (m_buttons & ~0x7) | translateMouseButtons(event->state);
- m_buttons |= translateMouseButton(event->detail);
- qCDebug(lcQpaXInput, "xcb: pressed mouse button %d, button state %X", event->detail, static_cast<unsigned int>(m_buttons));
-}
-
-void QXcbConnection::handleButtonRelease(xcb_generic_event_t *ev)
-{
- xcb_button_release_event_t *event = (xcb_button_release_event_t *)ev;
-
- // the event explicitly contains the state of the three first buttons,
- // the rest we need to manage ourselves
- m_buttons = (m_buttons & ~0x7) | translateMouseButtons(event->state);
- m_buttons &= ~translateMouseButton(event->detail);
- qCDebug(lcQpaXInput, "xcb: released mouse button %d, button state %X", event->detail, static_cast<unsigned int>(m_buttons));
-}
-
-void QXcbConnection::handleMotionNotify(xcb_generic_event_t *ev)
-{
- xcb_motion_notify_event_t *event = (xcb_motion_notify_event_t *)ev;
-
- m_buttons = (m_buttons & ~0x7) | translateMouseButtons(event->state);
-#ifdef Q_XCB_DEBUG
- qCDebug(lcQpaXInput, "xcb: moved mouse to %4d, %4d; button state %X",
- event->event_x, event->event_y, static_cast<unsigned int>(m_buttons));
-#endif
-}
-
#ifndef QT_NO_XKB
namespace {
typedef union {
@@ -1018,18 +985,35 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event)
switch (response_type) {
case XCB_EXPOSE:
HANDLE_PLATFORM_WINDOW_EVENT(xcb_expose_event_t, window, handleExposeEvent);
- case XCB_BUTTON_PRESS:
- m_keyboard->updateXKBStateFromCore(((xcb_button_press_event_t *)event)->state);
- handleButtonPress(event);
+
+ // press/release/motion is only delivered here when XI 2.2+ is _not_ in use
+ case XCB_BUTTON_PRESS: {
+ xcb_button_press_event_t *ev = (xcb_button_press_event_t *)event;
+ m_keyboard->updateXKBStateFromCore(ev->state);
+ // the event explicitly contains the state of the three first buttons,
+ // the rest we need to manage ourselves
+ m_buttons = (m_buttons & ~0x7) | translateMouseButtons(ev->state);
+ m_buttons |= translateMouseButton(ev->detail);
+ qCDebug(lcQpaXInput, "legacy mouse press, button %d state %X", ev->detail, static_cast<unsigned int>(m_buttons));
HANDLE_PLATFORM_WINDOW_EVENT(xcb_button_press_event_t, event, handleButtonPressEvent);
- case XCB_BUTTON_RELEASE:
- m_keyboard->updateXKBStateFromCore(((xcb_button_release_event_t *)event)->state);
- handleButtonRelease(event);
+ }
+ case XCB_BUTTON_RELEASE: {
+ xcb_button_release_event_t *ev = (xcb_button_release_event_t *)event;
+ m_keyboard->updateXKBStateFromCore(ev->state);
+ m_buttons = (m_buttons & ~0x7) | translateMouseButtons(ev->state);
+ m_buttons &= ~translateMouseButton(ev->detail);
+ qCDebug(lcQpaXInput, "legacy mouse release, button %d state %X", ev->detail, static_cast<unsigned int>(m_buttons));
HANDLE_PLATFORM_WINDOW_EVENT(xcb_button_release_event_t, event, handleButtonReleaseEvent);
- case XCB_MOTION_NOTIFY:
- m_keyboard->updateXKBStateFromCore(((xcb_motion_notify_event_t *)event)->state);
- handleMotionNotify(event);
+ }
+ case XCB_MOTION_NOTIFY: {
+ xcb_motion_notify_event_t *ev = (xcb_motion_notify_event_t *)event;
+ m_keyboard->updateXKBStateFromCore(ev->state);
+ m_buttons = (m_buttons & ~0x7) | translateMouseButtons(ev->state);
+ qCDebug(lcQpaXInput, "legacy mouse move %d,%d button %d state %X", ev->event_x, ev->event_y,
+ ev->detail, static_cast<unsigned int>(m_buttons));
HANDLE_PLATFORM_WINDOW_EVENT(xcb_motion_notify_event_t, event, handleMotionNotifyEvent);
+ }
+
case XCB_CONFIGURE_NOTIFY:
HANDLE_PLATFORM_WINDOW_EVENT(xcb_configure_notify_event_t, event, handleConfigureNotifyEvent);
case XCB_MAP_NOTIFY:
@@ -1090,6 +1074,7 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event)
break;
#if defined(XCB_USE_XINPUT2)
case XCB_GE_GENERIC:
+ // Here the windowEventListener is invoked from xi2HandleEvent()
if (m_xi2Enabled)
xi2HandleEvent(reinterpret_cast<xcb_ge_event_t *>(event));
break;
@@ -1931,6 +1916,12 @@ void QXcbConnection::initializeXKB()
#endif
}
+bool QXcbConnection::xi2MouseEvents() const
+{
+ static bool mouseViaXI2 = !qEnvironmentVariableIsSet("QT_XCB_NO_XI2_MOUSE");
+ return mouseViaXI2;
+}
+
#if defined(XCB_USE_XINPUT2)
static int xi2ValuatorOffset(unsigned char *maskPtr, int maskLen, int number)
{
diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h
index e4274eca4d..2005ae0701 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.h
+++ b/src/plugins/platforms/xcb/qxcbconnection.h
@@ -69,7 +69,8 @@
#endif
#endif
struct XInput2TouchDeviceData;
-#endif
+#endif // XCB_USE_XINPUT2
+
struct xcb_randr_get_output_info_reply_t;
//#define Q_XCB_DEBUG
@@ -347,6 +348,7 @@ public:
virtual void handleFocusInEvent(const xcb_focus_in_event_t *) {}
virtual void handleFocusOutEvent(const xcb_focus_out_event_t *) {}
virtual void handlePropertyNotifyEvent(const xcb_property_notify_event_t *) {}
+ virtual void handleXIMouseEvent(xcb_ge_event_t *) {}
virtual QXcbWindow *toWindow() { return 0; }
};
@@ -413,14 +415,14 @@ public:
void xi2Select(xcb_window_t window);
#endif
#ifdef XCB_USE_XINPUT21
- bool isUsingXInput21() const { return m_xi2Enabled && m_xi2Minor >= 1; }
+ bool isAtLeastXI21() const { return m_xi2Enabled && m_xi2Minor >= 1; }
#else
- bool isUsingXInput21() const { return false; }
+ bool isAtLeastXI21() const { return false; }
#endif
#ifdef XCB_USE_XINPUT22
- bool isUsingXInput22() const { return m_xi2Enabled && m_xi2Minor >= 2; }
+ bool isAtLeastXI22() const { return m_xi2Enabled && m_xi2Minor >= 2; }
#else
- bool isUsingXInput22() const { return false; }
+ bool isAtLeastXI22() const { return false; }
#endif
void sync();
@@ -457,7 +459,9 @@ public:
xcb_timestamp_t getTimestamp();
+ void setButton(Qt::MouseButton button, bool down) { if (down) m_buttons |= button; else m_buttons &= ~button; }
Qt::MouseButtons buttons() const { return m_buttons; }
+ Qt::MouseButton translateMouseButton(xcb_button_t s);
QXcbWindow *focusWindow() const { return m_focusWindow; }
void setFocusWindow(QXcbWindow *);
@@ -477,11 +481,19 @@ public:
void handleEnterEvent(const xcb_enter_notify_event_t *);
#endif
+#ifdef XCB_USE_XINPUT22
+ bool xi2SetMouseGrabEnabled(xcb_window_t w, bool grab);
+#endif
+ Qt::MouseButton xiToQtMouseButton(uint32_t b);
+
QXcbEventReader *eventReader() const { return m_reader; }
bool canGrab() const { return m_canGrabServer; }
QXcbGlIntegration *glIntegration() const { return m_glIntegration; }
+
+ bool xi2MouseEvents() const;
+
protected:
bool event(QEvent *e) Q_DECL_OVERRIDE;
@@ -509,9 +521,6 @@ private:
bool checkOutputIsPrimary(xcb_window_t rootWindow, xcb_randr_output_t output);
void initializeScreens();
void updateScreens(const xcb_randr_notify_event_t *event);
- void handleButtonPress(xcb_generic_event_t *event);
- void handleButtonRelease(xcb_generic_event_t *event);
- void handleMotionNotify(xcb_generic_event_t *event);
bool m_xi2Enabled;
int m_xi2Minor;
@@ -524,6 +533,9 @@ private:
void xi2HandleHierachyEvent(void *event);
void xi2HandleDeviceChangedEvent(void *event);
int m_xiOpCode, m_xiEventBase, m_xiErrorBase;
+#ifdef XCB_USE_XINPUT22
+ void xi2ProcessTouch(void *xiDevEvent, QXcbWindow *platformWindow);
+#endif // XCB_USE_XINPUT22
#ifndef QT_NO_TABLETEVENT
struct TabletData {
TabletData() : deviceId(0), pointerType(QTabletEvent::UnknownPointer),
@@ -543,10 +555,10 @@ private:
};
QHash<int, ValuatorClassInfo> valuatorInfo;
};
- bool xi2HandleTabletEvent(void *event, TabletData *tabletData);
+ bool xi2HandleTabletEvent(void *event, TabletData *tabletData, QXcbWindowEventListener *eventListener);
void xi2ReportTabletEvent(TabletData &tabletData, void *event);
QVector<TabletData> m_tabletData;
-#endif
+#endif // !QT_NO_TABLETEVENT
struct ScrollingDevice {
ScrollingDevice() : deviceId(0), verticalIndex(0), horizontalIndex(0), orientations(0), legacyOrientations(0) { }
int deviceId;
@@ -559,9 +571,7 @@ private:
void updateScrollingDevice(ScrollingDevice& scrollingDevice, int num_classes, void *classes);
void xi2HandleScrollEvent(void *event, ScrollingDevice &scrollingDevice);
QHash<int, ScrollingDevice> m_scrollingDevices;
-#endif // XCB_USE_XINPUT2
-#if defined(XCB_USE_XINPUT2)
static bool xi2GetValuatorValueIfSet(void *event, int valuatorNum, double *value);
static bool xi2PrepareXIGenericDeviceEvent(xcb_ge_event_t *event, int opCode);
#endif
@@ -633,6 +643,7 @@ private:
QByteArray m_startupId;
QXcbSystemTrayTracker *m_systemTrayTracker;
QXcbGlIntegration *m_glIntegration;
+ bool m_xiGrab;
friend class QXcbEventReader;
};
diff --git a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
index c43816fa05..0e8a162a7d 100644
--- a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
@@ -43,7 +43,6 @@
#include <X11/extensions/XInput2.h>
#include <X11/extensions/XI2proto.h>
-#define FINGER_MAX_WIDTH_MM 10
struct XInput2TouchDeviceData {
XInput2TouchDeviceData()
@@ -276,34 +275,37 @@ void QXcbConnection::xi2Select(xcb_window_t window)
unsigned char *xiBitMask = reinterpret_cast<unsigned char *>(&bitMask);
#ifdef XCB_USE_XINPUT22
- if (isUsingXInput22()) {
+ if (isAtLeastXI22()) {
bitMask |= XI_TouchBeginMask;
bitMask |= XI_TouchUpdateMask;
bitMask |= XI_TouchEndMask;
+ bitMask |= XI_PropertyEventMask; // for tablets
+ if (xi2MouseEvents()) {
+ // We want both mouse and touch through XI2 if touch is supported (>= 2.2).
+ // The plain xcb press and motion events will not be delivered after this.
+ bitMask |= XI_ButtonPressMask;
+ bitMask |= XI_ButtonReleaseMask;
+ bitMask |= XI_MotionMask;
+ qCDebug(lcQpaXInput, "XInput 2.2: Selecting press/release/motion events in addition to touch");
+ }
XIEventMask mask;
mask.mask_len = sizeof(bitMask);
mask.mask = xiBitMask;
- if (!m_touchDevices.isEmpty()) {
- // If we select for touch events on the master pointer, XInput2
- // will not synthesize mouse events. This means Qt must do it,
- // which is also preferable, since Qt can control better when
- // to do so.
- mask.deviceid = XIAllMasterDevices;
- Status result = XISelectEvents(xDisplay, window, &mask, 1);
- if (result != Success)
- qCDebug(lcQpaXInput, "XInput 2.2: failed to select touch events, window %x, result %d", window, result);
- }
+ // 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.
+ mask.deviceid = XIAllMasterDevices;
+ Status result = XISelectEvents(xDisplay, window, &mask, 1);
+ if (result != Success)
+ qCDebug(lcQpaXInput, "XInput 2.2: failed to select pointer/touch events, window %x, result %d", window, result);
}
#endif // XCB_USE_XINPUT22
+ const bool pointerSelected = isAtLeastXI22() && xi2MouseEvents();
QSet<int> tabletDevices;
#ifndef QT_NO_TABLETEVENT
- // For each tablet, select some additional event types.
- // Press, motion, etc. events must never be selected for _all_ devices
- // as that would render the standard XCB_MOTION_NOTIFY and
- // similar handlers useless and we have no intention to infect
- // all the pure xcb code with Xlib-based XI2.
- if (!m_tabletData.isEmpty()) {
+ if (!m_tabletData.isEmpty() && !pointerSelected) {
unsigned int tabletBitMask;
unsigned char *xiTabletBitMask = reinterpret_cast<unsigned char *>(&tabletBitMask);
QVector<XIEventMask> xiEventMask(m_tabletData.count());
@@ -324,7 +326,8 @@ void QXcbConnection::xi2Select(xcb_window_t window)
#ifdef XCB_USE_XINPUT21
// Enable each scroll device
- if (!m_scrollingDevices.isEmpty()) {
+ if (!m_scrollingDevices.isEmpty() && !pointerSelected) {
+ // Only when XI2 mouse events are not enabled, otherwise motion and release are selected already.
QVector<XIEventMask> xiEventMask(m_scrollingDevices.size());
unsigned int scrollBitMask;
unsigned char *xiScrollBitMask = reinterpret_cast<unsigned char *>(&scrollBitMask);
@@ -426,7 +429,7 @@ XInput2TouchDeviceData *QXcbConnection::touchDeviceForId(int id)
dev->size.width() > 10000 || dev->size.height() > 10000)
dev->size = QSizeF(130, 110);
}
- if (!isUsingXInput22() || type == QTouchDevice::TouchPad)
+ if (!isAtLeastXI22() || type == QTouchDevice::TouchPad)
caps |= QTouchDevice::MouseEmulation;
if (type >= QTouchDevice::TouchScreen && type <= QTouchDevice::TouchPad) {
@@ -448,7 +451,7 @@ XInput2TouchDeviceData *QXcbConnection::touchDeviceForId(int id)
}
#if defined(XCB_USE_XINPUT21) || !defined(QT_NO_TABLETEVENT)
-static qreal fixed1616ToReal(FP1616 val)
+static inline qreal fixed1616ToReal(FP1616 val)
{
return qreal(val) / 0x10000;
}
@@ -469,163 +472,280 @@ void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event)
{
if (xi2PrepareXIGenericDeviceEvent(event, m_xiOpCode)) {
xXIGenericDeviceEvent *xiEvent = reinterpret_cast<xXIGenericDeviceEvent *>(event);
+ int sourceDeviceId = xiEvent->deviceid; // may be the master id
+ xXIDeviceEvent *xiDeviceEvent = 0;
+ QXcbWindowEventListener *eventListener = 0;
- if (xiEvent->evtype == XI_HierarchyChanged) {
+ switch (xiEvent->evtype) {
+ case XI_ButtonPress:
+ case XI_ButtonRelease:
+ case XI_Motion:
+ case XI_TouchBegin:
+ case XI_TouchUpdate:
+ case XI_TouchEnd:
+ {
+ xiDeviceEvent = reinterpret_cast<xXIDeviceEvent *>(event);
+ eventListener = windowEventListenerFromId(xiDeviceEvent->event);
+ if (eventListener) {
+ long result = 0;
+ if (eventListener->handleGenericEvent(reinterpret_cast<xcb_generic_event_t *>(event), &result))
+ return;
+ }
+ sourceDeviceId = xiDeviceEvent->sourceid; // use the actual device id instead of the master
+ break;
+ }
+ case XI_HierarchyChanged:
xi2HandleHierachyEvent(xiEvent);
return;
- }
- if (xiEvent->evtype == XI_DeviceChanged) {
+ 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 == xiEvent->deviceid) {
- if (xi2HandleTabletEvent(xiEvent, &m_tabletData[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<int, ScrollingDevice>::iterator device = m_scrollingDevices.find(xiEvent->deviceid);
+ QHash<int, ScrollingDevice>::iterator device = m_scrollingDevices.find(sourceDeviceId);
if (device != m_scrollingDevices.end())
xi2HandleScrollEvent(xiEvent, device.value());
#endif // XCB_USE_XINPUT21
#ifdef XCB_USE_XINPUT22
- if (xiEvent->evtype == XI_TouchBegin || xiEvent->evtype == XI_TouchUpdate || xiEvent->evtype == XI_TouchEnd) {
- xXIDeviceEvent* xiDeviceEvent = reinterpret_cast<xXIDeviceEvent *>(event);
- 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",
- event->event_type, xiEvent->sequenceNumber, xiDeviceEvent->detail,
- fixed1616ToReal(xiDeviceEvent->event_x), fixed1616ToReal(xiDeviceEvent->event_y),
- fixed1616ToReal(xiDeviceEvent->root_x), fixed1616ToReal(xiDeviceEvent->root_y) );
-
- if (QXcbWindow *platformWindow = platformWindowFromId(xiDeviceEvent->event)) {
- XInput2TouchDeviceData *dev = touchDeviceForId(xiDeviceEvent->sourceid);
- Q_ASSERT(dev);
- const bool firstTouch = m_touchPoints.isEmpty();
- if (xiEvent->evtype == XI_TouchBegin) {
- QWindowSystemInterface::TouchPoint tp;
- tp.id = xiDeviceEvent->detail % INT_MAX;
- tp.state = Qt::TouchPointPressed;
- tp.pressure = -1.0;
- m_touchPoints[tp.id] = tp;
- }
- QWindowSystemInterface::TouchPoint &touchPoint = m_touchPoints[xiDeviceEvent->detail];
- qreal x = fixed1616ToReal(xiDeviceEvent->root_x);
- qreal y = fixed1616ToReal(xiDeviceEvent->root_y);
- qreal nx = -1.0, ny = -1.0, w = 0.0, h = 0.0;
- QXcbScreen* screen = m_screens.at(0);
- for (int i = 0; i < dev->xiDeviceInfo->num_classes; ++i) {
- XIAnyClassInfo *classinfo = dev->xiDeviceInfo->classes[i];
- if (classinfo->type == XIValuatorClass) {
- XIValuatorClassInfo *vci = reinterpret_cast<XIValuatorClassInfo *>(classinfo);
- int n = vci->number;
- double value;
- if (!xi2GetValuatorValueIfSet(xiDeviceEvent, n, &value))
- continue;
- if (Q_UNLIKELY(lcQpaXInput().isDebugEnabled()))
- qCDebug(lcQpaXInput, " valuator %20s value %lf from range %lf -> %lf",
- atomName(vci->label).constData(), value, vci->min, vci->max );
- if (vci->label == atom(QXcbAtom::RelX)) {
- nx = valuatorNormalized(value, vci);
- } else if (vci->label == atom(QXcbAtom::RelY)) {
- ny = valuatorNormalized(value, vci);
- } else if (vci->label == atom(QXcbAtom::AbsX)) {
- nx = valuatorNormalized(value, vci);
- } else if (vci->label == atom(QXcbAtom::AbsY)) {
- ny = valuatorNormalized(value, vci);
- } else if (vci->label == atom(QXcbAtom::AbsMTPositionX)) {
- nx = valuatorNormalized(value, vci);
- } else if (vci->label == atom(QXcbAtom::AbsMTPositionY)) {
- ny = valuatorNormalized(value, vci);
- } else if (vci->label == atom(QXcbAtom::AbsMTTouchMajor)) {
- // Convert the value within its range as a fraction of a finger's max (contact patch)
- // width in mm, and from there to pixels depending on screen resolution
- w = valuatorNormalized(value, vci) * FINGER_MAX_WIDTH_MM *
- screen->geometry().width() / screen->physicalSize().width();
- } else if (vci->label == atom(QXcbAtom::AbsMTTouchMinor)) {
- h = valuatorNormalized(value, vci) * FINGER_MAX_WIDTH_MM *
- screen->geometry().height() / screen->physicalSize().height();
- } else if (vci->label == atom(QXcbAtom::AbsMTPressure) ||
- vci->label == atom(QXcbAtom::AbsPressure)) {
- touchPoint.pressure = valuatorNormalized(value, vci);
- }
- }
- }
- // If any value was not updated, use the last-known value.
- if (nx == -1.0) {
- x = touchPoint.area.center().x();
- nx = x / screen->geometry().width();
- }
- if (ny == -1.0) {
- y = touchPoint.area.center().y();
- ny = y / screen->geometry().height();
- }
- if (xiEvent->evtype != XI_TouchEnd) {
- if (w == 0.0)
- w = touchPoint.area.width();
- if (h == 0.0)
- h = touchPoint.area.height();
- }
-
- switch (xiEvent->evtype) {
- case XI_TouchBegin:
- if (firstTouch) {
- dev->firstPressedPosition = QPointF(x, y);
- dev->firstPressedNormalPosition = QPointF(nx, ny);
- }
- dev->pointPressedPosition.insert(touchPoint.id, QPointF(x, y));
- break;
- case XI_TouchUpdate:
- if (dev->qtTouchDevice->type() == QTouchDevice::TouchPad && dev->pointPressedPosition.value(touchPoint.id) == QPointF(x, y)) {
- qreal dx = (nx - dev->firstPressedNormalPosition.x()) *
- dev->size.width() * screen->geometry().width() / screen->physicalSize().width();
- qreal dy = (ny - dev->firstPressedNormalPosition.y()) *
- dev->size.height() * screen->geometry().height() / screen->physicalSize().height();
- x = dev->firstPressedPosition.x() + dx;
- y = dev->firstPressedPosition.y() + dy;
- touchPoint.state = Qt::TouchPointMoved;
- } else if (touchPoint.area.center() != QPoint(x, y)) {
- touchPoint.state = Qt::TouchPointMoved;
- dev->pointPressedPosition[touchPoint.id] = QPointF(x, y);
- }
- break;
- case XI_TouchEnd:
- touchPoint.state = Qt::TouchPointReleased;
- if (dev->qtTouchDevice->type() == QTouchDevice::TouchPad && dev->pointPressedPosition.value(touchPoint.id) == QPointF(x, y)) {
- qreal dx = (nx - dev->firstPressedNormalPosition.x()) *
- dev->size.width() * screen->geometry().width() / screen->physicalSize().width();
- qreal dy = (ny - dev->firstPressedNormalPosition.y()) *
- dev->size.width() * screen->geometry().width() / screen->physicalSize().width();
- x = dev->firstPressedPosition.x() + dx;
- y = dev->firstPressedPosition.y() + dy;
- }
- dev->pointPressedPosition.remove(touchPoint.id);
- }
- touchPoint.area = QRectF(x - w/2, y - h/2, w, h);
- touchPoint.normalPosition = QPointF(nx, ny);
+ if (xiDeviceEvent) {
+ switch (xiDeviceEvent->evtype) {
+ case XI_ButtonPress:
+ case XI_ButtonRelease:
+ case XI_Motion:
+ if (xi2MouseEvents() && eventListener)
+ eventListener->handleXIMouseEvent(event);
+ break;
+ case XI_TouchBegin:
+ case XI_TouchUpdate:
+ case XI_TouchEnd:
if (Q_UNLIKELY(lcQpaXInput().isDebugEnabled()))
- qCDebug(lcQpaXInput) << " touchpoint " << touchPoint.id << " state " << touchPoint.state << " pos norm " << touchPoint.normalPosition <<
- " area " << touchPoint.area << " pressure " << touchPoint.pressure;
- QWindowSystemInterface::handleTouchEvent(platformWindow->window(), xiEvent->time, dev->qtTouchDevice, m_touchPoints.values());
- if (touchPoint.state == Qt::TouchPointReleased)
- // If a touchpoint was released, we can forget it, because the ID won't be reused.
- m_touchPoints.remove(touchPoint.id);
- else
- // Make sure that we don't send TouchPointPressed/Moved in more than one QTouchEvent
- // with this touch point if the next XI2 event is about a different touch point.
- touchPoint.state = Qt::TouchPointStationary;
+ 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
}
}
+#ifdef XCB_USE_XINPUT22
+void QXcbConnection::xi2ProcessTouch(void *xiDevEvent, QXcbWindow *platformWindow)
+{
+ xXIDeviceEvent *xiDeviceEvent = static_cast<xXIDeviceEvent *>(xiDevEvent);
+ XInput2TouchDeviceData *dev = touchDeviceForId(xiDeviceEvent->sourceid);
+ Q_ASSERT(dev);
+ const bool firstTouch = m_touchPoints.isEmpty();
+ if (xiDeviceEvent->evtype == XI_TouchBegin) {
+ QWindowSystemInterface::TouchPoint tp;
+ tp.id = xiDeviceEvent->detail % INT_MAX;
+ tp.state = Qt::TouchPointPressed;
+ tp.pressure = -1.0;
+ m_touchPoints[tp.id] = tp;
+ }
+ QWindowSystemInterface::TouchPoint &touchPoint = m_touchPoints[xiDeviceEvent->detail];
+ qreal x = fixed1616ToReal(xiDeviceEvent->root_x);
+ qreal y = fixed1616ToReal(xiDeviceEvent->root_y);
+ qreal nx = -1.0, ny = -1.0, d = 0.0;
+ QXcbScreen* screen = m_screens.at(0);
+ for (int i = 0; i < dev->xiDeviceInfo->num_classes; ++i) {
+ XIAnyClassInfo *classinfo = dev->xiDeviceInfo->classes[i];
+ if (classinfo->type == XIValuatorClass) {
+ XIValuatorClassInfo *vci = reinterpret_cast<XIValuatorClassInfo *>(classinfo);
+ int n = vci->number;
+ double value;
+ if (!xi2GetValuatorValueIfSet(xiDeviceEvent, n, &value))
+ continue;
+ if (Q_UNLIKELY(lcQpaXInput().isDebugEnabled()))
+ qCDebug(lcQpaXInput, " valuator %20s value %lf from range %lf -> %lf",
+ atomName(vci->label).constData(), value, vci->min, vci->max );
+ if (vci->label == atom(QXcbAtom::RelX)) {
+ nx = valuatorNormalized(value, vci);
+ } else if (vci->label == atom(QXcbAtom::RelY)) {
+ ny = valuatorNormalized(value, vci);
+ } else if (vci->label == atom(QXcbAtom::AbsX)) {
+ nx = valuatorNormalized(value, vci);
+ } else if (vci->label == atom(QXcbAtom::AbsY)) {
+ ny = valuatorNormalized(value, vci);
+ } else if (vci->label == atom(QXcbAtom::AbsMTPositionX)) {
+ nx = valuatorNormalized(value, vci);
+ } else if (vci->label == atom(QXcbAtom::AbsMTPositionY)) {
+ ny = valuatorNormalized(value, vci);
+ } else if (vci->label == atom(QXcbAtom::AbsMTTouchMajor)) {
+ d = valuatorNormalized(value, vci) * screen->geometry().width();
+ } else if (vci->label == atom(QXcbAtom::AbsMTPressure) ||
+ vci->label == atom(QXcbAtom::AbsPressure)) {
+ touchPoint.pressure = valuatorNormalized(value, vci);
+ }
+ }
+ }
+ // If any value was not updated, use the last-known value.
+ if (nx == -1.0) {
+ x = touchPoint.area.center().x();
+ nx = x / screen->geometry().width();
+ }
+ if (ny == -1.0) {
+ y = touchPoint.area.center().y();
+ ny = y / screen->geometry().height();
+ }
+ if (xiDeviceEvent->evtype != XI_TouchEnd) {
+ if (d == 0.0)
+ d = touchPoint.area.width();
+ }
+
+ switch (xiDeviceEvent->evtype) {
+ case XI_TouchBegin:
+ if (firstTouch) {
+ dev->firstPressedPosition = QPointF(x, y);
+ dev->firstPressedNormalPosition = QPointF(nx, ny);
+ }
+ dev->pointPressedPosition.insert(touchPoint.id, QPointF(x, y));
+
+ // Touches must be accepted when we are grabbing touch events. Otherwise the entire sequence
+ // will get replayed when the grab ends.
+ if (m_xiGrab) {
+ // XIAllowTouchEvents deadlocks with libXi < 1.7.4 (this has nothing to do with the XI2 versions like 2.2)
+ // http://lists.x.org/archives/xorg-devel/2014-July/043059.html
+#ifndef LIBXI_MAJOR
+ static bool allowTouchWarningShown = false;
+ if (!allowTouchWarningShown) {
+ allowTouchWarningShown = true;
+ qWarning("Skipping XIAllowTouchEvents() because it was not possible to detect libXi version at build time."
+ " Minimum libXi version required is 1.7.4."
+ " Expect issues with touch behavior.");
+ }
+#elif LIBXI_MAJOR == 1 && (LIBXI_MINOR < 7 || (LIBXI_MINOR == 7 && LIBXI_PATCH < 4))
+ static bool allowTouchWarningShown = false;
+ if (!allowTouchWarningShown) {
+ allowTouchWarningShown = true;
+ qWarning("Skipping XIAllowTouchEvents() due to not having libXi >= 1.7.4."
+ " libXi version at build time was %d.%d.%d."
+ " Expect issues with touch behavior.", LIBXI_MAJOR, LIBXI_MINOR, LIBXI_PATCH);
+ }
+#else
+ XIAllowTouchEvents(static_cast<Display *>(m_xlib_display), xiDeviceEvent->deviceid,
+ xiDeviceEvent->detail, xiDeviceEvent->event, XIAcceptTouch);
+#endif
+ }
+ break;
+ case XI_TouchUpdate:
+ if (dev->qtTouchDevice->type() == QTouchDevice::TouchPad && dev->pointPressedPosition.value(touchPoint.id) == QPointF(x, y)) {
+ qreal dx = (nx - dev->firstPressedNormalPosition.x()) *
+ dev->size.width() * screen->geometry().width() / screen->physicalSize().width();
+ qreal dy = (ny - dev->firstPressedNormalPosition.y()) *
+ dev->size.height() * screen->geometry().height() / screen->physicalSize().height();
+ x = dev->firstPressedPosition.x() + dx;
+ y = dev->firstPressedPosition.y() + dy;
+ touchPoint.state = Qt::TouchPointMoved;
+ } else if (touchPoint.area.center() != QPoint(x, y)) {
+ touchPoint.state = Qt::TouchPointMoved;
+ dev->pointPressedPosition[touchPoint.id] = QPointF(x, y);
+ }
+ break;
+ case XI_TouchEnd:
+ touchPoint.state = Qt::TouchPointReleased;
+ if (dev->qtTouchDevice->type() == QTouchDevice::TouchPad && dev->pointPressedPosition.value(touchPoint.id) == QPointF(x, y)) {
+ qreal dx = (nx - dev->firstPressedNormalPosition.x()) *
+ dev->size.width() * screen->geometry().width() / screen->physicalSize().width();
+ qreal dy = (ny - dev->firstPressedNormalPosition.y()) *
+ dev->size.width() * screen->geometry().width() / screen->physicalSize().width();
+ x = dev->firstPressedPosition.x() + dx;
+ y = dev->firstPressedPosition.y() + dy;
+ }
+ dev->pointPressedPosition.remove(touchPoint.id);
+ }
+ touchPoint.area = QRectF(x - d/2, y - d/2, d, d);
+ touchPoint.normalPosition = QPointF(nx, ny);
+
+ if (Q_UNLIKELY(lcQpaXInput().isDebugEnabled()))
+ qCDebug(lcQpaXInput) << " touchpoint " << touchPoint.id << " state " << touchPoint.state << " pos norm " << touchPoint.normalPosition <<
+ " area " << touchPoint.area << " pressure " << touchPoint.pressure;
+ QWindowSystemInterface::handleTouchEvent(platformWindow->window(), xiDeviceEvent->time, dev->qtTouchDevice, m_touchPoints.values());
+ if (touchPoint.state == Qt::TouchPointReleased)
+ // If a touchpoint was released, we can forget it, because the ID won't be reused.
+ m_touchPoints.remove(touchPoint.id);
+ else
+ // Make sure that we don't send TouchPointPressed/Moved in more than one QTouchEvent
+ // with this touch point if the next XI2 event is about a different touch point.
+ touchPoint.state = Qt::TouchPointStationary;
+}
+
+bool QXcbConnection::xi2SetMouseGrabEnabled(xcb_window_t w, bool grab)
+{
+ if (grab && !canGrab())
+ return false;
+
+ int num_devices = 0;
+ Display *xDisplay = static_cast<Display *>(xlib_display());
+ XIDeviceInfo *info = XIQueryDevice(xDisplay, XIAllMasterDevices, &num_devices);
+ if (!info)
+ return false;
+
+ XIEventMask evmask;
+ unsigned char mask[XIMaskLen(XI_LASTEVENT)];
+ evmask.mask = mask;
+ evmask.mask_len = sizeof(mask);
+ memset(mask, 0, sizeof(mask));
+ evmask.deviceid = XIAllMasterDevices;
+
+ XISetMask(mask, XI_ButtonPress);
+ XISetMask(mask, XI_ButtonRelease);
+ XISetMask(mask, XI_Motion);
+ XISetMask(mask, XI_TouchBegin);
+ XISetMask(mask, XI_TouchUpdate);
+ XISetMask(mask, XI_TouchEnd);
+
+ bool grabbed = true;
+ for (int i = 0; i < num_devices; i++) {
+ int id = info[i].deviceid, n = 0;
+ XIDeviceInfo *deviceInfo = XIQueryDevice(xDisplay, id, &n);
+ if (deviceInfo) {
+ const bool grabbable = deviceInfo->use != XIMasterKeyboard;
+ XIFreeDeviceInfo(deviceInfo);
+ if (!grabbable)
+ continue;
+ }
+ if (!grab) {
+ Status result = XIUngrabDevice(xDisplay, id, CurrentTime);
+ if (result != Success) {
+ grabbed = false;
+ qCDebug(lcQpaXInput, "XInput 2.2: failed to ungrab events for device %d (result %d)", id, result);
+ }
+ } else {
+ Status result = XIGrabDevice(xDisplay, id, w, CurrentTime, None, XIGrabModeAsync,
+ XIGrabModeAsync, False, &evmask);
+ if (result != Success) {
+ grabbed = false;
+ qCDebug(lcQpaXInput, "XInput 2.2: failed to grab events for device %d on window %x (result %d)", id, w, result);
+ }
+ }
+ }
+
+ XIFreeDeviceInfo(info);
+
+ m_xiGrab = grabbed;
+
+ return grabbed;
+}
+#endif // XCB_USE_XINPUT22
+
void QXcbConnection::xi2HandleHierachyEvent(void *event)
{
xXIHierarchyEvent *xiEvent = reinterpret_cast<xXIHierarchyEvent *>(event);
@@ -794,7 +914,8 @@ void QXcbConnection::xi2HandleScrollEvent(void *event, ScrollingDevice &scrollin
#endif // XCB_USE_XINPUT21
}
-static Qt::MouseButton xiToQtMouseButton(uint32_t b) {
+Qt::MouseButton QXcbConnection::xiToQtMouseButton(uint32_t b)
+{
switch (b) {
case 1: return Qt::LeftButton;
case 2: return Qt::MiddleButton;
@@ -841,20 +962,29 @@ static QTabletEvent::TabletDevice toolIdToTabletDevice(quint32 toolId) {
}
#ifndef QT_NO_TABLETEVENT
-bool QXcbConnection::xi2HandleTabletEvent(void *event, TabletData *tabletData)
+bool QXcbConnection::xi2HandleTabletEvent(void *event, TabletData *tabletData, QXcbWindowEventListener *eventListener)
{
bool handled = true;
Display *xDisplay = static_cast<Display *>(m_xlib_display);
xXIGenericDeviceEvent *xiEvent = static_cast<xXIGenericDeviceEvent *>(event);
+ xXIDeviceEvent *xiDeviceEvent = reinterpret_cast<xXIDeviceEvent *>(xiEvent);
+
+#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));
+#endif
+
switch (xiEvent->evtype) {
case XI_ButtonPress: {
- Qt::MouseButton b = xiToQtMouseButton(reinterpret_cast<xXIDeviceEvent *>(event)->detail);
+ Qt::MouseButton b = xiToQtMouseButton(xiDeviceEvent->detail);
tabletData->buttons |= b;
xi2ReportTabletEvent(*tabletData, xiEvent);
break;
}
case XI_ButtonRelease: {
- Qt::MouseButton b = xiToQtMouseButton(reinterpret_cast<xXIDeviceEvent *>(event)->detail);
+ Qt::MouseButton b = xiToQtMouseButton(xiDeviceEvent->detail);
tabletData->buttons ^= b;
xi2ReportTabletEvent(*tabletData, xiEvent);
break;
@@ -917,7 +1047,7 @@ bool QXcbConnection::xi2HandleTabletEvent(void *event, TabletData *tabletData)
// TODO maybe have a hash of tabletData->deviceId to device data so we can
// look up the tablet name here, and distinguish multiple tablets
qCDebug(lcQpaXInput, "XI2 proximity change on tablet %d (USB %x): last tool: %x id %x current tool: %x id %x TabletDevice %d",
- ev->deviceid, ptr[_WACSER_USB_ID], ptr[_WACSER_LAST_TOOL_SERIAL], ptr[_WACSER_LAST_TOOL_ID],
+ tabletData->deviceId, ptr[_WACSER_USB_ID], ptr[_WACSER_LAST_TOOL_SERIAL], ptr[_WACSER_LAST_TOOL_ID],
ptr[_WACSER_TOOL_SERIAL], ptr[_WACSER_TOOL_ID], tabletData->tool);
}
XFree(data);
@@ -981,7 +1111,7 @@ 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 pos %6.1f, %6.1f root pos %6.1f, %6.1f buttons 0x%x pressure %4.2lf tilt %d, %d rotation %6.2lf",
- ev->deviceid, tabletData.tool, ev->evtype, ev->sequenceNumber, ev->detail,
+ tabletData.deviceId, tabletData.tool, ev->evtype, ev->sequenceNumber, ev->detail,
fixed1616ToReal(ev->event_x), fixed1616ToReal(ev->event_y),
fixed1616ToReal(ev->root_x), fixed1616ToReal(ev->root_y),
(int)tabletData.buttons, pressure, xTilt, yTilt, rotation);
diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.cpp b/src/plugins/platforms/xcb/qxcbkeyboard.cpp
index 6a9ef5869e..2d96ed1c21 100644
--- a/src/plugins/platforms/xcb/qxcbkeyboard.cpp
+++ b/src/plugins/platforms/xcb/qxcbkeyboard.cpp
@@ -47,6 +47,12 @@
#include <stdio.h>
#include <X11/keysym.h>
+#ifdef XCB_USE_XINPUT22
+#include <X11/extensions/XI2proto.h>
+#undef KeyPress
+#undef KeyRelease
+#endif
+
#ifndef XK_ISO_Left_Tab
#define XK_ISO_Left_Tab 0xFE20
#endif
@@ -791,6 +797,31 @@ void QXcbKeyboard::updateXKBStateFromCore(quint16 state)
}
}
+void QXcbKeyboard::updateXKBStateFromXI(void *modInfo, void *groupInfo)
+{
+#ifdef XCB_USE_XINPUT22
+ if (m_config && !connection()->hasXKB()) {
+ xXIModifierInfo *mods = static_cast<xXIModifierInfo *>(modInfo);
+ xXIGroupInfo *group = static_cast<xXIGroupInfo *>(groupInfo);
+ const xkb_state_component newState = xkb_state_update_mask(xkb_state,
+ mods->base_mods,
+ mods->latched_mods,
+ mods->locked_mods,
+ group->base_group,
+ group->latched_group,
+ group->locked_group);
+
+ if ((newState & XKB_STATE_LAYOUT_EFFECTIVE) == XKB_STATE_LAYOUT_EFFECTIVE) {
+ //qWarning("TODO: Support KeyboardLayoutChange on QPA (QTBUG-27681)");
+ }
+ }
+#else
+ Q_UNUSED(modInfo);
+ Q_UNUSED(groupInfo);
+ Q_ASSERT(false); // this can't be
+#endif
+}
+
quint32 QXcbKeyboard::xkbModMask(quint16 state)
{
quint32 xkb_mask = 0;
diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.h b/src/plugins/platforms/xcb/qxcbkeyboard.h
index 2281674e2f..d2e37d624c 100644
--- a/src/plugins/platforms/xcb/qxcbkeyboard.h
+++ b/src/plugins/platforms/xcb/qxcbkeyboard.h
@@ -68,6 +68,7 @@ public:
void updateXKBMods();
quint32 xkbModMask(quint16 state);
void updateXKBStateFromCore(quint16 state);
+ void updateXKBStateFromXI(void *modInfo, void *groupInfo);
#ifndef QT_NO_XKB
// when XKEYBOARD is present on the X server
int coreDeviceId() const { return core_device_id; }
diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp
index 3188a7f19d..d1b688857d 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.cpp
+++ b/src/plugins/platforms/xcb/qxcbwindow.cpp
@@ -96,6 +96,7 @@
#if defined(XCB_USE_XINPUT2)
#include <X11/extensions/XInput2.h>
+#include <X11/extensions/XI2proto.h>
#endif
#define XCOORD_MAX 16383
@@ -2106,16 +2107,17 @@ void QXcbWindow::handleUnmapNotifyEvent(const xcb_unmap_notify_event_t *event)
}
}
-void QXcbWindow::handleButtonPressEvent(const xcb_button_press_event_t *event)
+void QXcbWindow::handleButtonPressEvent(int event_x, int event_y, int root_x, int root_y,
+ int detail, Qt::KeyboardModifiers modifiers, xcb_timestamp_t timestamp)
{
- const bool isWheel = event->detail >= 4 && event->detail <= 7;
+ const bool isWheel = detail >= 4 && detail <= 7;
if (!isWheel && window() != QGuiApplication::focusWindow()) {
QWindow *w = static_cast<QWindowPrivate *>(QObjectPrivate::get(window()))->eventReceiver();
if (!(w->flags() & Qt::WindowDoesNotAcceptFocus))
w->requestActivate();
}
- updateNetWmUserTime(event->time);
+ updateNetWmUserTime(timestamp);
if (m_embedded) {
if (window() != QGuiApplication::focusWindow()) {
@@ -2126,53 +2128,125 @@ void QXcbWindow::handleButtonPressEvent(const xcb_button_press_event_t *event)
}
}
const int dpr = int(devicePixelRatio());
- QPoint local(event->event_x/dpr, event->event_y/dpr);
- QPoint global = xcbScreen()->mapFromNative(QPoint(event->root_x, event->root_y));
-
- Qt::KeyboardModifiers modifiers = connection()->keyboard()->translateModifiers(event->state);
+ QPoint local(event_x / dpr, event_y / dpr);
+ QPoint global = xcbScreen()->mapFromNative(QPoint(root_x, root_y));
if (isWheel) {
- if (!connection()->isUsingXInput21()) {
+ if (!connection()->isAtLeastXI21()) {
// Logic borrowed from qapplication_x11.cpp
- int delta = 120 * ((event->detail == 4 || event->detail == 6) ? 1 : -1);
- bool hor = (((event->detail == 4 || event->detail == 5)
+ int delta = 120 * ((detail == 4 || detail == 6) ? 1 : -1);
+ bool hor = (((detail == 4 || detail == 5)
&& (modifiers & Qt::AltModifier))
- || (event->detail == 6 || event->detail == 7));
+ || (detail == 6 || detail == 7));
- QWindowSystemInterface::handleWheelEvent(window(), event->time,
+ QWindowSystemInterface::handleWheelEvent(window(), timestamp,
local, global, delta, hor ? Qt::Horizontal : Qt::Vertical, modifiers);
}
return;
}
- handleMouseEvent(event->time, local, global, modifiers);
+ handleMouseEvent(timestamp, local, global, modifiers);
}
-void QXcbWindow::handleButtonReleaseEvent(const xcb_button_release_event_t *event)
+void QXcbWindow::handleButtonReleaseEvent(int event_x, int event_y, int root_x, int root_y,
+ int detail, Qt::KeyboardModifiers modifiers, xcb_timestamp_t timestamp)
{
const int dpr = int(devicePixelRatio());
- QPoint local(event->event_x/dpr, event->event_y/dpr);
- QPoint global = xcbScreen()->mapFromNative(QPoint(event->root_x, event->root_y));
- Qt::KeyboardModifiers modifiers = connection()->keyboard()->translateModifiers(event->state);
+ QPoint local(event_x / dpr, event_y / dpr);
+ QPoint global = xcbScreen()->mapFromNative(QPoint(root_x, root_y));
- if (event->detail >= 4 && event->detail <= 7) {
+ if (detail >= 4 && detail <= 7) {
// mouse wheel, handled in handleButtonPressEvent()
return;
}
- handleMouseEvent(event->time, local, global, modifiers);
+ handleMouseEvent(timestamp, local, global, modifiers);
}
-void QXcbWindow::handleMotionNotifyEvent(const xcb_motion_notify_event_t *event)
+void QXcbWindow::handleMotionNotifyEvent(int event_x, int event_y, int root_x, int root_y,
+ Qt::KeyboardModifiers modifiers, xcb_timestamp_t timestamp)
{
- const int dpr = int(devicePixelRatio());
- QPoint local(event->event_x/dpr, event->event_y/dpr);
if (!xcbScreen())
return;
- QPoint global = xcbScreen()->mapFromNative(QPoint(event->root_x, event->root_y));
+ const int dpr = int(devicePixelRatio());
+ QPoint local(event_x / dpr, event_y / dpr);
+ QPoint global = xcbScreen()->mapFromNative(QPoint(root_x, root_y));
+ handleMouseEvent(timestamp, local, global, modifiers);
+}
+
+// Handlers for plain xcb events. Used only when XI 2.2 or newer is not available.
+void QXcbWindow::handleButtonPressEvent(const xcb_button_press_event_t *event)
+{
Qt::KeyboardModifiers modifiers = connection()->keyboard()->translateModifiers(event->state);
+ handleButtonPressEvent(event->event_x, event->event_y, event->root_x, event->root_y, event->detail,
+ modifiers, event->time);
+}
- handleMouseEvent(event->time, local, global, modifiers);
+void QXcbWindow::handleButtonReleaseEvent(const xcb_button_release_event_t *event)
+{
+ Qt::KeyboardModifiers modifiers = connection()->keyboard()->translateModifiers(event->state);
+ handleButtonReleaseEvent(event->event_x, event->event_y, event->root_x, event->root_y, event->detail,
+ modifiers, event->time);
+}
+
+void QXcbWindow::handleMotionNotifyEvent(const xcb_motion_notify_event_t *event)
+{
+ Qt::KeyboardModifiers modifiers = connection()->keyboard()->translateModifiers(event->state);
+ handleMotionNotifyEvent(event->event_x, event->event_y, event->root_x, event->root_y, modifiers, event->time);
+}
+
+#ifdef XCB_USE_XINPUT22
+static inline int fixed1616ToInt(FP1616 val)
+{
+ return int((qreal(val >> 16)) + (val & 0xFFFF) / (qreal)0xFFFF);
+}
+#endif
+
+// With XI 2.2+ press/release/motion comes here instead of the above handlers.
+void QXcbWindow::handleXIMouseEvent(xcb_ge_event_t *event)
+{
+#ifdef XCB_USE_XINPUT22
+ QXcbConnection *conn = connection();
+ xXIDeviceEvent *ev = reinterpret_cast<xXIDeviceEvent *>(event);
+ const Qt::KeyboardModifiers modifiers = conn->keyboard()->translateModifiers(ev->mods.effective_mods);
+ const int event_x = fixed1616ToInt(ev->event_x);
+ const int event_y = fixed1616ToInt(ev->event_y);
+ const int root_x = fixed1616ToInt(ev->root_x);
+ const int root_y = fixed1616ToInt(ev->root_y);
+
+ conn->keyboard()->updateXKBStateFromXI(&ev->mods, &ev->group);
+
+ const Qt::MouseButton button = conn->xiToQtMouseButton(ev->detail);
+
+ if (ev->buttons_len > 0) {
+ unsigned char *buttonMask = (unsigned char *) &ev[1];
+ for (int i = 1; i <= 15; ++i)
+ conn->setButton(conn->translateMouseButton(i), XIMaskIsSet(buttonMask, i));
+ }
+
+ switch (ev->evtype) {
+ case XI_ButtonPress:
+ qCDebug(lcQpaXInput, "XI2 mouse press, button %d", button);
+ conn->setButton(button, true);
+ handleButtonPressEvent(event_x, event_y, root_x, root_y, ev->detail, modifiers, ev->time);
+ break;
+ case XI_ButtonRelease:
+ qCDebug(lcQpaXInput, "XI2 mouse release, button %d", button);
+ conn->setButton(button, false);
+ handleButtonReleaseEvent(event_x, event_y, root_x, root_y, ev->detail, modifiers, ev->time);
+ break;
+ case XI_Motion:
+ qCDebug(lcQpaXInput, "XI2 mouse motion %d,%d", event_x, event_y);
+ handleMotionNotifyEvent(event_x, event_y, root_x, root_y, modifiers, ev->time);
+ break;
+ default:
+ qWarning() << "Unrecognized XI2 mouse event" << ev->evtype;
+ break;
+ }
+#else
+ Q_UNUSED(event);
+ Q_ASSERT(false); // this can't be
+#endif
}
QXcbWindow *QXcbWindow::toWindow() { return this; }
@@ -2356,6 +2430,10 @@ bool QXcbWindow::setKeyboardGrabEnabled(bool grab)
bool QXcbWindow::setMouseGrabEnabled(bool grab)
{
+#ifdef XCB_USE_XINPUT22
+ if (connection()->xi2MouseEvents())
+ return connection()->xi2SetMouseGrabEnabled(m_window, grab);
+#endif
if (grab && !connection()->canGrab())
return false;
diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h
index 512bc54255..e62bfcba64 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.h
+++ b/src/plugins/platforms/xcb/qxcbwindow.h
@@ -131,6 +131,7 @@ public:
void handleFocusInEvent(const xcb_focus_in_event_t *event) Q_DECL_OVERRIDE;
void handleFocusOutEvent(const xcb_focus_out_event_t *event) Q_DECL_OVERRIDE;
void handlePropertyNotifyEvent(const xcb_property_notify_event_t *event) Q_DECL_OVERRIDE;
+ void handleXIMouseEvent(xcb_ge_event_t *) Q_DECL_OVERRIDE;
QXcbWindow *toWindow() Q_DECL_OVERRIDE;
@@ -199,6 +200,15 @@ protected:
void doFocusIn();
void doFocusOut();
+ void handleButtonPressEvent(int event_x, int event_y, int root_x, int root_y,
+ int detail, Qt::KeyboardModifiers modifiers, xcb_timestamp_t timestamp);
+
+ void handleButtonReleaseEvent(int event_x, int event_y, int root_x, int root_y,
+ int detail, Qt::KeyboardModifiers modifiers, xcb_timestamp_t timestamp);
+
+ void handleMotionNotifyEvent(int event_x, int event_y, int root_x, int root_y,
+ Qt::KeyboardModifiers modifiers, xcb_timestamp_t timestamp);
+
xcb_window_t m_window;
QXcbScreen *m_xcbScreen;
diff --git a/src/plugins/platforms/xcb/xcb_qpa_lib.pro b/src/plugins/platforms/xcb/xcb_qpa_lib.pro
index fd704dd904..12987567ff 100644
--- a/src/plugins/platforms/xcb/xcb_qpa_lib.pro
+++ b/src/plugins/platforms/xcb/xcb_qpa_lib.pro
@@ -59,6 +59,11 @@ contains(QT_CONFIG, xcb-xlib) {
DEFINES += XCB_USE_XINPUT2
SOURCES += qxcbconnection_xi2.cpp
LIBS += -lXi
+ !isEmpty(QMAKE_LIBXI_VERSION_MAJOR) {
+ DEFINES += LIBXI_MAJOR=$$QMAKE_LIBXI_VERSION_MAJOR \
+ LIBXI_MINOR=$$QMAKE_LIBXI_VERSION_MINOR \
+ LIBXI_PATCH=$$QMAKE_LIBXI_VERSION_PATCH
+ }
}
}