1/****************************************************************************
2**
3** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4** Contact: http://www.qt-project.org/legal
5**
6** This file is part of the QtDBus module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Digia. For licensing terms and
14** conditions see http://qt.digia.com/licensing. For further information
15** use the contact form at http://qt.digia.com/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 2.1 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 2.1 requirements
23** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24**
25** In addition, as a special exception, Digia gives you certain additional
26** rights. These rights are described in the Digia Qt LGPL Exception
27** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28**
29** GNU General Public License Usage
30** Alternatively, this file may be used under the terms of the GNU
31** General Public License version 3.0 as published by the Free Software
32** Foundation and appearing in the file LICENSE.GPL included in the
33** packaging of this file. Please review the following information to
34** ensure the GNU General Public License version 3.0 requirements will be
35** met: http://www.gnu.org/copyleft/gpl.html.
36**
37**
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qdbusabstractinterface.h"
43#include "qdbusabstractinterface_p.h"
44
45#include <qthread.h>
46
47#include "qdbusargument.h"
48#include "qdbuspendingcall.h"
49#include "qdbusmessage_p.h"
50#include "qdbusmetaobject_p.h"
51#include "qdbusmetatype_p.h"
52#include "qdbusutil_p.h"
53
54#include <qdebug.h>
55
56#ifndef QT_NO_DBUS
57
58QT_BEGIN_NAMESPACE
59
60static QDBusError checkIfValid(const QString &service, const QString &path,
61 const QString &interface, bool isDynamic, bool isPeer)
62{
63 // We should be throwing exceptions here... oh well
64 QDBusError error;
65
66 // dynamic interfaces (QDBusInterface) can have empty interfaces, but not service and object paths
67 // non-dynamic is the opposite: service and object paths can be empty, but not the interface
68 if (!isDynamic) {
69 // use assertion here because this should never happen, at all
70 Q_ASSERT_X(!interface.isEmpty(), "QDBusAbstractInterface", "Interface name cannot be empty");
71 }
72 if (!QDBusUtil::checkBusName(service, (isDynamic && !isPeer) ? QDBusUtil::EmptyNotAllowed : QDBusUtil::EmptyAllowed, &error))
73 return error;
74 if (!QDBusUtil::checkObjectPath(path, isDynamic ? QDBusUtil::EmptyNotAllowed : QDBusUtil::EmptyAllowed, &error))
75 return error;
76 if (!QDBusUtil::checkInterfaceName(interface, QDBusUtil::EmptyAllowed, &error))
77 return error;
78
79 // no error
80 return QDBusError();
81}
82
83QDBusAbstractInterfacePrivate::QDBusAbstractInterfacePrivate(const QString &serv,
84 const QString &p,
85 const QString &iface,
86 const QDBusConnection& con,
87 bool isDynamic)
88 : connection(con), service(serv), path(p), interface(iface),
89 lastError(checkIfValid(serv, p, iface, isDynamic, (connectionPrivate() &&
90 connectionPrivate()->mode == QDBusConnectionPrivate::PeerMode))),
91 timeout(-1),
92 isValid(!lastError.isValid())
93{
94 if (!isValid)
95 return;
96
97 if (!connection.isConnected()) {
98 lastError = QDBusError(QDBusError::Disconnected,
99 QLatin1String("Not connected to D-Bus server"));
100 } else if (!service.isEmpty()) {
101 currentOwner = connectionPrivate()->getNameOwner(service); // verify the name owner
102 if (currentOwner.isEmpty()) {
103 lastError = connectionPrivate()->lastError;
104 }
105 }
106}
107
108bool QDBusAbstractInterfacePrivate::canMakeCalls() const
109{
110 // recheck only if we have a wildcard (i.e. empty) service or path
111 // if any are empty, set the error message according to QDBusUtil
112 if (service.isEmpty() && connectionPrivate()->mode != QDBusConnectionPrivate::PeerMode)
113 return QDBusUtil::checkBusName(service, QDBusUtil::EmptyNotAllowed, &lastError);
114 if (path.isEmpty())
115 return QDBusUtil::checkObjectPath(path, QDBusUtil::EmptyNotAllowed, &lastError);
116 return true;
117}
118
119void QDBusAbstractInterfacePrivate::property(const QMetaProperty &mp, QVariant &where) const
120{
121 if (!isValid || !canMakeCalls()) { // can't make calls
122 where.clear();
123 return;
124 }
125
126 // is this metatype registered?
127 const char *expectedSignature = "";
128 if (mp.type() != 0xff) {
129 expectedSignature = QDBusMetaType::typeToSignature(where.userType());
130 if (expectedSignature == 0) {
131 qWarning("QDBusAbstractInterface: type %s must be registered with QtDBus before it can be "
132 "used to read property %s.%s",
133 mp.typeName(), qPrintable(interface), mp.name());
134 lastError = QDBusError(QDBusError::Failed,
135 QString::fromLatin1("Unregistered type %1 cannot be handled")
136 .arg(QLatin1String(mp.typeName())));
137 where.clear();
138 return;
139 }
140 }
141
142 // try to read this property
143 QDBusMessage msg = QDBusMessage::createMethodCall(service, path,
144 QLatin1String(DBUS_INTERFACE_PROPERTIES),
145 QLatin1String("Get"));
146 QDBusMessagePrivate::setParametersValidated(msg, true);
147 msg << interface << QString::fromUtf8(mp.name());
148 QDBusMessage reply = connection.call(msg, QDBus::Block, timeout);
149
150 if (reply.type() != QDBusMessage::ReplyMessage) {
151 lastError = reply;
152 where.clear();
153 return;
154 }
155 if (reply.signature() != QLatin1String("v")) {
156 QString errmsg = QLatin1String("Invalid signature `%1' in return from call to "
157 DBUS_INTERFACE_PROPERTIES);
158 lastError = QDBusError(QDBusError::InvalidSignature, errmsg.arg(reply.signature()));
159 where.clear();
160 return;
161 }
162
163 QByteArray foundSignature;
164 const char *foundType = 0;
165 QVariant value = qvariant_cast<QDBusVariant>(reply.arguments().at(0)).variant();
166
167 if (value.userType() == where.userType() || mp.type() == 0xff
168 || (expectedSignature[0] == 'v' && expectedSignature[1] == '\0')) {
169 // simple match
170 where = value;
171 return;
172 }
173
174 if (value.userType() == qMetaTypeId<QDBusArgument>()) {
175 QDBusArgument arg = qvariant_cast<QDBusArgument>(value);
176
177 foundType = "user type";
178 foundSignature = arg.currentSignature().toLatin1();
179 if (foundSignature == expectedSignature) {
180 // signatures match, we can demarshall
181 QDBusMetaType::demarshall(arg, where.userType(), where.data());
182 return;
183 }
184 } else {
185 foundType = value.typeName();
186 foundSignature = QDBusMetaType::typeToSignature(value.userType());
187 }
188
189 // there was an error...
190 QString errmsg = QLatin1String("Unexpected `%1' (%2) when retrieving property `%3.%4' "
191 "(expected type `%5' (%6))");
192 lastError = QDBusError(QDBusError::InvalidSignature,
193 errmsg.arg(QString::fromLatin1(foundType),
194 QString::fromLatin1(foundSignature),
195 interface,
196 QString::fromUtf8(mp.name()),
197 QString::fromLatin1(mp.typeName()),
198 QString::fromLatin1(expectedSignature)));
199 where.clear();
200 return;
201}
202
203bool QDBusAbstractInterfacePrivate::setProperty(const QMetaProperty &mp, const QVariant &value)
204{
205 if (!isValid || !canMakeCalls()) // can't make calls
206 return false;
207
208 // send the value
209 QDBusMessage msg = QDBusMessage::createMethodCall(service, path,
210 QLatin1String(DBUS_INTERFACE_PROPERTIES),
211 QLatin1String("Set"));
212 QDBusMessagePrivate::setParametersValidated(msg, true);
213 msg << interface << QString::fromUtf8(mp.name()) << QVariant::fromValue(QDBusVariant(value));
214 QDBusMessage reply = connection.call(msg, QDBus::Block, timeout);
215
216 if (reply.type() != QDBusMessage::ReplyMessage) {
217 lastError = reply;
218 return false;
219 }
220 return true;
221}
222
223void QDBusAbstractInterfacePrivate::_q_serviceOwnerChanged(const QString &name,
224 const QString &oldOwner,
225 const QString &newOwner)
226{
227 Q_UNUSED(oldOwner);
228 //qDebug() << "QDBusAbstractInterfacePrivate serviceOwnerChanged" << name << oldOwner << newOwner;
229 if (name == service) {
230 currentOwner = newOwner;
231 }
232}
233
234QDBusAbstractInterfaceBase::QDBusAbstractInterfaceBase(QDBusAbstractInterfacePrivate &d, QObject *parent)
235 : QObject(d, parent)
236{
237}
238
239int QDBusAbstractInterfaceBase::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
240{
241 int saved_id = _id;
242 _id = QObject::qt_metacall(_c, _id, _a);
243 if (_id < 0)
244 return _id;
245
246 if (_c == QMetaObject::ReadProperty || _c == QMetaObject::WriteProperty) {
247 QMetaProperty mp = metaObject()->property(saved_id);
248 int &status = *reinterpret_cast<int *>(_a[2]);
249 QVariant &variant = *reinterpret_cast<QVariant *>(_a[1]);
250
251 if (_c == QMetaObject::WriteProperty) {
252 status = d_func()->setProperty(mp, variant) ? 1 : 0;
253 } else {
254 d_func()->property(mp, variant);
255 status = variant.isValid() ? 1 : 0;
256 }
257 _id = -1;
258 }
259 return _id;
260}
261
262/*!
263 \class QDBusAbstractInterface
264 \inmodule QtDBus
265 \since 4.2
266
267 \brief The QDBusAbstractInterface class is the base class for all D-Bus interfaces in the QtDBus binding, allowing access to remote interfaces
268
269 Generated-code classes also derive from QDBusAbstractInterface,
270 all methods described here are also valid for generated-code
271 classes. In addition to those described here, generated-code
272 classes provide member functions for the remote methods, which
273 allow for compile-time checking of the correct parameters and
274 return values, as well as property type-matching and signal
275 parameter-matching.
276
277 \sa {qdbusxml2cpp.html}{The QDBus compiler}, QDBusInterface
278*/
279
280/*!
281 \internal
282 This is the constructor called from QDBusInterface::QDBusInterface.
283*/
284QDBusAbstractInterface::QDBusAbstractInterface(QDBusAbstractInterfacePrivate &d, QObject *parent)
285 : QDBusAbstractInterfaceBase(d, parent)
286{
287 // keep track of the service owner
288 if (d.isValid &&
289 d.connection.isConnected()
290 && !d.service.isEmpty()
291 && !d.service.startsWith(QLatin1Char(':')))
292 d_func()->connection.connect(QLatin1String(DBUS_SERVICE_DBUS), // service
293 QString(), // path
294 QLatin1String(DBUS_INTERFACE_DBUS), // interface
295 QLatin1String("NameOwnerChanged"),
296 QStringList() << d.service,
297 QString(), // signature
298 this, SLOT(_q_serviceOwnerChanged(QString,QString,QString)));
299}
300
301/*!
302 \internal
303 This is the constructor called from static classes derived from
304 QDBusAbstractInterface (i.e., those generated by dbusxml2cpp).
305*/
306QDBusAbstractInterface::QDBusAbstractInterface(const QString &service, const QString &path,
307 const char *interface, const QDBusConnection &con,
308 QObject *parent)
309 : QDBusAbstractInterfaceBase(*new QDBusAbstractInterfacePrivate(service, path, QString::fromLatin1(interface),
310 con, false), parent)
311{
312 // keep track of the service owner
313 if (d_func()->isValid &&
314 d_func()->connection.isConnected()
315 && !service.isEmpty()
316 && !service.startsWith(QLatin1Char(':')))
317 d_func()->connection.connect(QLatin1String(DBUS_SERVICE_DBUS), // service
318 QString(), // path
319 QLatin1String(DBUS_INTERFACE_DBUS), // interface
320 QLatin1String("NameOwnerChanged"),
321 QStringList() << service,
322 QString(), //signature
323 this, SLOT(_q_serviceOwnerChanged(QString,QString,QString)));
324}
325
326/*!
327 Releases this object's resources.
328*/
329QDBusAbstractInterface::~QDBusAbstractInterface()
330{
331}
332
333/*!
334 Returns true if this is a valid reference to a remote object. It returns false if
335 there was an error during the creation of this interface (for instance, if the remote
336 application does not exist).
337
338 Note: when dealing with remote objects, it is not always possible to determine if it
339 exists when creating a QDBusInterface.
340*/
341bool QDBusAbstractInterface::isValid() const
342{
343 return !d_func()->currentOwner.isEmpty();
344}
345
346/*!
347 Returns the connection this interface is assocated with.
348*/
349QDBusConnection QDBusAbstractInterface::connection() const
350{
351 return d_func()->connection;
352}
353
354/*!
355 Returns the name of the service this interface is associated with.
356*/
357QString QDBusAbstractInterface::service() const
358{
359 return d_func()->service;
360}
361
362/*!
363 Returns the object path that this interface is associated with.
364*/
365QString QDBusAbstractInterface::path() const
366{
367 return d_func()->path;
368}
369
370/*!
371 Returns the name of this interface.
372*/
373QString QDBusAbstractInterface::interface() const
374{
375 return d_func()->interface;
376}
377
378/*!
379 Returns the error the last operation produced, or an invalid error if the last operation did not
380 produce an error.
381*/
382QDBusError QDBusAbstractInterface::lastError() const
383{
384 return d_func()->lastError;
385}
386
387/*!
388 Sets the timeout in milliseconds for all future DBus calls to \a timeout.
389 -1 means the default DBus timeout (usually 25 seconds).
390
391 \since 4.8
392*/
393void QDBusAbstractInterface::setTimeout(int timeout)
394{
395 d_func()->timeout = timeout;
396}
397
398/*!
399 Returns the current value of the timeout in milliseconds.
400 -1 means the default DBus timeout (usually 25 seconds).
401
402 \since 4.8
403*/
404int QDBusAbstractInterface::timeout() const
405{
406 return d_func()->timeout;
407}
408
409/*!
410 Places a call to the remote method specified by \a method on this interface, using \a args as
411 arguments. This function returns the message that was received as a reply, which can be a normal
412 QDBusMessage::ReplyMessage (indicating success) or QDBusMessage::ErrorMessage (if the call
413 failed). The \a mode parameter specifies how this call should be placed.
414
415 If the call succeeds, lastError() will be cleared; otherwise, it will contain the error this
416 call produced.
417
418 Normally, you should place calls using call().
419
420 \warning If you use \c UseEventLoop, your code must be prepared to deal with any reentrancy:
421 other method calls and signals may be delivered before this function returns, as well
422 as other Qt queued signals and events.
423
424 \threadsafe
425*/
426QDBusMessage QDBusAbstractInterface::callWithArgumentList(QDBus::CallMode mode,
427 const QString& method,
428 const QList<QVariant>& args)
429{
430 Q_D(QDBusAbstractInterface);
431
432 if (!d->isValid || !d->canMakeCalls())
433 return QDBusMessage::createError(d->lastError);
434
435 QString m = method;
436 // split out the signature from the method
437 int pos = method.indexOf(QLatin1Char('.'));
438 if (pos != -1)
439 m.truncate(pos);
440
441 if (mode == QDBus::AutoDetect) {
442 // determine if this a sync or async call
443 mode = QDBus::Block;
444 const QMetaObject *mo = metaObject();
445 QByteArray match = m.toLatin1() + '(';
446
447 for (int i = staticMetaObject.methodCount(); i < mo->methodCount(); ++i) {
448 QMetaMethod mm = mo->method(i);
449 if (QByteArray(mm.signature()).startsWith(match)) {
450 // found a method with the same name as what we're looking for
451 // hopefully, nobody is overloading asynchronous and synchronous methods with
452 // the same name
453
454 QList<QByteArray> tags = QByteArray(mm.tag()).split(' ');
455 if (tags.contains("Q_NOREPLY"))
456 mode = QDBus::NoBlock;
457
458 break;
459 }
460 }
461 }
462
463// qDebug() << "QDBusAbstractInterface" << "Service" << service() << "Path:" << path();
464 QDBusMessage msg = QDBusMessage::createMethodCall(service(), path(), interface(), m);
465 QDBusMessagePrivate::setParametersValidated(msg, true);
466 msg.setArguments(args);
467
468 QDBusMessage reply = d->connection.call(msg, mode, d->timeout);
469 if (thread() == QThread::currentThread())
470 d->lastError = reply; // will clear if reply isn't an error
471
472 // ensure that there is at least one element
473 if (reply.arguments().isEmpty())
474 reply << QVariant();
475
476 return reply;
477}
478
479/*!
480 \since 4.5
481 Places a call to the remote method specified by \a method on this
482 interface, using \a args as arguments. This function returns a
483 QDBusPendingCall object that can be used to track the status of the
484 reply and access its contents once it has arrived.
485
486 Normally, you should place calls using asyncCall().
487
488 \threadsafe
489*/
490QDBusPendingCall QDBusAbstractInterface::asyncCallWithArgumentList(const QString& method,
491 const QList<QVariant>& args)
492{
493 Q_D(QDBusAbstractInterface);
494
495 if (!d->isValid || !d->canMakeCalls())
496 return QDBusPendingCall::fromError(d->lastError);
497
498 QDBusMessage msg = QDBusMessage::createMethodCall(service(), path(), interface(), method);
499 QDBusMessagePrivate::setParametersValidated(msg, true);
500 msg.setArguments(args);
501 return d->connection.asyncCall(msg, d->timeout);
502}
503
504/*!
505 Places a call to the remote method specified by \a method
506 on this interface, using \a args as arguments. This function
507 returns immediately after queueing the call. The reply from
508 the remote function is delivered to the \a returnMethod on
509 object \a receiver. If an error occurs, the \a errorMethod
510 on object \a receiver is called instead.
511
512 This function returns true if the queueing succeeds. It does
513 not indicate that the executed call succeeded. If it fails,
514 the \a errorMethod is called. If the queueing failed, this
515 function returns false and no slot will be called.
516
517 The \a returnMethod must have as its parameters the types returned
518 by the function call. Optionally, it may have a QDBusMessage
519 parameter as its last or only parameter. The \a errorMethod must
520 have a QDBusError as its only parameter.
521
522 \since 4.3
523 \sa QDBusError, QDBusMessage
524 */
525bool QDBusAbstractInterface::callWithCallback(const QString &method,
526 const QList<QVariant> &args,
527 QObject *receiver,
528 const char *returnMethod,
529 const char *errorMethod)
530{
531 Q_D(QDBusAbstractInterface);
532
533 if (!d->isValid || !d->canMakeCalls())
534 return false;
535
536 QDBusMessage msg = QDBusMessage::createMethodCall(service(),
537 path(),
538 interface(),
539 method);
540 QDBusMessagePrivate::setParametersValidated(msg, true);
541 msg.setArguments(args);
542
543 d->lastError = 0;
544 return d->connection.callWithCallback(msg,
545 receiver,
546 returnMethod,
547 errorMethod,
548 d->timeout);
549}
550
551/*!
552 \overload
553
554 This function is deprecated. Please use the overloaded version.
555
556 Places a call to the remote method specified by \a method
557 on this interface, using \a args as arguments. This function
558 returns immediately after queueing the call. The reply from
559 the remote function or any errors emitted by it are delivered
560 to the \a slot slot on object \a receiver.
561
562 This function returns true if the queueing succeeded: it does
563 not indicate that the call succeeded. If it failed, the slot
564 will be called with an error message. lastError() will not be
565 set under those circumstances.
566
567 \sa QDBusError, QDBusMessage
568*/
569bool QDBusAbstractInterface::callWithCallback(const QString &method,
570 const QList<QVariant> &args,
571 QObject *receiver,
572 const char *slot)
573{
574 return callWithCallback(method, args, receiver, slot, 0);
575}
576
577/*!
578 \internal
579 Catch signal connections.
580*/
581void QDBusAbstractInterface::connectNotify(const char *signal)
582{
583 // someone connecting to one of our signals
584 Q_D(QDBusAbstractInterface);
585 if (!d->isValid)
586 return;
587
588 // we end up recursing here, so optimize away
589 if (qstrcmp(signal + 1, "destroyed(QObject*)") == 0)
590 return;
591
592 QDBusConnectionPrivate *conn = d->connectionPrivate();
593 if (conn) {
594 conn->connectRelay(d->service, d->path, d->interface,
595 this, signal);
596 }
597}
598
599/*!
600 \internal
601 Catch signal disconnections.
602*/
603void QDBusAbstractInterface::disconnectNotify(const char *signal)
604{
605 // someone disconnecting from one of our signals
606 Q_D(QDBusAbstractInterface);
607 if (!d->isValid)
608 return;
609
610 QDBusConnectionPrivate *conn = d->connectionPrivate();
611 if (conn)
612 conn->disconnectRelay(d->service, d->path, d->interface,
613 this, signal);
614}
615
616/*!
617 \internal
618 Get the value of the property \a propname.
619*/
620QVariant QDBusAbstractInterface::internalPropGet(const char *propname) const
621{
622 // assume this property exists and is readable
623 // we're only called from generated code anyways
624
625 return property(propname);
626}
627
628/*!
629 \internal
630 Set the value of the property \a propname to \a value.
631*/
632void QDBusAbstractInterface::internalPropSet(const char *propname, const QVariant &value)
633{
634 setProperty(propname, value);
635}
636
637/*!
638 Calls the method \a method on this interface and passes the parameters to this function to the
639 method.
640
641 The parameters to \c call are passed on to the remote function via D-Bus as input
642 arguments. Output arguments are returned in the QDBusMessage reply. If the reply is an error
643 reply, lastError() will also be set to the contents of the error message.
644
645 This function can be used with up to 8 parameters, passed in arguments \a arg1, \a arg2,
646 \a arg3, \a arg4, \a arg5, \a arg6, \a arg7 and \a arg8. If you need more than 8
647 parameters or if you have a variable number of parameters to be passed, use
648 callWithArgumentList().
649
650 It can be used the following way:
651
652 \snippet doc/src/snippets/code/src_qdbus_qdbusabstractinterface.cpp 0
653
654 This example illustrates function calling with 0, 1 and 2 parameters and illustrates different
655 parameter types passed in each (the first call to \c "ProcessWorkUnicode" will contain one
656 Unicode string, the second call to \c "ProcessWork" will contain one string and one byte array).
657*/
658QDBusMessage QDBusAbstractInterface::call(const QString &method, const QVariant &arg1,
659 const QVariant &arg2,
660 const QVariant &arg3,
661 const QVariant &arg4,
662 const QVariant &arg5,
663 const QVariant &arg6,
664 const QVariant &arg7,
665 const QVariant &arg8)
666{
667 return call(QDBus::AutoDetect, method, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
668}
669
670/*!
671 \overload
672
673 Calls the method \a method on this interface and passes the
674 parameters to this function to the method. If \a mode is \c
675 NoWaitForReply, then this function will return immediately after
676 placing the call, without waiting for a reply from the remote
677 method. Otherwise, \a mode indicates whether this function should
678 activate the Qt Event Loop while waiting for the reply to arrive.
679
680 This function can be used with up to 8 parameters, passed in arguments \a arg1, \a arg2,
681 \a arg3, \a arg4, \a arg5, \a arg6, \a arg7 and \a arg8. If you need more than 8
682 parameters or if you have a variable number of parameters to be passed, use
683 callWithArgumentList().
684
685 If this function reenters the Qt event loop in order to wait for the
686 reply, it will exclude user input. During the wait, it may deliver
687 signals and other method calls to your application. Therefore, it
688 must be prepared to handle a reentrancy whenever a call is placed
689 with call().
690*/
691QDBusMessage QDBusAbstractInterface::call(QDBus::CallMode mode, const QString &method,
692 const QVariant &arg1,
693 const QVariant &arg2,
694 const QVariant &arg3,
695 const QVariant &arg4,
696 const QVariant &arg5,
697 const QVariant &arg6,
698 const QVariant &arg7,
699 const QVariant &arg8)
700{
701 QList<QVariant> argList;
702 int count = 0 + arg1.isValid() + arg2.isValid() + arg3.isValid() + arg4.isValid() +
703 arg5.isValid() + arg6.isValid() + arg7.isValid() + arg8.isValid();
704
705 switch (count) {
706 case 8:
707 argList.prepend(arg8);
708 case 7:
709 argList.prepend(arg7);
710 case 6:
711 argList.prepend(arg6);
712 case 5:
713 argList.prepend(arg5);
714 case 4:
715 argList.prepend(arg4);
716 case 3:
717 argList.prepend(arg3);
718 case 2:
719 argList.prepend(arg2);
720 case 1:
721 argList.prepend(arg1);
722 }
723
724 return callWithArgumentList(mode, method, argList);
725}
726
727
728/*!
729 \since 4.5
730 Calls the method \a method on this interface and passes the parameters to this function to the
731 method.
732
733 The parameters to \c call are passed on to the remote function via D-Bus as input
734 arguments. The returned QDBusPendingCall object can be used to find out information about
735 the reply.
736
737 This function can be used with up to 8 parameters, passed in arguments \a arg1, \a arg2,
738 \a arg3, \a arg4, \a arg5, \a arg6, \a arg7 and \a arg8. If you need more than 8
739 parameters or if you have a variable number of parameters to be passed, use
740 asyncCallWithArgumentList().
741
742 It can be used the following way:
743
744 \snippet doc/src/snippets/code/src_qdbus_qdbusabstractinterface.cpp 1
745
746 This example illustrates function calling with 0, 1 and 2 parameters and illustrates different
747 parameter types passed in each (the first call to \c "ProcessWorkUnicode" will contain one
748 Unicode string, the second call to \c "ProcessWork" will contain one string and one byte array).
749*/
750QDBusPendingCall QDBusAbstractInterface::asyncCall(const QString &method, const QVariant &arg1,
751 const QVariant &arg2,
752 const QVariant &arg3,
753 const QVariant &arg4,
754 const QVariant &arg5,
755 const QVariant &arg6,
756 const QVariant &arg7,
757 const QVariant &arg8)
758{
759 QList<QVariant> argList;
760 int count = 0 + arg1.isValid() + arg2.isValid() + arg3.isValid() + arg4.isValid() +
761 arg5.isValid() + arg6.isValid() + arg7.isValid() + arg8.isValid();
762
763 switch (count) {
764 case 8:
765 argList.prepend(arg8);
766 case 7:
767 argList.prepend(arg7);
768 case 6:
769 argList.prepend(arg6);
770 case 5:
771 argList.prepend(arg5);
772 case 4:
773 argList.prepend(arg4);
774 case 3:
775 argList.prepend(arg3);
776 case 2:
777 argList.prepend(arg2);
778 case 1:
779 argList.prepend(arg1);
780 }
781
782 return asyncCallWithArgumentList(method, argList);
783}
784
785/*!
786 \internal
787*/
788QDBusMessage QDBusAbstractInterface::internalConstCall(QDBus::CallMode mode,
789 const QString &method,
790 const QList<QVariant> &args) const
791{
792 // ### move the code here, and make the other functions call this
793 return const_cast<QDBusAbstractInterface*>(this)->callWithArgumentList(mode, method, args);
794}
795
796QT_END_NAMESPACE
797
798#endif // QT_NO_DBUS
799
800#include "moc_qdbusabstractinterface.cpp"
801