QDBusPendingCallPrivate: save 8 bytes on 64-bit archs
[profile/ivi/qtbase.git] / src / dbus / qdbusconnectioninterface.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 "qdbusconnectioninterface.h"
43
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>
52
53 #include "qdbus_symbols_p.h"          // for the DBUS_* constants
54
55 #ifndef QT_NO_DBUS
56
57 QT_BEGIN_NAMESPACE
58
59 /*
60  * Implementation of interface class QDBusConnectionInterface
61  */
62
63 /*!
64     \class QDBusConnectionInterface
65     \inmodule QtDBus
66     \since 4.2
67
68     \brief The QDBusConnectionInterface class provides access to the D-Bus bus daemon service.
69
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
74     interface.
75
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()
83     signals.
84 */
85
86 /*!
87     \enum QDBusConnectionInterface::ServiceQueueOptions
88
89     Flags for determining how a service registration should behave, in
90     case the service name is already registered.
91
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.
96                                 This is the default.
97
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
105                                 happens.
106
107     \value ReplaceExistingService If another application already has
108                                 the service name registered, attempt
109                                 to replace it.
110
111     \sa ServiceReplacementOptions
112 */
113
114 /*!
115     \enum QDBusConnectionInterface::ServiceReplacementOptions
116
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.
120
121     The possible values are:
122
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.
128                                 This is the default.
129
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
135                                 emitted.
136
137     \sa ServiceQueueOptions
138 */
139
140 /*!
141     \enum QDBusConnectionInterface::RegisterServiceReply
142
143     The possible return values from registerService():
144
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.
149
150     The serviceRegistered() signal will be emitted when the service is
151     acquired by this application.
152 */
153
154 /*!
155     \internal
156 */
157 const char *QDBusConnectionInterface::staticInterfaceName()
158 { return "org.freedesktop.DBus"; }
159
160 /*!
161     \internal
162 */
163 QDBusConnectionInterface::QDBusConnectionInterface(const QDBusConnection &connection,
164                                                    QObject *parent)
165     : QDBusAbstractInterface(QLatin1String(DBUS_SERVICE_DBUS),
166                              QLatin1String(DBUS_PATH_DBUS),
167                              DBUS_INTERFACE_DBUS, connection, parent)
168 {
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)));
173 }
174
175 /*!
176     \internal
177 */
178 QDBusConnectionInterface::~QDBusConnectionInterface()
179 {
180 }
181
182 /*!
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.
186 */
187 QDBusReply<QString> QDBusConnectionInterface::serviceOwner(const QString &name) const
188 {
189     return internalConstCall(QDBus::AutoDetect, QLatin1String("GetNameOwner"), QList<QVariant>() << name);
190 }
191
192 /*!
193   \property QDBusConnectionInterface::registeredServiceNames
194   \brief holds the registered service names
195
196   Lists all names currently registered on the bus.
197 */
198 QDBusReply<QStringList> QDBusConnectionInterface::registeredServiceNames() const
199 {
200     return internalConstCall(QDBus::AutoDetect, QLatin1String("ListNames"));
201 }
202
203 /*!
204     Returns true if the service name \a serviceName has is currently
205     registered.
206 */
207 QDBusReply<bool> QDBusConnectionInterface::isServiceRegistered(const QString &serviceName) const
208 {
209     return internalConstCall(QDBus::AutoDetect, QLatin1String("NameHasOwner"),
210                              QList<QVariant>() << serviceName);
211 }
212
213 /*!
214     Returns the Unix Process ID (PID) for the process currently
215     holding the bus service \a serviceName.
216 */
217 QDBusReply<uint> QDBusConnectionInterface::servicePid(const QString &serviceName) const
218 {
219     return internalConstCall(QDBus::AutoDetect, QLatin1String("GetConnectionUnixProcessID"),
220                              QList<QVariant>() << serviceName);
221 }
222
223 /*!
224     Returns the Unix User ID (UID) for the process currently holding
225     the bus service \a serviceName.
226 */
227 QDBusReply<uint> QDBusConnectionInterface::serviceUid(const QString &serviceName) const
228 {
229     return internalConstCall(QDBus::AutoDetect, QLatin1String("GetConnectionUnixUser"),
230                              QList<QVariant>() << serviceName);
231 }
232
233 /*!
234     Requests that the bus start the service given by the name \a name.
235 */
236 QDBusReply<void> QDBusConnectionInterface::startService(const QString &name)
237 {
238     return call(QLatin1String("StartServiceByName"), name, uint(0));
239 }
240
241 /*!
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.
247
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.
253
254     \sa unregisterService()
255 */
256 QDBusReply<QDBusConnectionInterface::RegisterServiceReply>
257 QDBusConnectionInterface::registerService(const QString &serviceName,
258                                           ServiceQueueOptions qoption,
259                                           ServiceReplacementOptions roption)
260 {
261     // reconstruct the low-level flags
262     uint flags = 0;
263     switch (qoption) {
264     case DontQueueService:
265         flags = DBUS_NAME_FLAG_DO_NOT_QUEUE;
266         break;
267     case QueueService:
268         flags = 0;
269         break;
270     case ReplaceExistingService:
271         flags = DBUS_NAME_FLAG_DO_NOT_QUEUE | DBUS_NAME_FLAG_REPLACE_EXISTING;
272         break;
273     }
274
275     switch (roption) {
276     case DontAllowReplacement:
277         break;
278     case AllowReplacement:
279         flags |= DBUS_NAME_FLAG_ALLOW_REPLACEMENT;
280         break;
281     }
282
283     QDBusMessage reply = call(QLatin1String("RequestName"), serviceName, flags);
284 //    qDebug() << "QDBusConnectionInterface::registerService" << serviceName << "Reply:" << reply;
285
286     // convert the low-level flags to something that we can use
287     if (reply.type() == QDBusMessage::ReplyMessage) {
288         uint code = 0;
289
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);
294             break;
295
296         case DBUS_REQUEST_NAME_REPLY_EXISTS:
297             code = uint(ServiceNotRegistered);
298             break;
299
300         case DBUS_REQUEST_NAME_REPLY_IN_QUEUE:
301             code = uint(ServiceQueued);
302             break;
303         }
304
305         reply.setArguments(QVariantList() << code);
306     }
307
308     return reply;
309 }
310
311 /*!
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.
317 */
318 QDBusReply<bool>
319 QDBusConnectionInterface::unregisterService(const QString &serviceName)
320 {
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);
325     }
326     return reply;
327 }
328
329 /*!
330     \internal
331 */
332 void QDBusConnectionInterface::connectNotify(const QMetaMethod &signal)
333 {
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);
344
345     else if (signal == serviceUnregisteredSignal)
346         QDBusAbstractInterface::connectNotify(NameLostSignal);
347
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;
353         }
354         QDBusAbstractInterface::connectNotify(NameOwnerChangedSignal);
355     }
356 }
357
358 /*!
359     \internal
360 */
361 void QDBusConnectionInterface::disconnectNotify(const QMetaMethod &signal)
362 {
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);
373
374     else if (signal == serviceUnregisteredSignal)
375         QDBusAbstractInterface::disconnectNotify(NameLostSignal);
376
377     else if (signal == serviceOwnerChangedSignal)
378         QDBusAbstractInterface::disconnectNotify(NameOwnerChangedSignal);
379 }
380
381 // signals
382 /*!
383     \fn QDBusConnectionInterface::serviceRegistered(const QString &serviceName)
384
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.
388
389     Acquisition happens after this application has requested a name using
390     registerService().
391 */
392
393 /*!
394     \fn QDBusConnectionInterface::serviceUnregistered(const QString &serviceName)
395
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.
398 */
399
400 /*!
401     \fn QDBusConnectionInterface::serviceOwnerChanged(const QString &name, const QString &oldOwner, const QString &newOwner)
402
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.
406
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
411     no longer available.
412
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.
418 */
419
420 /*!
421   \fn void QDBusConnectionInterface::callWithCallbackFailed(const QDBusError &error, const QDBusMessage &call)
422
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.
426
427   \sa QDBusConnection::callWithCallback()
428  */
429
430 QT_END_NAMESPACE
431
432 #endif // QT_NO_DBUS