Commit eccae890 authored by Dmitry Kazakov's avatar Dmitry Kazakov

Fix wheel events in Krita 3.0

In Qt 5.5 and later we are no longer subscribed to the synthesized
mouse/wheel events of the basic x11 protocol. Instead we process the
valuator-based events of XInput2. Therefore when overriding the events
processing by Qt, by should also reimplement resending the wheel events.

Fixes T1272
parent 7971e922
......@@ -520,6 +520,21 @@ public:
int z;
qint64 uid;
};
class WheelEvent : public InputEvent {
public:
WheelEvent(QWindow *w, ulong time, const QPointF & local, const QPointF & global, QPoint pixelD, QPoint angleD, int qt4D, Qt::Orientation qt4O,
Qt::KeyboardModifiers mods, Qt::ScrollPhase phase = Qt::ScrollUpdate, Qt::MouseEventSource src = Qt::MouseEventNotSynthesized)
: InputEvent(w, time, Wheel, mods), pixelDelta(pixelD), angleDelta(angleD), qt4Delta(qt4D), qt4Orientation(qt4O), localPos(local), globalPos(global), phase(phase), source(src) { }
QPoint pixelDelta;
QPoint angleDelta;
int qt4Delta;
Qt::Orientation qt4Orientation;
QPointF localPos;
QPointF globalPos;
Qt::ScrollPhase phase;
Qt::MouseEventSource source;
};
};
void processTabletEvent(QWindowSystemInterfacePrivate::TabletEvent *e);
......@@ -633,3 +648,84 @@ void QWindowSystemInterface::handleTabletLeaveProximityEvent(int device, int poi
ev.setTimestamp(timestamp);
QGuiApplication::sendEvent(qGuiApp, &ev);
}
void processWheelEvent(QWindowSystemInterfacePrivate::WheelEvent *e);
void QWindowSystemInterface::handleWheelEvent(QWindow *tlw, ulong timestamp, const QPointF & local, const QPointF & global, QPoint pixelDelta, QPoint angleDelta, Qt::KeyboardModifiers mods, Qt::ScrollPhase phase, Qt::MouseEventSource source)
{
// Qt 4 sends two separate wheel events for horizontal and vertical
// deltas. For Qt 5 we want to send the deltas in one event, but at the
// same time preserve source and behavior compatibility with Qt 4.
//
// In addition high-resolution pixel-based deltas are also supported.
// Platforms that does not support these may pass a null point here.
// Angle deltas must always be sent in addition to pixel deltas.
QWindowSystemInterfacePrivate::WheelEvent *e;
// Pass Qt::ScrollBegin and Qt::ScrollEnd through
// even if the wheel delta is null.
if (angleDelta.isNull() && phase == Qt::ScrollUpdate)
return;
// Simple case: vertical deltas only:
if (angleDelta.y() != 0 && angleDelta.x() == 0) {
e = new QWindowSystemInterfacePrivate::WheelEvent(tlw, timestamp, local, global, pixelDelta, angleDelta, angleDelta.y(), Qt::Vertical, mods, phase, source);
processWheelEvent(e);
return;
}
// Simple case: horizontal deltas only:
if (angleDelta.y() == 0 && angleDelta.x() != 0) {
e = new QWindowSystemInterfacePrivate::WheelEvent(tlw, timestamp, local, global, pixelDelta, angleDelta, angleDelta.x(), Qt::Horizontal, mods, phase, source);
processWheelEvent(e);
return;
}
// Both horizontal and vertical deltas: Send two wheel events.
// The first event contains the Qt 5 pixel and angle delta as points,
// and in addition the Qt 4 compatibility vertical angle delta.
e = new QWindowSystemInterfacePrivate::WheelEvent(tlw, timestamp, local, global, pixelDelta, angleDelta, angleDelta.y(), Qt::Vertical, mods, phase, source);
processWheelEvent(e);
// The second event contains null pixel and angle points and the
// Qt 4 compatibility horizontal angle delta.
e = new QWindowSystemInterfacePrivate::WheelEvent(tlw, timestamp, local, global, QPoint(), QPoint(), angleDelta.x(), Qt::Horizontal, mods, phase, source);
processWheelEvent(e);
}
void processWheelEvent(QWindowSystemInterfacePrivate::WheelEvent *e)
{
#ifndef QT_NO_WHEELEVENT
QWindow *window = e->window.data();
QPointF globalPoint = e->globalPos;
QPointF localPoint = e->localPos;
if (e->nullWindow()) {
window = QGuiApplication::topLevelAt(globalPoint.toPoint());
if (window) {
QPointF delta = globalPoint - globalPoint.toPoint();
localPoint = window->mapFromGlobal(globalPoint.toPoint()) + delta;
}
}
if (!window)
return;
// Cut off in Krita...
//
// QGuiApplicationPrivate::lastCursorPosition = globalPoint;
// modifier_buttons = e->modifiers;
//if (window->d_func()->blockedByModalWindow) {
if (QGuiApplication::modalWindow() &&
QGuiApplication::modalWindow() != window) {
// a modal window is blocking this window, don't allow wheel events through
return;
}
QWheelEvent ev(localPoint, globalPoint, e->pixelDelta, e->angleDelta, e->qt4Delta, e->qt4Orientation, QGuiApplication::mouseButtons(), e->modifiers, e->phase, e->source);
ev.setTimestamp(e->timestamp);
QGuiApplication::sendEvent(window, &ev);
#endif /* ifndef QT_NO_WHEELEVENT */
}
......@@ -506,6 +506,9 @@ bool QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event)
#endif // QT_NO_TABLETEVENT
#ifdef XCB_USE_XINPUT21
QHash<int, ScrollingDevice>::iterator device = m_scrollingDevices.find(sourceDeviceId);
if (device != m_scrollingDevices.end())
xi2HandleScrollEvent(xiEvent, device.value());
// Removed from Qt...
#endif // XCB_USE_XINPUT21
......@@ -883,6 +886,82 @@ void QXcbConnection::xi2ReportTabletEvent(TabletData &tabletData, void *event)
modifiers);
}
void QXcbConnection::xi2HandleScrollEvent(void *event, ScrollingDevice &scrollingDevice)
{
#ifdef XCB_USE_XINPUT21
xXIGenericDeviceEvent *xiEvent = reinterpret_cast<xXIGenericDeviceEvent *>(event);
if (xiEvent->evtype == XI_Motion && scrollingDevice.orientations) {
xXIDeviceEvent* xiDeviceEvent = reinterpret_cast<xXIDeviceEvent *>(event);
if (QWindow *platformWindow = windowFromId(xiDeviceEvent->event)) {
QPoint rawDelta;
QPoint angleDelta;
double value;
if (scrollingDevice.orientations & Qt::Vertical) {
if (xi2GetValuatorValueIfSet(xiDeviceEvent, scrollingDevice.verticalIndex, &value)) {
double delta = scrollingDevice.lastScrollPosition.y() - value;
scrollingDevice.lastScrollPosition.setY(value);
angleDelta.setY((delta / scrollingDevice.verticalIncrement) * 120);
// We do not set "pixel" delta if it is only measured in ticks.
if (scrollingDevice.verticalIncrement > 1)
rawDelta.setY(delta);
}
}
if (scrollingDevice.orientations & Qt::Horizontal) {
if (xi2GetValuatorValueIfSet(xiDeviceEvent, scrollingDevice.horizontalIndex, &value)) {
double delta = scrollingDevice.lastScrollPosition.x() - value;
scrollingDevice.lastScrollPosition.setX(value);
angleDelta.setX((delta / scrollingDevice.horizontalIncrement) * 120);
// We do not set "pixel" delta if it is only measured in ticks.
if (scrollingDevice.horizontalIncrement > 1)
rawDelta.setX(delta);
}
}
if (!angleDelta.isNull()) {
const int dpr = int(platformWindow->devicePixelRatio());
QPoint local(fixed1616ToReal(xiDeviceEvent->event_x)/dpr, fixed1616ToReal(xiDeviceEvent->event_y)/dpr);
QPoint global(fixed1616ToReal(xiDeviceEvent->root_x)/dpr, fixed1616ToReal(xiDeviceEvent->root_y)/dpr);
Qt::KeyboardModifiers modifiers = QApplication::queryKeyboardModifiers();
if (modifiers & Qt::AltModifier) {
std::swap(angleDelta.rx(), angleDelta.ry());
std::swap(rawDelta.rx(), rawDelta.ry());
}
QWindowSystemInterface::handleWheelEvent(platformWindow, xiEvent->time, local, global, rawDelta, angleDelta, modifiers);
}
}
} else if (xiEvent->evtype == XI_ButtonRelease && scrollingDevice.legacyOrientations) {
xXIDeviceEvent* xiDeviceEvent = reinterpret_cast<xXIDeviceEvent *>(event);
if (QWindow *platformWindow = windowFromId(xiDeviceEvent->event)) {
QPoint angleDelta;
if (scrollingDevice.legacyOrientations & Qt::Vertical) {
if (xiDeviceEvent->detail == 4)
angleDelta.setY(120);
else if (xiDeviceEvent->detail == 5)
angleDelta.setY(-120);
}
if (scrollingDevice.legacyOrientations & Qt::Horizontal) {
if (xiDeviceEvent->detail == 6)
angleDelta.setX(120);
else if (xiDeviceEvent->detail == 7)
angleDelta.setX(-120);
}
if (!angleDelta.isNull()) {
const int dpr = int(platformWindow->devicePixelRatio());
QPoint local(fixed1616ToReal(xiDeviceEvent->event_x)/dpr, fixed1616ToReal(xiDeviceEvent->event_y)/dpr);
QPoint global(fixed1616ToReal(xiDeviceEvent->root_x)/dpr, fixed1616ToReal(xiDeviceEvent->root_y)/dpr);
Qt::KeyboardModifiers modifiers = QApplication::queryKeyboardModifiers();
if (modifiers & Qt::AltModifier)
std::swap(angleDelta.rx(), angleDelta.ry());
QWindowSystemInterface::handleWheelEvent(platformWindow, xiEvent->time, local, global, QPoint(), angleDelta, modifiers);
}
}
}
#else
Q_UNUSED(event);
Q_UNUSED(scrollingDevice);
#endif // XCB_USE_XINPUT21
}
#endif // QT_NO_TABLETEVENT
#endif // XCB_USE_XINPUT2
......@@ -107,20 +107,7 @@ public:
ENTER_FUNCTION();
}
static void handleWheelEvent(QWindow *w, ulong timestamp, const QPointF & local, const QPointF & global, QPoint pixelDelta, QPoint angleDelta, Qt::KeyboardModifiers mods = Qt::NoModifier, Qt::ScrollPhase phase = Qt::ScrollUpdate, Qt::MouseEventSource source = Qt::MouseEventNotSynthesized)
{
Q_UNUSED(w);
Q_UNUSED(timestamp);
Q_UNUSED(local);
Q_UNUSED(global);
Q_UNUSED(pixelDelta);
Q_UNUSED(phase);
Q_UNUSED(source);
Q_UNUSED(angleDelta);
Q_UNUSED(mods);
ENTER_FUNCTION();
}
static void handleWheelEvent(QWindow *w, ulong timestamp, const QPointF & local, const QPointF & global, QPoint pixelDelta, QPoint angleDelta, Qt::KeyboardModifiers mods = Qt::NoModifier, Qt::ScrollPhase phase = Qt::ScrollUpdate, Qt::MouseEventSource source = Qt::MouseEventNotSynthesized);
static void handleTabletEnterProximityEvent(int device, int pointerType, qint64 uid);
static void handleTabletLeaveProximityEvent(int device, int pointerType, qint64 uid);
......@@ -404,7 +391,6 @@ public:
bool xi2HandleTabletEvent(void *event, TabletData *tabletData, QWindow *window);
void xi2ReportTabletEvent(TabletData &tabletData, void *event);
inline xcb_atom_t atom(QXcbAtom::Atom atom) const { return m_allAtoms[atom]; }
QXcbAtom::Atom qatom(xcb_atom_t xatom) const;
QByteArray atomName(xcb_atom_t atom);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment