1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtDBus module of the Qt Toolkit.
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.
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.
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.
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.
40 ****************************************************************************/
42 #include "qdbusconnectioninterface.h"
44 #include <QtCore/QByteArray>
45 #include <QtCore/QList>
46 #include <QtCore/QMap>
47 #include <QtCore/QMetaMethod>
48 #include <QtCore/QString>
49 #include <QtCore/QStringList>
50 #include <QtCore/QVariant>
51 #include <QtCore/QDebug>
53 #include "qdbus_symbols_p.h" // for the DBUS_* constants
60 * Implementation of interface class QDBusConnectionInterface
64 \class QDBusConnectionInterface
68 \brief The QDBusConnectionInterface class provides access to the D-Bus bus daemon service.
70 The D-Bus bus server daemon provides one special interface \c
71 org.freedesktop.DBus that allows clients to access certain
72 properties of the bus, such as the current list of clients
73 connected. The QDBusConnectionInterface class provides access to that
76 The most common uses of this class are to register and unregister
77 service names on the bus using the registerService() and
78 unregisterService() functions, query about existing names using
79 the isServiceRegistered(), registeredServiceNames() and
80 serviceOwner() functions, and to receive notification that a
81 client has registered or de-registered through the
82 serviceRegistered(), serviceUnregistered() and serviceOwnerChanged()
87 \enum QDBusConnectionInterface::ServiceQueueOptions
89 Flags for determining how a service registration should behave, in
90 case the service name is already registered.
92 \value DontQueueService If an application requests a name that
93 is already owned, no queueing will be
94 performed. The registeredService()
95 call will simply fail.
98 \value QueueService Attempts to register the requested
99 service, but do not try to replace it
100 if another application already has it
101 registered. Instead, simply put this
102 application in queue, until it is
103 given up. The serviceRegistered()
104 signal will be emitted when that
107 \value ReplaceExistingService If another application already has
108 the service name registered, attempt
111 \sa ServiceReplacementOptions
115 \enum QDBusConnectionInterface::ServiceReplacementOptions
117 Flags for determining if the D-Bus server should allow another
118 application to replace a name that this application has registered
119 with the ReplaceExistingService option.
121 The possible values are:
123 \value DontAllowReplacement Do not allow another application to
124 replace us. The service must be
125 explicitly unregistered with
126 unregisterService() for another
127 application to acquire it.
130 \value AllowReplacement Allow other applications to replace us
131 with the ReplaceExistingService option
132 to registerService() without
133 intervention. If that happens, the
134 serviceUnregistered() signal will be
137 \sa ServiceQueueOptions
141 \enum QDBusConnectionInterface::RegisterServiceReply
143 The possible return values from registerService():
145 \value ServiceNotRegistered The call failed and the service name was not registered.
146 \value ServiceRegistered The caller is now the owner of the service name.
147 \value ServiceQueued The caller specified the QueueService flag and the
148 service was already registered, so we are in queue.
150 The serviceRegistered() signal will be emitted when the service is
151 acquired by this application.
157 const char *QDBusConnectionInterface::staticInterfaceName()
158 { return "org.freedesktop.DBus"; }
163 QDBusConnectionInterface::QDBusConnectionInterface(const QDBusConnection &connection,
165 : QDBusAbstractInterface(QLatin1String(DBUS_SERVICE_DBUS),
166 QLatin1String(DBUS_PATH_DBUS),
167 DBUS_INTERFACE_DBUS, connection, parent)
169 connect(this, SIGNAL(NameAcquired(QString)), this, SIGNAL(serviceRegistered(QString)));
170 connect(this, SIGNAL(NameLost(QString)), this, SIGNAL(serviceUnregistered(QString)));
171 connect(this, SIGNAL(NameOwnerChanged(QString,QString,QString)),
172 this, SIGNAL(serviceOwnerChanged(QString,QString,QString)));
178 QDBusConnectionInterface::~QDBusConnectionInterface()
183 Returns the unique connection name of the primary owner of the
184 name \a name. If the requested name doesn't have an owner, returns
185 a \c org.freedesktop.DBus.Error.NameHasNoOwner error.
187 QDBusReply<QString> QDBusConnectionInterface::serviceOwner(const QString &name) const
189 return internalConstCall(QDBus::AutoDetect, QLatin1String("GetNameOwner"), QList<QVariant>() << name);
193 \property QDBusConnectionInterface::registeredServiceNames
194 \brief holds the registered service names
196 Lists all names currently registered on the bus.
198 QDBusReply<QStringList> QDBusConnectionInterface::registeredServiceNames() const
200 return internalConstCall(QDBus::AutoDetect, QLatin1String("ListNames"));
204 Returns true if the service name \a serviceName has is currently
207 QDBusReply<bool> QDBusConnectionInterface::isServiceRegistered(const QString &serviceName) const
209 return internalConstCall(QDBus::AutoDetect, QLatin1String("NameHasOwner"),
210 QList<QVariant>() << serviceName);
214 Returns the Unix Process ID (PID) for the process currently
215 holding the bus service \a serviceName.
217 QDBusReply<uint> QDBusConnectionInterface::servicePid(const QString &serviceName) const
219 return internalConstCall(QDBus::AutoDetect, QLatin1String("GetConnectionUnixProcessID"),
220 QList<QVariant>() << serviceName);
224 Returns the Unix User ID (UID) for the process currently holding
225 the bus service \a serviceName.
227 QDBusReply<uint> QDBusConnectionInterface::serviceUid(const QString &serviceName) const
229 return internalConstCall(QDBus::AutoDetect, QLatin1String("GetConnectionUnixUser"),
230 QList<QVariant>() << serviceName);
234 Requests that the bus start the service given by the name \a name.
236 QDBusReply<void> QDBusConnectionInterface::startService(const QString &name)
238 return call(QLatin1String("StartServiceByName"), name, uint(0));
242 Requests to register the service name \a serviceName on the
243 bus. The \a qoption flag specifies how the D-Bus server should behave
244 if \a serviceName is already registered. The \a roption flag
245 specifies if the server should allow another application to
246 replace our registered name.
248 If the service registration succeeds, the serviceRegistered()
249 signal will be emitted. If we are placed in queue, the signal will
250 be emitted when we obtain the name. If \a roption is
251 AllowReplacement, the serviceUnregistered() signal will be emitted
252 if another application replaces this one.
254 \sa unregisterService()
256 QDBusReply<QDBusConnectionInterface::RegisterServiceReply>
257 QDBusConnectionInterface::registerService(const QString &serviceName,
258 ServiceQueueOptions qoption,
259 ServiceReplacementOptions roption)
261 // reconstruct the low-level flags
264 case DontQueueService:
265 flags = DBUS_NAME_FLAG_DO_NOT_QUEUE;
270 case ReplaceExistingService:
271 flags = DBUS_NAME_FLAG_DO_NOT_QUEUE | DBUS_NAME_FLAG_REPLACE_EXISTING;
276 case DontAllowReplacement:
278 case AllowReplacement:
279 flags |= DBUS_NAME_FLAG_ALLOW_REPLACEMENT;
283 QDBusMessage reply = call(QLatin1String("RequestName"), serviceName, flags);
284 // qDebug() << "QDBusConnectionInterface::registerService" << serviceName << "Reply:" << reply;
286 // convert the low-level flags to something that we can use
287 if (reply.type() == QDBusMessage::ReplyMessage) {
290 switch (reply.arguments().at(0).toUInt()) {
291 case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER:
292 case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER:
293 code = uint(ServiceRegistered);
296 case DBUS_REQUEST_NAME_REPLY_EXISTS:
297 code = uint(ServiceNotRegistered);
300 case DBUS_REQUEST_NAME_REPLY_IN_QUEUE:
301 code = uint(ServiceQueued);
305 reply.setArguments(QVariantList() << code);
312 Releases the claim on the bus service name \a serviceName, that
313 had been previously registered with registerService(). If this
314 application had ownership of the name, it will be released for
315 other applications to claim. If it only had the name queued, it
316 gives up its position in the queue.
319 QDBusConnectionInterface::unregisterService(const QString &serviceName)
321 QDBusMessage reply = call(QLatin1String("ReleaseName"), serviceName);
322 if (reply.type() == QDBusMessage::ReplyMessage) {
323 bool success = reply.arguments().at(0).toUInt() == DBUS_RELEASE_NAME_REPLY_RELEASED;
324 reply.setArguments(QVariantList() << success);
332 void QDBusConnectionInterface::connectNotify(const QMetaMethod &signal)
334 // translate the signal names to what we really want
335 // this avoids setting hooks for signals that don't exist on the bus
336 static const QMetaMethod serviceRegisteredSignal = QMetaMethod::fromSignal(&QDBusConnectionInterface::serviceRegistered);
337 static const QMetaMethod serviceUnregisteredSignal = QMetaMethod::fromSignal(&QDBusConnectionInterface::serviceUnregistered);
338 static const QMetaMethod serviceOwnerChangedSignal = QMetaMethod::fromSignal(&QDBusConnectionInterface::serviceOwnerChanged);
339 static const QMetaMethod NameAcquiredSignal = QMetaMethod::fromSignal(&QDBusConnectionInterface::NameAcquired);
340 static const QMetaMethod NameLostSignal = QMetaMethod::fromSignal(&QDBusConnectionInterface::NameLost);
341 static const QMetaMethod NameOwnerChangedSignal = QMetaMethod::fromSignal(&QDBusConnectionInterface::NameOwnerChanged);
342 if (signal == serviceRegisteredSignal)
343 QDBusAbstractInterface::connectNotify(NameAcquiredSignal);
345 else if (signal == serviceUnregisteredSignal)
346 QDBusAbstractInterface::connectNotify(NameLostSignal);
348 else if (signal == serviceOwnerChangedSignal) {
349 static bool warningPrinted = false;
350 if (!warningPrinted) {
351 qWarning("Connecting to deprecated signal QDBusConnectionInterface::serviceOwnerChanged(QString,QString,QString)");
352 warningPrinted = true;
354 QDBusAbstractInterface::connectNotify(NameOwnerChangedSignal);
361 void QDBusConnectionInterface::disconnectNotify(const QMetaMethod &signal)
363 // translate the signal names to what we really want
364 // this avoids setting hooks for signals that don't exist on the bus
365 static const QMetaMethod serviceRegisteredSignal = QMetaMethod::fromSignal(&QDBusConnectionInterface::serviceRegistered);
366 static const QMetaMethod serviceUnregisteredSignal = QMetaMethod::fromSignal(&QDBusConnectionInterface::serviceUnregistered);
367 static const QMetaMethod serviceOwnerChangedSignal = QMetaMethod::fromSignal(&QDBusConnectionInterface::serviceOwnerChanged);
368 static const QMetaMethod NameAcquiredSignal = QMetaMethod::fromSignal(&QDBusConnectionInterface::NameAcquired);
369 static const QMetaMethod NameLostSignal = QMetaMethod::fromSignal(&QDBusConnectionInterface::NameLost);
370 static const QMetaMethod NameOwnerChangedSignal = QMetaMethod::fromSignal(&QDBusConnectionInterface::NameOwnerChanged);
371 if (signal == serviceRegisteredSignal)
372 QDBusAbstractInterface::disconnectNotify(NameAcquiredSignal);
374 else if (signal == serviceUnregisteredSignal)
375 QDBusAbstractInterface::disconnectNotify(NameLostSignal);
377 else if (signal == serviceOwnerChangedSignal)
378 QDBusAbstractInterface::disconnectNotify(NameOwnerChangedSignal);
383 \fn QDBusConnectionInterface::serviceRegistered(const QString &serviceName)
385 This signal is emitted by the D-Bus server when the bus service
386 name (unique connection name or well-known service name) given by
387 \a serviceName is acquired by this application.
389 Acquisition happens after this application has requested a name using
394 \fn QDBusConnectionInterface::serviceUnregistered(const QString &serviceName)
396 This signal is emitted by the D-Bus server when this application
397 loses ownership of the bus service name given by \a serviceName.
401 \fn QDBusConnectionInterface::serviceOwnerChanged(const QString &name, const QString &oldOwner, const QString &newOwner)
403 This signal is emitted by the D-Bus server whenever a service
404 ownership change happens in the bus, including apparition and
405 disparition of names.
407 This signal means the application \a oldOwner lost ownership of
408 bus name \a name to application \a newOwner. If \a oldOwner is an
409 empty string, it means the name \a name has just been created; if
410 \a newOwner is empty, the name \a name has no current owner and is
413 \note connecting to this signal will make the application listen for and
414 receive every single service ownership change on the bus. Depending on
415 how many services are running, this make the application be activated to
416 receive more signals than it needs. To avoid this problem, use the
417 QDBusServiceWatcher class, which can listen for specific changes.
421 \fn void QDBusConnectionInterface::callWithCallbackFailed(const QDBusError &error, const QDBusMessage &call)
423 This signal is emitted when there is an error during a
424 QDBusConnection::callWithCallback(). \a error specifies the error.
425 \a call is the message that couldn't be delivered.
427 \sa QDBusConnection::callWithCallback()