Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qdbusservicewatcher.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
7#include "qdbusutil_p.h"
8
9#include <QStringList>
10
11#include <private/qproperty_p.h>
12#include <private/qobject_p.h>
13#include <private/qdbusconnection_p.h>
14
15#ifndef QT_NO_DBUS
16
18
20{
21 Q_DECLARE_PUBLIC(QDBusServiceWatcher)
22public:
27
34
36 void setWatchModeForwardToQ(QDBusServiceWatcher::WatchMode mode)
37 {
38 q_func()->setWatchMode(mode);
39 }
41 &QDBusServiceWatcherPrivate::setWatchModeForwardToQ)
42
43 void _q_serviceOwnerChanged(const QString &, const QString &, const QString &);
44 void setConnection(const QStringList &newServices, const QDBusConnection &newConnection,
45 QDBusServiceWatcher::WatchMode newMode);
46
47 void addService(const QString &service, QDBusServiceWatcher::WatchMode mode);
48 void removeService(const QString &service, QDBusServiceWatcher::WatchMode mode);
49};
50
51void QDBusServiceWatcherPrivate::_q_serviceOwnerChanged(const QString &service, const QString &oldOwner, const QString &newOwner)
52{
53 Q_Q(QDBusServiceWatcher);
54 emit q->serviceOwnerChanged(service, oldOwner, newOwner);
55 if (oldOwner.isEmpty())
56 emit q->serviceRegistered(service);
57 else if (newOwner.isEmpty())
58 emit q->serviceUnregistered(service);
59}
60
61void QDBusServiceWatcherPrivate::setConnection(const QStringList &newServices,
62 const QDBusConnection &newConnection,
63 QDBusServiceWatcher::WatchMode newMode)
64{
65 const QStringList oldServices = watchedServicesData.valueBypassingBindings();
66 const QDBusServiceWatcher::WatchMode oldMode = watchMode.valueBypassingBindings();
67 if (connection.isConnected()) {
68 // remove older rules
69 for (const QString &s : oldServices)
70 removeService(s, oldMode);
71 }
72
73 connection = newConnection;
74 watchMode.setValueBypassingBindings(newMode); // caller has to call notify()
75 watchedServicesData.setValueBypassingBindings(newServices); // caller has to call notify()
76
77 if (connection.isConnected()) {
78 // add new rules
79 for (const QString &s : newServices)
80 addService(s, newMode);
81 }
82}
83
84void QDBusServiceWatcherPrivate::addService(const QString &service,
85 QDBusServiceWatcher::WatchMode mode)
86{
87 QDBusConnectionPrivate *d = QDBusConnectionPrivate::d(connection);
88 if (d && d->shouldWatchService(service))
89 d->watchService(service, mode, q_func(), SLOT(_q_serviceOwnerChanged(QString,QString,QString)));
90}
91
92void QDBusServiceWatcherPrivate::removeService(const QString &service,
93 QDBusServiceWatcher::WatchMode mode)
94{
95 QDBusConnectionPrivate *d = QDBusConnectionPrivate::d(connection);
96 if (d && d->shouldWatchService(service))
97 d->unwatchService(service, mode, q_func(), SLOT(_q_serviceOwnerChanged(QString,QString,QString)));
98}
99
100/*!
101 \class QDBusServiceWatcher
102 \since 4.6
103 \inmodule QtDBus
104
105 \brief The QDBusServiceWatcher class allows the user to watch for a bus service change.
106
107 A QDBusServiceWatcher object can be used to notify the application about
108 an ownership change of a service name on the bus. It has three watch
109 modes:
110
111 \list
112 \li Watching for service registration only.
113 \li Watching for service unregistration only.
114 \li Watching for any kind of service ownership change (the default mode).
115 \endlist
116
117 Besides being created or deleted, services may change owners without a
118 unregister/register operation happening. So the serviceRegistered()
119 and serviceUnregistered() signals may not be emitted if that
120 happens.
121
122 This class is more efficient than using the
123 QDBusConnectionInterface::serviceOwnerChanged() signal because it allows
124 one to receive only the signals for which the class is interested in.
125
126 Ending a service name with the character '*' will match all service names
127 within the specified namespace.
128
129 For example "com.example.backend1*" will match
130 \list
131 \li com.example.backend1
132 \li com.example.backend1.foo
133 \li com.example.backend1.foo.bar
134 \endlist
135 Substrings in the same domain will not be matched, i.e "com.example.backend12".
136
137 \sa QDBusConnection
138*/
139
140/*!
141 \enum QDBusServiceWatcher::WatchModeFlag
142
143 QDBusServiceWatcher supports three different watch modes, which are configured by this flag:
144
145 \value WatchForRegistration watch for service registration only, ignoring
146 any signals related to other service ownership change.
147
148 \value WatchForUnregistration watch for service unregistration only,
149 ignoring any signals related to other service ownership change.
150
151 \value WatchForOwnerChange watch for any kind of service ownership
152 change.
153*/
154
155/*!
156 \property QDBusServiceWatcher::watchMode
157 \brief the current watch mode for this QDBusServiceWatcher object.
158
159 The default value for this property is
160 QDBusServiceWatcher::WatchForOwnershipChange.
161*/
162
163/*!
164 \property QDBusServiceWatcher::watchedServices
165 \brief the list of services watched.
166
167 \note Modifying this list with setServicesWatched() is an expensive
168 operation. If you can, prefer to change it by way of addWatchedService()
169 and removeWatchedService().
170*/
171
172/*!
173 \fn void QDBusServiceWatcher::serviceRegistered(const QString &serviceName)
174
175 This signal is emitted whenever this object detects that the service \a
176 serviceName became available on the bus.
177
178 \sa serviceUnregistered(), serviceOwnerChanged()
179*/
180
181/*!
182 \fn void QDBusServiceWatcher::serviceUnregistered(const QString &serviceName)
183
184 This signal is emitted whenever this object detects that the service \a
185 serviceName was unregistered from the bus and is no longer available.
186
187 \sa serviceRegistered(), serviceOwnerChanged()
188*/
189
190/*!
191 \fn void QDBusServiceWatcher::serviceOwnerChanged(const QString &serviceName, const QString &oldOwner, const QString &newOwner)
192
193 This signal is emitted whenever this object detects that there was a
194 service ownership change relating to the \a serviceName service. The \a
195 oldOwner parameter contains the old owner name and \a newOwner is the new
196 owner. Both \a oldOwner and \a newOwner are unique connection names.
197
198 Note that this signal is also emitted whenever the \a serviceName service
199 was registered or unregistered. If it was registered, \a oldOwner will
200 contain an empty string, whereas if it was unregistered, \a newOwner will
201 contain an empty string.
202
203 If you need only to find out if the service is registered or unregistered
204 only, without being notified that the ownership changed, consider using
205 the specific modes for those operations. This class is more efficient if
206 you use the more specific modes.
207
208 \sa serviceRegistered(), serviceUnregistered()
209*/
210
211/*!
212 Creates a QDBusServiceWatcher object. Note that until you set a
213 connection with setConnection(), this object will not emit any signals.
214
215 The \a parent parameter is passed to QObject to set the parent of this
216 object.
217*/
218QDBusServiceWatcher::QDBusServiceWatcher(QObject *parent)
219 : QObject(*new QDBusServiceWatcherPrivate(QDBusConnection(QString()), WatchForOwnerChange), parent)
220{
221}
222
223/*!
224 Creates a QDBusServiceWatcher object and attaches it to the \a connection
225 connection. Also, this function immediately starts watching for \a
226 watchMode changes to service \a service.
227
228 The \a parent parameter is passed to QObject to set the parent of this
229 object.
230*/
231QDBusServiceWatcher::QDBusServiceWatcher(const QString &service, const QDBusConnection &connection, WatchMode watchMode, QObject *parent)
232 : QObject(*new QDBusServiceWatcherPrivate(connection, watchMode), parent)
233{
234 d_func()->setConnection(QStringList() << service, connection, watchMode);
235}
236
237/*!
238 Destroys the QDBusServiceWatcher object and releases any resources
239 associated with it.
240*/
241QDBusServiceWatcher::~QDBusServiceWatcher()
242{
243}
244
245/*!
246 Returns the list of D-Bus services that are being watched.
247
248 \sa setWatchedServices()
249*/
250QStringList QDBusServiceWatcher::watchedServices() const
251{
252 return d_func()->watchedServicesData;
253}
254
255/*!
256 Sets the list of D-Bus services being watched to be \a services.
257
258 Note that setting the entire list means removing all previous rules for
259 watching services and adding new ones. This is an expensive operation and
260 should be avoided, if possible. Instead, use addWatchedService() and
261 removeWatchedService() if you can to manipulate entries in the list.
262
263 Removes any existing binding of watchedServices.
264*/
265void QDBusServiceWatcher::setWatchedServices(const QStringList &services)
266{
267 Q_D(QDBusServiceWatcher);
268 d->watchedServicesData.removeBindingUnlessInWrapper();
269 if (services == d->watchedServicesData.valueBypassingBindings())
270 return;
271 // trigger watchMode re-evaluation, but only once for the setter
272 d->setConnection(services, d->connection, d->watchMode);
273 d->watchedServicesData.notify();
274}
275
276QBindable<QStringList> QDBusServiceWatcher::bindableWatchedServices()
277{
278 Q_D(QDBusServiceWatcher);
279 return &d->watchedServicesData;
280}
281
282/*!
283 Adds \a newService to the list of services to be watched by this object.
284 This function is more efficient than setWatchedServices() and should be
285 used whenever possible to add services.
286
287 Removes any existing binding of watchedServices.
288*/
289void QDBusServiceWatcher::addWatchedService(const QString &newService)
290{
291 Q_D(QDBusServiceWatcher);
292 d->watchedServicesData.removeBindingUnlessInWrapper();
293 auto services = d->watchedServicesData.valueBypassingBindings();
294 if (services.contains(newService))
295 return;
296 // re-evaluate watch mode
297 d->addService(newService, d->watchMode);
298
299 services << newService;
300 d->watchedServicesData.setValueBypassingBindings(services);
301
302 d->watchedServicesData.notify();
303}
304
305/*!
306 Removes the \a service from the list of services being watched by this
307 object. Note that D-Bus notifications are asynchronous, so there may
308 still be signals pending delivery about \a service. Those signals will
309 still be emitted whenever the D-Bus messages are processed.
310
311 Removes any existing binding of watchedServices.
312
313 This function returns \c true if any services were removed.
314*/
315bool QDBusServiceWatcher::removeWatchedService(const QString &service)
316{
317 Q_D(QDBusServiceWatcher);
318 d->watchedServicesData.removeBindingUnlessInWrapper();
319 auto tempList = d->watchedServicesData.valueBypassingBindings();
320 const bool result = tempList.removeOne(service);
321 if (!result)
322 return false; // nothing changed
323
324 // re-evaluate watch mode
325 d->removeService(service, d->watchMode);
326 d->watchedServicesData.setValueBypassingBindings(tempList);
327 d->watchedServicesData.notify();
328 return true;
329}
330
331QDBusServiceWatcher::WatchMode QDBusServiceWatcher::watchMode() const
332{
333 return d_func()->watchMode;
334}
335
336QBindable<QDBusServiceWatcher::WatchMode> QDBusServiceWatcher::bindableWatchMode()
337{
338 return &d_func()->watchMode;
339}
340
341void QDBusServiceWatcher::setWatchMode(WatchMode mode)
342{
343 Q_D(QDBusServiceWatcher);
344 d->watchMode.removeBindingUnlessInWrapper();
345 if (mode == d->watchMode.valueBypassingBindings())
346 return;
347 // trigger watchedServicesData re-evaluation, but only once for the setter
348 d->setConnection(d->watchedServicesData, d->connection, mode);
349 d->watchMode.notify();
350}
351
352/*!
353 Returns the QDBusConnection that this object is attached to.
354
355 \sa setConnection()
356*/
357QDBusConnection QDBusServiceWatcher::connection() const
358{
359 return d_func()->connection;
360}
361
362/*!
363 Sets the D-Bus connection that this object is attached to be \a
364 connection. All services watched will be transferred to this connection.
365
366 Note that QDBusConnection objects are reference counted:
367 QDBusServiceWatcher will keep a reference for this connection while it
368 exists. The connection is not closed until the reference count drops to
369 zero, so this will ensure that any notifications are received while this
370 QDBusServiceWatcher object exists.
371
372 \sa connection()
373*/
374void QDBusServiceWatcher::setConnection(const QDBusConnection &connection)
375{
376 Q_D(QDBusServiceWatcher);
377 if (connection.name() == d->connection.name())
378 return;
379 d->setConnection(d->watchedServicesData, connection, d->watchMode);
380}
381
382QT_END_NAMESPACE
383
384#endif // QT_NO_DBUS
385
386#include "moc_qdbusservicewatcher.cpp"
const QString const QString &void setConnection(const QStringList &newServices, const QDBusConnection &newConnection, QDBusServiceWatcher::WatchMode newMode)
void setWatchModeForwardToQ(QDBusServiceWatcher::WatchMode mode)
Q_OBJECT_COMPAT_PROPERTY(QDBusServiceWatcherPrivate, QDBusServiceWatcher::WatchMode, watchMode, &QDBusServiceWatcherPrivate::setWatchModeForwardToQ) void _q_serviceOwnerChanged(const QString &
void removeService(const QString &service, QDBusServiceWatcher::WatchMode mode)
void addService(const QString &service, QDBusServiceWatcher::WatchMode mode)