[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-commits
Subject:    [wacomtablet/marethuskinson] src/common: Added XInput device parser.
From:       Alexander Maret-Huskinson <alex () maret ! de>
Date:       2012-09-30 19:01:11
Message-ID: 20120930190111.E49B3A605D () git ! kde ! org
[Download RAW message or body]

Git commit f6891ff5d9713e2c6fb1ef2768b43d6ba7f61ffc by Alexander Maret-Huskinson.
Committed on 30/09/2012 at 20:57.
Pushed by marethuskinson into branch 'marethuskinson'.

Added XInput device parser.

Added an XInput parser which uses the visitor pattern to allow easy
access to all input devices. This moves most of the code from X11Utils
into proper classes which is much cleaner and much more flexible. As
soon as all code is ported to the new parser, X11Utils will be removed.

M  +2    -0    src/common/CMakeLists.txt
A  +48   -0    src/common/x11input.cpp     [License: GPL (v2+)]
A  +42   -0    src/common/x11input.h     [License: GPL (v2+)]
A  +406  -0    src/common/x11inputdevice.cpp     [License: GPL (v2+)]
A  +204  -0    src/common/x11inputdevice.h     [License: GPL (v2+)]
A  +38   -0    src/common/x11inputvisitor.h     [License: GPL (v2+)]

http://commits.kde.org/wacomtablet/f6891ff5d9713e2c6fb1ef2768b43d6ba7f61ffc

diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index 1aadd50..56decb8 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -17,6 +17,8 @@ set(wacom_common_SRC
     tabletprofile.cpp
     tabletprofileconfigadaptor.cpp
     tabletrotation.cpp
+    x11input.cpp
+    x11inputdevice.cpp
     x11utils.cpp
 )
 
diff --git a/src/common/x11input.cpp b/src/common/x11input.cpp
new file mode 100644
index 0000000..394deab
--- /dev/null
+++ b/src/common/x11input.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2012 Alexander Maret-Huskinson <alex@maret.de>
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "debug.h"
+#include "x11input.h"
+#include "x11inputdevice.h"
+
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+#include <X11/extensions/XInput.h>
+//#include <X11/extensions/XInput2.h>
+#include <X11/Xutil.h>
+
+using namespace Wacom;
+
+void X11Input::scanDevices(X11InputVisitor& visitor)
+{
+    int         ndevices = 0;
+    Display     *dpy     = QX11Info::display();
+    XDeviceInfo *info    = XListInputDevices( dpy, &ndevices );
+
+    for( int i = 0; i < ndevices; ++i ) {
+
+        X11InputDevice device(dpy, info[i].id);
+
+        if (!visitor.visit(device)) {
+            break;
+        }
+    }
+
+    if (info) {
+        XFreeDeviceList( info );
+    }
+}
diff --git a/src/common/x11input.h b/src/common/x11input.h
new file mode 100644
index 0000000..f049e3a
--- /dev/null
+++ b/src/common/x11input.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2012 Alexander Maret-Huskinson <alex@maret.de>
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef X11INPUT_H
+#define X11INPUT_H
+
+#include "x11inputdevice.h"
+#include "x11inputvisitor.h"
+
+// X11 forward declarations
+struct _XDeviceInfo;
+
+namespace Wacom
+{
+class X11Input
+{
+public:
+
+    /**
+     * Iterates over all X11 input devices and passes each device to the
+     * visitor object. The visitor can then decide either to continue
+     * iteration or abort it.
+     */
+    static void scanDevices(X11InputVisitor& visitor);
+
+}; // CLASS
+}  // NAMESPACE
+#endif // HEADER PROTECTION
diff --git a/src/common/x11inputdevice.cpp b/src/common/x11inputdevice.cpp
new file mode 100644
index 0000000..e2e478b
--- /dev/null
+++ b/src/common/x11inputdevice.cpp
@@ -0,0 +1,406 @@
+/*
+ * Copyright 2012 Alexander Maret-Huskinson <alex@maret.de>
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "debug.h"
+#include "x11inputdevice.h"
+
+#include <QtCore/QStringList>
+
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+#include <X11/extensions/XInput.h>
+//#include <X11/extensions/XInput2.h>
+#include <X11/Xutil.h>
+
+using namespace Wacom;
+
+/**
+ * Helper struct which allows us to forward declare XDevice.
+ */
+struct X11InputDevice::XDevice : public ::XDevice {};
+
+/**
+ * Class for private members.
+ */
+namespace Wacom {
+    class X11InputDevicePrivate
+    {
+        public:
+            X11InputDevice::XDevice* device;
+            Display*                 display;
+            X11InputDevice::XID      xid;
+    };
+}
+
+X11InputDevice::X11InputDevice() : d_ptr(new X11InputDevicePrivate)
+{
+    Q_D(X11InputDevice);
+    d->device  = NULL;
+    d->display = NULL;
+    d->xid     = 0;
+}
+
+
+X11InputDevice::X11InputDevice(Display* dpy, X11InputDevice::XID xid) : d_ptr(new \
X11InputDevicePrivate) +{
+    Q_D(X11InputDevice);
+    d->device  = NULL;
+    d->display = NULL;
+    d->xid     = 0;
+
+    open(dpy, xid);
+}
+
+
+
+X11InputDevice::~X11InputDevice()
+{
+    close();
+    delete d_ptr;
+}
+
+
+bool X11InputDevice::close()
+{
+    Q_D(X11InputDevice);
+
+    if (d->device == NULL) {
+        assert(d->display != NULL);
+        return false;
+    }
+
+    XCloseDevice(d->display, d->device);
+
+    d->display = NULL;
+    d->device  = NULL;
+    d->xid     = 0;
+
+    return true;
+}
+
+
+
+bool X11InputDevice::getFloatProperty(const QString& property, long int nelements, \
QList< float >& values) +{
+    Q_D(X11InputDevice);
+
+    Atom expectedType = XInternAtom (d->display, "FLOAT", False);
+
+    if (expectedType == None) {
+        kError() << QLatin1String("Float values are unsupported by this XInput \
implementation!"); +        return false;
+    }
+
+    return getProperty<float>(property, expectedType, nelements, values);
+}
+
+
+
+bool X11InputDevice::getLongProperty(const QString& property, long int nelements, \
QList< long >& values) +{
+    return getProperty<long>(property, XA_INTEGER, nelements, values);
+}
+
+
+
+
+bool X11InputDevice::hasProperty(const QString& property)
+{
+    Q_D(X11InputDevice);
+
+    if (!isOpen()) {
+        return false;
+    }
+
+    Atom atom;
+    if (!lookupProperty(property, &atom)) {
+        return false;
+    }
+
+    bool  found  = false;
+    int   natoms = 0;
+    Atom* atoms = XListDeviceProperties (d->display, d->device, &natoms);
+
+    for (int i = 0 ; i < natoms ; ++i) {
+        if (atoms[i] == atom) {
+            found = true;
+            break;
+        }
+    }
+
+    XFree(atoms);
+
+    return found;
+}
+
+
+
+bool X11InputDevice::isOpen() const
+{
+    Q_D(const X11InputDevice);
+    return (d->device != NULL && d->display != NULL);
+}
+
+
+
+bool X11InputDevice::isTabletDevice()
+{
+    return hasProperty(QLatin1String("Wacom Tool Type"));
+}
+
+
+
+
+bool X11InputDevice::open(Display* display, X11InputDevice::XID xid)
+{
+    Q_D(X11InputDevice);
+
+    if (isOpen()) {
+        close();
+    }
+
+    XDevice* device = (XDevice*) XOpenDevice(display, xid);
+
+    if (device == NULL) {
+        return false;
+    }
+
+    d->device  = device;
+    d->display = display;
+    d->xid     = xid;
+
+    return true;
+}
+
+
+
+bool X11InputDevice::setFloatProperty(const QString& property, const QString& \
values) +{
+    QStringList valueList = values.split (QLatin1String(" "));
+
+    bool         ok;
+    QString      svalue;
+    float        fvalue;
+    QList<float> fvalues;
+
+    for (int i = 0  ; i < valueList.size() ; ++i) {
+        svalue = valueList.at(i);
+
+        if (svalue.isEmpty()) {
+            continue;
+        }
+
+        fvalue = svalue.toFloat(&ok);
+
+        if (!ok) {
+            kError() << QString::fromLatin1("Could not convert value '%1' to \
float!").arg(svalue); +            return false;
+        }
+
+        fvalues.append(fvalue);
+    }
+
+    return setFloatProperty(property, fvalues);
+}
+
+
+
+bool X11InputDevice::setFloatProperty(const QString& property, const QList< float >& \
values) +{
+    Q_D(X11InputDevice);
+
+    Atom expectedType = XInternAtom (d->display, "FLOAT", False);
+
+    if (expectedType == None) {
+        kError() << QLatin1String("Float values are unsupported by this XInput \
implementation!"); +        return false;
+    }
+
+    return setProperty<float>(property, expectedType, values);
+}
+
+
+
+bool X11InputDevice::setLongProperty(const QString& property, const QString& values)
+{
+    QStringList valueList = values.split (QLatin1String(" "));
+
+    bool        ok;
+    QString     svalue;
+    long        lvalue = 0;
+    QList<long> lvalues;
+
+    for (int i = 0  ; i < valueList.size() ; ++i) {
+
+        svalue = valueList.at(i);
+
+        if (svalue.isEmpty()) {
+            continue;
+        }
+
+        lvalue = svalue.toLong(&ok, 10);
+
+        if (!ok) {
+            kError() << QString::fromLatin1("Could not convert value '%1' to \
long!").arg(svalue); +            return false;
+        }
+
+        lvalues.append(lvalue);
+    }
+
+    return setLongProperty(property, lvalues);
+}
+
+
+
+bool X11InputDevice::setLongProperty(const QString& property, const QList<long>& \
values) +{
+    return setProperty<long>(property, XA_INTEGER, values);
+}
+
+
+
+
+template<typename T>
+bool X11InputDevice::getProperty(const QString& property, Atom expectedType, long \
nelements, QList<T>& values) +{
+    Q_D(X11InputDevice);
+
+    int expectedFormat = 32;
+
+    // check parameters
+    if (!isOpen() || nelements < 1) {
+        kError() << QLatin1String("Invalid parameters to \
X11InputDevice::getProperty()!"); +        return false;
+    }
+
+    // we expect a long value to be 4 Byte = 32 Bit which is the default size used \
by XInput1 +    if ((sizeof(long) * 8) != expectedFormat) {
+        kError() << QString::fromLatin1("Invalid XInput property value size \
detected!"); +        return false;
+    }
+
+    long          *data         = NULL;
+    unsigned long  nitems       = 0;
+    unsigned long  bytes_after  = 0;
+    Atom           actualType   = None;
+    Atom           propertyAtom = None;
+    int            actualFormat = 0;
+
+    if (!lookupProperty(property, &propertyAtom)) {
+        kError() << QString::fromLatin1("Could not get unsupported property \
'%1'!").arg(property); +        return false;
+    }
+
+    if (XGetDeviceProperty (d->display, d->device, propertyAtom, 0, nelements, \
False, AnyPropertyType, &actualType, &actualFormat, &nitems, &bytes_after, (unsigned \
char**)&data) != Success) { +        kError() << QString::fromLatin1("Could not get \
property '%1'!").arg(property); +        return false;
+    }
+
+    if (actualFormat != expectedFormat || actualType != expectedType) {
+        kError() << QString::fromLatin1("Invalid property type detected!");
+        XFree(data);
+        return false;
+    }
+
+    for (unsigned long i = 0 ; i < nitems ; i++) {
+        values.append(*((T*)(data + i)));
+    }
+
+    XFree(data);
+    return true;
+}
+
+
+
+bool X11InputDevice::lookupProperty(const QString& property, X11InputDevice::Atom* \
atom) +{
+    Q_D(X11InputDevice);
+
+    if (!isOpen() || property.isEmpty() || atom == NULL) {
+        return false;
+    }
+
+    *atom = XInternAtom (d->display, property.toLatin1().constData(), True);
+
+    if (*atom == None) {
+        kError() << QString::fromLatin1("Failed to lookup XInput property \
'%1'!").arg(property); +        return false;
+    }
+
+    return true;
+}
+
+
+
+template<typename T>
+bool X11InputDevice::setProperty(const QString& property, Atom expectedType, const \
QList<T>& values) +{
+    Q_D(X11InputDevice);
+
+    int expectedFormat = 32;
+
+    // check parameters
+    if (!isOpen() || values.size() == 0) {
+        kError() << QLatin1String("Invalid parameters to \
X11InputDevice::setProperty()!"); +        return false;
+    }
+
+    // we expect a long value to be 4 Byte = 32 Bit which is the default size used \
by XInput1 +    if ((sizeof(long) * 8) != expectedFormat) {
+        kError() << QString::fromLatin1("Invalid XInput property value size \
detected!"); +        return false;
+    }
+
+    // lookup Atom
+    Atom propertyAtom = None;
+
+    if (!lookupProperty(property, &propertyAtom)) {
+        kError() << QString::fromLatin1("Could not get unsupported property \
'%1'!").arg(property); +        return false;
+    }
+
+    // get property so we can validate format and type
+    Atom           actualType;
+    int            actualFormat;
+    unsigned long  nitems, bytes_after;
+    unsigned char *actualData  = NULL;
+
+    XGetDeviceProperty (d->display, d->device, propertyAtom, 0, values.size(), \
False, AnyPropertyType, &actualType, &actualFormat, &nitems, &bytes_after, (unsigned \
char **)&actualData); +    XFree(actualData);
+
+    if (actualFormat != expectedFormat || actualType != expectedType) {
+        kError() << QString::fromLatin1("Can not set incompatible Xinput property \
'%1'!").arg(property); +        return false;
+    }
+
+    // create new data
+    long *data = new long[values.size()];
+
+    for (int i = 0 ; i < values.size() ; ++i) {
+        *((T*)(data + i)) = values.at(i);
+    }
+
+    // set property
+    XChangeDeviceProperty (d->display, d->device, propertyAtom, expectedType, 32, \
PropModeReplace, (unsigned char*)data, values.size()); +    XFlush( d->display );
+
+    delete[] data;
+
+    return true;
+}
+
diff --git a/src/common/x11inputdevice.h b/src/common/x11inputdevice.h
new file mode 100644
index 0000000..98c814d
--- /dev/null
+++ b/src/common/x11inputdevice.h
@@ -0,0 +1,204 @@
+/*
+ * Copyright 2012 Alexander Maret-Huskinson <alex@maret.de>
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef X11INPUTDEVICE_H
+#define X11INPUTDEVICE_H
+
+#include <QtCore/QString>
+#include <QtCore/QList>
+
+#include <QtGui/QX11Info>
+
+namespace Wacom
+{
+
+class X11InputDevicePrivate;
+
+class X11InputDevice
+{
+public:
+    /*
+     * Typedefs & Forward Declarations
+     */
+    typedef long unsigned int XID;
+    typedef long unsigned int Atom;
+
+    /* 
+     * We can not forward declare X11's' anonymous XDevice struct.
+     * To keep the header clean from includes we only need for private
+     * methods, we just define our own version of this struct.
+     */
+    struct XDevice;
+
+    /**
+     * Default Constructor
+     */
+    X11InputDevice();
+
+    /**
+     * Constructor which opens a device directly.
+     */
+    X11InputDevice (Display* dpy, XID xid);
+
+    virtual ~X11InputDevice();
+
+    /**
+     * Closes this device.
+     *
+     * @return True if the device was successfully closed, else false.
+     */
+    bool close();
+
+    /**
+     * Gets a float property.
+     *
+     * @param property  The property to get.
+     * @param nelements The maximum number of elements to get.
+     * @param values    A reference to a QList which will contain the values on \
success. +     *
+     * @return True if the property could be retrieved, else false.
+     */
+    bool getFloatProperty (const QString& property, long nelements, QList<float>& \
values); +
+    /**
+     * Gets a long property.
+     * 
+     * @param property  The property to get.
+     * @param nelements The maximum number of elements to get.
+     * @param values    A reference to a QList which will contain the values on \
success. +     *
+     * @return True if the property could be retrieved, else false.
+     */
+    bool getLongProperty (const QString& property, long nelements, QList<long>& \
values); +
+    /**
+     * Checks if this device has the given property. The device has to be open for
+     * this method to succeed.
+     *
+     * @return True if this device has the property, else false.
+     */
+    bool hasProperty (const QString& property);
+
+    /**
+     * Checks if the device is open.
+     *
+     * @return True if the device is open, else false.
+     */
+    bool isOpen() const;
+
+    /**
+     * Checks if this device is a tablet device.
+     *
+     * @return True if this device is a tablet device, else false.
+     */
+    bool isTabletDevice();
+
+    /**
+     * Opens a X11 device.
+     *
+     * @param dpy The X11 display to use.
+     * @param xid The X11 device identifier.
+     *
+     * @return True if the device was sucessfully opened, else false.
+     */
+    bool open (Display* dpy, XID xid);
+
+    /**
+     * Sets a float property. The values have to be separated by a single \
whitespace. +     *
+     * @param property The property to set.
+     * @param values   A string containing all values separated by a whitespace.
+     *
+     * @return True if the property could be set, else false.
+     */
+    bool setFloatProperty (const QString& property, const QString& values);
+
+    /**
+     * Sets a float property.
+     *
+     * @param propert The property to set.
+     * @param values  A list of values to set on this property.
+     *
+     * @return True if the property could be set, else false.
+     */
+    bool setFloatProperty (const QString& property, const QList<float>& values);
+
+    /**
+     * Sets a long property. The values have to be separated by a single whitespace.
+     *
+     * @param property The property to set.
+     * @param values   A string containing all values separated by a whitespace.
+     *
+     * @return True if the property could be set, else false.
+     */
+    bool setLongProperty (const QString& property, const QString& values);
+
+    /**
+     * Sets a long property.
+     *
+     * @param property The property to set.
+     * @param values   A list of values to set on this property.
+     *
+     * @return True if the property could be set, else false.
+     */
+    bool setLongProperty (const QString& property, const QList<long>& values);
+
+
+private:
+
+    /**
+     * A template method which fetches property values from this device.
+     *
+     * @param property     The property to get.
+     * @param expectedType The expected Xinput type of the property.
+     * @param nelements    The maximum number of elements to fetch.
+     * @param values       A reference to a list which will contain the values on \
success. +     *
+     * @return True if the property could be fetched, else false.
+     */
+    template<typename T>
+    bool getProperty (const QString& property, Atom expectedType, long nelements, \
QList< T >& values); +
+    /**
+     * Looks up a X11 property atom.
+     *
+     * @param property The property to lookup.
+     * @param atom     Pointer to an Atom which will contain the result.
+     *
+     * @return True if the property could be resolved, else false.
+     */
+    bool lookupProperty (const QString& property, Atom* atom);
+
+    /**
+     * A template method which sets a property on this device. The property has to \
exist already! +     *
+     * @param property     The property to set.
+     * @param expectedType The expected type of the property.
+     * @param values       The values to set on the property.
+     *
+     * @return True if the property could be set, else false.
+     */
+    template<typename T>
+    bool setProperty (const QString& property, Atom expectedType, const QList<T>& \
values); +
+
+    Q_DECLARE_PRIVATE(X11InputDevice)
+    X11InputDevicePrivate *const d_ptr;
+
+}; // CLASS
+}  // NAMESPACE
+#endif // HEADER PROTECTION
diff --git a/src/common/x11inputvisitor.h b/src/common/x11inputvisitor.h
new file mode 100644
index 0000000..337fbe0
--- /dev/null
+++ b/src/common/x11inputvisitor.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2012 Alexander Maret-Huskinson <alex@maret.de>
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef X11INPUTVISITOR_H
+#define X11INPUTVISITOR_H
+
+#include "x11inputdevice.h"
+
+namespace Wacom
+{
+class X11InputVisitor
+{
+public:
+    virtual ~X11InputVisitor() {};
+
+    /**
+     * Called by X11Input when iterating the X11 input devices.
+     *
+     * @return True to continue iteration, false to end current device scanning.
+     */
+    virtual bool visit(X11InputDevice& device) = 0;
+};
+}
+#endif


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic