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

Provided by KDAB

Privacy Policy
Start learning QML with our Intro Training
Find out more

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