[2] | 1 | /****************************************************************************
|
---|
| 2 | **
|
---|
[846] | 3 | ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
---|
[561] | 4 | ** All rights reserved.
|
---|
| 5 | ** Contact: Nokia Corporation (qt-info@nokia.com)
|
---|
[2] | 6 | **
|
---|
| 7 | ** This file is part of the QtDBus module of the Qt Toolkit.
|
---|
| 8 | **
|
---|
| 9 | ** $QT_BEGIN_LICENSE:LGPL$
|
---|
| 10 | ** Commercial Usage
|
---|
| 11 | ** Licensees holding valid Qt Commercial licenses may use this file in
|
---|
| 12 | ** accordance with the Qt Commercial License Agreement provided with the
|
---|
| 13 | ** Software or, alternatively, in accordance with the terms contained in
|
---|
| 14 | ** a written agreement between you and Nokia.
|
---|
| 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 | **
|
---|
[561] | 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.
|
---|
[2] | 27 | **
|
---|
| 28 | ** GNU General Public License Usage
|
---|
| 29 | ** Alternatively, this file may be used under the terms of the GNU
|
---|
| 30 | ** General Public License version 3.0 as published by the Free Software
|
---|
| 31 | ** Foundation and appearing in the file LICENSE.GPL included in the
|
---|
| 32 | ** packaging of this file. Please review the following information to
|
---|
| 33 | ** ensure the GNU General Public License version 3.0 requirements will be
|
---|
| 34 | ** met: http://www.gnu.org/copyleft/gpl.html.
|
---|
| 35 | **
|
---|
[561] | 36 | ** If you have questions regarding the use of this file, please contact
|
---|
| 37 | ** Nokia at qt-info@nokia.com.
|
---|
[2] | 38 | ** $QT_END_LICENSE$
|
---|
| 39 | **
|
---|
| 40 | ****************************************************************************/
|
---|
| 41 |
|
---|
| 42 | #include "qdbusconnectioninterface.h"
|
---|
| 43 |
|
---|
| 44 | #include <QtCore/QByteArray>
|
---|
| 45 | #include <QtCore/QList>
|
---|
| 46 | #include <QtCore/QMap>
|
---|
| 47 | #include <QtCore/QString>
|
---|
| 48 | #include <QtCore/QStringList>
|
---|
| 49 | #include <QtCore/QVariant>
|
---|
| 50 | #include <QtCore/QDebug>
|
---|
| 51 |
|
---|
[561] | 52 | #include "qdbus_symbols_p.h" // for the DBUS_* constants
|
---|
[2] | 53 |
|
---|
[846] | 54 | #ifndef QT_NO_DBUS
|
---|
| 55 |
|
---|
[2] | 56 | QT_BEGIN_NAMESPACE
|
---|
| 57 |
|
---|
| 58 | /*
|
---|
| 59 | * Implementation of interface class QDBusConnectionInterface
|
---|
| 60 | */
|
---|
| 61 |
|
---|
| 62 | /*!
|
---|
| 63 | \class QDBusConnectionInterface
|
---|
| 64 | \inmodule QtDBus
|
---|
| 65 | \since 4.2
|
---|
| 66 |
|
---|
| 67 | \brief The QDBusConnectionInterface class provides access to the D-Bus bus daemon service.
|
---|
| 68 |
|
---|
| 69 | The D-Bus bus server daemon provides one special interface \c
|
---|
| 70 | org.freedesktop.DBus that allows clients to access certain
|
---|
| 71 | properties of the bus, such as the current list of clients
|
---|
| 72 | connected. The QDBusConnectionInterface class provides access to that
|
---|
| 73 | interface.
|
---|
| 74 |
|
---|
| 75 | The most common uses of this class are to register and unregister
|
---|
| 76 | service names on the bus using the registerService() and
|
---|
| 77 | unregisterService() functions, query about existing names using
|
---|
| 78 | the isServiceRegistered(), registeredServiceNames() and
|
---|
| 79 | serviceOwner() functions, and to receive notification that a
|
---|
| 80 | client has registered or de-registered through the
|
---|
| 81 | serviceRegistered(), serviceUnregistered() and serviceOwnerChanged()
|
---|
| 82 | signals.
|
---|
| 83 | */
|
---|
| 84 |
|
---|
| 85 | /*!
|
---|
| 86 | \enum QDBusConnectionInterface::ServiceQueueOptions
|
---|
| 87 |
|
---|
| 88 | Flags for determining how a service registration should behave, in
|
---|
| 89 | case the service name is already registered.
|
---|
| 90 |
|
---|
| 91 | \value DontQueueService If an application requests a name that
|
---|
| 92 | is already owned, no queueing will be
|
---|
| 93 | performed. The registeredService()
|
---|
| 94 | call will simply fail.
|
---|
| 95 | This is the default.
|
---|
| 96 |
|
---|
| 97 | \value QueueService Attempts to register the requested
|
---|
| 98 | service, but do not try to replace it
|
---|
| 99 | if another application already has it
|
---|
| 100 | registered. Instead, simply put this
|
---|
| 101 | application in queue, until it is
|
---|
| 102 | given up. The serviceRegistered()
|
---|
| 103 | signal will be emitted when that
|
---|
| 104 | happens.
|
---|
| 105 |
|
---|
| 106 | \value ReplaceExistingService If another application already has
|
---|
| 107 | the service name registered, attempt
|
---|
| 108 | to replace it.
|
---|
| 109 |
|
---|
| 110 | \sa ServiceReplacementOptions
|
---|
| 111 | */
|
---|
| 112 |
|
---|
| 113 | /*!
|
---|
| 114 | \enum QDBusConnectionInterface::ServiceReplacementOptions
|
---|
| 115 |
|
---|
| 116 | Flags for determining if the D-Bus server should allow another
|
---|
| 117 | application to replace a name that this application has registered
|
---|
| 118 | with the ReplaceExistingService option.
|
---|
| 119 |
|
---|
| 120 | The possible values are:
|
---|
| 121 |
|
---|
| 122 | \value DontAllowReplacement Do not allow another application to
|
---|
| 123 | replace us. The service must be
|
---|
| 124 | explicitly unregistered with
|
---|
| 125 | unregisterService() for another
|
---|
| 126 | application to acquire it.
|
---|
| 127 | This is the default.
|
---|
| 128 |
|
---|
| 129 | \value AllowReplacement Allow other applications to replace us
|
---|
| 130 | with the ReplaceExistingService option
|
---|
| 131 | to registerService() without
|
---|
| 132 | intervention. If that happens, the
|
---|
| 133 | serviceUnregistered() signal will be
|
---|
| 134 | emitted.
|
---|
| 135 |
|
---|
| 136 | \sa ServiceQueueOptions
|
---|
| 137 | */
|
---|
| 138 |
|
---|
| 139 | /*!
|
---|
| 140 | \enum QDBusConnectionInterface::RegisterServiceReply
|
---|
| 141 |
|
---|
| 142 | The possible return values from registerService():
|
---|
| 143 |
|
---|
| 144 | \value ServiceNotRegistered The call failed and the service name was not registered.
|
---|
| 145 | \value ServiceRegistered The caller is now the owner of the service name.
|
---|
| 146 | \value ServiceQueued The caller specified the QueueService flag and the
|
---|
| 147 | service was already registered, so we are in queue.
|
---|
| 148 |
|
---|
| 149 | The serviceRegistered() signal will be emitted when the service is
|
---|
| 150 | acquired by this application.
|
---|
| 151 | */
|
---|
| 152 |
|
---|
| 153 | /*!
|
---|
| 154 | \internal
|
---|
| 155 | */
|
---|
| 156 | const char *QDBusConnectionInterface::staticInterfaceName()
|
---|
| 157 | { return "org.freedesktop.DBus"; }
|
---|
| 158 |
|
---|
| 159 | /*!
|
---|
| 160 | \internal
|
---|
| 161 | */
|
---|
| 162 | QDBusConnectionInterface::QDBusConnectionInterface(const QDBusConnection &connection,
|
---|
| 163 | QObject *parent)
|
---|
| 164 | : QDBusAbstractInterface(QLatin1String(DBUS_SERVICE_DBUS),
|
---|
| 165 | QLatin1String(DBUS_PATH_DBUS),
|
---|
| 166 | DBUS_INTERFACE_DBUS, connection, parent)
|
---|
| 167 | {
|
---|
| 168 | connect(this, SIGNAL(NameAcquired(QString)), this, SIGNAL(serviceRegistered(QString)));
|
---|
| 169 | connect(this, SIGNAL(NameLost(QString)), this, SIGNAL(serviceUnregistered(QString)));
|
---|
| 170 | connect(this, SIGNAL(NameOwnerChanged(QString,QString,QString)),
|
---|
| 171 | this, SIGNAL(serviceOwnerChanged(QString,QString,QString)));
|
---|
| 172 | }
|
---|
| 173 |
|
---|
| 174 | /*!
|
---|
| 175 | \internal
|
---|
| 176 | */
|
---|
| 177 | QDBusConnectionInterface::~QDBusConnectionInterface()
|
---|
| 178 | {
|
---|
| 179 | }
|
---|
| 180 |
|
---|
| 181 | /*!
|
---|
| 182 | Returns the unique connection name of the primary owner of the
|
---|
| 183 | name \a name. If the requested name doesn't have an owner, returns
|
---|
| 184 | a \c org.freedesktop.DBus.Error.NameHasNoOwner error.
|
---|
| 185 | */
|
---|
| 186 | QDBusReply<QString> QDBusConnectionInterface::serviceOwner(const QString &name) const
|
---|
| 187 | {
|
---|
| 188 | return internalConstCall(QDBus::AutoDetect, QLatin1String("GetNameOwner"), QList<QVariant>() << name);
|
---|
| 189 | }
|
---|
| 190 |
|
---|
| 191 | /*!
|
---|
| 192 | \property QDBusConnectionInterface::registeredServiceNames
|
---|
| 193 | \brief holds the registered service names
|
---|
| 194 |
|
---|
| 195 | Lists all names currently registered on the bus.
|
---|
| 196 | */
|
---|
| 197 | QDBusReply<QStringList> QDBusConnectionInterface::registeredServiceNames() const
|
---|
| 198 | {
|
---|
| 199 | return internalConstCall(QDBus::AutoDetect, QLatin1String("ListNames"));
|
---|
| 200 | }
|
---|
| 201 |
|
---|
| 202 | /*!
|
---|
| 203 | Returns true if the service name \a serviceName has is currently
|
---|
| 204 | registered.
|
---|
| 205 | */
|
---|
| 206 | QDBusReply<bool> QDBusConnectionInterface::isServiceRegistered(const QString &serviceName) const
|
---|
| 207 | {
|
---|
| 208 | return internalConstCall(QDBus::AutoDetect, QLatin1String("NameHasOwner"),
|
---|
| 209 | QList<QVariant>() << serviceName);
|
---|
| 210 | }
|
---|
| 211 |
|
---|
| 212 | /*!
|
---|
| 213 | Returns the Unix Process ID (PID) for the process currently
|
---|
| 214 | holding the bus service \a serviceName.
|
---|
| 215 | */
|
---|
| 216 | QDBusReply<uint> QDBusConnectionInterface::servicePid(const QString &serviceName) const
|
---|
| 217 | {
|
---|
| 218 | return internalConstCall(QDBus::AutoDetect, QLatin1String("GetConnectionUnixProcessID"),
|
---|
| 219 | QList<QVariant>() << serviceName);
|
---|
| 220 | }
|
---|
| 221 |
|
---|
| 222 | /*!
|
---|
| 223 | Returns the Unix User ID (UID) for the process currently holding
|
---|
| 224 | the bus service \a serviceName.
|
---|
| 225 | */
|
---|
| 226 | QDBusReply<uint> QDBusConnectionInterface::serviceUid(const QString &serviceName) const
|
---|
| 227 | {
|
---|
| 228 | return internalConstCall(QDBus::AutoDetect, QLatin1String("GetConnectionUnixUser"),
|
---|
| 229 | QList<QVariant>() << serviceName);
|
---|
| 230 | }
|
---|
| 231 |
|
---|
| 232 | /*!
|
---|
| 233 | Requests that the bus start the service given by the name \a name.
|
---|
| 234 | */
|
---|
| 235 | QDBusReply<void> QDBusConnectionInterface::startService(const QString &name)
|
---|
| 236 | {
|
---|
| 237 | return call(QLatin1String("StartServiceByName"), name, uint(0));
|
---|
| 238 | }
|
---|
| 239 |
|
---|
| 240 | /*!
|
---|
| 241 | Requests to register the service name \a serviceName on the
|
---|
| 242 | bus. The \a qoption flag specifies how the D-Bus server should behave
|
---|
| 243 | if \a serviceName is already registered. The \a roption flag
|
---|
| 244 | specifies if the server should allow another application to
|
---|
| 245 | replace our registered name.
|
---|
| 246 |
|
---|
| 247 | If the service registration succeeds, the serviceRegistered()
|
---|
| 248 | signal will be emitted. If we are placed in queue, the signal will
|
---|
| 249 | be emitted when we obtain the name. If \a roption is
|
---|
| 250 | AllowReplacement, the serviceUnregistered() signal will be emitted
|
---|
| 251 | if another application replaces this one.
|
---|
| 252 |
|
---|
| 253 | \sa unregisterService()
|
---|
| 254 | */
|
---|
| 255 | QDBusReply<QDBusConnectionInterface::RegisterServiceReply>
|
---|
| 256 | QDBusConnectionInterface::registerService(const QString &serviceName,
|
---|
| 257 | ServiceQueueOptions qoption,
|
---|
| 258 | ServiceReplacementOptions roption)
|
---|
| 259 | {
|
---|
| 260 | // reconstruct the low-level flags
|
---|
| 261 | uint flags = 0;
|
---|
| 262 | switch (qoption) {
|
---|
| 263 | case DontQueueService:
|
---|
| 264 | flags = DBUS_NAME_FLAG_DO_NOT_QUEUE;
|
---|
| 265 | break;
|
---|
| 266 | case QueueService:
|
---|
| 267 | flags = 0;
|
---|
| 268 | break;
|
---|
| 269 | case ReplaceExistingService:
|
---|
| 270 | flags = DBUS_NAME_FLAG_DO_NOT_QUEUE | DBUS_NAME_FLAG_REPLACE_EXISTING;
|
---|
| 271 | break;
|
---|
| 272 | }
|
---|
| 273 |
|
---|
| 274 | switch (roption) {
|
---|
| 275 | case DontAllowReplacement:
|
---|
| 276 | break;
|
---|
| 277 | case AllowReplacement:
|
---|
| 278 | flags |= DBUS_NAME_FLAG_ALLOW_REPLACEMENT;
|
---|
| 279 | break;
|
---|
| 280 | }
|
---|
| 281 |
|
---|
| 282 | QDBusMessage reply = call(QLatin1String("RequestName"), serviceName, flags);
|
---|
| 283 | // qDebug() << "QDBusConnectionInterface::registerService" << serviceName << "Reply:" << reply;
|
---|
| 284 |
|
---|
| 285 | // convert the low-level flags to something that we can use
|
---|
| 286 | if (reply.type() == QDBusMessage::ReplyMessage) {
|
---|
| 287 | uint code = 0;
|
---|
| 288 |
|
---|
| 289 | switch (reply.arguments().at(0).toUInt()) {
|
---|
| 290 | case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER:
|
---|
| 291 | case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER:
|
---|
| 292 | code = uint(ServiceRegistered);
|
---|
| 293 | break;
|
---|
| 294 |
|
---|
| 295 | case DBUS_REQUEST_NAME_REPLY_EXISTS:
|
---|
| 296 | code = uint(ServiceNotRegistered);
|
---|
| 297 | break;
|
---|
| 298 |
|
---|
| 299 | case DBUS_REQUEST_NAME_REPLY_IN_QUEUE:
|
---|
| 300 | code = uint(ServiceQueued);
|
---|
| 301 | break;
|
---|
| 302 | }
|
---|
| 303 |
|
---|
| 304 | reply.setArguments(QVariantList() << code);
|
---|
| 305 | }
|
---|
| 306 |
|
---|
| 307 | return reply;
|
---|
| 308 | }
|
---|
| 309 |
|
---|
| 310 | /*!
|
---|
| 311 | Releases the claim on the bus service name \a serviceName, that
|
---|
| 312 | had been previously registered with registerService(). If this
|
---|
| 313 | application had ownership of the name, it will be released for
|
---|
| 314 | other applications to claim. If it only had the name queued, it
|
---|
| 315 | gives up its position in the queue.
|
---|
| 316 | */
|
---|
| 317 | QDBusReply<bool>
|
---|
| 318 | QDBusConnectionInterface::unregisterService(const QString &serviceName)
|
---|
| 319 | {
|
---|
| 320 | QDBusMessage reply = call(QLatin1String("ReleaseName"), serviceName);
|
---|
| 321 | if (reply.type() == QDBusMessage::ReplyMessage) {
|
---|
| 322 | bool success = reply.arguments().at(0).toUInt() == DBUS_RELEASE_NAME_REPLY_RELEASED;
|
---|
| 323 | reply.setArguments(QVariantList() << success);
|
---|
| 324 | }
|
---|
| 325 | return reply;
|
---|
| 326 | }
|
---|
| 327 |
|
---|
| 328 | /*!
|
---|
| 329 | \internal
|
---|
| 330 | */
|
---|
| 331 | void QDBusConnectionInterface::connectNotify(const char *signalName)
|
---|
| 332 | {
|
---|
| 333 | // translate the signal names to what we really want
|
---|
| 334 | // this avoids setting hooks for signals that don't exist on the bus
|
---|
| 335 | if (qstrcmp(signalName, SIGNAL(serviceRegistered(QString))) == 0)
|
---|
| 336 | QDBusAbstractInterface::connectNotify(SIGNAL(NameAcquired(QString)));
|
---|
| 337 |
|
---|
| 338 | else if (qstrcmp(signalName, SIGNAL(serviceUnregistered(QString))) == 0)
|
---|
| 339 | QDBusAbstractInterface::connectNotify(SIGNAL(NameLost(QString)));
|
---|
| 340 |
|
---|
[561] | 341 | else if (qstrcmp(signalName, SIGNAL(serviceOwnerChanged(QString,QString,QString))) == 0) {
|
---|
| 342 | static bool warningPrinted = false;
|
---|
| 343 | if (!warningPrinted) {
|
---|
| 344 | qWarning("Connecting to deprecated signal QDBusConnectionInterface::serviceOwnerChanged(QString,QString,QString)");
|
---|
| 345 | warningPrinted = true;
|
---|
| 346 | }
|
---|
[2] | 347 | QDBusAbstractInterface::connectNotify(SIGNAL(NameOwnerChanged(QString,QString,QString)));
|
---|
[561] | 348 | }
|
---|
[2] | 349 | }
|
---|
| 350 |
|
---|
| 351 | /*!
|
---|
| 352 | \internal
|
---|
| 353 | */
|
---|
| 354 | void QDBusConnectionInterface::disconnectNotify(const char *signalName)
|
---|
| 355 | {
|
---|
| 356 | // translate the signal names to what we really want
|
---|
| 357 | // this avoids setting hooks for signals that don't exist on the bus
|
---|
| 358 | if (qstrcmp(signalName, SIGNAL(serviceRegistered(QString))) == 0)
|
---|
| 359 | QDBusAbstractInterface::disconnectNotify(SIGNAL(NameAcquired(QString)));
|
---|
| 360 |
|
---|
| 361 | else if (qstrcmp(signalName, SIGNAL(serviceUnregistered(QString))) == 0)
|
---|
| 362 | QDBusAbstractInterface::disconnectNotify(SIGNAL(NameLost(QString)));
|
---|
| 363 |
|
---|
| 364 | else if (qstrcmp(signalName, SIGNAL(serviceOwnerChanged(QString,QString,QString))) == 0)
|
---|
| 365 | QDBusAbstractInterface::disconnectNotify(SIGNAL(NameOwnerChanged(QString,QString,QString)));
|
---|
| 366 | }
|
---|
| 367 |
|
---|
| 368 | // signals
|
---|
| 369 | /*!
|
---|
| 370 | \fn QDBusConnectionInterface::serviceRegistered(const QString &serviceName)
|
---|
| 371 |
|
---|
| 372 | This signal is emitted by the D-Bus server when the bus service
|
---|
| 373 | name (unique connection name or well-known service name) given by
|
---|
| 374 | \a serviceName is acquired by this application.
|
---|
| 375 |
|
---|
| 376 | Acquisition happens after this application has requested a name using
|
---|
| 377 | registerService().
|
---|
| 378 | */
|
---|
| 379 |
|
---|
| 380 | /*!
|
---|
| 381 | \fn QDBusConnectionInterface::serviceUnregistered(const QString &serviceName)
|
---|
| 382 |
|
---|
| 383 | This signal is emitted by the D-Bus server when this application
|
---|
| 384 | loses ownership of the bus service name given by \a serviceName.
|
---|
| 385 | */
|
---|
| 386 |
|
---|
| 387 | /*!
|
---|
| 388 | \fn QDBusConnectionInterface::serviceOwnerChanged(const QString &name, const QString &oldOwner, const QString &newOwner)
|
---|
| 389 |
|
---|
| 390 | This signal is emitted by the D-Bus server whenever a service
|
---|
| 391 | ownership change happens in the bus, including apparition and
|
---|
| 392 | disparition of names.
|
---|
| 393 |
|
---|
| 394 | This signal means the application \a oldOwner lost ownership of
|
---|
| 395 | bus name \a name to application \a newOwner. If \a oldOwner is an
|
---|
| 396 | empty string, it means the name \a name has just been created; if
|
---|
| 397 | \a newOwner is empty, the name \a name has no current owner and is
|
---|
| 398 | no longer available.
|
---|
[561] | 399 |
|
---|
| 400 | \note connecting to this signal will make the application listen for and
|
---|
| 401 | receive every single service ownership change on the bus. Depending on
|
---|
| 402 | how many services are running, this make the application be activated to
|
---|
| 403 | receive more signals than it needs. To avoid this problem, use the
|
---|
| 404 | QDBusServiceWatcher class, which can listen for specific changes.
|
---|
[2] | 405 | */
|
---|
| 406 |
|
---|
| 407 | /*!
|
---|
| 408 | \fn void QDBusConnectionInterface::callWithCallbackFailed(const QDBusError &error, const QDBusMessage &call)
|
---|
| 409 |
|
---|
| 410 | This signal is emitted when there is an error during a
|
---|
| 411 | QDBusConnection::callWithCallback(). \a error specifies the error.
|
---|
| 412 | \a call is the message that couldn't be delivered.
|
---|
| 413 |
|
---|
| 414 | \sa QDBusConnection::callWithCallback()
|
---|
| 415 | */
|
---|
| 416 |
|
---|
| 417 | QT_END_NAMESPACE
|
---|
[846] | 418 |
|
---|
| 419 | #endif // QT_NO_DBUS
|
---|