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