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 | |
58 | QT_BEGIN_NAMESPACE |
59 | |
60 | static 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 | |
83 | QDBusAbstractInterfacePrivate::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 | |
108 | bool 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 | |
119 | void 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 | |
203 | bool 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 | |
223 | void 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 | |
234 | QDBusAbstractInterfaceBase::QDBusAbstractInterfaceBase(QDBusAbstractInterfacePrivate &d, QObject *parent) |
235 | : QObject(d, parent) |
236 | { |
237 | } |
238 | |
239 | int 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 | */ |
284 | QDBusAbstractInterface::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 | */ |
306 | QDBusAbstractInterface::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 | */ |
329 | QDBusAbstractInterface::~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 | */ |
341 | bool QDBusAbstractInterface::isValid() const |
342 | { |
343 | return !d_func()->currentOwner.isEmpty(); |
344 | } |
345 | |
346 | /*! |
347 | Returns the connection this interface is assocated with. |
348 | */ |
349 | QDBusConnection 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 | */ |
357 | QString QDBusAbstractInterface::service() const |
358 | { |
359 | return d_func()->service; |
360 | } |
361 | |
362 | /*! |
363 | Returns the object path that this interface is associated with. |
364 | */ |
365 | QString QDBusAbstractInterface::path() const |
366 | { |
367 | return d_func()->path; |
368 | } |
369 | |
370 | /*! |
371 | Returns the name of this interface. |
372 | */ |
373 | QString 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 | */ |
382 | QDBusError 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 | */ |
393 | void 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 | */ |
404 | int 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 | */ |
426 | QDBusMessage 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 | */ |
490 | QDBusPendingCall 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 | */ |
525 | bool 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 | */ |
569 | bool 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 | */ |
581 | void 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 | */ |
603 | void 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 | */ |
620 | QVariant 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 | */ |
632 | void 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 | */ |
658 | QDBusMessage 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 | */ |
691 | QDBusMessage 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 | */ |
750 | QDBusPendingCall 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 | */ |
788 | QDBusMessage 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 | |
796 | QT_END_NAMESPACE |
797 | |
798 | #endif // QT_NO_DBUS |
799 | |
800 | #include "moc_qdbusabstractinterface.cpp" |
801 | |