File indexing completed on 2024-05-12 05:35:47

0001 /*
0002     SPDX-FileCopyrightText: 2018 Roman Gilg <subdiff@gmail.com>
0003     SPDX-FileCopyrightText: 2021 Aleix Pol Gonzalez <aleixpol@kde.org>
0004 
0005     Work sponsored by Technische Universität Dresden:
0006     SPDX-FileCopyrightText: 2022 Klarälvdalens Datakonsult AB a KDAB Group company <info@kdab.com>
0007 
0008     SPDX-License-Identifier: GPL-2.0-or-later
0009 */
0010 
0011 #include "devicesmodel.h"
0012 
0013 #include <utility>
0014 
0015 #include <QDBusInterface>
0016 
0017 #include "inputdevice.h"
0018 #include "logging.h"
0019 
0020 DevicesModel::DevicesModel(const QByteArray &kind, QObject *parent)
0021     : QAbstractListModel(parent)
0022     , m_kind(kind)
0023 {
0024     m_deviceManager = new QDBusInterface(QStringLiteral("org.kde.KWin"),
0025                                          QStringLiteral("/org/kde/KWin/InputDevice"),
0026                                          QStringLiteral("org.kde.KWin.InputDeviceManager"),
0027                                          QDBusConnection::sessionBus(),
0028                                          this);
0029 
0030     resetModel();
0031 
0032     m_deviceManager->connection().connect(QStringLiteral("org.kde.KWin"),
0033                                           QStringLiteral("/org/kde/KWin/InputDevice"),
0034                                           QStringLiteral("org.kde.KWin.InputDeviceManager"),
0035                                           QStringLiteral("deviceAdded"),
0036                                           this,
0037                                           SLOT(onDeviceAdded(QString)));
0038     m_deviceManager->connection().connect(QStringLiteral("org.kde.KWin"),
0039                                           QStringLiteral("/org/kde/KWin/InputDevice"),
0040                                           QStringLiteral("org.kde.KWin.InputDeviceManager"),
0041                                           QStringLiteral("deviceRemoved"),
0042                                           this,
0043                                           SLOT(onDeviceRemoved(QString)));
0044 }
0045 
0046 void DevicesModel::resetModel()
0047 {
0048     beginResetModel();
0049     m_devices.clear();
0050 
0051     QStringList devicesSysNames;
0052     const QVariant reply = m_deviceManager->property("devicesSysNames");
0053     if (reply.isValid()) {
0054         devicesSysNames = reply.toStringList();
0055     } else {
0056         qCWarning(LIBKWINDEVICES) << "Error on receiving device list from KWin.";
0057         return;
0058     }
0059 
0060     for (const QString &sysname : std::as_const(devicesSysNames)) {
0061         addDevice(sysname, false);
0062     }
0063     endResetModel();
0064 }
0065 
0066 QVariant DevicesModel::data(const QModelIndex &index, int role) const
0067 {
0068     if (!checkIndex(index, CheckIndexOption::IndexIsValid) || index.column() != 0) {
0069         return {};
0070     }
0071 
0072     switch (role) {
0073     case Qt::DisplayRole:
0074         return m_devices.at(index.row())->name();
0075     case Qt::UserRole:
0076         return QVariant::fromValue<QObject *>(m_devices.at(index.row()).get());
0077     }
0078     return {};
0079 }
0080 
0081 int DevicesModel::rowCount(const QModelIndex &parent) const
0082 {
0083     return parent.isValid() ? 0 : m_devices.size();
0084 }
0085 
0086 void DevicesModel::onDeviceAdded(const QString &sysName)
0087 {
0088     if (std::any_of(m_devices.cbegin(), m_devices.cend(), [sysName](auto &t) {
0089             return t->sysName() == sysName;
0090         })) {
0091         return;
0092     }
0093 
0094     addDevice(sysName, true);
0095 }
0096 
0097 void DevicesModel::addDevice(const QString &sysName, bool tellModel)
0098 {
0099     QDBusInterface deviceIface(QStringLiteral("org.kde.KWin"),
0100                                QStringLiteral("/org/kde/KWin/InputDevice/") + sysName,
0101                                QStringLiteral("org.kde.KWin.InputDevice"),
0102                                QDBusConnection::sessionBus(),
0103                                this);
0104     QVariant reply = deviceIface.property(m_kind);
0105     if (reply.isValid() && reply.toBool()) {
0106         auto dev = std::make_unique<InputDevice>(sysName, this);
0107         connect(dev.get(), &InputDevice::needsSaveChanged, this, &DevicesModel::needsSaveChanged);
0108 
0109         if (tellModel) {
0110             beginInsertRows({}, m_devices.size(), m_devices.size());
0111         }
0112         qCDebug(LIBKWINDEVICES).nospace() << "Device connected: " << dev->name() << " (" << dev->sysName() << ")";
0113         m_devices.push_back(std::move(dev));
0114         if (tellModel) {
0115             endInsertRows();
0116         }
0117     }
0118 }
0119 
0120 void DevicesModel::onDeviceRemoved(const QString &sysName)
0121 {
0122     auto it = std::find_if(m_devices.cbegin(), m_devices.cend(), [sysName](auto &t) {
0123         return t->sysName() == sysName;
0124     });
0125     if (it == m_devices.cend()) {
0126         return;
0127     }
0128 
0129     auto dev = static_cast<InputDevice *>(it->get());
0130     qCDebug(LIBKWINDEVICES).nospace() << "Device disconnected: " << dev->name() << " (" << dev->sysName() << ")";
0131 
0132     int index = std::distance(m_devices.cbegin(), it);
0133 
0134     beginRemoveRows({}, index, index);
0135     m_devices.erase(it);
0136     endRemoveRows();
0137 }
0138 
0139 InputDevice *DevicesModel::deviceAt(int row) const
0140 {
0141     if (row == -1) {
0142         return nullptr;
0143     }
0144 
0145     return m_devices.at(row).get();
0146 }
0147 
0148 QHash<int, QByteArray> DevicesModel::roleNames() const
0149 {
0150     return {
0151         {Qt::DisplayRole, "display"},
0152     };
0153 }
0154 
0155 void DevicesModel::defaults()
0156 {
0157     for (auto &device : m_devices) {
0158         device->defaults();
0159     }
0160 }
0161 
0162 void DevicesModel::load()
0163 {
0164     for (auto &device : m_devices) {
0165         device->load();
0166     }
0167 }
0168 
0169 void DevicesModel::save()
0170 {
0171     for (auto &device : m_devices) {
0172         device->save();
0173     }
0174 }
0175 
0176 bool DevicesModel::isDefaults() const
0177 {
0178     return std::all_of(m_devices.cbegin(), m_devices.cend(), [](auto &dev) {
0179         return dev->isDefaults();
0180     });
0181 }
0182 
0183 bool DevicesModel::isSaveNeeded() const
0184 {
0185     return std::any_of(m_devices.cbegin(), m_devices.cend(), [](auto &dev) {
0186         return dev->isSaveNeeded();
0187     });
0188 }