Solid

frontend/devicemanager.cpp
1/*
2 SPDX-FileCopyrightText: 2005-2007 Kevin Ottens <ervin@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
5*/
6
7#include "devicemanager_p.h" //krazy:exclude=includes (devicenotifier.h is the header file for this class)
8#include "devicenotifier.h"
9
10#include "device.h"
11#include "device_p.h"
12#include "devices_debug.h"
13#include "predicate.h"
14#include "storageaccess.h"
15#include "storagevolume.h"
16
17#include "ifaces/device.h"
18#include "ifaces/devicemanager.h"
19
20#include "soliddefs_p.h"
21
22#include <QLoggingCategory>
23
24#include <set>
25
26Q_GLOBAL_STATIC(Solid::DeviceManagerStorage, globalDeviceStorage)
27
28Solid::DeviceManagerPrivate::DeviceManagerPrivate()
29 : m_nullDevice(new DevicePrivate(QString()))
30{
31 loadBackends();
32
33 const auto backends = managerBackends();
34 for (const auto &backend : backends) {
35 connect(backend, &Solid::Ifaces::DeviceManager::deviceAdded, this, &Solid::DeviceManagerPrivate::_k_deviceAdded);
36 connect(backend, &Solid::Ifaces::DeviceManager::deviceRemoved, this, &Solid::DeviceManagerPrivate::_k_deviceRemoved);
37 }
38}
39
40Solid::DeviceManagerPrivate::~DeviceManagerPrivate()
41{
42 const auto backends = managerBackends();
43 for (const auto &backend : backends) {
44 disconnect(backend, &Solid::Ifaces::DeviceManager::deviceAdded, this, &Solid::DeviceManagerPrivate::_k_deviceAdded);
45 disconnect(backend, &Solid::Ifaces::DeviceManager::deviceRemoved, this, &Solid::DeviceManagerPrivate::_k_deviceRemoved);
46 }
47
48 // take a copy as m_devicesMap is changed by Solid::DeviceManagerPrivate::_k_destroyed
49 const auto deviceMap = m_devicesMap;
50 for (QPointer<DevicePrivate> dev : deviceMap) {
51 if (!dev.data()->ref.deref()) {
52 delete dev.data();
53 }
54 }
55
56 m_devicesMap.clear();
57}
58
60{
61 QList<Device> list;
62 const auto backends = globalDeviceStorage->managerBackends();
63
64 for (const auto &backend : backends) {
65 const auto udis = backend->allDevices();
66 for (const auto &udi : udis) {
67 list.append(Device(udi));
68 }
69 }
70
71 return list;
72}
73
75{
76 Predicate p = Predicate::fromString(predicate);
77
78 if (p.isValid()) {
79 return listFromQuery(p, parentUdi);
80 } else {
81 return QList<Device>();
82 }
83}
84
86{
87 QList<Device> list;
88 const auto backends = globalDeviceStorage->managerBackends();
89
90 for (const auto &backend : backends) {
91 if (!backend->supportedInterfaces().contains(type)) {
92 continue;
93 }
94
95 const auto udis = backend->devicesFromQuery(parentUdi, type);
96 for (const auto &udi : udis) {
97 list.append(Device(udi));
98 }
99 }
100
101 return list;
102}
103
105{
106 QList<Device> list;
107 const auto usedTypes = predicate.usedTypes();
108 const auto backends = globalDeviceStorage->managerBackends();
109
110 for (const auto &backend : backends) {
111 QStringList udis;
112 if (predicate.isValid()) {
113 auto supportedTypes = backend->supportedInterfaces();
114 if (supportedTypes.intersect(usedTypes).isEmpty()) {
115 continue;
116 }
117
118 auto sortedTypes = supportedTypes.values();
119 std::sort(sortedTypes.begin(), sortedTypes.end());
120 for (const auto &type : std::as_const(sortedTypes)) {
121 udis += backend->devicesFromQuery(parentUdi, type);
122 }
123 } else {
124 udis += backend->allDevices();
125 }
126
127 std::set<QString> seen;
128 for (const auto &udi : std::as_const(udis)) {
129 const auto [it, isInserted] = seen.insert(udi);
130 if (!isInserted) {
131 continue;
132 }
133 const Device dev(udi);
134
135 bool matches = false;
136
137 if (!predicate.isValid()) {
138 matches = true;
139 } else {
140 matches = predicate.matches(dev);
141 }
142
143 if (matches) {
144 list.append(dev);
145 }
146 }
147 }
148
149 return list;
150}
151
153{
154 const QList<Device> list = Solid::Device::listFromType(DeviceInterface::Type::StorageAccess);
155 Device match;
156 int match_length = 0;
157 for (const Device &device : list) {
158 auto storageVolume = device.as<StorageVolume>();
159 if (storageVolume && storageVolume->usage() != StorageVolume::UsageType::FileSystem) {
160 continue;
161 }
162
163 auto storageAccess = device.as<StorageAccess>();
164 QString mountPath = storageAccess->filePath();
165
166 if (mountPath.size() <= match_length || !path.startsWith(mountPath)) {
167 continue;
168 }
169
170 const auto realLength = mountPath.back() == QLatin1Char('/') ? mountPath.size() - 1 : mountPath.size();
171
172 // `startsWith` implies `path.size() >= mountPath.size()`
173 if (path.size() == realLength || path[realLength] == QLatin1Char('/')) {
174 match_length = realLength;
175 match = device;
176 }
177 }
178 return match;
179}
180
181Solid::DeviceNotifier *Solid::DeviceNotifier::instance()
182{
183 return globalDeviceStorage->notifier();
184}
185
186void Solid::DeviceManagerPrivate::_k_deviceAdded(const QString &udi)
187{
188 if (m_devicesMap.contains(udi)) {
189 DevicePrivate *dev = m_devicesMap[udi].data();
190
191 // Ok, this one was requested somewhere was invalid
192 // and now becomes magically valid!
193
194 if (dev && dev->backendObject() == nullptr) {
195 dev->setBackendObject(createBackendObject(udi));
196 Q_ASSERT(dev->backendObject() != nullptr);
197 }
198 }
199
200 Q_EMIT deviceAdded(udi);
201}
202
203void Solid::DeviceManagerPrivate::_k_deviceRemoved(const QString &udi)
204{
205 if (m_devicesMap.contains(udi)) {
206 DevicePrivate *dev = m_devicesMap[udi].data();
207
208 // Ok, this one was requested somewhere was valid
209 // and now becomes magically invalid!
210
211 if (dev) {
212 dev->setBackendObject(nullptr);
213 Q_ASSERT(dev->backendObject() == nullptr);
214 }
215 }
216
217 Q_EMIT deviceRemoved(udi);
218}
219
220void Solid::DeviceManagerPrivate::_k_destroyed(QObject *object)
221{
222 QString udi = m_reverseMap.take(object);
223
224 if (!udi.isEmpty()) {
225 m_devicesMap.remove(udi);
226 }
227}
228
229Solid::DevicePrivate *Solid::DeviceManagerPrivate::findRegisteredDevice(const QString &udi)
230{
231 if (udi.isEmpty()) {
232 return m_nullDevice.data();
233 } else if (m_devicesMap.contains(udi)) {
234 return m_devicesMap[udi].data();
235 } else {
236 Ifaces::Device *iface = createBackendObject(udi);
237
238 DevicePrivate *devData = new DevicePrivate(udi);
239 devData->setBackendObject(iface);
240
241 QPointer<DevicePrivate> ptr(devData);
242 m_devicesMap[udi] = ptr;
243 m_reverseMap[devData] = udi;
244
245 connect(devData, &QObject::destroyed, this, &DeviceManagerPrivate::_k_destroyed);
246
247 return devData;
248 }
249}
250
251Solid::Ifaces::Device *Solid::DeviceManagerPrivate::createBackendObject(const QString &udi)
252{
253 const auto backends = globalDeviceStorage->managerBackends();
254
255 for (const auto &backend : backends) {
256 if (!udi.startsWith(backend->udiPrefix())) {
257 continue;
258 }
259
260 Ifaces::Device *iface = nullptr;
261
262 QObject *object = backend->createDevice(udi);
263 iface = qobject_cast<Ifaces::Device *>(object);
264
265 if (iface == nullptr) {
266 delete object;
267 }
268
269 return iface;
270 }
271
272 return nullptr;
273}
274
275Solid::DeviceManagerStorage::DeviceManagerStorage()
276{
277}
278
279QList<Solid::Ifaces::DeviceManager *> Solid::DeviceManagerStorage::managerBackends()
280{
281 ensureManagerCreated();
282 return m_storage.localData()->managerBackends();
283}
284
285Solid::DeviceNotifier *Solid::DeviceManagerStorage::notifier()
286{
287 ensureManagerCreated();
288 return m_storage.localData();
289}
290
291void Solid::DeviceManagerStorage::ensureManagerCreated()
292{
293 if (!m_storage.hasLocalData()) {
294 m_storage.setLocalData(new DeviceManagerPrivate());
295 }
296}
297
298#include "moc_devicemanager_p.cpp"
299#include "moc_devicenotifier.cpp"
Type
This enum type defines the type of device interface that a Device can have.
This class allow to query the underlying system to obtain information about the hardware available.
This class allows applications to deal with devices available in the underlying system.
static QList< Device > listFromType(const DeviceInterface::Type &type, const QString &parentUdi=QString())
Retrieves a list of devices of the system given matching the given constraints (parent and device int...
QString udi() const
Retrieves the Universal Device Identifier (UDI).
static QList< Device > allDevices()
Retrieves all the devices available in the underlying system.
static Device storageAccessFromPath(const QString &path)
Returns the Device containing the filesystem for the given path.
Device(const QString &udi=QString())
Constructs a device for a given Universal Device Identifier (UDI).
static QList< Device > listFromQuery(const Predicate &predicate, const QString &parentUdi=QString())
Retrieves a list of devices of the system given matching the given constraints (parent and predicate)
void deviceAdded(const QString &udi)
This signal is emitted when a new device appears in the system.
void deviceRemoved(const QString &udi)
This signal is emitted when a device disappears from the system.
This class specifies the interface a device will have to comply to in order to be used in the system.
This class implements predicates for devices.
bool matches(const Device &device) const
Checks if a device matches the predicate.
bool isValid() const
Indicates if the predicate is valid.
QSet< DeviceInterface::Type > usedTypes() const
Retrieves the device interface types used in this predicate.
static Predicate fromString(const QString &predicate)
Converts a string to a predicate.
This device interface is available on volume devices to access them (i.e.
This device interface is available on volume devices.
void append(QList< T > &&value)
void destroyed(QObject *obj)
QChar & back()
bool isEmpty() const const
qsizetype size() const const
bool startsWith(QChar c, Qt::CaseSensitivity cs) const const
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 18 2024 12:14:22 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.