diff --git a/src/common/buttonshortcut.cpp b/src/common/buttonshortcut.cpp index 3ad03fe..114b01d 100644 --- a/src/common/buttonshortcut.cpp +++ b/src/common/buttonshortcut.cpp @@ -1,560 +1,560 @@ /* * This file is part of the KDE wacomtablet project. For copyright * information and license terms see the AUTHORS and COPYING files * in the top-level directory of this distribution. * * 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 . */ // this include always needs to be the first one! #include "debug.h" #include "buttonshortcut.h" #include #include #include #include using namespace Wacom; /* * When mapping multiple keys to the same name, the last entry * will be the default one. This is because QMap.find() returns * the most recently added value as default. * * Example: * * super_l = meta * super = meta <-- default entry when searching for "meta" * */ const char* ButtonShortcut::CONVERT_KEY_MAP_DATA[][2] = { {"alt_l", "alt"}, {"alt_r", "alt"}, {"alt", "alt"}, // "alt" default {"ampersand", "&"}, {"apostrophe", "'"}, {"asciicircum", "^"}, {"asciitilde", "~"}, {"asterisk", "*"}, {"at", "@"}, {"backslash", "\\"}, {"bar", "|"}, {"braceleft", "{"}, {"braceright", "}"}, {"bracketleft", "["}, {"bracketright", "]"}, {"colon", ":"}, {"comma", ","}, {"ctrl_l", "ctrl"}, {"ctrl_r", "ctrl"}, {"ctrl", "ctrl"}, // "ctrl" default {"dollar", "$"}, {"equal", "="}, {"exclam", "!"}, {"greater", ">"}, {"less", "<"}, {"pgdn", "pgdown"}, {"numbersign", "#"}, {"period", "."}, {"plus", "+"}, {"minus", "-"}, {"parenleft", "("}, {"parenright", ")"}, {"percent", "%"}, {"question", "?"}, {"quotedbl", "\""}, {"quoteleft", "`"}, {"semicolon", ";"}, {"slash", "/"}, {"super_l", "meta"}, {"super_r", "meta"}, {"super", "meta"}, // "super" default {"underscore", "_"}, - {NULL, NULL} + {nullptr, nullptr} }; namespace Wacom { class ButtonShortcutPrivate { public: ButtonShortcutPrivate() { type = ButtonShortcut::NONE; button = 0; } ButtonShortcut::ShortcutType type; //!< The shortcut type. QString sequence; //!< The key or modifier sequence. int button; //!< The button number. }; } ButtonShortcut::ButtonShortcut() : d_ptr(new ButtonShortcutPrivate) { } ButtonShortcut::ButtonShortcut(const ButtonShortcut& that) : d_ptr(new ButtonShortcutPrivate) { operator=(that); } ButtonShortcut::ButtonShortcut(const QString& shortcut) : d_ptr(new ButtonShortcutPrivate) { set(shortcut); } ButtonShortcut::ButtonShortcut(int buttonNumber) : d_ptr(new ButtonShortcutPrivate) { setButton(buttonNumber); } ButtonShortcut::~ButtonShortcut() { delete this->d_ptr; } ButtonShortcut& ButtonShortcut::operator=(const ButtonShortcut& that) { Q_D ( ButtonShortcut ); *d = *(that.d_ptr); return *this; } ButtonShortcut& ButtonShortcut::operator=(const QString& shortcut) { set(shortcut); return *this; } bool ButtonShortcut::operator==(const ButtonShortcut& that) const { Q_D ( const ButtonShortcut ); if ( d->type != that.d_ptr->type ) { return false; } if ( d->button != that.d_ptr->button ) { return false; } if ( d->sequence.compare(that.d_ptr->sequence, Qt::CaseInsensitive) != 0 ) { return false; } return true; } bool ButtonShortcut::operator!=(const ButtonShortcut& that) const { return (!operator==(that)); } void ButtonShortcut::clear() { Q_D ( ButtonShortcut ); d->type = ButtonShortcut::NONE; d->button = 0; d->sequence.clear(); } int ButtonShortcut::getButton() const { Q_D (const ButtonShortcut); return d->button; } ButtonShortcut::ShortcutType ButtonShortcut::getType() const { Q_D( const ButtonShortcut ); return d->type; } bool ButtonShortcut::isButton() const { return (getType() == BUTTON); } bool ButtonShortcut::isKeystroke() const { return (getType() == KEYSTROKE); } bool ButtonShortcut::isModifier() const { return (getType() == MODIFIER); } bool ButtonShortcut::isSet() const { return (getType() != NONE); } bool ButtonShortcut::setButton(int buttonNumber) { Q_D ( ButtonShortcut ); clear(); if (buttonNumber > 0 && buttonNumber <= 32) { d->type = ButtonShortcut::BUTTON; d->button = buttonNumber; return true; } return false; } bool ButtonShortcut::set(const QString& sequence) { clear(); QString seq = sequence.trimmed(); if (seq.isEmpty()) { return true; } QRegExp modifierRx (QLatin1String("^(?:key )?(?:\\s*\\+?(?:alt|ctrl|meta|shift|super))+$"), Qt::CaseInsensitive); QRegExp buttonRx (QLatin1String ("^(?:button\\s+)?\\+?\\d+$"), Qt::CaseInsensitive); if (seq.contains(buttonRx)) { // this is a button return setButtonSequence(seq); } else if (seq.contains(modifierRx)) { // this is a modifier sequence return setModifierSequence(seq); } // this is probably a key sequence return setKeySequence(seq); } const QString ButtonShortcut::toDisplayString() const { Q_D (const ButtonShortcut); QList< KGlobalShortcutInfo > globalShortcutList; QString displayString; int buttonNr = getButton(); switch (d->type) { case BUTTON: if (buttonNr == 1) { displayString = i18nc("Tablet button triggers a left mouse button click.", "Left Mouse Button Click"); } else if (buttonNr == 2) { displayString = i18nc("Tablet button triggers a middle mouse button click.", "Middle Mouse Button Click"); } else if (buttonNr == 3) { displayString = i18nc("Tablet button triggers a right mouse button click.", "Right Mouse Button Click"); } else if (buttonNr == 4) { displayString = i18nc("Tablet button triggers mouse wheel up.", "Mouse Wheel Up"); } else if (buttonNr == 5) { displayString = i18nc("Tablet button triggers mouse wheel down.", "Mouse Wheel Down"); } else { displayString = i18nc("Tablet button triggers a click of mouse button with number #", "Mouse Button %1 Click", buttonNr); } break; case MODIFIER: displayString = d->sequence; convertKeySequenceToQKeySequenceFormat(displayString); break; case KEYSTROKE: displayString = d->sequence; convertKeySequenceToQKeySequenceFormat(displayString); // check if a global shortcut is assigned to this sequence globalShortcutList = KGlobalAccel::getGlobalShortcutsByKey(QKeySequence(displayString)); if(!globalShortcutList.isEmpty()) { displayString = globalShortcutList.at(0).uniqueName(); } break; case NONE: break; default: dbgWacom << QString::fromLatin1("INTERNAL ERROR: Invalid type '%1' detected in ButtonShortcut!").arg(d->type); } return displayString; } const QString ButtonShortcut::toQKeySequenceString() const { Q_D (const ButtonShortcut); QString keySequence; if (d->type == KEYSTROKE) { keySequence = d->sequence; convertKeySequenceToQKeySequenceFormat(keySequence); } return keySequence; } const QString ButtonShortcut::toString() const { Q_D (const ButtonShortcut); QString shortcutString = QLatin1String("0"); switch (d->type) { case BUTTON: shortcutString = QString::number(d->button); break; case MODIFIER: case KEYSTROKE: shortcutString = QString::fromLatin1("key %2").arg(d->sequence); break; case NONE: break; default: dbgWacom << QString::fromLatin1("INTERNAL ERROR: Invalid type '%1' detected in ButtonShortcut!").arg(d->type); } return shortcutString.toLower(); } bool ButtonShortcut::convertKey(QString& key, bool fromStorage) const { QMap::ConstIterator iter; QMap::ConstIterator iterEnd; if (fromStorage) { iter = getConvertFromStorageMap().find(key.toLower()); iterEnd = getConvertFromStorageMap().constEnd(); } else { iter = getConvertToStorageMap().find(key.toLower()); iterEnd = getConvertToStorageMap().constEnd(); } if (iter == iterEnd) { return false; } key = iter.value(); return true; } void ButtonShortcut::convertToNormalizedKeySequence(QString& sequence, bool fromStorage) const { normalizeKeySequence(sequence); QStringList keyList = sequence.split (QRegExp (QLatin1String ("\\s+")), QString::SkipEmptyParts); bool isFirstKey = true; sequence.clear(); for (QStringList::iterator iter = keyList.begin() ; iter != keyList.end() ; ++iter) { convertKey (*iter, fromStorage); prettifyKey (*iter); if (isFirstKey) { sequence.append(*iter); isFirstKey = false; } else { sequence.append(QString::fromLatin1(" %1").arg(*iter)); } } } void ButtonShortcut::convertKeySequenceToStorageFormat(QString& sequence) const { convertToNormalizedKeySequence(sequence, false); } void ButtonShortcut::convertKeySequenceToQKeySequenceFormat(QString& sequence) const { convertToNormalizedKeySequence(sequence, true); sequence.replace(QLatin1String(" "), QLatin1String("+")); } const QMap< QString, QString >& ButtonShortcut::getConvertFromStorageMap() { static QMap map = initConversionMap(true); return map; } const QMap< QString, QString >& ButtonShortcut::getConvertToStorageMap() { static QMap map = initConversionMap(false); return map; } QMap< QString, QString > ButtonShortcut::initConversionMap(bool fromStorageMap) { QMap map; for (int i = 0 ; ; ++i) { - if (CONVERT_KEY_MAP_DATA[i][0] == NULL || CONVERT_KEY_MAP_DATA[i][1] == NULL) { + if (CONVERT_KEY_MAP_DATA[i][0] == nullptr || CONVERT_KEY_MAP_DATA[i][1] == nullptr) { return map; } if (fromStorageMap) { map.insert(QLatin1String(CONVERT_KEY_MAP_DATA[i][0]), QLatin1String(CONVERT_KEY_MAP_DATA[i][1])); } else { map.insert(QLatin1String(CONVERT_KEY_MAP_DATA[i][1]), QLatin1String(CONVERT_KEY_MAP_DATA[i][0])); } } return map; } void ButtonShortcut::normalizeKeySequence(QString& sequence) const { // When setting a shortcut like "ctrl+x", xsetwacom will convert it to "key +ctrl +x -x" // therefore we just truncate the string on the first "-key" we find. QRegExp minusKeyRx (QLatin1String ("(^|\\s)-\\S")); int pos = 0; if ((pos = minusKeyRx.indexIn(sequence, 0)) != -1) { sequence = sequence.left(pos); } // cleanup leading "key " identifier from xsetwacom sequences sequence.remove(QRegExp (QLatin1String ("^\\s*key\\s+"), Qt::CaseInsensitive)); // Remove all '+' prefixes from keys. // This will convert shortcuts like "+ctrl +alt" to "ctrl alt", but not // shortcuts like "ctrl +" which is required to keep compatibility to older // (buggy) configuration files. sequence.replace(QRegExp (QLatin1String ("(^|\\s)\\+(\\S)")), QLatin1String ("\\1\\2")); // Cleanup plus signs between keys. // This will convert shortcuts like "ctrl+alt+shift" or "Ctrl++" to "ctrl alt shift" or "Ctrl +". sequence.replace (QRegExp (QLatin1String ("(\\S)\\+(\\S)")), QLatin1String ("\\1 \\2")); // replace multiple whitespaces with one sequence.replace (QRegExp (QLatin1String ("\\s{2,}")), QLatin1String (" ")); // trim the string sequence = sequence.trimmed(); } void ButtonShortcut::prettifyKey(QString& key) const { if (!key.isEmpty()) { key = key.toLower(); key[0] = key.at(0).toUpper(); } } bool ButtonShortcut::setButtonSequence(const QString& buttonSequence) { QString buttonNumber = buttonSequence; buttonNumber.remove(QRegExp (QLatin1String ("^\\s*button\\s+"), Qt::CaseInsensitive)); bool ok = false; int button = buttonNumber.toInt(&ok); if (!ok) { return false; } return setButton(button); } bool ButtonShortcut::setKeySequence(QString sequence) { Q_D (ButtonShortcut); clear(); // Check if this keysequence is valid by converting it to a QKeySequence and then back // again. If both sequences are equal the sequence should be valid. This is not very // effective but it leaves us with something KDE can handle and it makes sure a key // is always converted to its default key name if there are multiple mappings. // TODO improve this QString convertedSequence = sequence; convertKeySequenceToQKeySequenceFormat(convertedSequence); QKeySequence qkeySequence(convertedSequence); convertedSequence = qkeySequence.toString(); convertKeySequenceToStorageFormat(convertedSequence); convertKeySequenceToStorageFormat(sequence); // we do not allow invalid sequences to be set // the sequences have to be equal and only one sequence is allowed if (sequence.compare(convertedSequence, Qt::CaseInsensitive) != 0 || qkeySequence.count() != 1) { return false; } d->type = ButtonShortcut::KEYSTROKE; d->sequence = sequence; return true; } bool ButtonShortcut::setModifierSequence(QString sequence) { Q_D (ButtonShortcut); clear(); convertKeySequenceToStorageFormat(sequence); d->type = ButtonShortcut::MODIFIER; d->sequence = sequence; return true; } diff --git a/src/common/configadaptor.h b/src/common/configadaptor.h index f7209ac..502b658 100644 --- a/src/common/configadaptor.h +++ b/src/common/configadaptor.h @@ -1,77 +1,77 @@ /* * This file is part of the KDE wacomtablet project. For copyright * information and license terms see the AUTHORS and COPYING files * in the top-level directory of this distribution. * * 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 . */ #ifndef CONFIGADAPTOR_H #define CONFIGADAPTOR_H #include "propertyadaptor.h" #include namespace Wacom { /** * The interface for configuration adpaters. * * These adaptors support direct reading and writing of KDE config groups as * well as property mapping between configuration file keys and config or * system properties. In case of a general adapter, an adaptee can be provided * where all configuration properties will be read from. */ class ConfigAdaptor : public PropertyAdaptor { public: /** * Default constructor. * * @param adaptee The property adapter where all properties are read from (possibly NULL). */ - explicit ConfigAdaptor(PropertyAdaptor* adaptee) : PropertyAdaptor(adaptee) {}; + explicit ConfigAdaptor(PropertyAdaptor* adaptee) : PropertyAdaptor(adaptee) {} /** * Default destructor */ - virtual ~ConfigAdaptor() {}; + virtual ~ConfigAdaptor() {} /** * Loads a config from the given config group. The default implementation * does nothing and always returns false. * * @param config The configuration group to load the configuration from. * * @return True on success, false on error. */ virtual bool loadConfig( const KConfigGroup& config ) = 0; /** * Save the configuration to a config group. The default implementation * does nothing and always returns false. * * @param config The configuration group to save to configuration in. * * @return True on success, false on error. */ virtual bool saveConfig( KConfigGroup& config ) const = 0; }; // CLASS } // NAMESPACE #endif // HEADER PROTECTION diff --git a/src/common/deviceprofile.cpp b/src/common/deviceprofile.cpp index 5603cd2..c98eef3 100644 --- a/src/common/deviceprofile.cpp +++ b/src/common/deviceprofile.cpp @@ -1,255 +1,255 @@ /* * This file is part of the KDE wacomtablet project. For copyright * information and license terms see the AUTHORS and COPYING files * in the top-level directory of this distribution. * * 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 . */ #include "deviceprofile.h" #include "property.h" #include "deviceproperty.h" #include using namespace Wacom; namespace Wacom { /** * Private class of the DeviceProfile for the d-pointer * */ class DeviceProfilePrivate { public: QString deviceType; /** * Stores most of the configuration properties. In the future * more and more properties might get switched to real member * variables but for now this is the most convenient way. */ QHash config; }; } -DeviceProfile::DeviceProfile() : PropertyAdaptor(NULL), d_ptr(new DeviceProfilePrivate) { } +DeviceProfile::DeviceProfile() : PropertyAdaptor(nullptr), d_ptr(new DeviceProfilePrivate) { } DeviceProfile::DeviceProfile(const DeviceType& type) - : PropertyAdaptor(NULL), d_ptr(new DeviceProfilePrivate) + : PropertyAdaptor(nullptr), d_ptr(new DeviceProfilePrivate) { setDeviceType(type); } DeviceProfile::DeviceProfile(const DeviceProfile& profile) - : PropertyAdaptor(NULL), d_ptr(new DeviceProfilePrivate) + : PropertyAdaptor(nullptr), d_ptr(new DeviceProfilePrivate) { operator=(profile); } DeviceProfile::~DeviceProfile() { delete this->d_ptr; } DeviceProfile& DeviceProfile::operator= ( const DeviceProfile& that ) { Q_D( DeviceProfile ); d->deviceType = that.d_ptr->deviceType; d->config = that.d_ptr->config; return *this; } const QString DeviceProfile::getButton(int number) const { switch(number) { case 1: return getProperty(Property::Button1); case 2: return getProperty(Property::Button2); case 3: return getProperty(Property::Button3); case 4: return getProperty(Property::Button4); case 5: return getProperty(Property::Button5); case 6: return getProperty(Property::Button6); case 7: return getProperty(Property::Button7); case 8: return getProperty(Property::Button8); case 9: return getProperty(Property::Button9); case 10: return getProperty(Property::Button10); case 11: return getProperty(Property::Button11); case 12: return getProperty(Property::Button12); case 13: return getProperty(Property::Button13); case 14: return getProperty(Property::Button14); case 15: return getProperty(Property::Button15); case 16: return getProperty(Property::Button16); case 17: return getProperty(Property::Button17); case 18: return getProperty(Property::Button18); default: errWacom << QString::fromLatin1("Unsupported button number '%1'!").arg(number); } return QString(); } const QString DeviceProfile::getDeviceType() const { return getName(); } const QString& DeviceProfile::getName() const { Q_D( const DeviceProfile ); return d->deviceType; } const QString DeviceProfile::getProperty(const Property& property) const { Q_D( const DeviceProfile ); return d->config.value(property.key()); } const QList DeviceProfile::getProperties() const { return DeviceProperty::ids(); } bool DeviceProfile::setButton(int number, const QString& shortcut) { switch(number) { case 1: setProperty(Property::Button1, shortcut); break; case 2: setProperty(Property::Button2, shortcut); break; case 3: setProperty(Property::Button3, shortcut); break; case 4: setProperty(Property::Button4, shortcut); break; case 5: setProperty(Property::Button5, shortcut); break; case 6: setProperty(Property::Button6, shortcut); break; case 7: setProperty(Property::Button7, shortcut); break; case 8: setProperty(Property::Button8, shortcut); break; case 9: setProperty(Property::Button9, shortcut); break; case 10: setProperty(Property::Button10, shortcut); break; case 11: setProperty(Property::Button11, shortcut); break; case 12: setProperty(Property::Button12, shortcut); break; case 13: setProperty(Property::Button13, shortcut); break; case 14: setProperty(Property::Button14, shortcut); break; case 15: setProperty(Property::Button15, shortcut); break; case 16: setProperty(Property::Button16, shortcut); break; case 17: setProperty(Property::Button17, shortcut); break; case 18: setProperty(Property::Button18, shortcut); break; default: errWacom << QString::fromLatin1("Unsupported button number '%1'!").arg(number); return false; } return true; } void DeviceProfile::setDeviceType(const DeviceType& type) { Q_D( DeviceProfile ); d->deviceType = type.key(); } bool DeviceProfile::setProperty(const Property& property, const QString& value) { Q_D( DeviceProfile ); if (!supportsProperty(property)) { return false; } if (value.isEmpty()) { d->config.remove(property.key()); } else { d->config.insert(property.key(), value); } return true; } bool DeviceProfile::supportsProperty(const Property& property) const { - return (DeviceProperty::map(property) != NULL); + return (DeviceProperty::map(property) != nullptr); } diff --git a/src/common/enum.h b/src/common/enum.h index 162b6e8..5666c3b 100644 --- a/src/common/enum.h +++ b/src/common/enum.h @@ -1,248 +1,248 @@ /* * This file is part of the KDE wacomtablet project. For copyright * information and license terms see the AUTHORS and COPYING files * in the top-level directory of this distribution. * * 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 . */ #ifndef ENUM_H #define ENUM_H #include namespace Wacom { /** * A typesafe enumeration template class. It can be used as a comfortable replacement * for C++ enums and supports the following features: * * - enumerators can be listed and iterated over * - enumerator lists are sorted by a given comparator * - enumerators can have a key assigned * - enumerator keys can be listed and searched for * * NOTICE * This class uses template specialization to store a static set of all instances. * Thereofore a specialization of the private instances member 'instances' has * to be declared and instanciated before this template can be used. * * \tparam D The derived sub class type. This is the class which contains the enum instances. * \tparam K The key type used for these instances. * \tparam L A "less than" functor which can compare objects of type D*. * \tparam E A "equal to" functor which can compare objects of type K. */ template< class D, class K, class L, class E > class Enum { private: typedef QList Container; typedef typename Container::const_iterator ContainerConstIterator; public: typedef typename Container::size_type size_type; /** * A constant iterator which can be used to iterator over all known Enum instances. */ class const_iterator { public: const_iterator() {} const_iterator(const const_iterator& iter) { operator=(iter); } const_iterator(const ContainerConstIterator& iter) { m_iter = iter; } const D& operator*() const { return **m_iter; } const D* operator->() const { return *m_iter; } const_iterator& operator= (const const_iterator& iter) { m_iter = iter.m_iter; return *this; } bool operator==(const const_iterator& iter) const { return (m_iter == iter.m_iter); } bool operator!=(const const_iterator& iter) const { return (m_iter != iter.m_iter); } const_iterator& operator++() { ++m_iter; return *this; } const_iterator operator++(int) { const_iterator copy(*this); ++(*this); return copy; } const_iterator& operator--() { --m_iter; return *this; } const_iterator operator--(int) { const_iterator copy(*this); --(*this); return copy; } private: ContainerConstIterator m_iter; }; /** * Equal-Compare Operator. */ bool operator==(const Enum& that) const { return (m_derived == that.m_derived); } /** * Not-Equal-Compare Operator. */ bool operator!=(const Enum& that) const { return (m_derived != that.m_derived); } /** * @return A constant iterator to the first element. */ static const_iterator begin() { // force the use of const_iterator - fixes compile problem with some containers const Enum::Container* container = &Enum::instances; return const_iterator(container->begin()); } /** * @return A constant iterator to the last element. */ static const_iterator end() { // force the use of const_iterator - fixes compile problem with some containers const Enum::Container* container = &Enum::instances; return const_iterator(container->end()); } /** * Searches for the enumeration instance by key. * * @param key The key of the instance to search. * - * @return A constant pointer to the instance or NULL if not found. + * @return A constant pointer to the instance or nullptr if not found. */ static const D* find(const K& key) { E comp; for (const_iterator i = begin() ; i != end() ; ++i) { if (comp(i->key(), key)) { return &(*i); } } - return NULL; + return nullptr; } /** * @return A list of all valid enum instances of this specialization. */ static QList list() { QList enums; for (const_iterator i = begin() ; i != end() ; ++i) { enums.push_back(*i); } return enums; } /** * @return The key of this enum instance. */ const K& key() const { return m_key; } /** * Returns a list of all instances' keys of this specialization. * * @return A list of keys sorted by the less-than-functor. */ static QList keys() { QList keys; for (const_iterator i = begin() ; i != end() ; ++i) { keys.push_back(i->key()); } return keys; } /** * @return The number of enum instances of this specialization. */ static size_type size() { return Enum::instances.size(); } protected: /** * Initialization constructor. * Used to initialize class-static members. Never make this constructor * available to the public! Never use it for normal instances! It may * only be used to instanciate class-static Enum instances. * * @param key The key of this class-static Enum instance. * @param priority The sort order priority of this instance. */ explicit Enum( const D* derived, const K& key ) : m_key(key) { m_derived = derived; insert(derived); } /** * \return A const pointer to the derived class of this instance. */ const D* derived() const { return m_derived; } private: /** * Inserts an element into to the static instances container. * This method should only be called by the constructor! * * \param derived An instance of the derived class, never NULL. */ void insert(const D* derived) { L comp; typename Enum::Container::iterator i = this->instances.begin(); for (; i != this->instances.end() ; ++i) { if (comp(derived, *i)) { this->instances.insert(i, derived); return; } } this->instances.push_back(derived); } K m_key; /**< The key of this instance */ const D* m_derived; /**< Pointer to derived class for fast comparison */ /** * A static container with all the class-static Enum instances. * Every specialization of this template has to declare and instanciate * the specialization of this member variable! */ static Container instances; }; // CLASS } // NAMESPACE #endif // HEADER PROTECTION diff --git a/src/common/propertyadaptor.cpp b/src/common/propertyadaptor.cpp index 8d7d0ad..3cd12c4 100644 --- a/src/common/propertyadaptor.cpp +++ b/src/common/propertyadaptor.cpp @@ -1,130 +1,129 @@ /* * This file is part of the KDE wacomtablet project. For copyright * information and license terms see the AUTHORS and COPYING files * in the top-level directory of this distribution. * * 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 . */ #include "debug.h" // always needs to be first include #include "propertyadaptor.h" #include "stringutils.h" using namespace Wacom; namespace Wacom { /** * Private class for the d-pointer */ class PropertyAdaptorPrivate { public: - PropertyAdaptor* adaptee; + PropertyAdaptor *adaptee = nullptr; }; } PropertyAdaptor::PropertyAdaptor() : d_ptr(new PropertyAdaptorPrivate) { - Q_D( PropertyAdaptor ); - d->adaptee = NULL; + } PropertyAdaptor::PropertyAdaptor(PropertyAdaptor* adaptee) : d_ptr(new PropertyAdaptorPrivate) { Q_D( PropertyAdaptor ); d->adaptee = adaptee; } PropertyAdaptor::~PropertyAdaptor() { delete this->d_ptr; } const QList PropertyAdaptor::getProperties() const { Q_D( const PropertyAdaptor ); - if (d->adaptee != NULL) { + if (d->adaptee) { return d->adaptee->getProperties(); } errWacom << QString::fromLatin1("Someone is trying to get a list of properties, but no one implemented PropertyAdaptor::getProperties()!"); return QList(); } const QString PropertyAdaptor::getProperty ( const Property& property ) const { Q_D( const PropertyAdaptor ); - if (d->adaptee != NULL) { + if (d->adaptee) { return d->adaptee->getProperty(property); } errWacom << QString::fromLatin1("Someone is trying to get property '%1', but no one implemented PropertyAdaptor::getProperty()!").arg(property.key()); return QString(); } bool PropertyAdaptor::getPropertyAsBool(const Property& property) const { return StringUtils::asBool(getProperty(property)); } bool PropertyAdaptor::setProperty ( const Property& property, const QString& value ) { Q_D( PropertyAdaptor ); - if (d->adaptee != NULL) { + if (d->adaptee) { return d->adaptee->setProperty(property, value); } errWacom << QString::fromLatin1("Someone is trying to set property '%1' to '%2', but no one implemented PropertyAdaptor::setProperty()!").arg(property.key()).arg(value); return false; } bool PropertyAdaptor::supportsProperty ( const Property& property ) const { Q_D( const PropertyAdaptor ); - if (d->adaptee != NULL) { + if (d->adaptee) { return d->adaptee->supportsProperty(property); } QList props = getProperties(); foreach(const Property& prop, props) { if(property == prop) { return true; } } return false; } PropertyAdaptor* PropertyAdaptor::getAdaptee() { Q_D( PropertyAdaptor ); return d->adaptee; } const PropertyAdaptor* PropertyAdaptor::getAdaptee() const { Q_D( const PropertyAdaptor ); return d->adaptee; } diff --git a/src/common/propertyset.h b/src/common/propertyset.h index 3cbc62a..146fdc6 100644 --- a/src/common/propertyset.h +++ b/src/common/propertyset.h @@ -1,139 +1,139 @@ /* * This file is part of the KDE wacomtablet project. For copyright * information and license terms see the AUTHORS and COPYING files * in the top-level directory of this distribution. * * 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 . */ #ifndef PROPERTYSET_H #define PROPERTYSET_H #include "debug.h" // this include has to come first! #include "enum.h" #include "property.h" #include #include #include #include namespace Wacom { template struct PropertySetTemplateSpecializationLessFunctor { bool operator()(const D* d1, const D* d2) { Q_UNUSED(d1); Q_UNUSED(d2); if ((d1 == d2) || !(d1->key().compare(d2->key(), Qt::CaseInsensitive))) { errWacom << "Adding the same key or the same element is a severe error"; } // property sets should keep the order they were defined return false; } }; /** * A typesafe property enumeration template class. It manages property keys, * mapping ids and priority handling for different kind of property sets. * * Different subsystems have different type of property sets and different * property identifier keys. Moreover properties have to be set in a specific * order or they might overwrite each other. Still all these property sets * have to be mapped on subsystem borders. * * NOTICE * This class uses template specialization to store a static set of all instances. * Thereofore a specialization of the private instances member 'm_instances' has * to be declared and instanciated before this template can be used. */ template, class E = PropertyKeyEqualsFunctor> class PropertySet : public Enum { public: // typedef for easy maintenance // this has to be the same as the specialization of our base class typedef Enum PropertySetTemplateSpecialization; /** * Maps the given property to an instance of this property set. * * @param id The property id to search for. * - * @return A constant pointer to the property or NULL if the property is not supported by this set. + * @return A constant pointer to the property or nullptr if the property is not supported by this set. */ static const D* map (const Property& property) { typename PropertySetTemplateSpecialization::const_iterator i = PropertySetTemplateSpecialization::begin(); for ( ; i != PropertySetTemplateSpecialization::end() ; ++i) { if (i->id() == property) { return &(*i); } } - return NULL; + return nullptr; } /** * @return The property identifier of this property instance. */ const Property& id() const { return *m_id; } /** * @return A list of property ids supported by this set. */ static QList ids() { QList ids; for (typename PropertySetTemplateSpecialization::const_iterator i = PropertySetTemplateSpecialization::begin() ; i != PropertySetTemplateSpecialization::end() ; ++i) { ids.push_back(i->id()); } return ids; } protected: /** * Initialization constructor. * Used to initialize class-static members. Never make this constructor * available to the public! It is only used to instanciate class-static * PropertySet instances. * * @param key The key of this class-static PropertySet instance. */ explicit PropertySet( const D* super, const Property& id, const QString& key ) : PropertySetTemplateSpecialization(super, key) { m_id = &id; } private: const Property* m_id; /**< The property identifier used to map between different property sets */ }; // CLASS } // NAMESPACE #endif // HEADER PROTECTION diff --git a/src/common/tabletinformation.cpp b/src/common/tabletinformation.cpp index ccfb053..939afe8 100644 --- a/src/common/tabletinformation.cpp +++ b/src/common/tabletinformation.cpp @@ -1,413 +1,413 @@ /* * This file is part of the KDE wacomtablet project. For copyright * information and license terms see the AUTHORS and COPYING files * in the top-level directory of this distribution. * * 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 . */ #include "tabletinformation.h" #include "debug.h" #include "stringutils.h" namespace Wacom { class TabletInformationPrivate { public: /* * Declarations */ typedef QMap DeviceInformationMap; typedef QMap TabletInfoMap; /* * Members */ QString unknown; //!< An empty string which allows us to return a const reference. QMap buttonMap; DeviceInformationMap deviceMap; TabletInfoMap infoMap; bool isAvailable; bool hasButtons; /* * Helper methods */ TabletInformationPrivate() { isAvailable = false; hasButtons = false; } TabletInformationPrivate& operator= (const TabletInformationPrivate& that) { buttonMap = that.buttonMap; deviceMap = that.deviceMap; infoMap = that.infoMap; isAvailable = that.isAvailable; hasButtons = that.hasButtons; return *this; } bool operator== (const TabletInformationPrivate& that) const { // we don't care if the device is available or not // we also don't care about the button map if (hasButtons != that.hasButtons || infoMap.size() != that.infoMap.size() || deviceMap.size() != that.deviceMap.size() ) { return false; } // QMap is always ordered by key so we can just iterate over it and compare keys directly TabletInfoMap::const_iterator thisInfoIter = infoMap.constBegin(); TabletInfoMap::const_iterator thatInfoIter = that.infoMap.constBegin(); while (thatInfoIter != infoMap.constEnd() && thatInfoIter != that.infoMap.constEnd()) { if (thisInfoIter.key().compare(thatInfoIter.key(), Qt::CaseInsensitive) != 0) { return false; } if (thisInfoIter.value().compare(thatInfoIter.value(), Qt::CaseInsensitive) != 0) { return false; } ++thisInfoIter; ++thatInfoIter; } DeviceInformationMap::const_iterator thisDevIter = deviceMap.constBegin(); DeviceInformationMap::const_iterator thatDevIter = that.deviceMap.constBegin(); while (thisDevIter != deviceMap.constEnd() && thatDevIter != that.deviceMap.constEnd()) { if (thisDevIter.key().compare(thatDevIter.key(), Qt::CaseInsensitive) != 0) { return false; } if (thisDevIter.value() != thatDevIter.value()) { return false; } ++thisDevIter; ++thatDevIter; } return true; } }; // CLASS TabletInformationPrivate } // NAMESPACE Wacom using namespace Wacom; TabletInformation::TabletInformation() : d_ptr(new TabletInformationPrivate) { d_ptr->unknown.clear(); } TabletInformation::TabletInformation(long int tabletSerial) : d_ptr(new TabletInformationPrivate) { set(TabletInfo::TabletSerial, QString::number(tabletSerial)); d_ptr->unknown.clear(); } TabletInformation::TabletInformation(const TabletInformation& that) : d_ptr(new TabletInformationPrivate) { operator=(that); } TabletInformation::~TabletInformation() { delete d_ptr; } TabletInformation& TabletInformation::operator=(const TabletInformation& that) { Q_D(TabletInformation); d->operator= (*(that.d_ptr)); return *this; } bool TabletInformation::operator!= (const TabletInformation& other) const { return !operator== (other); } bool TabletInformation::operator== (const TabletInformation& other) const { Q_D (const TabletInformation); return other.d_ptr != nullptr && d->operator== (*(other.d_ptr)); } const QString& TabletInformation::get (const TabletInfo& info) const { Q_D (const TabletInformation); TabletInformationPrivate::TabletInfoMap::const_iterator iter = d->infoMap.constFind(info.key()); if (iter == d->infoMap.constEnd()) { return d->unknown; } return iter.value(); } bool TabletInformation::getBool(const TabletInfo& info) const { return (StringUtils::asBool (get (info))); } int TabletInformation::getInt(const TabletInfo& info) const { return (get(info).toInt()); } const QMap< QString, QString >& TabletInformation::getButtonMap() const { Q_D (const TabletInformation); return d->buttonMap; } const DeviceInformation* TabletInformation::getDevice (const DeviceType& deviceType) const { Q_D (const TabletInformation); TabletInformationPrivate::DeviceInformationMap::ConstIterator iter = d->deviceMap.constFind(deviceType.key()); if (iter == d->deviceMap.constEnd()) { - return NULL; + return nullptr; } return &(iter.value()); } const QStringList TabletInformation::getDeviceList() const { QString device; QStringList deviceList; foreach (const DeviceType& type, DeviceType::list()) { device = getDeviceName(type); if (!device.isEmpty()) { deviceList.append(device); } } return deviceList; } const QString& TabletInformation::getDeviceName (const DeviceType& device) const { Q_D(const TabletInformation); TabletInformationPrivate::DeviceInformationMap::ConstIterator iter = d->deviceMap.find(device.key()); if (iter == d->deviceMap.constEnd()) { return d->unknown; } return iter->getName(); } long int TabletInformation::getTabletSerial() const { return get (TabletInfo::TabletSerial).toLong(); } bool TabletInformation::hasButtons() const { if (getBool (TabletInfo::HasLeftTouchStrip) || getBool (TabletInfo::HasRightTouchStrip) || getBool (TabletInfo::HasTouchRing) || getBool (TabletInfo::HasWheel) || getInt (TabletInfo::NumPadButtons) > 0) { return true; } return false; } bool TabletInformation::hasButtonMap() const { Q_D (const TabletInformation); return (d->buttonMap.size() > 0); } bool TabletInformation::hasDevice(int deviceId) const { foreach (const DeviceType& type, DeviceType::list()) { const DeviceInformation* device = getDevice(type); - if (device != NULL && device->getDeviceId() == deviceId) { + if (device && device->getDeviceId() == deviceId) { return true; } } return false; } bool TabletInformation::hasDevice (const DeviceType& device) const { Q_D(const TabletInformation); return d->deviceMap.contains(device.key()); } int TabletInformation::statusLEDs() const { return getInt(TabletInfo::StatusLEDs); } bool TabletInformation::isAvailable() const { Q_D(const TabletInformation); return d->isAvailable; } void TabletInformation::set (const TabletInfo& info, const QString& value) { Q_D (TabletInformation); // setting the tablet serial requires updating the id for now if (info == TabletInfo::TabletSerial) { long serial = value.toLong(); if (serial > 0) { set (TabletInfo::TabletId, QString::fromLatin1("%1").arg(serial, 4, 16, QLatin1Char('0')).toUpper()); } } TabletInformationPrivate::TabletInfoMap::iterator iter = d->infoMap.find(info.key()); // make sure only keys exist which actually have a value if (iter != d->infoMap.end()) { if (value.isEmpty()) { d->infoMap.erase(iter); } else { iter.value() = value; } } else if (!value.isEmpty()){ d->infoMap.insert(info.key(), value); } } void TabletInformation::set(const TabletInfo&info, bool value) { QString strValue = value ? QLatin1String("true") : QLatin1String("false"); set (info, strValue); } void TabletInformation::set(const TabletInfo &info, int value) { set(info, QString::number(value)); } void TabletInformation::setAvailable(bool value) { Q_D(TabletInformation); d->isAvailable = value; } void TabletInformation::setBool(const TabletInfo& info, const QString& value) { if (StringUtils::asBool(value)) { set (info, QLatin1String("true")); } else { set (info, QLatin1String("false")); } } void TabletInformation::setButtonMap(const QMap< QString, QString >& buttonMap) { Q_D(TabletInformation); d->buttonMap = buttonMap; } void TabletInformation::setDevice (const DeviceInformation& device) { Q_D(TabletInformation); d->deviceMap.insert (device.getType().key(), device); } QString TabletInformation::getUniqueDeviceId() const { return QString::fromLatin1("%1:%2") .arg(get(TabletInfo::CompanyId)) .arg(get(TabletInfo::TabletId)); } QString TabletInformation::getLegacyUniqueDeviceId() const { return get(TabletInfo::TabletName); } diff --git a/src/common/tabletprofile.cpp b/src/common/tabletprofile.cpp index e301aa9..a549cbf 100644 --- a/src/common/tabletprofile.cpp +++ b/src/common/tabletprofile.cpp @@ -1,158 +1,158 @@ /* * This file is part of the KDE wacomtablet project. For copyright * information and license terms see the AUTHORS and COPYING files * in the top-level directory of this distribution. * * 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 . */ #include "tabletprofile.h" #include "debug.h" #include "deviceprofile.h" #include using namespace Wacom; namespace Wacom { /** * Private class of the TabletProfile for the d-pointer * */ class TabletProfilePrivate { public: QHash devices; QString name; }; } TabletProfile::TabletProfile() : d_ptr(new TabletProfilePrivate) {} TabletProfile::TabletProfile(const QString& name) : d_ptr(new TabletProfilePrivate) { Q_D( TabletProfile ); d->name = name; } TabletProfile::TabletProfile(const TabletProfile& profile) : d_ptr(new TabletProfilePrivate) { operator=(profile); } TabletProfile::~TabletProfile() { delete this->d_ptr; } TabletProfile& TabletProfile::operator=(const TabletProfile& that) { Q_D( TabletProfile ); d->devices = that.d_ptr->devices; d->name = that.d_ptr->name; return *this; } void TabletProfile::clearDevices() { Q_D( TabletProfile ); d->devices.clear(); } const DeviceProfile TabletProfile::getDevice ( const DeviceType& device ) const { Q_D( const TabletProfile ); if (!hasDevice(device)) { return DeviceProfile(device); } return d->devices.value(device.key()); } QString TabletProfile::getName() const { Q_D( const TabletProfile ); return d->name; } bool TabletProfile::hasDevice(const DeviceType& device) const { Q_D( const TabletProfile ); return d->devices.contains(device.key()); } bool TabletProfile::hasDevice(const QString& device) const { const DeviceType* deviceType = DeviceType::find(device); - if (deviceType == NULL) { + if (!deviceType) { return false; } return hasDevice(*deviceType); } QStringList TabletProfile::listDevices() const { Q_D( const TabletProfile ); QStringList result; // keys are all lower case, but we want to list the names as-is QList keys = d->devices.keys(); for (const auto &key : qAsConst(keys)) { const DeviceType *deviceType = DeviceType::find(key); if (!deviceType) { errWacom << "DeviceType for" << key << "is null"; continue; } result.append(getDevice(*deviceType).getName()); } return result; } bool TabletProfile::setDevice ( const DeviceProfile& profile ) { Q_D( TabletProfile ); if (profile.getName().isEmpty()) { return false; } d->devices.insert(profile.getName().toLower(), profile); return true; } void TabletProfile::setName(const QString& name) { Q_D( TabletProfile ); d->name = name; } diff --git a/src/kcmodule/calibrationdialog.cpp b/src/kcmodule/calibrationdialog.cpp index 9eadb74..f598c48 100644 --- a/src/kcmodule/calibrationdialog.cpp +++ b/src/kcmodule/calibrationdialog.cpp @@ -1,154 +1,154 @@ /* * This file is part of the KDE wacomtablet project. For copyright * information and license terms see the AUTHORS and COPYING files * in the top-level directory of this distribution. * * 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 . */ #include "calibrationdialog.h" #include "debug.h" //KDE includes #include //Qt includes #include #include #include #include #include #include using namespace Wacom; const int frameGap = 10; const int boxwidth = 100; CalibrationDialog::CalibrationDialog( const QString &toolname ) : QDialog( ) { setWindowState( Qt::WindowFullScreen ); m_toolName = toolname; m_drawCross = 0; m_shiftLeft = frameGap; m_shiftTop = frameGap; m_originaltabletArea = X11Wacom::getMaximumTabletArea(m_toolName); QLabel *showInfo = new QLabel(); showInfo->setText( i18n( "Please tap into all four corners to calibrate the tablet.\nPress escape to cancel the process." ) ); showInfo->setAlignment( Qt::AlignCenter ); QVBoxLayout *mainLayout = new QVBoxLayout; mainLayout->addWidget( showInfo ); setLayout(mainLayout); } QRect CalibrationDialog::calibratedArea() { return m_newtabletArea.toRect(); } void CalibrationDialog::paintEvent( QPaintEvent *event ) { Q_UNUSED( event ); QPainter painter( this ); - painter.setPen( Qt::black ); + painter.setPen(palette().color(QPalette::WindowText)); // vertical line painter.drawLine( m_shiftLeft + boxwidth / 2, m_shiftTop, m_shiftLeft + boxwidth / 2, m_shiftTop + boxwidth ); // horizontal line painter.drawLine( m_shiftLeft, m_shiftTop + boxwidth / 2, m_shiftLeft + boxwidth, m_shiftTop + boxwidth / 2 ); // draw circle around center painter.drawEllipse( QPoint( m_shiftLeft + boxwidth / 2, m_shiftTop + boxwidth / 2 ), 10, 10 ); } void CalibrationDialog::mousePressEvent( QMouseEvent *event ) { if( event->pos().x() > m_shiftLeft && event->pos().x() < m_shiftLeft + boxwidth && event->pos().y() > m_shiftTop && event->pos().y() < m_shiftTop + boxwidth ) { m_drawCross++; switch( m_drawCross ) { case 1: m_topLeft = event->windowPos(); m_shiftLeft = frameGap; m_shiftTop = size().height() - frameGap - boxwidth; break; case 2: m_bottomLeft = event->windowPos(); m_shiftLeft = size().width() - frameGap - boxwidth; m_shiftTop = size().height() - frameGap - boxwidth; break; case 3: m_bottomRight = event->windowPos(); m_shiftLeft = size().width() - frameGap - boxwidth; m_shiftTop = frameGap; break; case 4: m_topRight = event->windowPos(); calculateNewArea(); close(); break; } update(); } } void CalibrationDialog::calculateNewArea() { qreal frameoffset = frameGeometry().height() - size().height(); qreal tabletScreenRatioWidth = m_originaltabletArea.width() / size().width(); qreal tabletScreenRatioHeight = m_originaltabletArea.height() / size().height(); qreal clickedX = ( m_topLeft.x() + m_bottomLeft.x() ) / 2; qreal newX = ( clickedX - frameGap - boxwidth / 2 ) * tabletScreenRatioWidth; qreal clickedY = ( m_topLeft.y() + m_topRight.y() ) / 2; qreal newY = ( clickedY - frameGap - boxwidth / 2 - frameoffset ) * tabletScreenRatioHeight; qreal clickedWidth = ( m_topRight.x() + m_bottomRight.x() ) / 2; qreal newWidth = ( clickedWidth + frameGap + boxwidth / 2 ) * tabletScreenRatioWidth; qreal clickedHeight = ( m_bottomRight.y() + m_bottomLeft.y() ) / 2; qreal newHeight = ( clickedHeight + frameGap + boxwidth / 2 + frameoffset ) * tabletScreenRatioHeight; m_newtabletArea.setX( newX ); m_newtabletArea.setY( newY ); m_newtabletArea.setWidth( newWidth ); m_newtabletArea.setHeight( newHeight ); dbgWacom << "Calibration debug:" << frameGeometry() << size() << m_originaltabletArea << m_topLeft << m_bottomLeft << m_topRight << m_bottomRight; dbgWacom << "Calibration debug:" << frameoffset << tabletScreenRatioWidth << tabletScreenRatioHeight << clickedX << clickedY << clickedWidth << clickedHeight; dbgWacom << "Calibration debug:" << m_newtabletArea; } diff --git a/src/kcmodule/tabletareaselectioncontroller.cpp b/src/kcmodule/tabletareaselectioncontroller.cpp index c4d5acc..f7b5dd4 100644 --- a/src/kcmodule/tabletareaselectioncontroller.cpp +++ b/src/kcmodule/tabletareaselectioncontroller.cpp @@ -1,360 +1,360 @@ /* * This file is part of the KDE wacomtablet project. For copyright * information and license terms see the AUTHORS and COPYING files * in the top-level directory of this distribution. * * 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 . */ #include "debug.h" // always needs to be first include #include "tabletareaselectioncontroller.h" #include "tabletareaselectionview.h" #include "calibrationdialog.h" #include "screenmap.h" #include "stringutils.h" #include "x11info.h" #include "x11wacom.h" using namespace Wacom; namespace Wacom { class TabletAreaSelectionControllerPrivate { public: TabletAreaSelectionView *view = nullptr; TabletArea tabletGeometry; // the original tablet geometry TabletArea tabletGeometryRotated; // the rotated tablet geometry if rotation is active QMap screenGeometries; // the geometries of all screens which form the desktop ScreenSpace currentScreen; QString deviceName; // the device this instance is handling ScreenMap screenMap; // the current screen mappings ScreenRotation tabletRotation = ScreenRotation::NONE; // the tablet rotation }; } TabletAreaSelectionController::TabletAreaSelectionController() : QObject(), d_ptr(new TabletAreaSelectionControllerPrivate) { // nothing to do except for initializing our private class } TabletAreaSelectionController::~TabletAreaSelectionController() { delete this->d_ptr; } const ScreenMap& TabletAreaSelectionController::getScreenMap() { Q_D(const TabletAreaSelectionController); // make sure the current mapping is included setMapping(d->currentScreen, d->view->getSelection()); // return mapping return d->screenMap; } const ScreenSpace TabletAreaSelectionController::getScreenSpace() const { Q_D(const TabletAreaSelectionController); return d->currentScreen; } void TabletAreaSelectionController::select(const ScreenSpace& screenSpace) { Q_D(TabletAreaSelectionController); if (!hasView()) { return; } setMapping(d->currentScreen, d->view->getSelection()); d->currentScreen = screenSpace; d->view->select(screenSpace.toString(), screenSpace.isDesktop(), getMapping(d->currentScreen)); } void TabletAreaSelectionController::setView(TabletAreaSelectionView* view) { Q_D(TabletAreaSelectionController); // cleanup signal/slot connections if we already have a view - if (d->view != NULL) { + if (d->view) { disconnect(d->view, SIGNAL(signalCalibrateClicked()), this, SLOT(onCalibrateClicked())); disconnect(d->view, SIGNAL(signalFullTabletSelection()), this, SLOT(onFullTabletSelected())); disconnect(d->view, SIGNAL(signalScreenToggle()), this, SLOT(onScreenToggle())); disconnect(d->view, SIGNAL(signalSetScreenProportions()), this, SLOT(onSetScreenProportions())); disconnect(d->view, SIGNAL(signalTabletAreaSelection()), this, SLOT(onTabletAreaSelected())); } // save view and connect signals d->view = view; - if (view != NULL) { + if (view) { connect(view, SIGNAL(signalCalibrateClicked()), this, SLOT(onCalibrateClicked())); connect(view, SIGNAL(signalFullTabletSelection()), this, SLOT(onFullTabletSelected())); connect(view, SIGNAL(signalScreenToggle()), this, SLOT(onScreenToggle())); connect(view, SIGNAL(signalSetScreenProportions()), this, SLOT(onSetScreenProportions())); connect(view, SIGNAL(signalTabletAreaSelection()), this, SLOT(onTabletAreaSelected())); } } void TabletAreaSelectionController::setupController(const ScreenMap& mappings, const QString& deviceName, const ScreenRotation& rotation) { Q_D(TabletAreaSelectionController); if (!hasView()) { return; } d->deviceName = deviceName; d->tabletGeometry = X11Wacom::getMaximumTabletArea(deviceName); d->screenGeometries = X11Info::getScreenGeometries(); d->screenMap = mappings; if (rotation == ScreenRotation::AUTO) { // TODO d->tabletRotation = X11Info::getScreenRotation(); // we have a tablet (not a canvas) viewpoint here, so we need to invert the screen rotation d->tabletRotation = d->tabletRotation.invert(); } else if (rotation == ScreenRotation::AUTO_INVERTED) { // TODO d->tabletRotation = X11Info::getScreenRotation(); } else { d->tabletRotation = rotation; } d->tabletGeometryRotated = d->tabletGeometry; if (d->tabletRotation == ScreenRotation::CW || d->tabletRotation == ScreenRotation::CCW) { d->tabletGeometryRotated.setWidth(d->tabletGeometry.height()); d->tabletGeometryRotated.setHeight(d->tabletGeometry.width()); } dbgWacom << "Calling setupScreens and setupTablet from setupController. ScreenGeometries: " << d->screenGeometries; d->view->setupScreens(d->screenGeometries, QSize(200,200)); d->view->setupTablet(d->tabletGeometryRotated, QSize(400,400)); // make sure we have valid data set d->view->select(d->currentScreen.toString(), d->currentScreen.isDesktop(), getMapping(d->currentScreen)); } void TabletAreaSelectionController::onCalibrateClicked() { Q_D(TabletAreaSelectionController); CalibrationDialog calibDialog(d->deviceName); calibDialog.exec(); setSelection(TabletArea(calibDialog.calibratedArea())); } void TabletAreaSelectionController::onFullTabletSelected() { checkConfigurationForTrackingModeProblems(); } void TabletAreaSelectionController::onScreenToggle() { Q_D(TabletAreaSelectionController); select(d->currentScreen.next()); } void TabletAreaSelectionController::onSetScreenProportions() { Q_D(TabletAreaSelectionController); QRect tabletGeometry = d->tabletGeometryRotated; QRect screenSelection = getScreenGeometry(d->currentScreen.toString()); if (screenSelection.isEmpty()) { return; } // calculate new height and width of the selection qreal screenAreaSelectionRatio = (float)screenSelection.width() / screenSelection.height(); qreal newWidth, newHeight; if (screenSelection.width() > screenSelection.height()) { newWidth = tabletGeometry.width(); newHeight = newWidth / screenAreaSelectionRatio; if (newHeight > tabletGeometry.height()) { newHeight = tabletGeometry.height(); newWidth = newHeight * screenAreaSelectionRatio; } } else { newHeight = tabletGeometry.height(); newWidth = newHeight * screenAreaSelectionRatio; if (newWidth > tabletGeometry.width()) { newWidth = tabletGeometry.width(); newHeight = newWidth / screenAreaSelectionRatio; } } // calculate x and y to center the selection int newX = (int)((tabletGeometry.width() - newWidth) / 2.); int newY = (int)((tabletGeometry.height() - newHeight) / 2.); setSelection(TabletArea(QRect(newX, newY, qRound(newWidth), qRound(newHeight)))); } void TabletAreaSelectionController::onTabletAreaSelected() { checkConfigurationForTrackingModeProblems(); } bool TabletAreaSelectionController::hasView() const { Q_D(const TabletAreaSelectionController); return (d->view != nullptr); } void TabletAreaSelectionController::checkConfigurationForTrackingModeProblems() { Q_D(TabletAreaSelectionController); // a device can not be mapped to a single screen in relative mode if (d->currentScreen.isMonitor()) { d->view->setTrackingModeWarning(true); } else { d->view->setTrackingModeWarning(false); } } const TabletArea TabletAreaSelectionController::convertAreaFromRotation(const TabletArea &tablet, const TabletArea &area, const ScreenRotation &rotation) const { TabletArea result = area; if (rotation == ScreenRotation::CW) { result.setX(area.y()); result.setY(tablet.height() - area.x() - area.width()); result.setWidth(area.height()); result.setHeight(area.width()); } else if (rotation == ScreenRotation::CCW) { result.setX(tablet.width() - area.y() - area.height()); result.setY(area.x()); result.setWidth(area.height()); result.setHeight(area.width()); } else if (rotation == ScreenRotation::HALF) { result.setX(tablet.width() - area.width() - area.x()); result.setY(tablet.height() - area.height() - area.y()); result.setWidth(area.width()); result.setHeight(area.height()); } return result; } const TabletArea TabletAreaSelectionController::convertAreaToRotation(const TabletArea &tablet, const TabletArea &area, const ScreenRotation &rotation) const { TabletArea result = area; if (rotation == ScreenRotation::CW) { result.setX(tablet.height() - area.height() - area.y()); result.setY(area.x()); result.setWidth(area.height()); result.setHeight(area.width()); } else if (rotation == ScreenRotation::CCW) { result.setX(area.y()); result.setY(tablet.width() - area.width() - area.x()); result.setWidth(area.height()); result.setHeight(area.width()); } else if (rotation == ScreenRotation::HALF) { result.setX(tablet.width() - area.width() - area.x()); result.setY(tablet.height() - area.height() - area.y()); result.setWidth(area.width()); result.setHeight(area.height()); } return result; } const QRect TabletAreaSelectionController::getScreenGeometry(QString output) const { Q_D(const TabletAreaSelectionController); return d->screenGeometries.value(output, X11Info::getDisplayGeometry()); } const TabletArea TabletAreaSelectionController::getMapping(ScreenSpace screenSpace) const { Q_D(const TabletAreaSelectionController); return convertAreaToRotation(d->tabletGeometry, d->screenMap.getMapping(screenSpace), d->tabletRotation); } void TabletAreaSelectionController::setMapping(ScreenSpace screenSpace, const TabletArea &mapping) { Q_D(TabletAreaSelectionController); TabletArea area = convertAreaFromRotation(d->tabletGeometry, mapping, d->tabletRotation); d->screenMap.setMapping(screenSpace, area); } void TabletAreaSelectionController::setSelection(const TabletArea &selection) { Q_D(TabletAreaSelectionController); if (!hasView()) { return; } if (selection.isEmpty() || selection == d->tabletGeometryRotated) { d->view->selectFullTablet(); } else { d->view->selectPartOfTablet(selection); } } diff --git a/src/kcmodule/tabletpagewidget.cpp b/src/kcmodule/tabletpagewidget.cpp index 0ef02df..d5899c2 100644 --- a/src/kcmodule/tabletpagewidget.cpp +++ b/src/kcmodule/tabletpagewidget.cpp @@ -1,457 +1,457 @@ /* * This file is part of the KDE wacomtablet project. For copyright * information and license terms see the AUTHORS and COPYING files * in the top-level directory of this distribution. * * 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 . */ #include "debug.h" // always needs to be first include #include "tabletpagewidget.h" #include "ui_tabletpagewidget.h" #include "dbustabletinterface.h" #include "deviceprofile.h" #include "profilemanagement.h" #include "property.h" #include "stringutils.h" #include "tabletareaselectiondialog.h" #include "x11info.h" #include "x11wacom.h" #include #include using namespace Wacom; namespace Wacom { class TabletPageWidgetPrivate { public: TabletPageWidgetPrivate() : ui(new Ui::TabletPageWidget), tabletRotation(ScreenRotation::NONE) {} ~TabletPageWidgetPrivate() { delete ui; } Ui::TabletPageWidget* ui; // Our UI widget. ScreenRotation tabletRotation; // The current tablet rotation with a hardware viewpoint (not the canvas!). TabletArea tabletGeometry; // The full tablet area as rectangle. ScreenMap screenMap; // The current tablet to screen mapping of the pad. ScreenSpace screenSpace; // The current screen mapping of the pad. QString deviceNameStylus; // The Xinput name of the stylus device of the current tablet. QString deviceNameTouch; // The Xinput name of the touch device of the current tablet. QString tabletId; }; } TabletPageWidget::TabletPageWidget(QWidget* parent) : QWidget(parent), d_ptr(new TabletPageWidgetPrivate) { setupUi(); } TabletPageWidget::~TabletPageWidget() { delete this->d_ptr; } void TabletPageWidget::setTabletId(const QString &tabletId) { Q_D( TabletPageWidget ); d->tabletId = tabletId; } void TabletPageWidget::loadFromProfile() { ProfileManagement* profileManagement = &ProfileManagement::instance(); DeviceProfile stylusProfile = profileManagement->loadDeviceProfile( DeviceType::Stylus ); setRotation( stylusProfile.getProperty( Property::Rotate ) ); setScreenSpace( stylusProfile.getProperty( Property::ScreenSpace ) ); setScreenMap( stylusProfile.getProperty( Property::ScreenMap ) ); setTrackingMode(stylusProfile.getProperty( Property::Mode )); } void TabletPageWidget::reloadWidget() { Q_D( TabletPageWidget ); // get all tablet device names we need QDBusReply stylusDeviceNameReply = DBusTabletInterface::instance().getDeviceName(d->tabletId, DeviceType::Stylus.key()); QDBusReply touchDeviceNameReply = DBusTabletInterface::instance().getDeviceName(d->tabletId, DeviceType::Touch.key()); // update name and maximum tablet area for all devices d->deviceNameStylus.clear(); d->deviceNameTouch.clear(); d->tabletGeometry = TabletArea(); d->screenMap = ScreenMap(); if (stylusDeviceNameReply.isValid()) { d->deviceNameStylus = stylusDeviceNameReply.value(); d->tabletGeometry = X11Wacom::getMaximumTabletArea(stylusDeviceNameReply.value()); d->screenMap = ScreenMap(d->tabletGeometry); } if (touchDeviceNameReply.isValid()) { d->deviceNameTouch = touchDeviceNameReply.value(); } } void TabletPageWidget::saveToProfile() { Q_D( const TabletPageWidget); ProfileManagement* profileManagement = &ProfileManagement::instance(); DeviceProfile padProfile = profileManagement->loadDeviceProfile( DeviceType::Pad ); DeviceProfile stylusProfile = profileManagement->loadDeviceProfile( DeviceType::Stylus ); DeviceProfile eraserProfile = profileManagement->loadDeviceProfile( DeviceType::Eraser ); DeviceProfile touchProfile = profileManagement->loadDeviceProfile( DeviceType::Touch ); stylusProfile.setProperty ( Property::Rotate, getRotation() ); eraserProfile.setProperty ( Property::Rotate, getRotation() ); touchProfile.setProperty ( Property::Rotate, getRotation() ); padProfile.setProperty ( Property::Rotate, QString()); // make sure it is not set on the pad - will mess up touch stylusProfile.setProperty ( Property::ScreenSpace, getScreenSpaceAsString() ); eraserProfile.setProperty ( Property::ScreenSpace, getScreenSpaceAsString() ); padProfile.setProperty ( Property::ScreenSpace, QString()); // should not be set on the pad, causes trouble padProfile.setProperty ( Property::Area, QString()); // should not be set on the pad, causes trouble stylusProfile.setProperty ( Property::ScreenMap, getScreenMapAsString() ); eraserProfile.setProperty ( Property::ScreenMap, getScreenMapAsString() ); padProfile.setProperty ( Property::ScreenMap, QString() ); // make sure it is not set on the pad stylusProfile.setProperty ( Property::Mode, getTrackingMode()); eraserProfile.setProperty ( Property::Mode, getTrackingMode()); profileManagement->saveDeviceProfile(padProfile); profileManagement->saveDeviceProfile(stylusProfile); profileManagement->saveDeviceProfile(eraserProfile); if (!d->deviceNameTouch.isEmpty()) { profileManagement->saveDeviceProfile(touchProfile); } } void TabletPageWidget::onAutoRotateChanged(int state) { setAutoRotationEnabled(state == Qt::Checked); onProfileChanged(); } void TabletPageWidget::onProfileChanged() { emit changed(); } void TabletPageWidget::onTabletMappingClicked() { Q_D(TabletPageWidget); // get current rotation settings // we need to invert it as our rotation settings in this widget have a canvas viewpoint const ScreenRotation* lookupRotation = ScreenRotation::find(getRotation()); - ScreenRotation rotation = (lookupRotation != NULL) ? lookupRotation->invert() : ScreenRotation::NONE; + ScreenRotation rotation = lookupRotation ? lookupRotation->invert() : ScreenRotation::NONE; TabletAreaSelectionDialog selectionDialog; selectionDialog.setupWidget( getScreenMap(), d->deviceNameStylus, rotation); selectionDialog.select( getScreenSpace() ); if (selectionDialog.exec() == QDialog::Accepted) { setScreenMap(selectionDialog.getScreenMap()); setScreenSpace(selectionDialog.getScreenSpace()); onProfileChanged(); } } void TabletPageWidget::onRotationChanged() { Q_D(TabletPageWidget); // determin rotation const ScreenRotation* lookupRotation = ScreenRotation::find(getRotation()); // we need to invert it as our rotation settings in this widget have a canvas viewpoint // and our private member variable has a tablet viewpoint - d->tabletRotation = (lookupRotation != NULL) ? lookupRotation->invert() : ScreenRotation::NONE; + d->tabletRotation = lookupRotation ? lookupRotation->invert() : ScreenRotation::NONE; emit rotationChanged(d->tabletRotation); } void TabletPageWidget::onTrackingModeAbsolute(bool activated) { if (!activated) { return; } setTrackingMode(QLatin1String("absolute")); onProfileChanged(); } void TabletPageWidget::onTrackingModeRelative(bool activated) { if (!activated) { return; } setTrackingMode(QLatin1String("relative")); onProfileChanged(); } const QString TabletPageWidget::getRotation() const { Q_D (const TabletPageWidget); QString rotation = ScreenRotation::NONE.key(); if (isAutoRotationEnabled()) { if (isAutoRotateInversionEnabled()) { rotation = ScreenRotation::AUTO_INVERTED.key(); } else { rotation = ScreenRotation::AUTO.key(); } } else { int index = d->ui->rotatationSelectionComboBox->currentIndex(); rotation = d->ui->rotatationSelectionComboBox->itemData(index).toString(); } return rotation; } const ScreenMap& TabletPageWidget::getScreenMap() const { Q_D (const TabletPageWidget); return d->screenMap; } const QString TabletPageWidget::getScreenMapAsString() const { return getScreenMap().toString(); } const ScreenSpace& TabletPageWidget::getScreenSpace() const { Q_D (const TabletPageWidget); return d->screenSpace; } const QString TabletPageWidget::getScreenSpaceAsString() const { return getScreenSpace().toString(); } const QString TabletPageWidget::getTrackingMode() const { Q_D (const TabletPageWidget); if (d->ui->trackAbsoluteRadioButton->isChecked()) { return QLatin1String("absolute"); } return QLatin1String("relative"); } bool TabletPageWidget::isAutoRotateInversionEnabled() const { Q_D (const TabletPageWidget); return d->ui->rotateWithScreenInvertCheckBox->isChecked(); } bool TabletPageWidget::isAutoRotationEnabled() const { Q_D (const TabletPageWidget); return d->ui->rotateWithScreenCheckBox->isChecked(); } void TabletPageWidget::setAutoRotateInversionEnabled(bool value) { Q_D (TabletPageWidget); d->ui->rotateWithScreenInvertCheckBox->blockSignals(true); d->ui->rotateWithScreenInvertCheckBox->setChecked(value); d->ui->rotateWithScreenInvertCheckBox->blockSignals(false); } void TabletPageWidget::setAutoRotationEnabled(bool value) { Q_D (TabletPageWidget); d->ui->rotatationSelectionComboBox->setEnabled(!value); d->ui->rotateWithScreenInvertCheckBox->setEnabled(value); if (value) { setRotation(ScreenRotation::NONE.key()); } else { setAutoRotateInversionEnabled(false); } d->ui->rotateWithScreenCheckBox->blockSignals(true); d->ui->rotateWithScreenCheckBox->setChecked(value); d->ui->rotateWithScreenCheckBox->blockSignals(false); } void TabletPageWidget::setRotation(const QString& value) { Q_D (TabletPageWidget); const ScreenRotation* lookup = ScreenRotation::find(value); - ScreenRotation rotation = (lookup != NULL) ? *lookup : ScreenRotation::NONE; + ScreenRotation rotation = lookup ? *lookup : ScreenRotation::NONE; QString rotationValue = rotation.key(); if (rotation == ScreenRotation::AUTO) { setAutoRotationEnabled(true); rotationValue = ScreenRotation::NONE.key(); } else if (rotation == ScreenRotation::AUTO_INVERTED) { setAutoRotationEnabled(true); setAutoRotateInversionEnabled(true); rotationValue = ScreenRotation::NONE.key(); } int rotationIndex = d->ui->rotatationSelectionComboBox->findData(rotationValue); d->ui->rotatationSelectionComboBox->blockSignals(true); d->ui->rotatationSelectionComboBox->setCurrentIndex(rotationIndex >= 0 ? rotationIndex : 0); d->ui->rotatationSelectionComboBox->blockSignals(false); onRotationChanged(); } void TabletPageWidget::setScreenMap(const ScreenMap &screenMap) { Q_D (TabletPageWidget); d->screenMap = screenMap; assertValidTabletMapping(); } void TabletPageWidget::setScreenMap(const QString& value) { setScreenMap(ScreenMap(value)); } void TabletPageWidget::setScreenSpace(const ScreenSpace& screenSpace) { Q_D (TabletPageWidget); d->screenSpace = screenSpace; assertValidTabletMapping(); } void TabletPageWidget::setScreenSpace(const QString& value) { setScreenSpace(ScreenSpace(value)); } void TabletPageWidget::setTrackingMode(const QString& value) { Q_D (TabletPageWidget); d->ui->trackAbsoluteRadioButton->blockSignals(true); d->ui->trackRelativeRadioButton->blockSignals(true); if (value.contains(QLatin1String("absolute"), Qt::CaseInsensitive)) { d->ui->trackAbsoluteRadioButton->setChecked(true); d->ui->trackRelativeRadioButton->setChecked(false); } else { d->ui->trackAbsoluteRadioButton->setChecked(false); d->ui->trackRelativeRadioButton->setChecked(true); } d->ui->trackAbsoluteRadioButton->blockSignals(false); d->ui->trackRelativeRadioButton->blockSignals(false); assertValidTabletMapping(); } void TabletPageWidget::assertValidTabletMapping() { Q_D (TabletPageWidget); bool isWarningVisible = false; if (d->ui->trackRelativeRadioButton->isChecked()) { // Relative mode is selected. In relative mode a // device can not be mapped to a single monitor ScreenSpace screenSpace = getScreenSpace(); if (screenSpace.isMonitor()) { isWarningVisible = true; } } d->ui->trackingWarningIcon->setVisible(isWarningVisible); d->ui->trackingWarningLabel->setVisible(isWarningVisible); } void TabletPageWidget::setupUi() { Q_D (TabletPageWidget); d->ui->setupUi(this); // init screen mapping warning d->ui->trackingWarningIcon->setPixmap(QIcon::fromTheme(QLatin1String("dialog-warning")).pixmap(QSize(16,16))); d->ui->trackingWarningIcon->setVisible(false); d->ui->trackingWarningLabel->setVisible(false); // fill rotation combo box // xsetwacom's rotation is based on coordinate rotation, but we are asking the user for a tablet rotation. // Therefore we have to swap the values for clockwise and counterclockwise rotation. d->ui->rotatationSelectionComboBox->addItem(i18nc("Either no orientation or the current screen orientation is applied to the tablet.", "Default Orientation"), ScreenRotation::NONE.key()); d->ui->rotatationSelectionComboBox->addItem(i18nc("The tablet will be rotated clockwise.", "Rotate Tablet Clockwise"), ScreenRotation::CCW.key()); d->ui->rotatationSelectionComboBox->addItem(i18nc("The tablet will be rotated counterclockwise.", "Rotate Tablet Counterclockwise"), ScreenRotation::CW.key()); d->ui->rotatationSelectionComboBox->addItem(i18nc("The tablet will be rotated up side down.", "Rotate Tablet Upside-Down"), ScreenRotation::HALF.key()); } diff --git a/src/kded/dbustabletservice.cpp b/src/kded/dbustabletservice.cpp index 8ccff9c..5cce716 100644 --- a/src/kded/dbustabletservice.cpp +++ b/src/kded/dbustabletservice.cpp @@ -1,249 +1,249 @@ /* * This file is part of the KDE wacomtablet project. For copyright * information and license terms see the AUTHORS and COPYING files * in the top-level directory of this distribution. * * 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 . */ #include "dbustabletinterface.h" #include "debug.h" #include "dbustabletservice.h" #include "devicetype.h" #include "property.h" #include "tabletinfo.h" #include "wacomadaptor.h" #include #include #include using namespace Wacom; namespace Wacom { class DBusTabletServicePrivate { public: WacomAdaptor* wacomAdaptor; TabletHandlerInterface* tabletHandler; QHash tabletInformationList; //!< Information of all currently connected tablets. QHash currentProfileList; //!< Currently active profile for each tablet. }; // CLASS } // NAMESPACE DBusTabletService::DBusTabletService(TabletHandlerInterface& tabletHandler) : QObject(), d_ptr(new DBusTabletServicePrivate) { Q_D ( DBusTabletService ); d->tabletHandler = &tabletHandler; DBusTabletInterface::registerMetaTypes(); d->wacomAdaptor = new WacomAdaptor( this ); QDBusConnection::sessionBus().registerObject( QLatin1String( "/Tablet" ), this ); QDBusConnection::sessionBus().registerService( QLatin1String( "org.kde.Wacom" ) ); } DBusTabletService::~DBusTabletService() { QDBusConnection::sessionBus().unregisterService( QLatin1String( "org.kde.Wacom" ) ); QDBusConnection::sessionBus().unregisterObject( QLatin1String( "/Tablet" )); delete d_ptr->wacomAdaptor; delete d_ptr; } const QStringList DBusTabletService::getTabletList() const { Q_D ( const DBusTabletService ); return d->tabletInformationList.keys(); } const QStringList DBusTabletService::getDeviceList(const QString &tabletId) const { Q_D ( const DBusTabletService ); return d->tabletInformationList.value(tabletId).getDeviceList(); } QString DBusTabletService::getDeviceName(const QString &tabletId, const QString& device) const { Q_D ( const DBusTabletService ); static const QString unknown; const DeviceType *type = DeviceType::find(device); - if (type == NULL) { + if (!type) { errWacom << QString::fromLatin1("Unsupported device type '%1'!").arg(device); return unknown; } return d->tabletInformationList.value(tabletId).getDeviceName(*type); } QString DBusTabletService::getInformation(const QString &tabletId,const QString& info) const { Q_D ( const DBusTabletService ); static const QString unknown; const TabletInfo* devinfo = TabletInfo::find(info); - if (devinfo == NULL) { + if (!devinfo) { errWacom << QString::fromLatin1("Can not get unsupported tablet information '%1'!").arg(info); return unknown; } return d->tabletInformationList.value(tabletId).get(*devinfo); } QString DBusTabletService::getProfile(const QString &tabletId) const { Q_D ( const DBusTabletService ); return d->currentProfileList.value(tabletId); } QString DBusTabletService::getProperty(const QString &tabletId, const QString& deviceType, const QString& property) const { Q_D ( const DBusTabletService ); const DeviceType* type = DeviceType::find(deviceType); - if (type == NULL) { + if (!type) { errWacom << QString::fromLatin1("Can not get property '%1' from invalid device '%2'!").arg(property).arg(deviceType); return QString(); } const Property* prop = Property::find(property); - if (prop == NULL) { + if (!prop) { errWacom << QString::fromLatin1("Can not get invalid property '%1' from device '%2'!").arg(property).arg(deviceType); return QString(); } return d->tabletHandler->getProperty(tabletId, *type, *prop); } bool DBusTabletService::hasPadButtons(const QString &tabletId) const { Q_D ( const DBusTabletService ); return d->tabletInformationList.value(tabletId).hasButtons(); } bool DBusTabletService::isAvailable(const QString &tabletId) const { Q_D ( const DBusTabletService ); return d->tabletInformationList.contains(tabletId); } QStringList DBusTabletService::listProfiles(const QString &tabletId) { Q_D ( const DBusTabletService ); return d->tabletHandler->listProfiles(tabletId); } void DBusTabletService::setProfile(const QString &tabletId, const QString& profile) { Q_D ( DBusTabletService ); d->tabletHandler->setProfile(tabletId, profile); } void DBusTabletService::setProperty(const QString &tabletId, const QString& deviceType, const QString& property, const QString& value) { Q_D ( DBusTabletService ); const DeviceType* type = DeviceType::find(deviceType); - if (type == NULL) { + if (!type) { errWacom << QString::fromLatin1("Can not set property '%1' on invalid device '%2' to '%3'!").arg(property).arg(deviceType).arg(value); return; } const Property* prop = Property::find(property); - if (prop == NULL) { + if (!prop) { errWacom << QString::fromLatin1("Can not set invalid property '%1' on device '%2' to '%3'!").arg(property).arg(deviceType).arg(value); return; } d->tabletHandler->setProperty(tabletId, *type, *prop, value); } QStringList DBusTabletService::getProfileRotationList(const QString &tabletId) { Q_D ( DBusTabletService ); return d->tabletHandler->getProfileRotationList(tabletId); } void DBusTabletService::setProfileRotationList(const QString &tabletId, const QStringList &rotationList) { Q_D ( DBusTabletService ); d->tabletHandler->setProfileRotationList(tabletId, rotationList); } void DBusTabletService::onProfileChanged(const QString &tabletId, const QString& profile) { Q_D ( DBusTabletService ); d->currentProfileList.insert(tabletId, profile); emit profileChanged(tabletId, profile); } void DBusTabletService::onTabletAdded(const TabletInformation& info) { Q_D ( DBusTabletService ); d->tabletInformationList.insert(info.get(TabletInfo::TabletId), info); emit tabletAdded(info.get(TabletInfo::TabletId)); } void DBusTabletService::onTabletRemoved(const QString &tabletId) { Q_D ( DBusTabletService ); d->currentProfileList.remove(tabletId); d->tabletInformationList.remove(tabletId); emit tabletRemoved(tabletId); } diff --git a/src/kded/procsystemadaptor.cpp b/src/kded/procsystemadaptor.cpp index fe9f0ba..bc268f2 100644 --- a/src/kded/procsystemadaptor.cpp +++ b/src/kded/procsystemadaptor.cpp @@ -1,109 +1,109 @@ /* * This file is part of the KDE wacomtablet project. For copyright * information and license terms see the AUTHORS and COPYING files * in the top-level directory of this distribution. * * 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 . */ #include "debug.h" // always needs to be first include #include "procsystemadaptor.h" #include "procsystemproperty.h" #include using namespace Wacom; namespace Wacom { class ProcSystemAdaptorPrivate { public: QString deviceName; }; // CLASS } // NAMESPACE ProcSystemAdaptor::ProcSystemAdaptor(const QString& deviceName) - : PropertyAdaptor(NULL), d_ptr(new ProcSystemAdaptorPrivate) + : PropertyAdaptor(nullptr), d_ptr(new ProcSystemAdaptorPrivate) { - Q_D( ProcSystemAdaptor ); + Q_D(ProcSystemAdaptor); d->deviceName = deviceName; } ProcSystemAdaptor::~ProcSystemAdaptor() { delete this->d_ptr; } const QList< Property > ProcSystemAdaptor::getProperties() const { return ProcSystemProperty::ids(); } const QString ProcSystemAdaptor::getProperty(const Property& property) const { Q_D(const ProcSystemAdaptor); errWacom << QString::fromLatin1("Can not get unsupported property '%1' from device '%2' using proc system!").arg(property.key()).arg(d->deviceName); return QString(); } bool ProcSystemAdaptor::setProperty(const Property& property, const QString& value) { Q_D(const ProcSystemAdaptor); dbgWacom << QString::fromLatin1("Setting property '%1' to '%2'.").arg(property.key()).arg(value); // https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-driver-wacom /* /sys/bus/usb/devices/-:./wacom_led/status_led0_select Writing to this file sets which one of the four (for Intuos 4 and Intuos 5) or of the right four (for Cintiq 21UX2 and Cintiq 24HD) status LEDs is active (0..3). The other three LEDs on the same side are always inactive. */ /* /sys/bus/usb/devices/-:./wacom_led/status_led1_select Writing to this file sets which one of the left four (for Cintiq 21UX2 and Cintiq 24HD) status LEDs is active (0..3). The other three LEDs on the left are always inactive. */ int statusLed = value.toInt(); QString cmd; if(statusLed < 4 && statusLed >= 0) { cmd = QString::fromLatin1("bash -c \"echo %1 > /sys/bus/usb/devices/*/wacom_led/status_led0_select\"").arg(statusLed); } else if(statusLed < 8 && statusLed >= 4) { statusLed -= 4; cmd = QString::fromLatin1("bash -c \"echo %1 > /sys/bus/usb/devices/*/wacom_led/status_led1_select\"").arg(statusLed); } else { return false; } int ret = QProcess::execute(cmd); return ret == 0; } bool ProcSystemAdaptor::supportsProperty(const Property& property) const { - return (ProcSystemProperty::map(property) != NULL); + return (ProcSystemProperty::map(property)); } diff --git a/src/kded/tabletdaemon.cpp b/src/kded/tabletdaemon.cpp index 5181a81..62385c5 100644 --- a/src/kded/tabletdaemon.cpp +++ b/src/kded/tabletdaemon.cpp @@ -1,234 +1,234 @@ /* * This file is part of the KDE wacomtablet project. For copyright * information and license terms see the AUTHORS and COPYING files * in the top-level directory of this distribution. * * 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 . */ #include "tabletdaemon.h" #include "debug.h" #include "dbustabletservice.h" #include "tabletfinder.h" #include "tablethandler.h" #include "wacomadaptor.h" #include "x11eventnotifier.h" #include "globalactions.h" #include "../wacomtablet-version.h" // common includes #include "aboutdata.h" // stdlib includes #include // KDE includes #include #include #include #include #include #include using namespace Wacom; K_PLUGIN_FACTORY_WITH_JSON(WacomTabletFactory, "wacomtablet.json", registerPlugin();) namespace Wacom { /** * Private class of the TabletDaemon for the d-pointer */ class TabletDaemonPrivate { public: TabletDaemonPrivate() : tabletHandler(), dbusTabletService(tabletHandler) {} TabletHandler tabletHandler; /**< tablet handler */ DBusTabletService dbusTabletService; std::shared_ptr actionCollection; /**< Collection of all global actions */ }; // CLASS } // NAMESPACE TabletDaemon::TabletDaemon( QObject *parent, const QVariantList &args ) : KDEDModule( parent ), d_ptr( new TabletDaemonPrivate ) { Q_UNUSED( args ); Q_D( TabletDaemon ); setupApplication(); setupDBus(); setupEventNotifier(); setupActions(); // scan for connected devices TabletFinder::instance().scan(); // connect profile changed handler after searching for tablets as this is only used for the global shortcut workaround. connect(&(d->tabletHandler), &TabletHandler::profileChanged, this, &TabletDaemon::onProfileChanged); // Connecting this after the device has been set up ensures that no notification is send on startup. connect( &(d->tabletHandler), SIGNAL(notify(QString,QString,QString)), this, SLOT(onNotify(QString,QString,QString)) ); } TabletDaemon::~TabletDaemon() { X11EventNotifier::instance().stop(); delete this->d_ptr; } void TabletDaemon::onNotify(const QString& eventId, const QString& title, const QString& message) { Q_D( TabletDaemon ); KNotification* notification = new KNotification(eventId); notification->setComponentName( QStringLiteral("wacomtablet") ); notification->setTitle(title); notification->setText(message); notification->setIconName( QLatin1String( "input-tablet" ) ); notification->sendEvent(); } void TabletDaemon::onProfileChanged(const QString &tabletId, const QString& profile) { Q_UNUSED(tabletId); Q_UNUSED(profile); // When closing the KCM module the KAction destructor disables all global shortcuts. // Make sure the global shortcuts are restored when a profile changes. This is not // optimal but at least it will enable the shortcuts again. dbgWacom << QLatin1String("Restoring global keyboard shortcuts..."); setupActions(); } void TabletDaemon::setupActions() { Q_D( TabletDaemon ); //if someone adds another action also add it to kcmodule/generalwidget.cpp // This method is called multiple times - make sure the action collection is only created once. - if (d->actionCollection.get() == NULL) { + if (!d->actionCollection) { d->actionCollection = std::shared_ptr(new GlobalActions(false, this)); d->actionCollection->setConfigGlobal(true); } connect( d->actionCollection.get(), SIGNAL(toggleTouchTriggered()), &(d->tabletHandler), SLOT(onToggleTouch()) ); connect( d->actionCollection.get(), SIGNAL(toggleStylusTriggered()), &(d->tabletHandler), SLOT(onTogglePenMode()) ); connect( d->actionCollection.get(), SIGNAL(toggleScreenMapTriggered()), &(d->tabletHandler), SLOT(onToggleScreenMapping()) ); connect( d->actionCollection.get(), SIGNAL(mapToFullScreenTriggered()), &(d->tabletHandler), SLOT(onMapToFullScreen()) ); connect( d->actionCollection.get(), SIGNAL(mapToScreen1Triggered()), &(d->tabletHandler), SLOT(onMapToScreen1()) ); connect( d->actionCollection.get(), SIGNAL(mapToScreen2Triggered()), &(d->tabletHandler), SLOT(onMapToScreen2()) ); connect( d->actionCollection.get(), SIGNAL(nextProfileTriggered()), &(d->tabletHandler), SLOT(onNextProfile()) ); connect( d->actionCollection.get(), SIGNAL(previousProfileTriggered()), &(d->tabletHandler), SLOT(onPreviousProfile()) ); } void TabletDaemon::setupApplication() { static AboutData about(QLatin1Literal("wacomtablet"), i18n( "Graphic Tablet Configuration daemon"), QLatin1String(WACOMTABLET_VERSION_STRING), i18n( "A Wacom tablet control daemon" )); } void TabletDaemon::setupDBus() { Q_D( TabletDaemon ); // connect tablet handler events to D-Bus // this is done here and not in the D-Bus tablet service to facilitate unit testing connect(&(d->tabletHandler), SIGNAL (profileChanged(QString, QString)), &(d->dbusTabletService), SLOT (onProfileChanged(QString, QString))); connect(&(d->tabletHandler), SIGNAL (tabletAdded(TabletInformation)), &(d->dbusTabletService), SLOT (onTabletAdded(TabletInformation))); connect(&(d->tabletHandler), SIGNAL (tabletRemoved(QString)), &(d->dbusTabletService), SLOT (onTabletRemoved(QString))); } void TabletDaemon::setupEventNotifier() { Q_D( TabletDaemon ); // Set up monitoring for individual screen geometry changes monitorAllScreensGeometry(); // Set up monitoring for screens being added, removed or reordered connect(qApp, &QGuiApplication::primaryScreenChanged, &(d->tabletHandler), &TabletHandler::onScreenAddedRemoved); connect(qApp, &QGuiApplication::screenAdded, &(d->tabletHandler), &TabletHandler::onScreenAddedRemoved); connect(qApp, &QGuiApplication::screenRemoved, &(d->tabletHandler), &TabletHandler::onScreenAddedRemoved); // Set up tablet connected/disconnected signals connect( &X11EventNotifier::instance(), &X11EventNotifier::tabletAdded, &TabletFinder::instance(), &TabletFinder::onX11TabletAdded); connect( &X11EventNotifier::instance(), &X11EventNotifier::tabletRemoved, &TabletFinder::instance(), &TabletFinder::onX11TabletRemoved); connect( &TabletFinder::instance(), &TabletFinder::tabletAdded, &(d->tabletHandler), &TabletHandler::onTabletAdded); connect( &TabletFinder::instance(), &TabletFinder::tabletRemoved, &(d->tabletHandler), &TabletHandler::onTabletRemoved); if (QX11Info::isPlatformX11()) { X11EventNotifier::instance().start(); } } void TabletDaemon::monitorAllScreensGeometry() { // Add existing screens for (const auto &screen : QGuiApplication::screens()) { monitorScreenGeometry(screen); } // Monitor future screens connect(qApp, &QGuiApplication::screenAdded, this, &TabletDaemon::monitorScreenGeometry); } void TabletDaemon::monitorScreenGeometry(QScreen *screen) { Q_D( TabletDaemon ); const auto &tabletHandler = &(d->tabletHandler); connect(screen, &QScreen::orientationChanged, [=](const Qt::ScreenOrientation &newScreenRotation){ tabletHandler->onScreenRotated(screen->name(), newScreenRotation); }); screen->setOrientationUpdateMask(Qt::LandscapeOrientation | Qt::PortraitOrientation | Qt::InvertedLandscapeOrientation | Qt::InvertedPortraitOrientation); connect(screen, &QScreen::geometryChanged, &(d->tabletHandler), &TabletHandler::onScreenGeometryChanged); } #include "tabletdaemon.moc" diff --git a/src/kded/tablethandler.cpp b/src/kded/tablethandler.cpp index dfc4dd2..7159173 100644 --- a/src/kded/tablethandler.cpp +++ b/src/kded/tablethandler.cpp @@ -1,692 +1,692 @@ /* * This file is part of the KDE wacomtablet project. For copyright * information and license terms see the AUTHORS and COPYING files * in the top-level directory of this distribution. * * 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 . */ #include "tablethandler.h" #include "debug.h" #include "tabletbackendinterface.h" #include "tabletbackendfactory.h" #include "tabletinfo.h" #include "devicetype.h" #include "screenmap.h" #include "screenspace.h" #include "stringutils.h" // common includes #include "deviceprofile.h" #include "tabletdatabase.h" #include "mainconfig.h" #include "profilemanager.h" #include "profilemanagement.h" #include "tabletprofile.h" #include "x11info.h" #include #include #include #include #include namespace Wacom { class TabletHandlerPrivate { public: MainConfig mainConfig; //!< Main config file which stores general parameters. QString profileFile; //!< Save which profile we should use QHash profileManagerList; //!< Profile manager which reads profile configuration from file. QHash tabletBackendList; //!< Tablet backend of all currently connected tablets. QHash tabletInformationList; //!< Information of all currently connected tablets. QHash currentProfileList; //!< Currently active profile for each tablet. }; // CLASS } // NAMESPACE using namespace Wacom; TabletHandler::TabletHandler() - : TabletHandlerInterface(NULL), d_ptr(new TabletHandlerPrivate) + : TabletHandlerInterface(nullptr), d_ptr(new TabletHandlerPrivate) { Q_D( TabletHandler ); d->profileFile = QLatin1String("tabletprofilesrc"); d->mainConfig.open(QLatin1String("wacomtablet-kderc")); } TabletHandler::TabletHandler(const QString& profileFile, const QString configFile) - : TabletHandlerInterface(NULL), d_ptr(new TabletHandlerPrivate) + : TabletHandlerInterface(nullptr), d_ptr(new TabletHandlerPrivate) { Q_D( TabletHandler ); d->profileFile = profileFile; d->mainConfig.open(configFile); } TabletHandler::~TabletHandler() { qDeleteAll(d_ptr->tabletBackendList); qDeleteAll(d_ptr->profileManagerList); delete d_ptr; } QString TabletHandler::getProperty(const QString &tabletId, const DeviceType& deviceType, const Property& property) const { Q_D( const TabletHandler ); - if( !d->tabletBackendList.contains(tabletId) || d->tabletBackendList.value(tabletId) == NULL) { + if( !d->tabletBackendList.contains(tabletId) || d->tabletBackendList.value(tabletId) == nullptr) { errWacom << QString::fromLatin1("Unable to get property '%1' from device '%2' as no device is currently available!").arg(property.key()).arg(deviceType.key()); return QString(); } return d->tabletBackendList.value(tabletId)->getProperty( deviceType, property ); } void TabletHandler::onTabletAdded( const TabletInformation& info ) { Q_D( TabletHandler ); // if we already have a device ... skip this step QString tabletId = info.get(TabletInfo::TabletId); if(d->tabletBackendList.contains(tabletId)) { dbgWacom << QString::fromLatin1("Ignoring tablet '%1' as another one with same name is already connected.") .arg(info.get(TabletInfo::TabletId)); return; } dbgWacom << "Taking control of new tablet" << info.get(TabletInfo::TabletName) << "(" << info.get(TabletInfo::TabletId) << ") [" << (info.hasDevice(DeviceType::Stylus) ? "stylus" : "") << (info.hasDevice(DeviceType::Eraser) ? "eraser" : "") << (info.hasDevice(DeviceType::Pad) ? "pad" : "") << (info.hasDevice(DeviceType::Touch) ? "touch" : "") << (info.hasDevice(DeviceType::Cursor) ? "cursor" : "") << "]"; // create tablet backend TabletBackendInterface *tbi = TabletBackendFactory::createBackend(info); - if (tbi == NULL) { + if (!tbi) { errWacom << "Could not create tablet backend interface. Ignoring Tablet"; return; // no valid backend found } d->tabletBackendList.insert(tabletId, tbi); // update tablet information d->profileManagerList.insert(tabletId, new ProfileManager(d->profileFile)); d->tabletInformationList.insert(tabletId, info); // if we found something notify about it and set the default profile to it emit notify( QLatin1String("tabletAdded"), i18n("Tablet Connected"), i18n("New tablet '%1' connected.", info.get(TabletInfo::TabletName) )); // set profile which was last used auto lastProfile = d->mainConfig.getLastProfile(info.getUniqueDeviceId()); if (lastProfile.isEmpty()) { // try reading profile using device name for compatibility with older config lastProfile = d->mainConfig.getLastProfile(info.getLegacyUniqueDeviceId()); if (!lastProfile.isEmpty()) { dbgWacom << "Found legacy profile setting for" << tabletId; } } setProfile(tabletId, lastProfile); // notify everyone else about the new tablet emit tabletAdded(info); } void TabletHandler::onTabletRemoved( const TabletInformation& info ) { Q_D( TabletHandler ); TabletBackendInterface *tbi = d->tabletBackendList.value(info.get(TabletInfo::TabletId)); TabletInformation ti = d->tabletInformationList.value(info.get(TabletInfo::TabletId)); if ( tbi && ti.getTabletSerial() == info.getTabletSerial() ) { emit notify( QLatin1String("tabletRemoved"), i18n("Tablet removed"), i18n("Tablet %1 removed", ti.get(TabletInfo::TabletName) )); QString tabletId = info.get(TabletInfo::TabletId); d->tabletBackendList.remove(tabletId); d->tabletInformationList.remove(tabletId); delete tbi; ProfileManager *pm = d->profileManagerList.take(tabletId); delete pm; emit tabletRemoved(tabletId); } } void TabletHandler::onScreenRotated(QString output, const Qt::ScreenOrientation &newScreenRotation) { Q_D( TabletHandler ); dbgWacom << "Screen" << output << "rotation has changed to" << newScreenRotation; //for each connected tablet, do the rotation foreach(const QString &tabletId, d->tabletInformationList.keys()) { QString curProfile = d->currentProfileList.value(tabletId); TabletProfile tabletProfile = d->profileManagerList.value(tabletId)->loadProfile(curProfile); ScreenRotation screenRotation = ScreenRotation::NONE; switch (newScreenRotation) { case Qt::PrimaryOrientation: case Qt::LandscapeOrientation: screenRotation = ScreenRotation::NONE; break; case Qt::PortraitOrientation: screenRotation = ScreenRotation::CW; break; case Qt::InvertedLandscapeOrientation: screenRotation = ScreenRotation::HALF; break; case Qt::InvertedPortraitOrientation: screenRotation = ScreenRotation::CCW; break; } // rotation has to be applied before screen mapping autoRotateTablet(tabletId, tabletProfile, output, screenRotation); // when the rotation changes, the screen mapping has to be applied again mapTabletToCurrentScreenSpace(tabletId, tabletProfile); } } void TabletHandler::onScreenAddedRemoved(QScreen *screen) { Q_D( TabletHandler ); Q_UNUSED(screen) dbgWacom << "Number of screens has changed"; foreach(const QString &tabletId, d->tabletInformationList.keys()) { QString curProfile = d->currentProfileList.value(tabletId); TabletProfile tabletProfile = d->profileManagerList.value(tabletId)->loadProfile(curProfile); mapTabletToCurrentScreenSpace(tabletId, tabletProfile); } } void TabletHandler::onScreenGeometryChanged() { Q_D( TabletHandler ); dbgWacom << "Screen geometry has changed"; foreach(const QString &tabletId, d->tabletInformationList.keys()) { QString curProfile = d->currentProfileList.value(tabletId); TabletProfile tabletProfile = d->profileManagerList.value(tabletId)->loadProfile(curProfile); mapTabletToCurrentScreenSpace(tabletId, tabletProfile); } } void TabletHandler::onTogglePenMode() { Q_D( TabletHandler ); foreach(const QString &tabletId, d->tabletInformationList.keys()) { if( !hasTablet(tabletId) || !hasDevice(tabletId, DeviceType::Stylus)) { continue; } // read current mode and screen space from profile QString curProfile = d->currentProfileList.value(tabletId); TabletProfile tabletProfile = d->profileManagerList.value(tabletId)->loadProfile(curProfile); DeviceProfile stylusProfile = tabletProfile.getDevice(DeviceType::Stylus); QString trackingMode = stylusProfile.getProperty(Property::Mode); ScreenSpace screenSpace(stylusProfile.getProperty(Property::ScreenSpace)); // toggle tracking mode if (trackingMode.contains(QLatin1String("relative"), Qt::CaseInsensitive)) { trackingMode = QLatin1String("absolute"); } else { // if the new mode is "relative" we have to switch to full desktop // as screen mappings are not supported in absolute mode trackingMode = QLatin1String("relative"); screenSpace = ScreenSpace::desktop(); } // map tablet to output which will also save the current mode in the profile mapDeviceToOutput(tabletId, DeviceType::Stylus, screenSpace, trackingMode, tabletProfile); mapDeviceToOutput(tabletId, DeviceType::Eraser, screenSpace, trackingMode, tabletProfile); d->profileManagerList.value(tabletId)->saveProfile(tabletProfile); } } void TabletHandler::onToggleTouch() { Q_D( TabletHandler ); foreach(const QString &tabletId, d->tabletInformationList.keys()) { if( !hasDevice(tabletId, DeviceType::Touch) ) { continue; } QString touchMode = getProperty(tabletId, DeviceType::Touch, Property::Touch); // also save the touch on/off into the profile to remember the user selection after // the tablet was reconnected QString curProfile = d->currentProfileList.value(tabletId); TabletProfile tabletProfile = d->profileManagerList.value(tabletId)->loadProfile(curProfile); DeviceProfile touchProfile = tabletProfile.getDevice(DeviceType::Touch); if( touchMode.compare( QLatin1String( "off" ), Qt::CaseInsensitive) == 0 ) { setProperty(tabletId, DeviceType::Touch, Property::Touch, QLatin1String("on")); touchProfile.setProperty( Property::Touch, QLatin1String("on" ) ); } else { setProperty(tabletId, DeviceType::Touch, Property::Touch, QLatin1String("off")); touchProfile.setProperty( Property::Touch, QLatin1String("off") ); } tabletProfile.setDevice(touchProfile); d->profileManagerList.value(tabletId)->saveProfile(tabletProfile); } } void TabletHandler::onToggleScreenMapping() { Q_D( TabletHandler ); foreach(const QString &tabletId, d->tabletInformationList.keys()) { if (!hasTablet(tabletId)) { continue; } QString curProfile = d->currentProfileList.value(tabletId); TabletProfile tabletProfile = d->profileManagerList.value(tabletId)->loadProfile(curProfile); DeviceProfile stylusProfile = tabletProfile.getDevice(DeviceType::Stylus); ScreenSpace screenSpace = ScreenSpace(stylusProfile.getProperty(Property::ScreenSpace)); mapPenToScreenSpace(tabletId, screenSpace.next()); } } void TabletHandler::onMapToFullScreen() { Q_D( TabletHandler ); foreach(const QString &tabletId, d->tabletInformationList.keys()) { mapPenToScreenSpace(tabletId, ScreenSpace::desktop().toString()); } } void TabletHandler::onMapToScreen1() { Q_D( TabletHandler ); foreach(const QString &tabletId, d->tabletInformationList.keys()) { mapPenToScreenSpace(tabletId, ScreenSpace::monitor(X11Info::getPrimaryScreenName())); } } void TabletHandler::onMapToScreen2() { Q_D( TabletHandler ); if (QGuiApplication::screens().count() > 1) { foreach(const QString &tabletId, d->tabletInformationList.keys()) { mapPenToScreenSpace(tabletId, ScreenSpace::monitor(X11Info::getPrimaryScreenName()).next()); } } } void TabletHandler::onNextProfile() { Q_D( TabletHandler ); foreach(const QString &tabletId, d->tabletInformationList.keys()) { if(d->profileManagerList.value(tabletId)->profileRotationList().empty()) { dbgWacom << "No items in the rotation list. Nothing to rotate"; } else { QString nextProfile = d->profileManagerList.value(tabletId)->nextProfile(); setProfile(tabletId, nextProfile); } } } void TabletHandler::onPreviousProfile() { Q_D( TabletHandler ); foreach(const QString &tabletId, d->tabletInformationList.keys()) { if(d->profileManagerList.value(tabletId)->profileRotationList().empty()) { dbgWacom << "No items in the rotation list. Nothing to rotate"; } else { QString previousProfile = d->profileManagerList.value(tabletId)->previousProfile(); setProfile(tabletId, previousProfile); } } } QStringList TabletHandler::listProfiles( const QString &tabletId ) { Q_D( TabletHandler ); ProfileManager *pm = d->profileManagerList.value(tabletId); if(!pm) { errWacom << "Could not retrieve ProfileManager for tablet" << tabletId; return QStringList(); } const TabletInformation ti = d->tabletInformationList.value(tabletId); pm->readProfiles(ti.getUniqueDeviceId()); return pm->listProfiles(); } void TabletHandler::setProfile( const QString &tabletId, const QString &profile ) { Q_D( TabletHandler ); dbgWacom << QString::fromLatin1("Loading tablet profile '%1'...").arg(profile); if (!hasTablet(tabletId)) { errWacom << QString::fromLatin1("Can not set tablet profile to '%1' as no backend is available!").arg(profile); return; } ProfileManager *profileManager = d->profileManagerList.value(tabletId); if(!profileManager) { errWacom << "Could not retrieve ProfileManager for tablet" << tabletId; return; } TabletInformation tabletInformation = d->tabletInformationList.value(tabletId); profileManager->readProfiles(tabletInformation.getUniqueDeviceId(), tabletInformation.getLegacyUniqueDeviceId()); TabletProfile tabletProfile = profileManager->loadProfile(profile); if (tabletProfile.listDevices().isEmpty()) { //may happen also if "last selected profile" was deleted. //thus we check if any profile exist and take the first one // or create a new empty profile and apply this instead QStringList pList = profileManager->listProfiles(); if(pList.isEmpty()) { // create a new default profile ProfileManagement* profileManagement = &ProfileManagement::instance(tabletId, tabletInformation.hasDevice(DeviceType::Touch)); profileManagement->createNewProfile(i18nc( "Name of the default profile that will be created if none exists.","Default" )); if(!profileManagement->availableProfiles().empty()) { d->currentProfileList.insert(tabletId, profileManagement->availableProfiles().first()); } else { errWacom << "Could not create new default profile. There seems to be an error on device detection"; } } else { errWacom << QString::fromLatin1("Tablet profile '%1' does not exist!").arg(profile); emit notify( QLatin1String( "tabletError" ), i18n( "Graphic Tablet error" ), i18n( "Profile %1 does not exist. Apply %2 instead", profile, pList.first() ) ); // set first known profile instead d->currentProfileList.insert(tabletId, pList.first()); } tabletProfile = profileManager->loadProfile(d->currentProfileList.value(tabletId)); } else { // set profile d->currentProfileList.insert(tabletId, profile); } // Handle auto-rotation. // This has to be done before screen mapping! autoRotateTablet(tabletId, tabletProfile); // Map tablet to screen. // This is necessary to ensure the correct area map is used. Somone might have changed // the ScreenSpace property without updating the Area property. mapTabletToCurrentScreenSpace(tabletId, tabletProfile); // set profile on tablet QString currentProfile = d->currentProfileList.value(tabletId); d->tabletBackendList.value(tabletId)->setProfile(tabletProfile); d->mainConfig.setLastProfile(tabletInformation.getUniqueDeviceId(), currentProfile); // check profile rotation values and LEDs profileManager->updateCurrentProfileNumber(currentProfile); d->tabletBackendList.value(tabletId)->setStatusLED( profileManager->profileNumber( currentProfile )); emit profileChanged( tabletId, currentProfile ); } void TabletHandler::setProperty(const QString &tabletId, const DeviceType& deviceType, const Property& property, const QString& value) { Q_D( TabletHandler ); if (!hasTablet(tabletId)) { errWacom << QString::fromLatin1("Unable to set property '%1' on device '%2' to '%3' as no device is currently available!").arg(property.key()).arg(deviceType.key()).arg(value); return; } d->tabletBackendList.value(tabletId)->setProperty(deviceType, property, value); } QStringList TabletHandler::getProfileRotationList(const QString &tabletId) { Q_D( TabletHandler ); if (!hasTablet(tabletId)) { errWacom << QString::fromLatin1("Unable to get profile rotation list as no device is currently available!"); return QStringList(); } return d->profileManagerList.value(tabletId)->profileRotationList(); } void TabletHandler::setProfileRotationList(const QString &tabletId, const QStringList &rotationList) { Q_D( TabletHandler ); if (!hasTablet(tabletId)) { errWacom << QString::fromLatin1("Unable to set profile rotation list as no device is currently available!"); return; } d->profileManagerList.value(tabletId)->setProfileRotationList(rotationList); } void TabletHandler::autoRotateTablet(const QString &tabletId, const TabletProfile &tabletProfile, QString output, ScreenRotation screenRotation) { // determine auto-rotation configuration DeviceProfile stylusProfile = tabletProfile.getDevice(DeviceType::Stylus); QString rotateProperty = stylusProfile.getProperty(Property::Rotate); const ScreenRotation* lookupRotation = ScreenRotation::find(rotateProperty); ScreenRotation tabletRotation = (lookupRotation != nullptr) ? *lookupRotation : ScreenRotation::NONE; bool doAutoInvert = (tabletRotation == ScreenRotation::AUTO_INVERTED); bool doAutoRotation = (doAutoInvert || tabletRotation == ScreenRotation::AUTO); if (!doAutoRotation) { dbgWacom << "Auto-rotation is disabled in profile settings"; return; } ScreenSpace stylusSpace = ScreenSpace(stylusProfile.getProperty(Property::ScreenSpace)); if (!stylusSpace.isMonitor() && QGuiApplication::screens().count() > 1) { dbgWacom << "We're not mapped to a specific display, can't determine auto-rotation"; return; } if (output.isEmpty()) { screenRotation = X11Info::getScreenRotation(stylusSpace.toString()); } else if (output != stylusSpace.toString() && QGuiApplication::screens().count() > 1) { dbgWacom << "Tablet is mapped to a different screen"; return; } // determine new rotation and set it ScreenRotation newRotation = (doAutoInvert) ? screenRotation.invert() : screenRotation; dbgWacom << "Rotate tablet :: " << newRotation.key(); setProperty( tabletId, DeviceType::Stylus, Property::Rotate, newRotation.key() ); setProperty( tabletId, DeviceType::Eraser, Property::Rotate, newRotation.key() ); if(hasDevice(tabletId, DeviceType::Touch)) { setProperty( tabletId, DeviceType::Touch, Property::Rotate, newRotation.key() ); } } bool TabletHandler::hasDevice(const QString &tabletId, const DeviceType& type) const { Q_D( const TabletHandler ); return (hasTablet(tabletId) && d->tabletInformationList.value(tabletId).hasDevice(type)); } bool TabletHandler::hasTablet(const QString &tabletId) const { Q_D( const TabletHandler ); return (d->tabletBackendList.contains(tabletId) && - d->tabletBackendList.value(tabletId) != NULL); + d->tabletBackendList.value(tabletId) != nullptr); } void TabletHandler::mapDeviceToOutput(const QString &tabletId, const DeviceType& device, const ScreenSpace& screenSpace, const QString& trackingMode, TabletProfile& tabletProfile) { if (!hasTablet(tabletId) || !hasDevice(tabletId, device)) { return; // we do not have a tablet or the requested device } ScreenSpace screen(screenSpace); if (screen.isMonitor() && (!X11Info::getScreenGeometries().contains(screen.toString()) || QGuiApplication::screens().count() == 1)) { /** * If we we have only one screen, or if the screen number is invalid, * map to whole desktop. */ screen = ScreenSpace::desktop(); } DeviceProfile deviceProfile = tabletProfile.getDevice(device); ScreenMap screenMap(deviceProfile.getProperty(Property::ScreenMap)); QString tabletArea = screenMap.getMappingAsString(screen); setProperty(tabletId, device, Property::Mode, trackingMode); setProperty(tabletId, device, Property::ScreenSpace, screen.toString()); setProperty(tabletId, device, Property::Area, tabletArea); deviceProfile.setProperty(Property::Mode, trackingMode); deviceProfile.setProperty(Property::ScreenSpace, screen.toString()); deviceProfile.setProperty(Property::Area, tabletArea); tabletProfile.setDevice(deviceProfile); } void TabletHandler::mapPenToScreenSpace(const QString &tabletId, const ScreenSpace& screenSpace, const QString& trackingMode) { Q_D( TabletHandler ); if (!hasTablet(tabletId)) { return; // we do not have a tablet } QString curProfile = d->currentProfileList.value(tabletId); TabletProfile tabletProfile = d->profileManagerList.value(tabletId)->loadProfile(curProfile); mapDeviceToOutput(tabletId, DeviceType::Stylus, screenSpace, trackingMode, tabletProfile); mapDeviceToOutput(tabletId, DeviceType::Eraser, screenSpace, trackingMode, tabletProfile); d->profileManagerList.value(tabletId)->saveProfile(tabletProfile); } void TabletHandler::mapTabletToCurrentScreenSpace(const QString &tabletId, TabletProfile& tabletProfile) { Q_D( TabletHandler ); DeviceProfile stylusProfile = tabletProfile.getDevice(DeviceType::Stylus); DeviceProfile touchProfile = tabletProfile.getDevice(DeviceType::Touch); QString stylusMode = stylusProfile.getProperty(Property::Mode); ScreenSpace stylusSpace = ScreenSpace(stylusProfile.getProperty(Property::ScreenSpace)); QString touchMode = touchProfile.getProperty(Property::Mode); ScreenSpace touchSpace = ScreenSpace(touchProfile.getProperty(Property::ScreenSpace)); mapDeviceToOutput(tabletId, DeviceType::Stylus, stylusSpace, stylusMode, tabletProfile); mapDeviceToOutput(tabletId, DeviceType::Eraser, stylusSpace, stylusMode, tabletProfile); mapDeviceToOutput(tabletId, DeviceType::Touch, touchSpace, touchMode, tabletProfile); d->profileManagerList.value(tabletId)->saveProfile(tabletProfile); } diff --git a/src/kded/x11tabletfinder.cpp b/src/kded/x11tabletfinder.cpp index 81addc2..ea2e3ce 100644 --- a/src/kded/x11tabletfinder.cpp +++ b/src/kded/x11tabletfinder.cpp @@ -1,295 +1,295 @@ /* * This file is part of the KDE wacomtablet project. For copyright * information and license terms see the AUTHORS and COPYING files * in the top-level directory of this distribution. * * 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 . */ #include "debug.h" #include "x11tabletfinder.h" #include "deviceinformation.h" #include "x11input.h" #if defined(HAVE_XCB_XINPUT) # include #else # include # include # include # include #endif #include #include using namespace Wacom; /** * Class for private members. */ namespace Wacom { class X11TabletFinderPrivate { public: typedef QMap TabletMap; TabletMap tabletMap; //!< A map which is used while visiting devices. QList scannedList; //!< A list which is build after scanning all devices. }; } X11TabletFinder::X11TabletFinder() : d_ptr(new X11TabletFinderPrivate) { } X11TabletFinder::~X11TabletFinder() { delete d_ptr; } const QList< TabletInformation >& X11TabletFinder::getTablets() const { Q_D (const X11TabletFinder); return d->scannedList; } bool X11TabletFinder::scanDevices() { Q_D (X11TabletFinder); d->tabletMap.clear(); d->scannedList.clear(); X11Input::scanDevices(*this); X11TabletFinderPrivate::TabletMap::ConstIterator iter; for (iter = d->tabletMap.constBegin() ; iter != d->tabletMap.constEnd() ; ++iter) { d->scannedList.append(iter.value()); } return (d->tabletMap.size() > 0); } bool X11TabletFinder::visit (X11InputDevice& x11device) { if (!x11device.isTabletDevice()) { return false; } // gather basic device information which we need to create a device information structure QString deviceName = x11device.getName(); const DeviceType* deviceType = getDeviceType (getToolType (x11device)); if (deviceName.isEmpty() || deviceType == nullptr) { errWacom << QString::fromLatin1("Unsupported device '%1' detected!").arg(deviceName); return false; } // create device information and gather all information we can DeviceInformation deviceInfo (*deviceType, x11device.getName()); gatherDeviceInformation(x11device, deviceInfo); // add device information to tablet map addDeviceInformation(deviceInfo); // true is only returned if device visiting should be aborted by X11Input return false; } void X11TabletFinder::addDeviceInformation (DeviceInformation& deviceInformation) { Q_D(X11TabletFinder); long serial = deviceInformation.getTabletSerial(); if (serial < 1) { dbgWacom << QString::fromLatin1("Device '%1' has an invalid serial number '%2'!").arg(deviceInformation.getName()).arg(serial); } X11TabletFinderPrivate::TabletMap::iterator mapIter = d->tabletMap.find (serial); if (mapIter == d->tabletMap.end()) { auto newTabletInformation = TabletInformation(serial); // LibWacom needs CompanyId so set it too newTabletInformation.set(TabletInfo::CompanyId, QString::fromLatin1("%1").arg(deviceInformation.getVendorId(), 4, 16, QLatin1Char('0')).toUpper()); mapIter = d->tabletMap.insert(serial, newTabletInformation); } mapIter.value().setDevice(deviceInformation); } void X11TabletFinder::gatherDeviceInformation(X11InputDevice& device, DeviceInformation& deviceInformation) const { // get X11 device id deviceInformation.setDeviceId(device.getDeviceId()); // get tablet serial deviceInformation.setTabletSerial(getTabletSerial(device)); // get product and vendor id if set long vendorId = 0, productId = 0; if (getProductId(device, vendorId, productId)) { deviceInformation.setVendorId(vendorId); deviceInformation.setProductId(productId); } // get the device node which is the full path to the input device deviceInformation.setDeviceNode(getDeviceNode(device)); } const QString X11TabletFinder::getDeviceNode(X11InputDevice& device) const { QList values; if (!device.getStringProperty(X11Input::PROPERTY_DEVICE_NODE, values, 1000) || values.size() == 0) { dbgWacom << QString::fromLatin1("Could not get device node from device '%1'!").arg(device.getName()); return QString(); } return values.at(0); } const DeviceType* X11TabletFinder::getDeviceType (const QString& toolType) const { if (toolType.contains (QLatin1String ("pad"), Qt::CaseInsensitive)) { return &(DeviceType::Pad); } else if (toolType.contains(QLatin1String ("eraser"), Qt::CaseInsensitive)) { return &(DeviceType::Eraser); } else if (toolType.contains(QLatin1String ("cursor"), Qt::CaseInsensitive)) { return &(DeviceType::Cursor); } else if (toolType.contains(QLatin1String ("touch"), Qt::CaseInsensitive)) { return &(DeviceType::Touch); } else if (toolType.contains(QLatin1String ("stylus"), Qt::CaseInsensitive)) { return &(DeviceType::Stylus); } - return NULL; + return nullptr; } bool X11TabletFinder::getProductId(X11InputDevice& device, long int& vendorId, long int& productId) const { QList values; if (!device.getLongProperty(X11Input::PROPERTY_DEVICE_PRODUCT_ID, values, 2)) { return false; } if (values.size() != 2) { errWacom << QString::fromLatin1("Unexpected number of values when fetching XInput property '%1'!").arg(X11Input::PROPERTY_DEVICE_PRODUCT_ID); return false; } long value; if ((value = values.at(0)) > 0) { vendorId = value; } if ((value = values.at(1)) > 0) { productId = value; } return true; } long int X11TabletFinder::getTabletSerial (X11InputDevice& device) const { long tabletId = 0; QList serialIdValues; if (!device.getLongProperty(X11Input::PROPERTY_WACOM_SERIAL_IDS, serialIdValues, 1000)) { return tabletId; } // the offset for the tablet id is 0 see wacom-properties.h in the xf86-input-wacom driver for more information on this if (serialIdValues.size() > 0) { tabletId = serialIdValues.at(0); if (tabletId > 0) { return tabletId; } } return tabletId; } const QString X11TabletFinder::getToolType (X11InputDevice& device) const { QList toolTypeAtoms; if (!device.getAtomProperty(X11Input::PROPERTY_WACOM_TOOL_TYPE, toolTypeAtoms)) { return QString(); } QString toolTypeName; if (toolTypeAtoms.size() == 1) { #if defined(HAVE_XCB_XINPUT) xcb_get_atom_name_cookie_t cookie = xcb_get_atom_name(QX11Info::connection(), toolTypeAtoms.at(0)); - xcb_get_atom_name_reply_t* reply = xcb_get_atom_name_reply(QX11Info::connection(), cookie, NULL); + xcb_get_atom_name_reply_t* reply = xcb_get_atom_name_reply(QX11Info::connection(), cookie, nullptr); if (reply) { toolTypeName = QString::fromLatin1(QByteArray(xcb_get_atom_name_name(reply), xcb_get_atom_name_name_length(reply))); free(reply); } #else // HAVE_XCB_XINPUT char *type_name = XGetAtomName (device.getDisplay(), (Atom)toolTypeAtoms.at(0)); - if (type_name != NULL) { + if (type_name != nullptr) { toolTypeName = QLatin1String(type_name); XFree( type_name ); } else { dbgWacom << "Could not get tool type of device" << device.getName(); } #endif // HAVE_XCB_XINPUT } return toolTypeName; } diff --git a/src/kded/xinputadaptor.cpp b/src/kded/xinputadaptor.cpp index fd626d9..6528350 100644 --- a/src/kded/xinputadaptor.cpp +++ b/src/kded/xinputadaptor.cpp @@ -1,300 +1,300 @@ /* * This file is part of the KDE wacomtablet project. For copyright * information and license terms see the AUTHORS and COPYING files * in the top-level directory of this distribution. * * 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 . */ #include "debug.h" // always needs to be first include #include "xinputadaptor.h" #include "screenspace.h" #include "stringutils.h" #include "xinputproperty.h" #include "x11input.h" #include "x11inputdevice.h" #include "x11info.h" #include "x11wacom.h" #include #include #include #include using namespace Wacom; namespace Wacom { class XinputAdaptorPrivate { public: QString deviceName; X11InputDevice device; }; // CLASS } // NAMESPACE XinputAdaptor::XinputAdaptor(const QString& deviceName) - : PropertyAdaptor(NULL), d_ptr(new XinputAdaptorPrivate) + : PropertyAdaptor(nullptr), d_ptr(new XinputAdaptorPrivate) { Q_D( XinputAdaptor ); d->deviceName = deviceName; X11Input::findDevice(deviceName, d->device); } XinputAdaptor::~XinputAdaptor() { delete this->d_ptr; } const QList< Property > XinputAdaptor::getProperties() const { return XinputProperty::ids(); } const QString XinputAdaptor::getProperty(const Property& property) const { Q_D(const XinputAdaptor); - const XinputProperty* xinputproperty = XinputProperty::map(property); + const XinputProperty *xinputproperty = XinputProperty::map(property); - if (xinputproperty == NULL) { + if (!xinputproperty) { errWacom << QString::fromLatin1("Can not get unsupported property '%1' from device '%2' using xinput!").arg(property.key()).arg(d->deviceName); return QString(); } if (!d->device.isOpen()) { errWacom << QString::fromLatin1("Can not get property '%1' from device '%2' because the device is not available!").arg(property.key()).arg(d->deviceName); return QString(); } return getProperty(*xinputproperty); } bool XinputAdaptor::setProperty(const Property& property, const QString& value) { Q_D(const XinputAdaptor); dbgWacom << QString::fromLatin1("Setting property '%1' to '%2'.").arg(property.key()).arg(value); - const XinputProperty* xinputproperty = XinputProperty::map(property); + const XinputProperty *xinputproperty = XinputProperty::map(property); - if (xinputproperty == NULL) { + if (!xinputproperty) { errWacom << QString::fromLatin1("Can not set unsupported property '%1' to '%2' on device '%3' using xinput!").arg(property.key()).arg(value).arg(d->deviceName); return false; } if (!d->device.isOpen()) { errWacom << QString::fromLatin1("Can not set property '%1' to '%2' on device '%3' because the device is not available!").arg(property.key()).arg(value).arg(d->deviceName); return false; } return setProperty(*xinputproperty, value); } bool XinputAdaptor::supportsProperty(const Property& property) const { - return (XinputProperty::map(property) != NULL); + return (XinputProperty::map(property) != nullptr); } const QString XinputAdaptor::getProperty(const XinputProperty& property) const { Q_D( const XinputAdaptor ); if (property == XinputProperty::CursorAccelProfile) { return getLongProperty (property); } else if (property == XinputProperty::CursorAccelAdaptiveDeceleration) { return getFloatProperty (property); } else if (property == XinputProperty::CursorAccelConstantDeceleration) { return getFloatProperty (property); } else if (property == XinputProperty::CursorAccelVelocityScaling) { return getFloatProperty (property); } else if (property == XinputProperty::InvertScroll) { return (X11Wacom::isScrollDirectionInverted(d->deviceName) ? QLatin1String("on") : QLatin1String("off")); } else { errWacom << QString::fromLatin1("Getting Xinput property '%1' is not yet implemented!").arg(property.key()); } return QString(); } const QString XinputAdaptor::getFloatProperty(const XinputProperty& property, long nelements) const { Q_D( const XinputAdaptor ); QList values; if (!d->device.getFloatProperty(property.key(), values, nelements)) { errWacom << QString::fromLatin1("Failed to get Xinput property '%1' from device '%2'!").arg(property.key()).arg(d->deviceName); return QString(); } return numbersToString(values); } const QString XinputAdaptor::getLongProperty(const XinputProperty& property, long nelements) const { Q_D( const XinputAdaptor ); QList values; if (!d->device.getLongProperty(property.key(), values, nelements)) { errWacom << QString::fromLatin1("Failed to get Xinput property '%1' from device '%2'!").arg(property.key()).arg(d->deviceName); return QString(); } return numbersToString(values); } bool XinputAdaptor::mapTabletToScreen(const QString& screenArea) const { Q_D( const XinputAdaptor ); // what we need is the Coordinate Transformation Matrix // in the normal case where the whole screen is used we end up with a 3x3 identity matrix //in our case we want to change that // | w 0 offsetX | // | 0 h offsetY | // | 0 0 1 | dbgWacom << "Mapping to area: " << screenArea; if (screenArea.isEmpty()) { return false; // nothing to do } // get the space the user wants to use to map the tablet QRect screenAreaGeometry; QRect fullScreenGeometry = X11Info::getDisplayGeometry(); ScreenSpace screenSpace(screenArea); if (screenSpace.isDesktop()) { // full screen area selected dbgWacom << "Full screen area selected: " << fullScreenGeometry; screenAreaGeometry = fullScreenGeometry; } else if (screenSpace.isMonitor()) { // monitor selected auto output = screenSpace.toString(); QMap screenList = X11Info::getScreenGeometries(); if (!screenList.contains(output)) { dbgWacom << "Selected monitor no longer connected - using full screen: " << fullScreenGeometry; screenAreaGeometry = fullScreenGeometry; } else { dbgWacom << "Use monitor geometry for screen " << output << ": " << screenList.value(output); screenAreaGeometry = screenList.value(output); } } else { // geometry selected dbgWacom << "Geometry selected: " << StringUtils::toQRect(screenArea, true); screenAreaGeometry = StringUtils::toQRect(screenArea, true); if (screenAreaGeometry.isEmpty()) { // the input is invalid - use full screen errWacom << "mapTabletToScreen :: can't parse ScreenSpace entry '" << screenArea << "' => device:" << d->deviceName; screenAreaGeometry = fullScreenGeometry; } } // calculate the new transformation matrix int screenX = screenAreaGeometry.x(); int screenY = screenAreaGeometry.y(); int screenW = screenAreaGeometry.width(); int screenH = screenAreaGeometry.height(); qreal w = static_cast(screenW) / fullScreenGeometry.width(); qreal h = static_cast(screenH) / fullScreenGeometry.height(); qreal offsetX = static_cast(screenX) / fullScreenGeometry.width(); qreal offsetY = static_cast(screenY) / fullScreenGeometry.height(); dbgWacom << "Apply Coordinate Transformation Matrix"; dbgWacom << w << "0" << offsetX; dbgWacom << "0" << h << offsetY; dbgWacom << "0" << "0" << "1"; return X11Wacom::setCoordinateTransformationMatrix(d->deviceName, offsetX, offsetY, w, h); } template const QString XinputAdaptor::numbersToString(const QList& values) const { QString result; for (int i = 0 ; i < values.size() ; ++i) { if (i > 0) { result += QLatin1String(" "); } result += QString::number(values.at(i)); } return result; } bool XinputAdaptor::setProperty (const XinputProperty& property, const QString& value) const { Q_D( const XinputAdaptor ); if (property == XinputProperty::CursorAccelProfile) { return d->device.setLongProperty (property.key(), value); } else if (property == XinputProperty::CursorAccelAdaptiveDeceleration) { return d->device.setFloatProperty (property.key(), value); } else if (property == XinputProperty::CursorAccelConstantDeceleration) { return d->device.setFloatProperty (property.key(), value); } else if (property == XinputProperty::CursorAccelVelocityScaling) { return d->device.setFloatProperty (property.key(), value); } else if (property == XinputProperty::InvertScroll) { return X11Wacom::setScrollDirection(d->deviceName, StringUtils::asBool(value)); } else if (property == XinputProperty::ScreenSpace) { return mapTabletToScreen (value); } else { errWacom << QString::fromLatin1("Setting Xinput property '%1' is not yet implemented!").arg(property.key()); } return false; } diff --git a/src/kded/xsetwacomadaptor.cpp b/src/kded/xsetwacomadaptor.cpp index ed6280b..256f325 100644 --- a/src/kded/xsetwacomadaptor.cpp +++ b/src/kded/xsetwacomadaptor.cpp @@ -1,272 +1,272 @@ /* * This file is part of the KDE wacomtablet project. For copyright * information and license terms see the AUTHORS and COPYING files * in the top-level directory of this distribution. * * 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 . */ #include "xsetwacomadaptor.h" #include "debug.h" #include "xsetwacomproperty.h" #include "stringutils.h" #include "buttonshortcut.h" #include "screenrotation.h" #include "tabletarea.h" #include #include using namespace Wacom; namespace Wacom { class XsetwacomAdaptorPrivate { public: QMap buttonMap; QString device; }; // CLASS } // NAMESPACE XsetwacomAdaptor::XsetwacomAdaptor(const QString& deviceName) - : PropertyAdaptor(NULL), d_ptr(new XsetwacomAdaptorPrivate) + : PropertyAdaptor(nullptr), d_ptr(new XsetwacomAdaptorPrivate) { Q_D( XsetwacomAdaptor ); d->device = deviceName; } XsetwacomAdaptor::XsetwacomAdaptor(const QString& deviceName, const QMap< QString, QString >& buttonMap) - : PropertyAdaptor(NULL), d_ptr(new XsetwacomAdaptorPrivate) + : PropertyAdaptor(nullptr), d_ptr(new XsetwacomAdaptorPrivate) { Q_D( XsetwacomAdaptor ); d->buttonMap = buttonMap; d->device = deviceName; } XsetwacomAdaptor::~XsetwacomAdaptor() { delete this->d_ptr; } const QList< Property > XsetwacomAdaptor::getProperties() const { return XsetwacomProperty::ids(); } const QString XsetwacomAdaptor::getProperty(const Property& property) const { Q_D( const XsetwacomAdaptor ); - const XsetwacomProperty* xsetproperty = XsetwacomProperty::map(property); + const XsetwacomProperty *xsetproperty = XsetwacomProperty::map(property); - if (xsetproperty == NULL) { + if (!xsetproperty) { errWacom << QString::fromLatin1("Can not get unsupported property '%1' using xsetwacom!").arg(property.key()); return QString(); } // TODO: get invert scroll parameter QString convertedParam = convertParameter (*xsetproperty); QString xsetwacomValue = getParameter (d->device, convertedParam); // convert value to a unified format convertFromXsetwacomValue (*xsetproperty, xsetwacomValue); dbgWacom << QString::fromLatin1("Reading property '%1' from device '%2' -> '%3'.").arg(property.key()).arg(d->device).arg(xsetwacomValue); return xsetwacomValue; } bool XsetwacomAdaptor::setProperty(const Property& property, const QString& value) { Q_D( const XsetwacomAdaptor ); dbgWacom << QString::fromLatin1("Setting property '%1' to '%2' on device '%3'.").arg(property.key()).arg(value).arg(d->device); - const XsetwacomProperty* xsetproperty = XsetwacomProperty::map(property); + const XsetwacomProperty *xsetproperty = XsetwacomProperty::map(property); - if (xsetproperty == NULL) { + if (!xsetproperty) { errWacom << QString::fromLatin1("Can not set unsupported property '%1' to '%2' on device '%3' using xsetwacom!").arg(property.key()).arg(value).arg(d->device); return false; } // check for properties which need special handling if (property == Property::Area) { return setArea(value); }else if (property == Property::Rotate) { return setRotation(value); } else { // normal property QString convertedParam = convertParameter(*xsetproperty); QString convertedValue = value; convertToXsetwacomValue(*xsetproperty, convertedValue); return setParameter(d->device, convertedParam, convertedValue); } return false; } bool XsetwacomAdaptor::supportsProperty(const Property& property) const { - return (XsetwacomProperty::map(property) != NULL); + return (XsetwacomProperty::map(property) != nullptr); } const QString XsetwacomAdaptor::convertParameter(const XsetwacomProperty& param) const { Q_D( const XsetwacomAdaptor ); QString modifiedParam = param.key(); // convert tablet button number to hardware button number QRegExp rx(QLatin1String("^Button\\s*([0-9]+)$"), Qt::CaseInsensitive); if (rx.indexIn(modifiedParam, 0) != -1) { QString hwButtonNumber = rx.cap(1); QString kernelButtonNumber; if (!d->buttonMap.isEmpty()) { kernelButtonNumber = d->buttonMap.value(hwButtonNumber); } if (kernelButtonNumber.isEmpty()) { kernelButtonNumber = hwButtonNumber; } //dbgWacom << QString::fromLatin1("Mapping tablet button %1 to X11 buton %2.").arg(hwButtonNumber).arg(kernelButtonNumber); modifiedParam = QString(QLatin1String("Button %1")).arg(kernelButtonNumber); } return modifiedParam; } void XsetwacomAdaptor::convertButtonShortcut (const XsetwacomProperty& property, QString& value) const { QRegExp rx (QLatin1String("^Button\\s*[0-9]+$"), Qt::CaseInsensitive); if (rx.indexIn(property.key(), 0) != -1) { ButtonShortcut buttonshortcut(value); value = buttonshortcut.toString(); } } void XsetwacomAdaptor::convertFromXsetwacomValue(const XsetwacomProperty& property, QString& value) const { // convert button shortcuts to a unified format convertButtonShortcut(property, value); } void XsetwacomAdaptor::convertToXsetwacomValue(const XsetwacomProperty& property, QString& value) const { // convert button shortcuts to a unified format convertButtonShortcut(property, value); } const QString XsetwacomAdaptor::getParameter(const QString& device, const QString& param) const { QString cmd = QString::fromLatin1( "xsetwacom get \"%1\" %2" ).arg( device ).arg( param ); QProcess getConf; getConf.start( cmd ); if( !getConf.waitForStarted() || !getConf.waitForFinished() ) { return QString(); } QString result = QLatin1String( getConf.readAll() ); return result.remove( QLatin1Char( '\n' ) ); } bool XsetwacomAdaptor::setArea(const QString& value) { Q_D( const XsetwacomAdaptor ); TabletArea area(value); if ( area.isEmpty() ) { return setParameter(d->device, XsetwacomProperty::ResetArea.key(), QString()); } return setParameter(d->device, XsetwacomProperty::Area.key(), area.toString()); } bool XsetwacomAdaptor::setRotation(const QString& value) { Q_D( const XsetwacomAdaptor ); const ScreenRotation* lookup = ScreenRotation::find(value); - ScreenRotation rotation = (lookup != NULL) ? *lookup : ScreenRotation::NONE; + ScreenRotation rotation = lookup ? *lookup : ScreenRotation::NONE; // only accept real rotations if (rotation == ScreenRotation::NONE || rotation == ScreenRotation::CW || rotation == ScreenRotation::CCW || rotation == ScreenRotation::HALF) { setParameter(d->device, XsetwacomProperty::Rotate.key(), rotation.key()); return true; } // do not set this value as it is not a real screen rotation // probably some auto-mode. return false; } bool XsetwacomAdaptor::setParameter(const QString& device, const QString& param, const QString& value) const { QString cmd; if (value.isEmpty()) { cmd = QString::fromLatin1( "xsetwacom set \"%1\" %2" ).arg( device ).arg( param ); } else { cmd = QString::fromLatin1( "xsetwacom set \"%1\" %2 \"%3\"" ).arg( device ).arg( param ).arg( value ); } QProcess setConf; setConf.start( cmd ); if( !setConf.waitForStarted() || !setConf.waitForFinished()) { return false; } QByteArray errorOutput = setConf.readAll(); if( !errorOutput.isEmpty() ) { dbgWacom << cmd << " : " << errorOutput; return false; } return true; }