Use XInput for "polling" the mouse positing
Replaces the timer based polling approach. If XInput is available we listen for the RawMotion event on the root window and use this to trigger a mouse pointer position. BUG: 357692 FIXED-IN: 5.6.0 REVIEW: 126733
This commit is contained in:
parent
9bf7ad4a9f
commit
5a31618461
4 changed files with 135 additions and 2 deletions
|
@ -189,6 +189,8 @@ set_package_properties(X11 PROPERTIES DESCRIPTION "X11 libraries"
|
|||
URL "http://www.x.org"
|
||||
TYPE REQUIRED
|
||||
)
|
||||
add_feature_info("XInput" X11_Xinput_FOUND "Required for poll-free mouse cursor updates")
|
||||
set(HAVE_X11_XINPUT ${X11_Xinput_FOUND})
|
||||
|
||||
# All the required XCB components
|
||||
find_package(XCB 1.10
|
||||
|
@ -480,6 +482,7 @@ set(kwin_XLIB_LIBS
|
|||
${X11_X11_LIB}
|
||||
${X11_ICE_LIB}
|
||||
${X11_SM_LIB}
|
||||
${X11_Xinput_LIB}
|
||||
)
|
||||
|
||||
set(kwin_XCB_LIBS
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#define KWIN_RULES_DIALOG_BIN "${CMAKE_INSTALL_FULL_LIBEXECDIR}/kwin_rules_dialog"
|
||||
#cmakedefine01 HAVE_INPUT
|
||||
#cmakedefine01 HAVE_X11_XCB
|
||||
#cmakedefine01 HAVE_X11_XINPUT
|
||||
#cmakedefine01 HAVE_DRM
|
||||
#cmakedefine01 HAVE_GBM
|
||||
#cmakedefine01 HAVE_LIBHYBRIS
|
||||
|
|
120
cursor.cpp
120
cursor.cpp
|
@ -24,18 +24,28 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
#include "input.h"
|
||||
#include "main.h"
|
||||
#include "utils.h"
|
||||
#include "x11eventfilter.h"
|
||||
#include "xcbutils.h"
|
||||
// KDE
|
||||
#include <KConfig>
|
||||
#include <KConfigGroup>
|
||||
#include <KSharedConfig>
|
||||
// Qt
|
||||
#include <QAbstractEventDispatcher>
|
||||
#include <QDBusConnection>
|
||||
#include <QScreen>
|
||||
#include <QTimer>
|
||||
// xcb
|
||||
#include <xcb/xfixes.h>
|
||||
#include <xcb/xcb_cursor.h>
|
||||
// X11
|
||||
#include <X11/Xlib.h>
|
||||
#if HAVE_X11_XINPUT
|
||||
#include <X11/extensions/XInput2.h>
|
||||
#else
|
||||
#define XI_RawMotion 0
|
||||
#endif
|
||||
#include <fixx11h.h>
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
@ -248,13 +258,36 @@ void Cursor::notifyCursorChanged(uint32_t serial)
|
|||
emit cursorChanged(serial);
|
||||
}
|
||||
|
||||
class XInputEventFilter : public X11EventFilter
|
||||
{
|
||||
public:
|
||||
XInputEventFilter(X11Cursor *parent, int xi_opcode)
|
||||
: X11EventFilter(XCB_GE_GENERIC, xi_opcode, XI_RawMotion)
|
||||
, m_x11Cursor(parent)
|
||||
{}
|
||||
virtual ~XInputEventFilter() = default;
|
||||
|
||||
bool event(xcb_generic_event_t *event) override {
|
||||
Q_UNUSED(event)
|
||||
m_x11Cursor->schedulePoll();
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
X11Cursor *m_x11Cursor;
|
||||
};
|
||||
|
||||
X11Cursor::X11Cursor(QObject *parent)
|
||||
: Cursor(parent)
|
||||
, m_timeStamp(XCB_TIME_CURRENT_TIME)
|
||||
, m_buttonMask(0)
|
||||
, m_resetTimeStampTimer(new QTimer(this))
|
||||
, m_mousePollingTimer(new QTimer(this))
|
||||
, m_hasXInput(false)
|
||||
, m_xiOpcode(0)
|
||||
, m_needsPoll(false)
|
||||
{
|
||||
initXInput();
|
||||
m_resetTimeStampTimer->setSingleShot(true);
|
||||
connect(m_resetTimeStampTimer, SIGNAL(timeout()), SLOT(resetTimeStamp()));
|
||||
// TODO: How often do we really need to poll?
|
||||
|
@ -268,6 +301,39 @@ X11Cursor::~X11Cursor()
|
|||
{
|
||||
}
|
||||
|
||||
void X11Cursor::initXInput()
|
||||
{
|
||||
#ifndef KCMRULES
|
||||
#if HAVE_X11_XINPUT
|
||||
if (qEnvironmentVariableIsSet("KWIN_NO_XI2")) {
|
||||
return;
|
||||
}
|
||||
Display *dpy = display();
|
||||
int xi_opcode, event, error;
|
||||
// init XInput extension
|
||||
if (!XQueryExtension(dpy, "XInputExtension", &xi_opcode, &event, &error)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// verify that the XInput extension is at at least version 2.0
|
||||
int major = 2, minor = 0;
|
||||
int result = XIQueryVersion(dpy, &major, &minor);
|
||||
if (result == BadImplementation) {
|
||||
// Xinput 2.2 returns BadImplementation if checked against 2.0
|
||||
major = 2;
|
||||
minor = 2;
|
||||
if (XIQueryVersion(dpy, &major, &minor) != Success) {
|
||||
return;
|
||||
}
|
||||
} else if (result != Success) {
|
||||
return;
|
||||
}
|
||||
m_hasXInput = true;
|
||||
m_xiOpcode = xi_opcode;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void X11Cursor::doSetPos()
|
||||
{
|
||||
const QPoint &pos = currentPos();
|
||||
|
@ -298,14 +364,64 @@ void X11Cursor::resetTimeStamp()
|
|||
m_timeStamp = XCB_TIME_CURRENT_TIME;
|
||||
}
|
||||
|
||||
void X11Cursor::aboutToBlock()
|
||||
{
|
||||
if (m_needsPoll) {
|
||||
mousePolled();
|
||||
m_needsPoll = false;
|
||||
}
|
||||
}
|
||||
|
||||
void X11Cursor::doStartMousePolling()
|
||||
{
|
||||
m_mousePollingTimer->start();
|
||||
if (m_hasXInput) {
|
||||
#ifndef KCMRULES
|
||||
#if HAVE_X11_XINPUT
|
||||
m_xiEventFilter.reset(new XInputEventFilter(this, m_xiOpcode));
|
||||
|
||||
// this assumes KWin is the only one setting events on the root window
|
||||
// given Qt's source code this seems to be true. If it breaks, we need to change
|
||||
XIEventMask evmasks[1];
|
||||
unsigned char mask1[XIMaskLen(XI_LASTEVENT)];
|
||||
|
||||
memset(mask1, 0, sizeof(mask1));
|
||||
|
||||
XISetMask(mask1, XI_RawMotion);
|
||||
|
||||
evmasks[0].deviceid = XIAllMasterDevices;
|
||||
evmasks[0].mask_len = sizeof(mask1);
|
||||
evmasks[0].mask = mask1;
|
||||
XISelectEvents(display(), rootWindow(), evmasks, 1);
|
||||
connect(qApp->eventDispatcher(), &QAbstractEventDispatcher::aboutToBlock, this, &X11Cursor::aboutToBlock);
|
||||
#endif
|
||||
#endif
|
||||
} else {
|
||||
m_mousePollingTimer->start();
|
||||
}
|
||||
}
|
||||
|
||||
void X11Cursor::doStopMousePolling()
|
||||
{
|
||||
m_mousePollingTimer->stop();
|
||||
if (m_hasXInput) {
|
||||
#ifndef KCMRULES
|
||||
#if HAVE_X11_XINPUT
|
||||
m_xiEventFilter.reset();
|
||||
|
||||
XIEventMask evmasks[1];
|
||||
unsigned char mask1[(XI_LASTEVENT + 7)/8];
|
||||
|
||||
memset(mask1, 0, sizeof(mask1));
|
||||
|
||||
evmasks[0].deviceid = XIAllMasterDevices;
|
||||
evmasks[0].mask_len = sizeof(mask1);
|
||||
evmasks[0].mask = mask1;
|
||||
XISelectEvents(display(), rootWindow(), evmasks, 1);
|
||||
disconnect(qApp->eventDispatcher(), &QAbstractEventDispatcher::aboutToBlock, this, &X11Cursor::aboutToBlock);
|
||||
#endif
|
||||
#endif
|
||||
} else {
|
||||
m_mousePollingTimer->stop();
|
||||
}
|
||||
}
|
||||
|
||||
void X11Cursor::doStartCursorTracking()
|
||||
|
|
13
cursor.h
13
cursor.h
|
@ -33,6 +33,8 @@ class QTimer;
|
|||
namespace KWin
|
||||
{
|
||||
|
||||
class XInputEventFilter;
|
||||
|
||||
/**
|
||||
* @short Replacement for QCursor.
|
||||
*
|
||||
|
@ -221,6 +223,11 @@ class X11Cursor : public Cursor
|
|||
Q_OBJECT
|
||||
public:
|
||||
virtual ~X11Cursor();
|
||||
|
||||
void schedulePoll() {
|
||||
m_needsPoll = true;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual xcb_cursor_t getX11Cursor(Qt::CursorShape shape);
|
||||
xcb_cursor_t getX11Cursor(const QByteArray &name) override;
|
||||
|
@ -239,14 +246,20 @@ private Q_SLOTS:
|
|||
*/
|
||||
void resetTimeStamp();
|
||||
void mousePolled();
|
||||
void aboutToBlock();
|
||||
private:
|
||||
X11Cursor(QObject *parent);
|
||||
void initXInput();
|
||||
xcb_cursor_t createCursor(const QByteArray &name);
|
||||
QHash<QByteArray, xcb_cursor_t > m_cursors;
|
||||
xcb_timestamp_t m_timeStamp;
|
||||
uint16_t m_buttonMask;
|
||||
QTimer *m_resetTimeStampTimer;
|
||||
QTimer *m_mousePollingTimer;
|
||||
bool m_hasXInput;
|
||||
int m_xiOpcode;
|
||||
bool m_needsPoll;
|
||||
QScopedPointer<XInputEventFilter> m_xiEventFilter;
|
||||
friend class Cursor;
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue