Warning, file /plasma/wacomtablet/src/kded/x11tabletfinder.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /*
0002  * This file is part of the KDE wacomtablet project. For copyright
0003  * information and license terms see the AUTHORS and COPYING files
0004  * in the top-level directory of this distribution.
0005  *
0006  * This program is free software; you can redistribute it and/or
0007  * modify it under the terms of the GNU General Public License as
0008  * published by the Free Software Foundation; either version 2 of
0009  * the License, or (at your option) any later version.
0010  *
0011  * This program is distributed in the hope that it will be useful,
0012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0014  * GNU General Public License for more details.
0015  *
0016  * You should have received a copy of the GNU General Public License
0017  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
0018  */
0019 
0020 #include "x11tabletfinder.h"
0021 
0022 #include "deviceinformation.h"
0023 #include "logging.h"
0024 #include "x11input.h"
0025 
0026 #include <xcb/xcb.h>
0027 
0028 #include <QMap>
0029 #include <QString>
0030 
0031 #include "private/qtx11extras_p.h"
0032 
0033 using namespace Wacom;
0034 
0035 /**
0036  * Class for private members.
0037  */
0038 namespace Wacom
0039 {
0040 class X11TabletFinderPrivate
0041 {
0042 public:
0043     typedef QMap<long, TabletInformation> TabletMap;
0044 
0045     TabletMap tabletMap; //!< A map which is used while visiting devices.
0046     QList<TabletInformation> scannedList; //!< A list which is build after scanning all devices.
0047 };
0048 }
0049 
0050 X11TabletFinder::X11TabletFinder()
0051     : d_ptr(new X11TabletFinderPrivate)
0052 {
0053 }
0054 
0055 X11TabletFinder::~X11TabletFinder()
0056 {
0057     delete d_ptr;
0058 }
0059 
0060 const QList<TabletInformation> &X11TabletFinder::getTablets() const
0061 {
0062     Q_D(const X11TabletFinder);
0063 
0064     return d->scannedList;
0065 }
0066 
0067 bool X11TabletFinder::scanDevices()
0068 {
0069     Q_D(X11TabletFinder);
0070 
0071     d->tabletMap.clear();
0072     d->scannedList.clear();
0073 
0074     X11Input::scanDevices(*this);
0075 
0076     X11TabletFinderPrivate::TabletMap::ConstIterator iter;
0077 
0078     for (iter = d->tabletMap.constBegin(); iter != d->tabletMap.constEnd(); ++iter) {
0079         d->scannedList.append(iter.value());
0080     }
0081 
0082     return (d->tabletMap.size() > 0);
0083 }
0084 
0085 bool X11TabletFinder::visit(X11InputDevice &x11device)
0086 {
0087     if (!x11device.isTabletDevice()) {
0088         return false;
0089     }
0090 
0091     // gather basic device information which we need to create a device information structure
0092     QString deviceName = x11device.getName();
0093     const DeviceType *deviceType = getDeviceType(getToolType(x11device));
0094 
0095     if (deviceName.isEmpty() || deviceType == nullptr) {
0096         qCWarning(KDED) << QString::fromLatin1("Unsupported device '%1' detected!").arg(deviceName);
0097         return false;
0098     }
0099 
0100     // create device information and gather all information we can
0101     DeviceInformation deviceInfo(*deviceType, x11device.getName());
0102 
0103     gatherDeviceInformation(x11device, deviceInfo);
0104 
0105     // add device information to tablet map
0106     addDeviceInformation(deviceInfo);
0107 
0108     // true is only returned if device visiting should be aborted by X11Input
0109     return false;
0110 }
0111 
0112 void X11TabletFinder::addDeviceInformation(DeviceInformation &deviceInformation)
0113 {
0114     Q_D(X11TabletFinder);
0115 
0116     long serial = deviceInformation.getTabletSerial();
0117 
0118     if (serial < 1) {
0119         qCDebug(KDED) << QString::fromLatin1("Device '%1' has an invalid serial number '%2'!").arg(deviceInformation.getName()).arg(serial);
0120     }
0121 
0122     X11TabletFinderPrivate::TabletMap::iterator mapIter = d->tabletMap.find(serial);
0123 
0124     if (mapIter == d->tabletMap.end()) {
0125         auto newTabletInformation = TabletInformation(serial);
0126         // LibWacom needs CompanyId so set it too
0127         newTabletInformation.set(TabletInfo::CompanyId, QString::fromLatin1("%1").arg(deviceInformation.getVendorId(), 4, 16, QLatin1Char('0')).toUpper());
0128         mapIter = d->tabletMap.insert(serial, newTabletInformation);
0129     }
0130 
0131     mapIter.value().setDevice(deviceInformation);
0132 }
0133 
0134 void X11TabletFinder::gatherDeviceInformation(X11InputDevice &device, DeviceInformation &deviceInformation) const
0135 {
0136     // get X11 device id
0137     deviceInformation.setDeviceId(device.getDeviceId());
0138 
0139     // get tablet serial
0140     deviceInformation.setTabletSerial(getTabletSerial(device));
0141 
0142     // get product and vendor id if set
0143     long vendorId = 0, productId = 0;
0144 
0145     if (getProductId(device, vendorId, productId)) {
0146         deviceInformation.setVendorId(vendorId);
0147         deviceInformation.setProductId(productId);
0148     }
0149 
0150     // get the device node which is the full path to the input device
0151     deviceInformation.setDeviceNode(getDeviceNode(device));
0152 }
0153 
0154 const QString X11TabletFinder::getDeviceNode(X11InputDevice &device) const
0155 {
0156     QList<QString> values;
0157 
0158     if (!device.getStringProperty(X11Input::PROPERTY_DEVICE_NODE, values, 1000) || values.size() == 0) {
0159         qCDebug(KDED) << QString::fromLatin1("Could not get device node from device '%1'!").arg(device.getName());
0160         return QString();
0161     }
0162 
0163     return values.at(0);
0164 }
0165 
0166 const DeviceType *X11TabletFinder::getDeviceType(const QString &toolType) const
0167 {
0168     if (toolType.contains(QLatin1String("pad"), Qt::CaseInsensitive)) {
0169         return &(DeviceType::Pad);
0170 
0171     } else if (toolType.contains(QLatin1String("eraser"), Qt::CaseInsensitive)) {
0172         return &(DeviceType::Eraser);
0173 
0174     } else if (toolType.contains(QLatin1String("cursor"), Qt::CaseInsensitive)) {
0175         return &(DeviceType::Cursor);
0176 
0177     } else if (toolType.contains(QLatin1String("touch"), Qt::CaseInsensitive)) {
0178         return &(DeviceType::Touch);
0179 
0180     } else if (toolType.contains(QLatin1String("stylus"), Qt::CaseInsensitive)) {
0181         return &(DeviceType::Stylus);
0182     }
0183 
0184     return nullptr;
0185 }
0186 
0187 bool X11TabletFinder::getProductId(X11InputDevice &device, long int &vendorId, long int &productId) const
0188 {
0189     QList<long> values;
0190 
0191     if (!device.getLongProperty(X11Input::PROPERTY_DEVICE_PRODUCT_ID, values, 2)) {
0192         return false;
0193     }
0194 
0195     if (values.size() != 2) {
0196         qCWarning(KDED) << QString::fromLatin1("Unexpected number of values when fetching XInput property '%1'!").arg(X11Input::PROPERTY_DEVICE_PRODUCT_ID);
0197         return false;
0198     }
0199 
0200     long value;
0201 
0202     if ((value = values.at(0)) > 0) {
0203         vendorId = value;
0204     }
0205 
0206     if ((value = values.at(1)) > 0) {
0207         productId = value;
0208     }
0209 
0210     return true;
0211 }
0212 
0213 long int X11TabletFinder::getTabletSerial(X11InputDevice &device) const
0214 {
0215     long tabletId = 0;
0216     QList<long> serialIdValues;
0217 
0218     if (!device.getLongProperty(X11Input::PROPERTY_WACOM_SERIAL_IDS, serialIdValues, 1000)) {
0219         return tabletId;
0220     }
0221 
0222     // the offset for the tablet id is 0 see wacom-properties.h in the xf86-input-wacom driver for more information on this
0223     if (serialIdValues.size() > 0) {
0224         tabletId = serialIdValues.at(0);
0225 
0226         if (tabletId > 0) {
0227             return tabletId;
0228         }
0229     }
0230 
0231     return tabletId;
0232 }
0233 
0234 const QString X11TabletFinder::getToolType(X11InputDevice &device) const
0235 {
0236     QList<long> toolTypeAtoms;
0237 
0238     if (!device.getAtomProperty(X11Input::PROPERTY_WACOM_TOOL_TYPE, toolTypeAtoms)) {
0239         return QString();
0240     }
0241 
0242     QString toolTypeName;
0243 
0244     if (toolTypeAtoms.size() == 1) {
0245         xcb_get_atom_name_cookie_t cookie = xcb_get_atom_name(QX11Info::connection(), toolTypeAtoms.at(0));
0246         xcb_get_atom_name_reply_t *reply = xcb_get_atom_name_reply(QX11Info::connection(), cookie, nullptr);
0247         if (reply) {
0248             toolTypeName = QString::fromLatin1(QByteArray(xcb_get_atom_name_name(reply), xcb_get_atom_name_name_length(reply)));
0249             free(reply);
0250         }
0251     }
0252 
0253     return toolTypeName;
0254 }