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