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