Qt 4.8
qdbuspendingcall.cpp
Go to the documentation of this file.
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 "qdbuspendingcall.h"
43 #include "qdbuspendingcall_p.h"
44 
45 #include "qdbusconnection_p.h"
46 #include "qdbusmetatype_p.h"
47 #include "qcoreapplication.h"
48 #include "qcoreevent.h"
49 #include <private/qobject_p.h>
50 
51 #ifndef QT_NO_DBUS
52 
54 
135 {
136  connect(this, SIGNAL(finished()), watcher, SLOT(_q_finished()), Qt::QueuedConnection);
137 }
138 
140 {
141  if (pending) {
142  q_dbus_pending_call_cancel(pending);
143  q_dbus_pending_call_unref(pending);
144  }
145  delete watcherHelper;
146 }
147 
148 bool QDBusPendingCallPrivate::setReplyCallback(QObject *target, const char *member)
149 {
150  receiver = target;
151  metaTypes.clear();
152  methodIdx = -1;
153  if (!target)
154  return true;; // unsetting
155 
156  if (!member || !*member) {
157  // would not be able to deliver a reply
158  qWarning("QDBusPendingCall::setReplyCallback: error: cannot deliver a reply to %s::%s (%s)",
159  target ? target->metaObject()->className() : "(null)",
160  member ? member + 1 : "(null)",
161  target ? qPrintable(target->objectName()) : "no name");
162  return false;
163  }
164 
165  methodIdx = QDBusConnectionPrivate::findSlot(target, member + 1, metaTypes);
166  if (methodIdx == -1) {
167  QByteArray normalizedName = QMetaObject::normalizedSignature(member + 1);
168  methodIdx = QDBusConnectionPrivate::findSlot(target, normalizedName, metaTypes);
169  }
170  if (methodIdx == -1) {
171  // would not be able to deliver a reply
172  qWarning("QDBusPendingCall::setReplyCallback: error: cannot deliver a reply to %s::%s (%s)",
173  target->metaObject()->className(),
174  member + 1, qPrintable(target->objectName()));
175  return false;
176  }
177 
178  // success
179  // construct the expected signature
180  int count = metaTypes.count() - 1;
181  if (count == 1 && metaTypes.at(1) == QDBusMetaTypeId::message) {
182  // wildcard slot, can receive anything, so don't set the signature
183  return true;
184  }
185 
186  if (metaTypes.at(count) == QDBusMetaTypeId::message)
187  --count;
188 
189  if (count == 0) {
190  setMetaTypes(count, 0);
191  } else {
193  setMetaTypes(count, types.constData() + 1);
194  }
195  return true;
196 }
197 
198 void QDBusPendingCallPrivate::setMetaTypes(int count, const int *types)
199 {
200  expectedReplyCount = count;
201  if (count == 0) {
202  expectedReplySignature = QLatin1String(""); // not null
203  return;
204  }
205 
206  QByteArray sig;
207  sig.reserve(count + count / 2);
208  for (int i = 0; i < count; ++i) {
209  const char *typeSig = QDBusMetaType::typeToSignature(types[i]);
210  if (!typeSig) {
211  qFatal("QDBusPendingReply: type %s is not registered with QtDBus",
212  QMetaType::typeName(types[i]));
213  }
214  sig += typeSig;
215  }
216 
217  expectedReplySignature = QString::fromLatin1(sig);
218 }
219 
221 {
222  // MUST BE CALLED WITH A LOCKED MUTEX!
223 
224  if (replyMessage.type() == QDBusMessage::InvalidMessage)
225  return; // not yet finished - no message to
226  // validate against
227  if (replyMessage.type() == QDBusMessage::ErrorMessage)
228  return; // we don't have to check the signature of an error reply
229 
230  if (expectedReplySignature.isNull())
231  return; // no signature to validate against
232 
233  // can't use startsWith here because a null string doesn't start or end with an empty string
234  if (!replyMessage.signature().indexOf(expectedReplySignature) == 0) {
235  QString errorMsg = QLatin1String("Unexpected reply signature: got \"%1\", "
236  "expected \"%2\"");
237  replyMessage = QDBusMessage::createError(
239  errorMsg.arg(replyMessage.signature(), expectedReplySignature));
240 
241  }
242 }
243 
245 {
246  QMutexLocker locker(&mutex);
247 
248  if (replyMessage.type() != QDBusMessage::InvalidMessage)
249  return; // already finished
250 
251  connection->waitForFinished(this);
252 }
253 
259  : d(other.d)
260 {
261 }
262 
267  : d(dd)
268 {
269  if (dd) {
270  bool r = dd->ref.deref();
271  Q_ASSERT(r);
272  Q_UNUSED(r);
273  }
274 }
275 
283 {
284  // d deleted by QExplicitlySharedDataPointer
285 }
286 
287 
299 {
300  d = other.d;
301  return *this;
302 }
303 
337 bool QDBusPendingCall::isFinished() const
338 {
339  if (!d)
340  return true; // considered finished
341 
342  QMutexLocker locker(&d->mutex);
344 }
345 
346 void QDBusPendingCall::waitForFinished()
347 {
348  if (d) d->waitForFinished();
349 }
350 
363 bool QDBusPendingCall::isValid() const
364 {
365  if (!d)
366  return false;
367  QMutexLocker locker(&d->mutex);
369 }
370 
383 bool QDBusPendingCall::isError() const
384 {
385  if (!d)
386  return true; // considered finished and an error
387  QMutexLocker locker(&d->mutex);
389 }
390 
403 {
404  if (d) {
405  QMutexLocker locker(&d->mutex);
406  return d->replyMessage;
407  }
408 
409  // not connected, return an error
411  QLatin1String("Not connected to D-Bus server"));
412  return err;
413 }
414 
429 QDBusMessage QDBusPendingCall::reply() const
430 {
431  if (!d)
433  QMutexLocker locker(&d->mutex);
434  return d->replyMessage;
435 }
436 
437 #if 0
438 
456 bool QDBusPendingCall::setReplyCallback(QObject *target, const char *member)
457 {
458  if (!d)
459  return false;
460 
461  return d->setReplyCallback(target, member);
462 }
463 #endif
464 
477 {
479 }
480 
497 {
499  if (msg.type() == QDBusMessage::ErrorMessage ||
500  msg.type() == QDBusMessage::ReplyMessage) {
502  d->replyMessage = msg;
503  d->ref = 1;
504  }
505 
506  return QDBusPendingCall(d);
507 }
508 
509 
511 {
512 public:
513  void _q_finished();
514 
516 };
517 
519 {
521  emit q->finished(q);
522 }
523 
531 {
532  if (d) { // QDBusPendingCall::d
533  QMutexLocker locker(&d->mutex);
534  if (!d->watcherHelper) {
537  // cause a signal emission anyways
539  }
540  }
541  d->watcherHelper->add(this);
542  }
543 }
544 
551 {
552 }
553 
568 {
569  if (d) {
570  d->waitForFinished();
571 
572  // our signals were queued, so deliver them
575  }
576 }
578 
579 #endif // QT_NO_DBUS
580 
581 #include "moc_qdbuspendingcall.cpp"
QAtomicInt ref
Definition: qshareddata.h:59
friend class QDBusPendingCallPrivate
double d
Definition: qnumeric_p.h:62
static QDBusMessage createError(const QString &name, const QString &msg)
Constructs a new DBus message representing an error, with the given name and msg. ...
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
static QByteArray normalizedSignature(const char *method)
Normalizes the signature of the given method.
#define error(msg)
QString objectName
the name of this object
Definition: qobject.h:114
The QByteArray class provides an array of bytes.
Definition: qbytearray.h:135
#define SLOT(a)
Definition: qobjectdefs.h:226
bool setReplyCallback(QObject *target, const char *member)
The QDBusError class represents an error received from the D-Bus bus or from remote applications foun...
Definition: qdbuserror.h:60
The QDBusPendingCall class refers to one pending asynchronous call.
QLatin1String(DBUS_INTERFACE_DBUS))) Q_GLOBAL_STATIC_WITH_ARGS(QString
The QDBusPendingCallWatcher class provides a convenient way for waiting for asynchronous replies...
The QString class provides a Unicode character string.
Definition: qstring.h:83
#define Q_ASSERT(cond)
Definition: qglobal.h:1823
The QObject class is the base class of all Qt objects.
Definition: qobject.h:111
static int findSlot(QObject *obj, const QByteArray &normalizedName, QList< int > &params)
QExplicitlySharedDataPointer< QDBusPendingCallPrivate > d
void add(QDBusPendingCallWatcher *watcher)
#define Q_Q(Class)
Definition: qglobal.h:2483
#define SIGNAL(a)
Definition: qobjectdefs.h:227
static const char * typeToSignature(int type)
Returns the D-Bus signature equivalent to the supplied meta type id type.
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
static bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
Creates a connection of the given type from the signal in the sender object to the method in the rece...
Definition: qobject.cpp:2580
static int message
void setMetaTypes(int count, const int *types)
#define emit
Definition: qobjectdefs.h:76
bool deref()
Atomically decrements the value of this QAtomicInt.
static QVector< T > fromList(const QList< T > &list)
Returns a QVector object with the data contained in list.
Definition: qvector.h:789
Q_CORE_EXPORT void qWarning(const char *,...)
static void sendPostedEvents()
QDBusPendingCallWatcher(const QDBusPendingCall &call, QObject *parent=0)
Creates a QDBusPendingCallWatcher object to watch for replies on the asynchronous pending call call a...
void waitForFinished()
Suspends the execution of the calling thread until the reply is received and processed.
QDBusPendingCall & operator=(const QDBusPendingCall &other)
Creates a copy of the other pending asynchronous call and drops the reference to the previously-refer...
Q_CORE_EXPORT void qFatal(const char *,...)
The QMutexLocker class is a convenience class that simplifies locking and unlocking mutexes...
Definition: qmutex.h:101
QString arg(qlonglong a, int fieldwidth=0, int base=10, const QChar &fillChar=QLatin1Char(' ')) const Q_REQUIRED_RESULT
Definition: qstring.cpp:7186
#define Q_DECLARE_PUBLIC(Class)
Definition: qglobal.h:2477
static const struct @32 types[]
static const char * typeName(int type)
Returns the type name associated with the given type, or 0 if no matching type was found...
Definition: qmetatype.cpp:406
static QString fromLatin1(const char *, int size=-1)
Returns a QString initialized with the first size characters of the Latin-1 string str...
Definition: qstring.cpp:4188
~QDBusPendingCall()
Destroys this copy of the QDBusPendingCall object.
QDBusPendingCallWatcherHelper * watcherHelper
const char * className() const
Returns the class name.
Definition: qobjectdefs.h:491
The QDBusMessage class represents one message sent or received over the D-Bus bus.
Definition: qdbusmessage.h:59
MessageType type() const
Returns the message type.
static bool invokeMethod(QObject *obj, const char *member, Qt::ConnectionType, QGenericReturnArgument ret, QGenericArgument val0=QGenericArgument(0), QGenericArgument val1=QGenericArgument(), QGenericArgument val2=QGenericArgument(), QGenericArgument val3=QGenericArgument(), QGenericArgument val4=QGenericArgument(), QGenericArgument val5=QGenericArgument(), QGenericArgument val6=QGenericArgument(), QGenericArgument val7=QGenericArgument(), QGenericArgument val8=QGenericArgument(), QGenericArgument val9=QGenericArgument())
Invokes the member (a signal or a slot name) on the object obj.
static QDBusPendingCall fromCompletedCall(const QDBusMessage &message)
Creates a QDBusPendingCall object based on the message msg.
static QDBusPendingCall fromError(const QDBusError &error)
Creates a QDBusPendingCall object based on the error condition error.
const T * constData() const
Returns a const pointer to the data stored in the vector.
Definition: qvector.h:154
void reserve(int size)
Attempts to allocate memory for at least size bytes.
Definition: qbytearray.h:449
#define qPrintable(string)
Definition: qglobal.h:1750
~QDBusPendingCallWatcher()
Destroys this object.
#define Q_UNUSED(x)
Indicates to the compiler that the parameter with the specified name is not used in the body of a fun...
Definition: qglobal.h:1729
virtual const QMetaObject * metaObject() const
Returns a pointer to the meta-object of this object.