src/dbus/qdbusservicewatcher.cpp
changeset 3 41300fa6a67c
child 4 3b1da2848fc7
equal deleted inserted replaced
2:56cd8111b7f7 3:41300fa6a67c
       
     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"