|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
4 ** All rights reserved. |
|
5 ** Contact: Nokia Corporation (qt-info@nokia.com) |
|
6 ** |
|
7 ** This file is part of the QtDBus module of the Qt Toolkit. |
|
8 ** |
|
9 ** $QT_BEGIN_LICENSE:LGPL$ |
|
10 ** No Commercial Usage |
|
11 ** This file contains pre-release code and may not be distributed. |
|
12 ** You may use this file in accordance with the terms and conditions |
|
13 ** contained in the Technology Preview License Agreement accompanying |
|
14 ** this package. |
|
15 ** |
|
16 ** GNU Lesser General Public License Usage |
|
17 ** Alternatively, this file may be used under the terms of the GNU Lesser |
|
18 ** General Public License version 2.1 as published by the Free Software |
|
19 ** Foundation and appearing in the file LICENSE.LGPL included in the |
|
20 ** packaging of this file. Please review the following information to |
|
21 ** ensure the GNU Lesser General Public License version 2.1 requirements |
|
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
|
23 ** |
|
24 ** In addition, as a special exception, Nokia gives you certain additional |
|
25 ** rights. These rights are described in the Nokia Qt LGPL Exception |
|
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
|
27 ** |
|
28 ** If you have questions regarding the use of this file, please contact |
|
29 ** Nokia at qt-info@nokia.com. |
|
30 ** |
|
31 ** |
|
32 ** |
|
33 ** |
|
34 ** |
|
35 ** |
|
36 ** |
|
37 ** |
|
38 ** $QT_END_LICENSE$ |
|
39 ** |
|
40 ****************************************************************************/ |
|
41 |
|
42 #include "qdbusservicewatcher.h" |
|
43 #include "qdbusconnection.h" |
|
44 #include "qdbus_symbols_p.h" |
|
45 |
|
46 #include <QStringList> |
|
47 |
|
48 #include <private/qobject_p.h> |
|
49 |
|
50 QT_BEGIN_NAMESPACE |
|
51 |
|
52 Q_GLOBAL_STATIC_WITH_ARGS(QString, busService, (QLatin1String(DBUS_SERVICE_DBUS))) |
|
53 Q_GLOBAL_STATIC_WITH_ARGS(QString, busInterface, (QLatin1String(DBUS_INTERFACE_DBUS))) |
|
54 Q_GLOBAL_STATIC_WITH_ARGS(QString, signalName, (QLatin1String("NameOwnerChanged"))) |
|
55 |
|
56 class QDBusServiceWatcherPrivate: public QObjectPrivate |
|
57 { |
|
58 Q_DECLARE_PUBLIC(QDBusServiceWatcher) |
|
59 public: |
|
60 QDBusServiceWatcherPrivate(const QDBusConnection &c, QDBusServiceWatcher::WatchMode wm) |
|
61 : connection(c), watchMode(wm) |
|
62 { |
|
63 } |
|
64 |
|
65 QStringList servicesWatched; |
|
66 QDBusConnection connection; |
|
67 QDBusServiceWatcher::WatchMode watchMode; |
|
68 |
|
69 void _q_serviceOwnerChanged(const QString &, const QString &, const QString &); |
|
70 void setConnection(const QStringList &services, const QDBusConnection &c, QDBusServiceWatcher::WatchMode watchMode); |
|
71 |
|
72 QStringList matchArgsForService(const QString &service); |
|
73 void addService(const QString &service); |
|
74 void removeService(const QString &service); |
|
75 }; |
|
76 |
|
77 void QDBusServiceWatcherPrivate::_q_serviceOwnerChanged(const QString &service, const QString &oldOwner, const QString &newOwner) |
|
78 { |
|
79 Q_Q(QDBusServiceWatcher); |
|
80 emit q->serviceOwnerChanged(service, oldOwner, newOwner); |
|
81 if (oldOwner.isEmpty()) |
|
82 emit q->serviceRegistered(service); |
|
83 else if (newOwner.isEmpty()) |
|
84 emit q->serviceUnregistered(service); |
|
85 } |
|
86 |
|
87 void QDBusServiceWatcherPrivate::setConnection(const QStringList &s, const QDBusConnection &c, QDBusServiceWatcher::WatchMode wm) |
|
88 { |
|
89 if (connection.isConnected()) { |
|
90 // remove older rules |
|
91 foreach (const QString &s, servicesWatched) |
|
92 removeService(s); |
|
93 } |
|
94 |
|
95 connection = c; |
|
96 watchMode = wm; |
|
97 servicesWatched = s; |
|
98 |
|
99 if (connection.isConnected()) { |
|
100 // add new rules |
|
101 foreach (const QString &s, servicesWatched) |
|
102 addService(s); |
|
103 } |
|
104 } |
|
105 |
|
106 QStringList QDBusServiceWatcherPrivate::matchArgsForService(const QString &service) |
|
107 { |
|
108 QStringList matchArgs; |
|
109 matchArgs << service; |
|
110 |
|
111 switch (watchMode) { |
|
112 case QDBusServiceWatcher::WatchForOwnerChange: |
|
113 break; |
|
114 |
|
115 case QDBusServiceWatcher::WatchForRegistration: |
|
116 matchArgs << QString::fromLatin1("", 0); |
|
117 break; |
|
118 |
|
119 case QDBusServiceWatcher::WatchForUnregistration: |
|
120 matchArgs << QString() << QString::fromLatin1("", 0); |
|
121 break; |
|
122 } |
|
123 return matchArgs; |
|
124 } |
|
125 |
|
126 void QDBusServiceWatcherPrivate::addService(const QString &service) |
|
127 { |
|
128 QStringList matchArgs = matchArgsForService(service); |
|
129 connection.connect(*busService(), QString(), *busInterface(), *signalName(), |
|
130 matchArgs, QString(), q_func(), |
|
131 SLOT(_q_serviceOwnerChanged(QString,QString,QString))); |
|
132 } |
|
133 |
|
134 void QDBusServiceWatcherPrivate::removeService(const QString &service) |
|
135 { |
|
136 QStringList matchArgs = matchArgsForService(service); |
|
137 connection.disconnect(*busService(), QString(), *busInterface(), *signalName(), |
|
138 matchArgs, QString(), q_func(), |
|
139 SLOT(_q_serviceOwnerChanged(QString,QString,QString))); |
|
140 } |
|
141 |
|
142 /*! |
|
143 \class QDBusServiceWatcher |
|
144 \since 4.6 |
|
145 \inmodule QtDBus |
|
146 |
|
147 \brief The QDBusServiceWatcher class allows the user to watch for a bus service change. |
|
148 |
|
149 A QDBusServiceWatcher object can be used to notify the application about |
|
150 an ownership change of a service name on the bus. It has three watch |
|
151 modes: |
|
152 |
|
153 \list |
|
154 \o Watching for service registration only. |
|
155 \o Watching for service unregistration only. |
|
156 \o Watching for any kind of service ownership change (the default mode). |
|
157 \endlist |
|
158 |
|
159 Besides being created or deleted, services may change owners without a |
|
160 unregister/register operation happening. So the serviceRegistered() |
|
161 and serviceUnregistered() signals may not be emitted if that |
|
162 happens. |
|
163 |
|
164 This class is more efficient than using the |
|
165 QDBusConnectionInterface::serviceOwnerChanged() signal because it allows |
|
166 one to receive only the signals for which the class is interested in. |
|
167 |
|
168 \sa QDBusConnection |
|
169 */ |
|
170 |
|
171 /*! |
|
172 \enum QDBusServiceWatcher::WatchModeFlag |
|
173 |
|
174 QDBusServiceWatcher supports three different watch modes, which are configured by this flag: |
|
175 |
|
176 \value WatchForRegistration watch for service registration only, ignoring |
|
177 any signals related to other service ownership change. |
|
178 |
|
179 \value WatchForUnregistration watch for service unregistration only, |
|
180 ignoring any signals related to other service ownership change. |
|
181 |
|
182 \value WatchForOwnerChange watch for any kind of service ownership |
|
183 change. |
|
184 */ |
|
185 |
|
186 /*! |
|
187 \property QDBusServiceWatcher::watchMode |
|
188 |
|
189 The \c watchMode property holds the current watch mode for this |
|
190 QDBusServiceWatcher object. The default value for this property is |
|
191 QDBusServiceWatcher::WatchForOwnershipChange. |
|
192 */ |
|
193 |
|
194 /*! |
|
195 \property QDBusServiceWatcher::watchedServices |
|
196 |
|
197 The \c servicesWatched property holds the list of services watched. |
|
198 |
|
199 Note that modifying this list with setServicesWatched() is an expensive |
|
200 operation. If you can, prefer to change it by way of addWatchedService() |
|
201 and removeWatchedService(). |
|
202 */ |
|
203 |
|
204 /*! |
|
205 \fn void QDBusServiceWatcher::serviceRegistered(const QString &serviceName) |
|
206 |
|
207 This signal is emitted whenever this object detects that the service \a |
|
208 serviceName became available on the bus. |
|
209 |
|
210 \sa serviceUnregistered(), serviceOwnerChanged() |
|
211 */ |
|
212 |
|
213 /*! |
|
214 \fn void QDBusServiceWatcher::serviceUnregistered(const QString &serviceName) |
|
215 |
|
216 This signal is emitted whenever this object detects that the service \a |
|
217 serviceName was unregistered from the bus and is no longer available. |
|
218 |
|
219 \sa serviceRegistered(), serviceOwnerChanged() |
|
220 */ |
|
221 |
|
222 /*! |
|
223 \fn void QDBusServiceWatcher::serviceOwnerChanged(const QString &serviceName, const QString &oldOwner, const QString &newOwner) |
|
224 |
|
225 This signal is emitted whenever this object detects that there was a |
|
226 service ownership change relating to the \a serviceName service. The \a |
|
227 oldOwner parameter contains the old owner name and \a newOwner is the new |
|
228 owner. Both \a oldOwner and \a newOwner are unique connection names. |
|
229 |
|
230 Note that this signal is also emitted whenever the \a serviceName service |
|
231 was registered or unregistered. If it was registered, \a oldOwner will |
|
232 contain an empty string, whereas if it was unregistered, \a newOwner will |
|
233 contain an empty string. |
|
234 |
|
235 If you need only to find out if the service is registered or unregistered |
|
236 only, without being notified that the ownership changed, consider using |
|
237 the specific modes for those operations. This class is more efficient if |
|
238 you use the more specific modes. |
|
239 |
|
240 \sa serviceRegistered(), serviceUnregistered() |
|
241 */ |
|
242 |
|
243 /*! |
|
244 Creates a QDBusServiceWatcher object. Note that until you set a |
|
245 connection with setConnection(), this object will not emit any signals. |
|
246 |
|
247 The \a parent parameter is passed to QObject to set the parent of this |
|
248 object. |
|
249 */ |
|
250 QDBusServiceWatcher::QDBusServiceWatcher(QObject *parent) |
|
251 : QObject(*new QDBusServiceWatcherPrivate(QDBusConnection(QString()), WatchForOwnerChange), parent) |
|
252 { |
|
253 } |
|
254 |
|
255 /*! |
|
256 Creates a QDBusServiceWatcher object and attaches it to the \a connection |
|
257 connection. Also, this function immediately starts watching for \a |
|
258 watchMode changes to service \a service. |
|
259 |
|
260 The \a parent parameter is passed to QObject to set the parent of this |
|
261 object. |
|
262 */ |
|
263 QDBusServiceWatcher::QDBusServiceWatcher(const QString &service, const QDBusConnection &connection, WatchMode watchMode, QObject *parent) |
|
264 : QObject(*new QDBusServiceWatcherPrivate(connection, watchMode), parent) |
|
265 { |
|
266 d_func()->setConnection(QStringList() << service, connection, watchMode); |
|
267 } |
|
268 |
|
269 /*! |
|
270 Destroys the QDBusServiceWatcher object and releases any resources |
|
271 associated with it. |
|
272 */ |
|
273 QDBusServiceWatcher::~QDBusServiceWatcher() |
|
274 { |
|
275 } |
|
276 |
|
277 /*! |
|
278 Returns the list of D-Bus services that are being watched. |
|
279 |
|
280 \sa setWatchedServices() |
|
281 */ |
|
282 QStringList QDBusServiceWatcher::watchedServices() const |
|
283 { |
|
284 return d_func()->servicesWatched; |
|
285 } |
|
286 |
|
287 /*! |
|
288 Sets the list of D-Bus services being watched to be \a services. |
|
289 |
|
290 Note that setting the entire list means removing all previous rules for |
|
291 watching services and adding new ones. This is an expensive operation and |
|
292 should be avoided, if possible. Instead, use addWatchedService() and |
|
293 removeWatchedService() if you can to manipulate entries in the list. |
|
294 */ |
|
295 void QDBusServiceWatcher::setWatchedServices(const QStringList &services) |
|
296 { |
|
297 Q_D(QDBusServiceWatcher); |
|
298 if (services == d->servicesWatched) |
|
299 return; |
|
300 d->setConnection(services, d->connection, d->watchMode); |
|
301 } |
|
302 |
|
303 /*! |
|
304 Adds \a newService to the list of services to be watched by this object. |
|
305 This function is more efficient than setWatchedServices() and should be |
|
306 used whenever possible to add services. |
|
307 */ |
|
308 void QDBusServiceWatcher::addWatchedService(const QString &newService) |
|
309 { |
|
310 Q_D(QDBusServiceWatcher); |
|
311 if (d->servicesWatched.contains(newService)) |
|
312 return; |
|
313 d->addService(newService); |
|
314 d->servicesWatched << newService; |
|
315 } |
|
316 |
|
317 /*! |
|
318 Removes the \a service from the list of services being watched by this |
|
319 object. Note that D-Bus notifications are asynchronous, so there may |
|
320 still be signals pending delivery about \a service. Those signals will |
|
321 still be emitted whenever the D-Bus messages are processed. |
|
322 |
|
323 This function returns true if any services were removed. |
|
324 */ |
|
325 bool QDBusServiceWatcher::removeWatchedService(const QString &service) |
|
326 { |
|
327 Q_D(QDBusServiceWatcher); |
|
328 d->removeService(service); |
|
329 return d->servicesWatched.removeOne(service); |
|
330 } |
|
331 |
|
332 QDBusServiceWatcher::WatchMode QDBusServiceWatcher::watchMode() const |
|
333 { |
|
334 return d_func()->watchMode; |
|
335 } |
|
336 |
|
337 void QDBusServiceWatcher::setWatchMode(WatchMode mode) |
|
338 { |
|
339 Q_D(QDBusServiceWatcher); |
|
340 if (mode == d->watchMode) |
|
341 return; |
|
342 d->setConnection(d->servicesWatched, d->connection, mode); |
|
343 } |
|
344 |
|
345 /*! |
|
346 Returns the QDBusConnection that this object is attached to. |
|
347 |
|
348 \sa setConnection() |
|
349 */ |
|
350 QDBusConnection QDBusServiceWatcher::connection() const |
|
351 { |
|
352 return d_func()->connection; |
|
353 } |
|
354 |
|
355 /*! |
|
356 Sets the D-Bus connection that this object is attached to be \a |
|
357 connection. All services watched will be transferred to this connection. |
|
358 |
|
359 Note that QDBusConnection objects are reference counted: |
|
360 QDBusServiceWatcher will keep a reference for this connection while it |
|
361 exists. The connection is not closed until the reference count drops to |
|
362 zero, so this will ensure that any notifications are received while this |
|
363 QDBusServiceWatcher object exists. |
|
364 |
|
365 \sa connection() |
|
366 */ |
|
367 void QDBusServiceWatcher::setConnection(const QDBusConnection &connection) |
|
368 { |
|
369 Q_D(QDBusServiceWatcher); |
|
370 if (connection.name() == d->connection.name()) |
|
371 return; |
|
372 d->setConnection(d->servicesWatched, connection, d->watchMode); |
|
373 } |
|
374 |
|
375 QT_END_NAMESPACE |
|
376 |
|
377 #include "moc_qdbusservicewatcher.cpp" |