File indexing completed on 2024-06-23 05:29:34

0001 /*
0002     SPDX-FileCopyrightText: 2018 Roman Gilg <subdiff@gmail.com>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "kwin_wl_backend.h"
0008 #include "kwin_wl_device.h"
0009 
0010 #include <algorithm>
0011 
0012 #include <KConfigGroup>
0013 #include <KLocalizedString>
0014 #include <KSharedConfig>
0015 
0016 #include <QDBusInterface>
0017 #include <QDBusMessage>
0018 #include <QDBusReply>
0019 #include <QKeySequence>
0020 #include <QStringList>
0021 
0022 #include "logging.h"
0023 
0024 KWinWaylandBackend::KWinWaylandBackend(QObject *parent)
0025     : InputBackend(parent)
0026 {
0027     m_mode = InputBackendMode::KWinWayland;
0028 
0029     m_deviceManager = new QDBusInterface(QStringLiteral("org.kde.KWin"),
0030                                          QStringLiteral("/org/kde/KWin/InputDevice"),
0031                                          QStringLiteral("org.kde.KWin.InputDeviceManager"),
0032                                          QDBusConnection::sessionBus(),
0033                                          this);
0034 
0035     findDevices();
0036 
0037     m_deviceManager->connection().connect(QStringLiteral("org.kde.KWin"),
0038                                           QStringLiteral("/org/kde/KWin/InputDevice"),
0039                                           QStringLiteral("org.kde.KWin.InputDeviceManager"),
0040                                           QStringLiteral("deviceAdded"),
0041                                           this,
0042                                           SLOT(onDeviceAdded(QString)));
0043     m_deviceManager->connection().connect(QStringLiteral("org.kde.KWin"),
0044                                           QStringLiteral("/org/kde/KWin/InputDevice"),
0045                                           QStringLiteral("org.kde.KWin.InputDeviceManager"),
0046                                           QStringLiteral("deviceRemoved"),
0047                                           this,
0048                                           SLOT(onDeviceRemoved(QString)));
0049 }
0050 
0051 KWinWaylandBackend::~KWinWaylandBackend()
0052 {
0053     qDeleteAll(m_devices);
0054     delete m_deviceManager;
0055 }
0056 
0057 void KWinWaylandBackend::findDevices()
0058 {
0059     QStringList devicesSysNames;
0060     const QVariant replyDevicesSysNames = m_deviceManager->property("devicesSysNames");
0061     if (replyDevicesSysNames.isValid()) {
0062         qCDebug(KCM_MOUSE) << "Devices list received successfully from KWin.";
0063         devicesSysNames = replyDevicesSysNames.toStringList();
0064     } else {
0065         qCCritical(KCM_MOUSE) << "Error on receiving device list from KWin.";
0066         m_errorString = i18n("Querying input devices failed. Please reopen this settings module.");
0067         return;
0068     }
0069 
0070     for (const QString &sn : std::as_const(devicesSysNames)) {
0071         QDBusInterface deviceIface(QStringLiteral("org.kde.KWin"),
0072                                    QStringLiteral("/org/kde/KWin/InputDevice/") + sn,
0073                                    QStringLiteral("org.kde.KWin.InputDevice"),
0074                                    QDBusConnection::sessionBus(),
0075                                    this);
0076         QVariant reply = deviceIface.property("pointer");
0077         if (reply.isValid() && reply.toBool()) {
0078             reply = deviceIface.property("touchpad");
0079             if (reply.isValid() && reply.toBool()) {
0080                 continue;
0081             }
0082 
0083             KWinWaylandDevice *dev = new KWinWaylandDevice(sn);
0084             if (!dev->init()) {
0085                 qCCritical(KCM_MOUSE) << "Error on creating device object" << sn;
0086                 m_errorString = i18n("Critical error on reading fundamental device infos of %1.", sn);
0087                 return;
0088             }
0089             m_devices.append(dev);
0090             qCDebug(KCM_MOUSE).nospace() << "Device found: " << dev->name() << " (" << dev->sysName() << ")";
0091         }
0092     }
0093 }
0094 
0095 bool KWinWaylandBackend::applyConfig()
0096 {
0097     KConfigGroup buttonGroup = KSharedConfig::openConfig(QStringLiteral("kcminputrc"))->group(QStringLiteral("ButtonRebinds")).group(QStringLiteral("Mouse"));
0098     for (auto it = m_buttonMapping.cbegin(); it != m_buttonMapping.cend(); ++it) {
0099         if (auto keys = it.value().value<QKeySequence>(); !keys.isEmpty()) {
0100             buttonGroup.writeEntry(it.key(), QStringList{"Key", keys.toString(QKeySequence::PortableText)}, KConfig::Notify);
0101         } else {
0102             buttonGroup.deleteEntry(it.key(), KConfig::Notify);
0103         }
0104     }
0105 
0106     return std::all_of(m_devices.constBegin(), m_devices.constEnd(), [](QObject *t) {
0107         return static_cast<KWinWaylandDevice *>(t)->applyConfig();
0108     });
0109 }
0110 
0111 bool KWinWaylandBackend::getConfig()
0112 {
0113     m_loadedButtonMapping.clear();
0114     const KConfigGroup buttonGroup = KSharedConfig::openConfig(QStringLiteral("kcminputrc"))->group(QStringLiteral("ButtonRebinds")).group(QStringLiteral("Mouse"));
0115     for (int i = 1; i <= 24; ++i) {
0116         const QString buttonName = QLatin1String("ExtraButton%1").arg(QString::number(i));
0117         auto entry = buttonGroup.readEntry(buttonName, QStringList());
0118         if (entry.size() == 2 && entry.first() == QLatin1String("Key")) {
0119             auto keys = QKeySequence::fromString(entry.at(1), QKeySequence::PortableText);
0120             if (!keys.isEmpty()) {
0121                 m_loadedButtonMapping.insert(buttonName, keys);
0122             }
0123         }
0124     }
0125     m_buttonMapping = m_loadedButtonMapping;
0126 
0127     return std::all_of(m_devices.constBegin(), m_devices.constEnd(), [](QObject *t) {
0128         return static_cast<KWinWaylandDevice *>(t)->init();
0129     });
0130 }
0131 
0132 bool KWinWaylandBackend::getDefaultConfig()
0133 {
0134     return std::all_of(m_devices.constBegin(), m_devices.constEnd(), [](QObject *t) {
0135         return static_cast<KWinWaylandDevice *>(t)->getDefaultConfig();
0136     });
0137 }
0138 
0139 bool KWinWaylandBackend::isChangedConfig() const
0140 {
0141     return m_buttonMapping != m_loadedButtonMapping || std::any_of(m_devices.constBegin(), m_devices.constEnd(), [](QObject *t) {
0142         return static_cast<KWinWaylandDevice *>(t)->isChangedConfig();
0143     });
0144 }
0145 
0146 QVariantMap KWinWaylandBackend::buttonMapping()
0147 {
0148     return m_buttonMapping;
0149 }
0150 
0151 void KWinWaylandBackend::setButtonMapping(const QVariantMap &mapping)
0152 {
0153     if (m_buttonMapping != mapping) {
0154         m_buttonMapping = mapping;
0155         Q_EMIT buttonMappingChanged();
0156     }
0157 }
0158 
0159 void KWinWaylandBackend::onDeviceAdded(QString sysName)
0160 {
0161     if (std::any_of(m_devices.constBegin(), m_devices.constEnd(), [sysName](QObject *t) {
0162             return static_cast<KWinWaylandDevice *>(t)->sysName() == sysName;
0163         })) {
0164         return;
0165     }
0166 
0167     QDBusInterface deviceIface(QStringLiteral("org.kde.KWin"),
0168                                QStringLiteral("/org/kde/KWin/InputDevice/") + sysName,
0169                                QStringLiteral("org.kde.KWin.InputDevice"),
0170                                QDBusConnection::sessionBus(),
0171                                this);
0172     QVariant reply = deviceIface.property("pointer");
0173 
0174     if (reply.isValid() && reply.toBool()) {
0175         reply = deviceIface.property("touchpad");
0176         if (reply.isValid() && reply.toBool()) {
0177             return;
0178         }
0179 
0180         KWinWaylandDevice *dev = new KWinWaylandDevice(sysName);
0181         if (!dev->init()) {
0182             Q_EMIT deviceAdded(false);
0183             return;
0184         }
0185 
0186         m_devices.append(dev);
0187         qCDebug(KCM_MOUSE).nospace() << "Device connected: " << dev->name() << " (" << dev->sysName() << ")";
0188         Q_EMIT deviceAdded(true);
0189     }
0190 }
0191 
0192 void KWinWaylandBackend::onDeviceRemoved(QString sysName)
0193 {
0194     QList<QObject *>::const_iterator it = std::find_if(m_devices.constBegin(), m_devices.constEnd(), [sysName](QObject *t) {
0195         return static_cast<KWinWaylandDevice *>(t)->sysName() == sysName;
0196     });
0197     if (it == m_devices.cend()) {
0198         return;
0199     }
0200 
0201     KWinWaylandDevice *dev = static_cast<KWinWaylandDevice *>(*it);
0202     qCDebug(KCM_MOUSE).nospace() << "Device disconnected: " << dev->name() << " (" << dev->sysName() << ")";
0203 
0204     int index = it - m_devices.cbegin();
0205     m_devices.removeAt(index);
0206     Q_EMIT deviceRemoved(index);
0207 }