Members of the KDE Community are recommended to subscribe to the kde-community mailing list at https://mail.kde.org/mailman/listinfo/kde-community to allow them to participate in important discussions and receive other important announcements

Commit ec417d6c authored by Dmitry Kazakov's avatar Dmitry Kazakov

Remove our own fork of Qt's tablet support on X11

parent 3bd76166
......@@ -306,16 +306,6 @@ find_package(Qt5 ${MIN_QT_VERSION}
Concurrent
)
if (UNIX AND NOT APPLE)
if (${Qt5_VERSION} VERSION_GREATER "5.11")
set (USE_QT_XCB ON)
else()
option(USE_QT_XCB "Do not use Krita's forked XCB connection and tablet support on X11, but leave everything to Qt." OFF)
add_feature_info("Use Qt's XCB and Tablet support on X11" USE_QT_XCB "Do not use Krita's forked XCB connection and tablet support on X11, but leave everything to Qt.")
endif()
configure_file(config_use_qt_xcb.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config_use_qt_xcb.h)
endif()
include (MacroAddFileDependencies)
include (MacroBoolTo01)
include (MacroEnsureOutOfSourceBuild)
......
/* config_use_qt_xcb.h. Generated from config_use_qt_xcb.h.cmake */
#cmakedefine USE_QT_XCB 1
......@@ -63,12 +63,6 @@
#include <kis_tablet_support_win.h>
#include <kis_tablet_support_win8.h>
#include <QLibrary>
#elif defined HAVE_X11
#include "config_use_qt_xcb.h"
#ifndef USE_QT_XCB
#include <kis_xi2_event_filter.h>
#endif
#endif
#if defined HAVE_KCRASH
......@@ -372,15 +366,8 @@ extern "C" int main(int argc, char **argv)
app.setAttribute(Qt::AA_DontShowIconsInMenus);
}
#if defined HAVE_X11
#ifndef USE_QT_XCB
app.installNativeEventFilter(KisXi2EventFilter::instance());
#endif
#endif
app.installEventFilter(KisQtWidgetsTweaker::instance());
if (!args.noSplash()) {
// then create the pixmap from an xpm: we cannot get the
// location of our datadir before we've started our components,
......
......@@ -430,20 +430,6 @@ if (UNIX)
${kritaui_LIB_SRCS}
qtlockedfile/qtlockedfile_unix.cpp
)
if(NOT USE_QT_XCB)
set(kritaui_LIB_SRCS
${kritaui_LIB_SRCS}
input/wintab/kis_tablet_support.cpp
)
endif()
if(NOT APPLE AND NOT USE_QT_XCB)
set(kritaui_LIB_SRCS
${kritaui_LIB_SRCS}
input/wintab/qxcbconnection_xi2.cpp
input/wintab/qxcbconnection.cpp
input/wintab/kis_xi2_event_filter.cpp
)
endif()
endif()
if(APPLE)
......
/*
* Copyright (c) 2013 Dmitry Kazakov <dimula73@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "kis_tablet_support.h"
Q_GLOBAL_STATIC(QTabletDeviceDataList, tablet_devices)
QTabletDeviceDataList *qt_tablet_devices()
{
return tablet_devices();
}
/*
* Copyright (c) 2013 Dmitry Kazakov <dimula73@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __KIS_TABLET_SUPPORT_H
#define __KIS_TABLET_SUPPORT_H
#include <QtGlobal>
#include <QLibrary>
#include <QPointer>
#include <QPointF>
#include <QVector>
#include <QList>
#include <QMap>
#include <QTabletEvent>
#ifdef HAVE_X11
#include "kis_config.h"
#include <algorithm>
#include <X11/extensions/XInput.h>
#include <kis_global.h>
#include "kis_incremental_average.h"
#endif
struct QTabletDeviceData
{
#ifndef Q_OS_OSX
int minPressure;
int maxPressure;
int minTanPressure;
int maxTanPressure;
int minX, maxX, minY, maxY, minZ, maxZ;
int sysOrgX, sysOrgY, sysExtX, sysExtY;
#ifdef HAVE_X11 // on windows the scale is fixed (and hardcoded)
int minRotation;
int maxRotation;
#endif /* HAVE_X11 */
inline QPointF scaleCoord(int coordX, int coordY, int outOriginX, int outExtentX,
int outOriginY, int outExtentY) const;
#endif
#if defined(HAVE_X11) || (defined(Q_OS_OSX) && !defined(QT_MAC_USE_COCOA))
QPointer<QWidget> widgetToGetPress;
#endif
#ifdef HAVE_X11
int deviceType;
enum {
TOTAL_XINPUT_EVENTS = 64
};
void *device;
int eventCount;
long unsigned int eventList[TOTAL_XINPUT_EVENTS]; // XEventClass is in fact a long unsigned int
int xinput_motion;
int xinput_key_press;
int xinput_key_release;
int xinput_button_press;
int xinput_button_release;
int xinput_proximity_in;
int xinput_proximity_out;
#elif defined(Q_OS_OSX)
quint64 tabletUniqueID;
int tabletDeviceType;
int tabletPointerType;
int capabilityMask;
#endif
// Added by Krita
#if defined(Q_OS_OSX) || defined(Q_OS_WIN32)
QMap<quint8, quint8> buttonsMap;
qint64 llId;
int currentPointerType;
int currentDevice;
#endif
#ifdef HAVE_X11
bool isTouchWacomTablet;
/**
* Different tablets have different assignment of axes reported by
* the XInput subsystem. More than that some of the drivers demand
* local storage of the tablet axes' state, because in the events
* they report only recently changed axes. SavedAxesData was
* created to handle all these complexities.
*/
class SavedAxesData {
public:
enum AxesIndexes {
XCoord = 0,
YCoord,
Pressure,
XTilt,
YTilt,
Rotation,
Unused,
NAxes
};
public:
SavedAxesData()
: m_workaroundX11SmoothPressureSteps(KisConfig(true).workaroundX11SmoothPressureSteps()),
m_pressureAverage(m_workaroundX11SmoothPressureSteps)
{
for (int i = 0; i < NAxes; i++) {
m_x11_to_local_axis_mapping.append((AxesIndexes)i);
}
if (m_workaroundX11SmoothPressureSteps) {
warnKrita << "WARNING: Workaround for broken tablet"
<< "pressure reports is activated. Number"
<< "of smooth steps:"
<< m_workaroundX11SmoothPressureSteps;
}
}
void tryFetchAxesMapping(XDevice *dev);
void setAxesMap(const QVector<AxesIndexes> &axesMap) {
// the size of \p axesMap can be smaller/equal/bigger
// than m_axes_data. Everything depends on the driver
m_x11_to_local_axis_mapping = axesMap;
}
inline QPointF position(const QTabletDeviceData *tablet, const QRect &screenArea) const {
return tablet->scaleCoord(m_axis_data[XCoord], m_axis_data[YCoord],
screenArea.x(), screenArea.width(),
screenArea.y(), screenArea.height());
}
inline int pressure() const {
return m_axis_data[Pressure];
}
inline int xTilt() const {
return m_axis_data[XTilt];
}
inline int yTilt() const {
return m_axis_data[YTilt];
}
inline int rotation() const {
return m_axis_data[Rotation];
}
bool updateAxesData(int firstAxis, int axesCount, const int *axes) {
for (int srcIt = 0, dstIt = firstAxis;
srcIt < axesCount;
srcIt++, dstIt++) {
int index = m_x11_to_local_axis_mapping[dstIt];
int newValue = axes[srcIt];
if (m_workaroundX11SmoothPressureSteps > 0 &&
index == Pressure) {
newValue = m_pressureAverage.pushThrough(newValue);
}
m_axis_data[index] = newValue;
}
return true;
}
private:
int m_axis_data[NAxes];
QVector<AxesIndexes> m_x11_to_local_axis_mapping;
int m_workaroundX11SmoothPressureSteps;
KisIncrementalAverage m_pressureAverage;
};
SavedAxesData savedAxesData;
#endif /* HAVE_X11 */
};
static inline int sign(int x)
{
return x >= 0 ? 1 : -1;
}
#ifndef Q_OS_OSX
inline QPointF QTabletDeviceData::scaleCoord(int coordX, int coordY,
int outOriginX, int outExtentX,
int outOriginY, int outExtentY) const
{
QPointF ret;
if (sign(outExtentX) == sign(maxX))
ret.setX(((coordX - minX) * qAbs(outExtentX) / qAbs(qreal(maxX - minX))) + outOriginX);
else
ret.setX(((qAbs(maxX) - (coordX - minX)) * qAbs(outExtentX) / qAbs(qreal(maxX - minX)))
+ outOriginX);
if (sign(outExtentY) == sign(maxY))
ret.setY(((coordY - minY) * qAbs(outExtentY) / qAbs(qreal(maxY - minY))) + outOriginY);
else
ret.setY(((qAbs(maxY) - (coordY - minY)) * qAbs(outExtentY) / qAbs(qreal(maxY - minY)))
+ outOriginY);
return ret;
}
#endif
typedef QList<QTabletDeviceData> QTabletDeviceDataList;
QTabletDeviceDataList *qt_tablet_devices();
#endif /* __KIS_TABLET_SUPPORT_H */
/*
* Copyright (c) 2015 Dmitry Kazakov <dimula73@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "kis_xi2_event_filter.h"
#include "kis_debug.h"
#include <QGlobalStatic>
#include <xcb/xcb.h>
#include "qxcbconnection_xi2.h"
//#include <X11/extensions/XInput2.h>
#include <X11/extensions/XI2proto.h>
#ifndef XCB_GE_GENERIC
#define XCB_GE_GENERIC 35
#endif
#ifndef XCB_GE_NOTIFY
#define XCB_ENTER_NOTIFY 7
#endif
namespace KisFakeXcb {
typedef uint32_t Window;
typedef uint32_t Time;
/**
* See a comment in QXcbConnection::xi2PrepareXIGenericDeviceEvent()
*
* This struct does the sam ething but without modifying the
* source event.
*/
typedef struct
{
uint8_t type; /**< Always GenericEvent */
uint8_t extension; /**< XI extension offset */
uint16_t sequenceNumber;
uint32_t length; /**< Length in 4 byte uints */
uint16_t evtype;
uint16_t deviceid;
Time time;
uint32_t detail; /**< Keycode or button */
Window root;
Window event;
Window child;
/* └──────── 32 byte boundary ────────┘ */
uint32_t __some_weird_padding; // this padding was introduced in xcb 1.9.3
FP1616 root_x; /**< Always screen coords, 16.16 fixed point */
FP1616 root_y;
FP1616 event_x; /**< Always screen coords, 16.16 fixed point */
FP1616 event_y;
uint16_t buttons_len; /**< Len of button flags in 4 b units */
uint16_t valuators_len; /**< Len of val. flags in 4 b units */
uint16_t sourceid; /**< The source device */
uint16_t pad0;
uint32_t flags; /**< ::XIKeyRepeat */
xXIModifierInfo mods;
xXIGroupInfo group;
} xXIDeviceEvent;
};
struct KisXi2EventFilter::Private
{
QScopedPointer<QXcbConnection> connection;
};
Q_GLOBAL_STATIC(KisXi2EventFilter, s_instance)
KisXi2EventFilter::KisXi2EventFilter()
: m_d(new Private)
{
m_d->connection.reset(new QXcbConnection(true, ":0"));
}
KisXi2EventFilter::~KisXi2EventFilter()
{
}
bool KisXi2EventFilter::nativeEventFilter(const QByteArray &eventType, void *message, long *result)
{
Q_UNUSED(eventType);
Q_UNUSED(result);
xcb_generic_event_t *event = static_cast<xcb_generic_event_t*>(message);
uint response_type = event->response_type & ~0x80;
switch (response_type) {
case XCB_GE_GENERIC: {
xcb_ge_event_t *geEvent = reinterpret_cast<xcb_ge_event_t *>(event);
const int eventSize = sizeof(xcb_ge_event_t) + 4 * geEvent->length;
// Qt's code *modifies* (!) the supplied event internally!!!
// And since we reuse Qt's code, we should make a copy of it.
xcb_ge_event_t *copiedEvent = (xcb_ge_event_t*) malloc(eventSize);
memcpy(copiedEvent, geEvent, eventSize);
bool result = m_d->connection->xi2HandleEvent(copiedEvent);
free(copiedEvent);
#if QT_VERSION >= 0x050500
/**
* I know we must be fed to crocodiles for hacks like this
* one, but it is the best thing we can do after Qt 5.5
* started to process all the events using XInput 2.2. It
* means that Qt is not longer subscribed to the emulated
* mouse events that usually go after the tablet. Instead of
* the flow which was previously generated by X11, Qt now
* re-emits mouse events itself in
* QXcbConnection::xi2HandleTabletEvent() using a call to
* QXcbWindow::handleXIMouseEvent(). And, yes, here in Krita
* we don't have access to QXcbWindow. Even through private
* headers. So we have to use this "elegant" solution.
*
* The solution is very simple. We just modify the 'sourceid'
* field of the currently processed event and pass it further
* to Qt. We change the source id to a random number, so Qt
* doesn't recognize it as a tablet, scrolling or touch device
* and therefore passes it further to the code that handles
* mouse events.
*
* Now just let's hope QT will not change this behavior in the
* future...
*/
KisFakeXcb::xXIDeviceEvent *ev =
reinterpret_cast<KisFakeXcb::xXIDeviceEvent*>(event);
switch (ev->evtype) {
case XI_ButtonPress:
case XI_ButtonRelease:
case XI_Motion: {
ev->sourceid = 4815; // just a random fake source id, which Qt doesn't know about
ev->valuators_len = 2;
return false;
}
default:
break;
};
#endif /* QT_VERSION >= 0x050500 */
return result;
}
case XCB_ENTER_NOTIFY: {
xcb_enter_notify_event_t *enter = (xcb_enter_notify_event_t *)event;
m_d->connection->notifyEnterEvent(enter);
}
default:
break;
}
return false;
}
KisXi2EventFilter* KisXi2EventFilter::instance()
{
return s_instance;
}
/*
* Copyright (c) 2015 Dmitry Kazakov <dimula73@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __KIS_XI2_EVENT_FILTER_H
#define __KIS_XI2_EVENT_FILTER_H
#include <QAbstractNativeEventFilter>
#include "kritaui_export.h"
#include <QScopedPointer>
class KRITAUI_EXPORT KisXi2EventFilter : public QAbstractNativeEventFilter
{
public:
KisXi2EventFilter();
~KisXi2EventFilter() override;
static KisXi2EventFilter* instance();
bool nativeEventFilter(const QByteArray &eventType, void *message, long *result) override;
private:
struct Private;
const QScopedPointer<Private> m_d;
};
#endif /* __KIS_XI2_EVENT_FILTER_H */
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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