File indexing completed on 2024-05-12 17:07:20
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 }