src/dbus/qdbusservicewatcher.cpp
changeset 3 41300fa6a67c
child 4 3b1da2848fc7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dbus/qdbusservicewatcher.cpp	Tue Feb 02 00:43:10 2010 +0200
@@ -0,0 +1,377 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights.  These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdbusservicewatcher.h"
+#include "qdbusconnection.h"
+#include "qdbus_symbols_p.h"
+
+#include <QStringList>
+
+#include <private/qobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_GLOBAL_STATIC_WITH_ARGS(QString, busService, (QLatin1String(DBUS_SERVICE_DBUS)))
+Q_GLOBAL_STATIC_WITH_ARGS(QString, busInterface, (QLatin1String(DBUS_INTERFACE_DBUS)))
+Q_GLOBAL_STATIC_WITH_ARGS(QString, signalName, (QLatin1String("NameOwnerChanged")))
+
+class QDBusServiceWatcherPrivate: public QObjectPrivate
+{
+    Q_DECLARE_PUBLIC(QDBusServiceWatcher)
+public:
+    QDBusServiceWatcherPrivate(const QDBusConnection &c, QDBusServiceWatcher::WatchMode wm)
+        : connection(c), watchMode(wm)
+    {
+    }
+
+    QStringList servicesWatched;
+    QDBusConnection connection;
+    QDBusServiceWatcher::WatchMode watchMode;
+
+    void _q_serviceOwnerChanged(const QString &, const QString &, const QString &);
+    void setConnection(const QStringList &services, const QDBusConnection &c, QDBusServiceWatcher::WatchMode watchMode);
+
+    QStringList matchArgsForService(const QString &service);
+    void addService(const QString &service);
+    void removeService(const QString &service);
+};
+
+void QDBusServiceWatcherPrivate::_q_serviceOwnerChanged(const QString &service, const QString &oldOwner, const QString &newOwner)
+{
+    Q_Q(QDBusServiceWatcher);
+    emit q->serviceOwnerChanged(service, oldOwner, newOwner);
+    if (oldOwner.isEmpty())
+        emit q->serviceRegistered(service);
+    else if (newOwner.isEmpty())
+        emit q->serviceUnregistered(service);
+}
+
+void QDBusServiceWatcherPrivate::setConnection(const QStringList &s, const QDBusConnection &c, QDBusServiceWatcher::WatchMode wm)
+{
+    if (connection.isConnected()) {
+        // remove older rules
+        foreach (const QString &s, servicesWatched)
+            removeService(s);
+    }
+
+    connection = c;
+    watchMode = wm;
+    servicesWatched = s;
+
+    if (connection.isConnected()) {
+        // add new rules
+        foreach (const QString &s, servicesWatched)
+            addService(s);
+    }
+}
+
+QStringList QDBusServiceWatcherPrivate::matchArgsForService(const QString &service)
+{
+    QStringList matchArgs;
+    matchArgs << service;
+
+    switch (watchMode) {
+    case QDBusServiceWatcher::WatchForOwnerChange:
+        break;
+
+    case QDBusServiceWatcher::WatchForRegistration:
+        matchArgs << QString::fromLatin1("", 0);
+        break;
+
+    case QDBusServiceWatcher::WatchForUnregistration:
+        matchArgs << QString() << QString::fromLatin1("", 0);
+        break;
+    }
+    return matchArgs;
+}
+
+void QDBusServiceWatcherPrivate::addService(const QString &service)
+{
+    QStringList matchArgs = matchArgsForService(service);
+    connection.connect(*busService(), QString(), *busInterface(), *signalName(),
+                       matchArgs, QString(), q_func(),
+                       SLOT(_q_serviceOwnerChanged(QString,QString,QString)));
+}
+
+void QDBusServiceWatcherPrivate::removeService(const QString &service)
+{
+    QStringList matchArgs = matchArgsForService(service);
+    connection.disconnect(*busService(), QString(), *busInterface(), *signalName(),
+                          matchArgs, QString(), q_func(),
+                          SLOT(_q_serviceOwnerChanged(QString,QString,QString)));
+}
+
+/*!
+    \class QDBusServiceWatcher
+    \since 4.6
+    \inmodule QtDBus
+
+    \brief The QDBusServiceWatcher class allows the user to watch for a bus service change.
+
+    A QDBusServiceWatcher object can be used to notify the application about
+    an ownership change of a service name on the bus. It has three watch
+    modes:
+
+    \list
+      \o Watching for service registration only.
+      \o Watching for service unregistration only.
+      \o Watching for any kind of service ownership change (the default mode).
+    \endlist
+
+    Besides being created or deleted, services may change owners without a
+    unregister/register operation happening. So the serviceRegistered()
+    and serviceUnregistered() signals may not be emitted if that
+    happens.
+
+    This class is more efficient than using the
+    QDBusConnectionInterface::serviceOwnerChanged() signal because it allows
+    one to receive only the signals for which the class is interested in.
+
+    \sa QDBusConnection
+*/
+
+/*!
+    \enum QDBusServiceWatcher::WatchModeFlag
+
+    QDBusServiceWatcher supports three different watch modes, which are configured by this flag:
+
+    \value WatchForRegistration watch for service registration only, ignoring
+    any signals related to other service ownership change.
+
+    \value WatchForUnregistration watch for service unregistration only,
+    ignoring any signals related to other service ownership change.
+
+    \value WatchForOwnerChange watch for any kind of service ownership
+    change.
+*/
+
+/*!
+    \property QDBusServiceWatcher::watchMode
+
+    The \c watchMode property holds the current watch mode for this
+    QDBusServiceWatcher object. The default value for this property is
+    QDBusServiceWatcher::WatchForOwnershipChange.
+*/
+
+/*!
+    \property QDBusServiceWatcher::watchedServices
+
+    The \c servicesWatched property holds the list of services watched.
+
+    Note that modifying this list with setServicesWatched() is an expensive
+    operation. If you can, prefer to change it by way of addWatchedService()
+    and removeWatchedService().
+*/
+
+/*!
+    \fn void QDBusServiceWatcher::serviceRegistered(const QString &serviceName)
+
+    This signal is emitted whenever this object detects that the service \a
+    serviceName became available on the bus.
+
+    \sa serviceUnregistered(), serviceOwnerChanged()
+*/
+
+/*!
+    \fn void QDBusServiceWatcher::serviceUnregistered(const QString &serviceName)
+
+    This signal is emitted whenever this object detects that the service \a
+    serviceName was unregistered from the bus and is no longer available.
+
+    \sa serviceRegistered(), serviceOwnerChanged()
+*/
+
+/*!
+    \fn void QDBusServiceWatcher::serviceOwnerChanged(const QString &serviceName, const QString &oldOwner, const QString &newOwner)
+
+    This signal is emitted whenever this object detects that there was a
+    service ownership change relating to the \a serviceName service. The \a
+    oldOwner parameter contains the old owner name and \a newOwner is the new
+    owner. Both \a oldOwner and \a newOwner are unique connection names.
+
+    Note that this signal is also emitted whenever the \a serviceName service
+    was registered or unregistered. If it was registered, \a oldOwner will
+    contain an empty string, whereas if it was unregistered, \a newOwner will
+    contain an empty string.
+
+    If you need only to find out if the service is registered or unregistered
+    only, without being notified that the ownership changed, consider using
+    the specific modes for those operations. This class is more efficient if
+    you use the more specific modes.
+
+    \sa serviceRegistered(), serviceUnregistered()
+*/
+
+/*!
+    Creates a QDBusServiceWatcher object. Note that until you set a
+    connection with setConnection(), this object will not emit any signals.
+
+    The \a parent parameter is passed to QObject to set the parent of this
+    object.
+*/
+QDBusServiceWatcher::QDBusServiceWatcher(QObject *parent)
+    : QObject(*new QDBusServiceWatcherPrivate(QDBusConnection(QString()), WatchForOwnerChange), parent)
+{
+}
+
+/*!
+    Creates a QDBusServiceWatcher object and attaches it to the \a connection
+    connection. Also, this function immediately starts watching for \a
+    watchMode changes to service \a service.
+
+    The \a parent parameter is passed to QObject to set the parent of this
+    object.
+*/
+QDBusServiceWatcher::QDBusServiceWatcher(const QString &service, const QDBusConnection &connection, WatchMode watchMode, QObject *parent)
+    : QObject(*new QDBusServiceWatcherPrivate(connection, watchMode), parent)
+{
+    d_func()->setConnection(QStringList() << service, connection, watchMode);
+}
+
+/*!
+    Destroys the QDBusServiceWatcher object and releases any resources
+    associated with it.
+*/
+QDBusServiceWatcher::~QDBusServiceWatcher()
+{
+}
+
+/*!
+    Returns the list of D-Bus services that are being watched.
+
+    \sa setWatchedServices()
+*/
+QStringList QDBusServiceWatcher::watchedServices() const
+{
+    return d_func()->servicesWatched;
+}
+
+/*!
+    Sets the list of D-Bus services being watched to be \a services.
+
+    Note that setting the entire list means removing all previous rules for
+    watching services and adding new ones. This is an expensive operation and
+    should be avoided, if possible. Instead, use addWatchedService() and
+    removeWatchedService() if you can to manipulate entries in the list.
+*/
+void QDBusServiceWatcher::setWatchedServices(const QStringList &services)
+{
+    Q_D(QDBusServiceWatcher);
+    if (services == d->servicesWatched)
+        return;
+    d->setConnection(services, d->connection, d->watchMode);
+}
+
+/*!
+    Adds \a newService to the list of services to be watched by this object.
+    This function is more efficient than setWatchedServices() and should be
+    used whenever possible to add services.
+*/
+void QDBusServiceWatcher::addWatchedService(const QString &newService)
+{
+    Q_D(QDBusServiceWatcher);
+    if (d->servicesWatched.contains(newService))
+        return;
+    d->addService(newService);
+    d->servicesWatched << newService;
+}
+
+/*!
+    Removes the \a service from the list of services being watched by this
+    object. Note that D-Bus notifications are asynchronous, so there may
+    still be signals pending delivery about \a service. Those signals will
+    still be emitted whenever the D-Bus messages are processed.
+
+    This function returns true if any services were removed.
+*/
+bool QDBusServiceWatcher::removeWatchedService(const QString &service)
+{
+    Q_D(QDBusServiceWatcher);
+    d->removeService(service);
+    return d->servicesWatched.removeOne(service);
+}
+
+QDBusServiceWatcher::WatchMode QDBusServiceWatcher::watchMode() const
+{
+    return d_func()->watchMode;
+}
+
+void QDBusServiceWatcher::setWatchMode(WatchMode mode)
+{
+    Q_D(QDBusServiceWatcher);
+    if (mode == d->watchMode)
+        return;
+    d->setConnection(d->servicesWatched, d->connection, mode);
+}
+
+/*!
+    Returns the QDBusConnection that this object is attached to.
+
+    \sa setConnection()
+*/
+QDBusConnection QDBusServiceWatcher::connection() const
+{
+    return d_func()->connection;
+}
+
+/*!
+    Sets the D-Bus connection that this object is attached to be \a
+    connection. All services watched will be transferred to this connection.
+
+    Note that QDBusConnection objects are reference counted:
+    QDBusServiceWatcher will keep a reference for this connection while it
+    exists. The connection is not closed until the reference count drops to
+    zero, so this will ensure that any notifications are received while this
+    QDBusServiceWatcher object exists.
+
+    \sa connection()
+*/
+void QDBusServiceWatcher::setConnection(const QDBusConnection &connection)
+{
+    Q_D(QDBusServiceWatcher);
+    if (connection.name() == d->connection.name())
+        return;
+    d->setConnection(d->servicesWatched, connection, d->watchMode);
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qdbusservicewatcher.cpp"