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
165 if (!storageAccess) {
166 continue;
167 }
168
169 QString mountPath = storageAccess->filePath();
170
171 if (mountPath.size() <= match_length || !path.startsWith(mountPath)) {
172 continue;
173 }
174
175 const auto realLength = mountPath.back() == QLatin1Char('/') ? mountPath.size() - 1 : mountPath.size();
176
177 // `startsWith` implies `path.size() >= mountPath.size()`
178 if (path.size() == realLength || path[realLength] == QLatin1Char('/')) {
179 match_length = realLength;
180 match = device;
181 }
182 }
183 return match;
184}
185
186Solid::DeviceNotifier *Solid::DeviceNotifier::instance()
187{
188 return globalDeviceStorage->notifier();
189}
190
191void Solid::DeviceManagerPrivate::_k_deviceAdded(const QString &udi)
192{
193 if (m_devicesMap.contains(udi)) {
194 DevicePrivate *dev = m_devicesMap[udi].data();
195
196 // Ok, this one was requested somewhere was invalid
197 // and now becomes magically valid!
198
199 if (dev && dev->backendObject() == nullptr) {
200 dev->setBackendObject(createBackendObject(udi));
201 Q_ASSERT(dev->backendObject() != nullptr);
202 }
203 }
204
205 Q_EMIT deviceAdded(udi);
206}
207
208void Solid::DeviceManagerPrivate::_k_deviceRemoved(const QString &udi)
209{
210 if (m_devicesMap.contains(udi)) {
211 DevicePrivate *dev = m_devicesMap[udi].data();
212
213 // Ok, this one was requested somewhere was valid
214 // and now becomes magically invalid!
215
216 if (dev) {
217 dev->setBackendObject(nullptr);
218 Q_ASSERT(dev->backendObject() == nullptr);
219 }
220 }
221
222 Q_EMIT deviceRemoved(udi);
223}
224
225void Solid::DeviceManagerPrivate::_k_destroyed(QObject *object)
226{
227 QString udi = m_reverseMap.take(object);
228
229 if (!udi.isEmpty()) {
230 m_devicesMap.remove(udi);
231 }
232}
233
234Solid::DevicePrivate *Solid::DeviceManagerPrivate::findRegisteredDevice(const QString &udi)
235{
236 if (udi.isEmpty()) {
237 return m_nullDevice.data();
238 } else if (m_devicesMap.contains(udi)) {
239 return m_devicesMap[udi].data();
240 } else {
241 Ifaces::Device *iface = createBackendObject(udi);
242
243 DevicePrivate *devData = new DevicePrivate(udi);
244 devData->setBackendObject(iface);
245
246 QPointer<DevicePrivate> ptr(devData);
247 m_devicesMap[udi] = ptr;
248 m_reverseMap[devData] = udi;
249
250 connect(devData, &QObject::destroyed, this, &DeviceManagerPrivate::_k_destroyed);
251
252 return devData;
253 }
254}
255
256Solid::Ifaces::Device *Solid::DeviceManagerPrivate::createBackendObject(const QString &udi)
257{
258 const auto backends = globalDeviceStorage->managerBackends();
259
260 for (const auto &backend : backends) {
261 if (!udi.startsWith(backend->udiPrefix())) {
262 continue;
263 }
264
265 Ifaces::Device *iface = nullptr;
266
267 QObject *object = backend->createDevice(udi);
268 iface = qobject_cast<Ifaces::Device *>(object);
269
270 if (iface == nullptr) {
271 delete object;
272 }
273
274 return iface;
275 }
276
277 return nullptr;
278}
279
280Solid::DeviceManagerStorage::DeviceManagerStorage()
281{
282}
283
284QList<Solid::Ifaces::DeviceManager *> Solid::DeviceManagerStorage::managerBackends()
285{
286 ensureManagerCreated();
287 return m_storage.localData()->managerBackends();
288}
289
290Solid::DeviceNotifier *Solid::DeviceManagerStorage::notifier()
291{
292 ensureManagerCreated();
293 return m_storage.localData();
294}
295
296void Solid::DeviceManagerStorage::ensureManagerCreated()
297{
298 if (!m_storage.hasLocalData()) {
299 m_storage.setLocalData(new DeviceManagerPrivate());
300 }
301}
302
303#include "moc_devicemanager_p.cpp"
304#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 Fri Dec 20 2024 11:47:35 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.