[platformx/x11] Fix touch events for internal Qt windows

Summary:
To have touch events working we need to do memory layout changes on the
xcb events. This is fine for identifying the touch events which should
trigger the screen edge. But when passed on to Qt to have QtQuick windows
(e.g. Alt+Tab) handle the touch events, this results in a problem:
Qt itself does also the memory movement and then the movement is double
and touch events break.

To prevent this problem an RAII class is added which moves the memory in
the ctor and moves it back in the dtor. So during KWin's processing it
has the right memory layout and later on in Qt's processing it has the
proper "wrong" layout which Qt can fix again.

Test Plan: Touch events in Alt+Tab work

Reviewers: #kwin, #plasma

Subscribers: plasma-devel, kwin

Tags: #kwin

Differential Revision: https://phabricator.kde.org/D5549
This commit is contained in:
Martin Gräßlin 2017-04-23 15:00:29 +02:00
parent 207eb167e1
commit 014afe1c05

View file

@ -43,6 +43,32 @@ static inline qreal fixed1616ToReal(FP1616 val)
return (val) * 1.0 / (1 << 16);
}
class GeEventMemMover
{
public:
GeEventMemMover(xcb_generic_event_t *event)
: m_event(reinterpret_cast<xcb_ge_generic_event_t *>(event))
{
// xcb event structs contain stuff that wasn't on the wire, the full_sequence field
// adds an extra 4 bytes and generic events cookie data is on the wire right after the standard 32 bytes.
// Move this data back to have the same layout in memory as it was on the wire
// and allow casting, overwriting the full_sequence field.
memmove((char*) m_event + 32, (char*) m_event + 36, m_event->length * 4);
}
~GeEventMemMover()
{
// move memory layout back, so that Qt can do the same without breaking
memmove((char*) m_event + 36, (char *) m_event + 32, m_event->length * 4);
}
xcb_ge_generic_event_t *operator->() const {
return m_event;
}
private:
xcb_ge_generic_event_t *m_event;
};
class XInputEventFilter : public X11EventFilter
{
public:
@ -52,8 +78,7 @@ public:
virtual ~XInputEventFilter() = default;
bool event(xcb_generic_event_t *event) override {
xcb_ge_generic_event_t *ge = reinterpret_cast<xcb_ge_generic_event_t *>(event);
xi2PrepareXIGenericDeviceEvent(ge);
GeEventMemMover ge(event);
switch (ge->event_type) {
case XI_RawKeyPress: {
auto re = reinterpret_cast<xXIRawEvent*>(event);
@ -118,7 +143,7 @@ public:
}
break;
case XI_TouchBegin: {
auto e = reinterpret_cast<xXIDeviceEvent*>(ge);
auto e = reinterpret_cast<xXIDeviceEvent*>(event);
m_lastTouchPositions.insert(e->detail, QPointF(fixed1616ToReal(e->event_x), fixed1616ToReal(e->event_y)));
break;
}
@ -175,14 +200,6 @@ private:
return m_x11Display;
}
void xi2PrepareXIGenericDeviceEvent(xcb_ge_generic_event_t *event) {
// xcb event structs contain stuff that wasn't on the wire, the full_sequence field
// adds an extra 4 bytes and generic events cookie data is on the wire right after the standard 32 bytes.
// Move this data back to have the same layout in memory as it was on the wire
// and allow casting, overwriting the full_sequence field.
memmove((char*) event + 32, (char*) event + 36, event->length * 4);
}
QPointer<X11Cursor> m_x11Cursor;
Display *m_x11Display = nullptr;
uint32_t m_trackingTouchId = 0;