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

source code of qtbase/src/dbus/qdbusabstractinterface.cpp