Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Toggle main menu visibility
Loading...
Searching...
No Matches
qdbuspendingcall.cpp
Go to the documentation of this file.
1
// Copyright (C) 2016 The Qt Company Ltd.
2
// Copyright (C) 2016 Intel Corporation.
3
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
// Qt-Security score:significant reason:default
5
6
#
include
"qdbuspendingcall.h"
7
#
include
"qdbuspendingcall_p.h"
8
9
#
include
"qdbusconnection_p.h"
10
#
include
"qdbusmetatype_p.h"
11
#
include
"qdbusutil_p.h"
12
#
include
"qcoreapplication.h"
13
#
include
"qcoreevent.h"
14
#
include
<
private
/
qobject_p
.
h
>
15
#
include
<
private
/
qlocking_p
.
h
>
16
17
#
ifndef
QT_NO_DBUS
18
19
QT_BEGIN_NAMESPACE
20
21
using
namespace
Qt::StringLiterals;
22
23
/*!
24
\class QDBusPendingCall
25
\inmodule QtDBus
26
\ingroup shared
27
\since 4.5
28
29
\brief The QDBusPendingCall class refers to one pending asynchronous call.
30
31
A QDBusPendingCall object is a reference to a method call that was
32
sent over D-Bus without waiting for a reply. QDBusPendingCall is an
33
opaque type, meant to be used as a handle for a pending reply.
34
35
In most programs, the QDBusPendingCall class will not be used
36
directly. It can be safely replaced with the template-based
37
QDBusPendingReply, in order to access the contents of the reply or
38
wait for it to be complete.
39
40
The QDBusPendingCallWatcher class allows one to connect to a signal
41
that will indicate when the reply has arrived or if the call has
42
timed out. It also provides the
43
QDBusPendingCallWatcher::waitForFinished() method which will suspend
44
the execution of the program until the reply has arrived.
45
46
\note If you create a copy of a QDBusPendingCall object, all
47
information will be shared among the many copies. Therefore,
48
QDBusPendingCall is an explicitly-shared object and does not
49
provide a method of detaching the copies (since they refer
50
to the same pending call)
51
52
\sa QDBusPendingReply, QDBusPendingCallWatcher
53
*/
54
55
/*!
56
\class QDBusPendingCallWatcher
57
\inmodule QtDBus
58
\since 4.5
59
60
\brief The QDBusPendingCallWatcher class provides a convenient way for
61
waiting for asynchronous replies.
62
63
The QDBusPendingCallWatcher provides the finished() signal that will be
64
emitted when a reply arrives.
65
66
It is usually used like the following example:
67
68
\snippet code/src_qdbus_qdbuspendingcall.cpp 0
69
70
Note that it is not necessary to keep the original QDBusPendingCall
71
object around since QDBusPendingCallWatcher inherits from that class
72
too.
73
74
The slot connected to by the above code could be something similar
75
to the following:
76
77
\snippet code/src_qdbus_qdbuspendingcall.cpp 1
78
79
Note the use of QDBusPendingReply to validate the argument types in
80
the reply. If the reply did not contain exactly two arguments
81
(one string and one QByteArray), QDBusPendingReply::isError() will
82
return true.
83
84
\sa QDBusPendingReply
85
*/
86
87
/*!
88
\fn void QDBusPendingCallWatcher::finished(QDBusPendingCallWatcher *self)
89
90
This signal is emitted when the pending call has finished and its
91
reply is available. The \a self parameter is a pointer to the
92
object itself, passed for convenience so that the slot can access
93
the properties and determine the contents of the reply.
94
*/
95
96
void
QDBusPendingCallWatcherHelper
::add(QDBusPendingCallWatcher *watcher)
97
{
98
connect(
this
, &QDBusPendingCallWatcherHelper::finished, watcher,
99
[watcher] { Q_EMIT watcher->finished(watcher); }, Qt::QueuedConnection);
100
}
101
102
QDBusPendingCallPrivate
::~
QDBusPendingCallPrivate
()
103
{
104
if
(
pending
) {
105
q_dbus_pending_call_cancel(
pending
);
106
q_dbus_pending_call_unref
(
pending
)
;
107
}
108
delete
watcherHelper
;
109
}
110
111
bool
QDBusPendingCallPrivate
::
setReplyCallback
(QObject *target,
const
char
*member)
112
{
113
receiver = target;
114
metaTypes.clear();
115
methodIdx
= -1;
116
if
(!target)
117
return
true
;;
// unsetting
118
119
if
(!member || !*member) {
120
// would not be able to deliver a reply
121
qWarning(
"QDBusPendingCall::setReplyCallback: error: cannot deliver a reply to %s::%s (%s)"
,
122
target ? target->metaObject()->className() :
"(null)"
,
123
member ? member + 1 :
"(null)"
,
124
target ? qPrintable(target->objectName()) :
"no name"
);
125
return
false
;
126
}
127
128
QString
errorMsg;
129
methodIdx
= QDBusConnectionPrivate::findSlot(target, member + 1, metaTypes, errorMsg);
130
if
(
methodIdx
== -1) {
131
QByteArray normalizedName = QMetaObject::normalizedSignature(member + 1);
132
methodIdx
= QDBusConnectionPrivate::findSlot(target, normalizedName, metaTypes, errorMsg);
133
}
134
if
(
methodIdx
== -1) {
135
// would not be able to deliver a reply
136
qWarning(
"QDBusPendingCall::setReplyCallback: error: cannot deliver a reply to %s::%s (%s) "
137
"because %s"
,
138
target->metaObject()->className(), member + 1, qPrintable(target->objectName()),
139
qPrintable(errorMsg));
140
return
false
;
141
}
142
143
// success
144
// construct the expected signature
145
int
count = metaTypes.size() - 1;
146
if
(count == 1 && metaTypes.at(1) == QDBusMetaTypeId::message()) {
147
// wildcard slot, can receive anything, so don't set the signature
148
return
true
;
149
}
150
151
if
(metaTypes.at(count) == QDBusMetaTypeId::message())
152
--count;
153
154
setMetaTypes(count, count ? metaTypes.constData() + 1 :
nullptr
);
155
return
true
;
156
}
157
158
void
QDBusPendingCallPrivate
::
setMetaTypes
(
int
count,
const
QMetaType *types)
159
{
160
if
(count == 0) {
161
expectedReplySignature =
""_L1
;
// not null
162
return
;
163
}
164
165
QByteArray sig;
166
sig.reserve(count + count / 2);
167
for
(
int
i = 0; i < count; ++i) {
168
const
char
*typeSig = QDBusMetaType::typeToSignature(types[i]);
169
if
(Q_UNLIKELY(!typeSig))
170
qFatal(
"QDBusPendingReply: type %s is not registered with QtDBus"
, types[i].name());
171
sig += typeSig;
172
}
173
174
expectedReplySignature = QString::fromLatin1(sig);
175
}
176
177
void
QDBusPendingCallPrivate
::
checkReceivedSignature
()
178
{
179
// MUST BE CALLED WITH A LOCKED MUTEX!
180
181
if
(replyMessage.type() == QDBusMessage::InvalidMessage)
182
return
;
// not yet finished - no message to
183
// validate against
184
if
(replyMessage.type() == QDBusMessage::ErrorMessage)
185
return
;
// we don't have to check the signature of an error reply
186
187
if
(expectedReplySignature.isNull())
188
return
;
// no signature to validate against
189
190
// can't use startsWith here because a null string doesn't start or end with an empty string
191
if
(replyMessage.signature().indexOf(expectedReplySignature) != 0) {
192
const
auto
errorMsg =
"Unexpected reply signature: got \"%1\", expected \"%2\""_L1
;
193
replyMessage = QDBusMessage::createError(
194
QDBusError::InvalidSignature,
195
errorMsg.arg(replyMessage.signature(), expectedReplySignature));
196
197
}
198
}
199
200
void
QDBusPendingCallPrivate
::
waitForFinished
()
201
{
202
const
auto
locker = qt_scoped_lock(mutex);
203
204
if
(replyMessage.type() != QDBusMessage::InvalidMessage)
205
return
;
// already finished
206
207
waitForFinishedCondition.wait(&mutex);
208
}
209
210
void
QDBusPendingCallPrivate
::
waitForFinishedWithGui
()
211
{
212
QEventLoop loop;
213
214
{
215
const
auto
locker = qt_scoped_lock(mutex);
216
if
(replyMessage.type() != QDBusMessage::InvalidMessage)
217
return
;
// already finished
218
219
Q_ASSERT(!
watcherHelper
);
220
watcherHelper
=
new
QDBusPendingCallWatcherHelper
;
221
loop.connect(
watcherHelper
, &QDBusPendingCallWatcherHelper::reply, &loop,
222
&QEventLoop::quit);
223
loop.connect(
watcherHelper
, &QDBusPendingCallWatcherHelper::error, &loop,
224
&QEventLoop::quit);
225
}
226
227
loop.exec(QEventLoop::ExcludeUserInputEvents | QEventLoop::WaitForMoreEvents);
228
}
229
230
/*!
231
\fn QDBusPendingCall::QDBusPendingCall(QDBusPendingCall &&other)
232
\since 6.10
233
234
Moves \a other into this object.
235
236
\include qdbuspendingcall.cpp partially-formed
237
*/
238
239
/*!
240
Creates a copy of the \a other pending asynchronous call. Note
241
that both objects will refer to the same pending call.
242
*/
243
QDBusPendingCall::QDBusPendingCall(
const
QDBusPendingCall &other)
244
: d(other.d)
245
{
246
}
247
248
/*!
249
\internal
250
*/
251
QDBusPendingCall::QDBusPendingCall(QDBusPendingCallPrivate *dd)
252
: d(dd)
253
{
254
if
(dd) {
255
bool
r = dd->ref.deref();
256
Q_ASSERT(r);
257
}
258
}
259
260
/*!
261
Destroys this copy of the QDBusPendingCall object. If this copy is
262
also the last copy of a pending asynchronous call, the call will
263
be canceled and no further notifications will be received. There
264
will be no way of accessing the reply's contents when it arrives.
265
*/
266
QDBusPendingCall::~QDBusPendingCall()
267
{
268
// d deleted by QExplicitlySharedDataPointer
269
}
270
271
QT_DEFINE_QESDP_SPECIALIZATION_DTOR
(QDBusPendingCallPrivate)
272
273
/*!
274
\fn QDBusPendingCall &QDBusPendingCall::operator=(QDBusPendingCall &&other)
275
276
Move-assigns \a other into this QDBusPendingCall.
277
278
//! [partially-formed]
279
\note The moved-from object \a other is placed in a partially-formed state,
280
in which the only valid operations are destruction and assignment of a new
281
value.
282
//! [partially-formed]
283
*/
284
285
/*!
286
Creates a copy of the \a other pending asynchronous call and drops
287
the reference to the previously-referenced call. Note that both
288
objects will refer to the same pending call after this function.
289
290
If this object contained the last reference of a pending
291
asynchronous call, the call will be canceled and no further
292
notifications will be received. There will be no way of accessing
293
the reply's contents when it arrives.
294
*/
295
QDBusPendingCall &QDBusPendingCall::operator=(
const
QDBusPendingCall &other)
296
{
297
d = other.d;
298
return
*
this
;
299
}
300
301
/*!
302
\fn void QDBusPendingCall::swap(QDBusPendingCall &other)
303
\since 5.0
304
\memberswap{pending call instance}
305
*/
306
307
/*!
308
\fn bool QDBusPendingCallWatcher::isFinished() const
309
310
Returns \c true if the pending call has finished processing and the
311
reply has been received.
312
313
Note that this function only changes state if you call
314
waitForFinished() or if an external D-Bus event happens, which in
315
general only happens if you return to the event loop execution.
316
317
\sa QDBusPendingReply::isFinished()
318
*/
319
320
/*!
321
\fn template <typename... Types> bool QDBusPendingReply<Types...>::isFinished() const
322
323
Returns \c true if the pending call has finished processing and the
324
reply has been received. If this function returns \c true, the
325
isError(), error() and reply() methods should return valid
326
information.
327
328
Note that this function only changes state if you call
329
waitForFinished() or if an external D-Bus event happens, which in
330
general only happens if you return to the event loop execution.
331
332
\sa QDBusPendingCallWatcher::isFinished()
333
*/
334
335
bool
QDBusPendingCall::isFinished()
const
336
{
337
if
(!d)
338
return
true
;
// considered finished
339
340
const
auto
locker = qt_scoped_lock(d->mutex);
341
return
d->replyMessage.type() != QDBusMessage::InvalidMessage;
342
}
343
344
void
QDBusPendingCall::waitForFinished()
345
{
346
if
(d) d->waitForFinished();
347
}
348
349
/*!
350
\fn template <typename... Types> bool QDBusPendingReply<Types...>::isValid() const
351
352
Returns \c true if the reply contains a normal reply message, false
353
if it contains anything else.
354
355
If the pending call has not finished processing, this function
356
return false.
357
*/
358
bool
QDBusPendingCall::isValid()
const
359
{
360
if
(!d)
361
return
false
;
362
const
auto
locker = qt_scoped_lock(d->mutex);
363
return
d->replyMessage.type() == QDBusMessage::ReplyMessage;
364
}
365
366
/*!
367
\fn template <typename... Types> bool QDBusPendingReply<Types...>::isError() const
368
369
Returns \c true if the reply contains an error message, false if it
370
contains a normal method reply.
371
372
If the pending call has not finished processing, this function
373
also returns \c true.
374
*/
375
bool
QDBusPendingCall::isError()
const
376
{
377
if
(!d)
378
return
true
;
// considered finished and an error
379
const
auto
locker = qt_scoped_lock(d->mutex);
380
return
d->replyMessage.type() == QDBusMessage::ErrorMessage;
381
}
382
383
/*!
384
\fn template <typename... Types> QDBusError QDBusPendingReply<Types...>::error() const
385
386
Retrieves the error content of the reply message, if it has
387
finished processing. If the reply message has not finished
388
processing or if it contains a normal reply message (non-error),
389
this function returns an invalid QDBusError.
390
*/
391
QDBusError QDBusPendingCall::error()
const
392
{
393
if
(d) {
394
const
auto
locker = qt_scoped_lock(d->mutex);
395
return
QDBusError(d->replyMessage);
396
}
397
398
// not connected, return an error
399
QDBusError err = QDBusError(QDBusError::Disconnected,
400
QDBusUtil::disconnectedErrorMessage());
401
return
err;
402
}
403
404
/*!
405
\fn template <typename... Types> QDBusMessage QDBusPendingReply<Types...>::reply() const
406
407
Retrieves the reply message received for the asynchronous call
408
that was sent, if it has finished processing. If the pending call
409
is not finished, this function returns a QDBusMessage of type
410
QDBusMessage::InvalidMessage.
411
412
After it has finished processing, the message type will either be
413
an error message or a normal method reply message.
414
*/
415
QDBusMessage QDBusPendingCall::reply()
const
416
{
417
if
(!d)
418
return
QDBusMessage::createError(error());
419
const
auto
locker = qt_scoped_lock(d->mutex);
420
return
d->replyMessage;
421
}
422
423
#
if
0
424
/*
425
Sets the slot \a member in object \a target to be called when the
426
reply arrives. The slot's parameter list must match the reply
427
message's arguments for it to be called.
428
429
It may, optionally, contain a QDBusMessage final parameter. If it
430
is present, the parameter will contain the reply message object.
431
432
The callback will not be called if the reply is an error message.
433
434
This function returns \c true if it could set the callback, false
435
otherwise. It is not a guarantee that the callback will be
436
called.
437
438
\warning QDBusPendingCall only supports one callback per pending
439
asynchronous call, even if multiple QDBusPendingCall
440
objects are referencing the same pending call.
441
*/
442
bool
QDBusPendingCall::setReplyCallback(QObject *target,
const
char
*member)
443
{
444
if
(!d)
445
return
false
;
446
447
return
d->setReplyCallback(target, member);
448
}
449
#
endif
450
451
/*!
452
\since 4.6
453
Creates a QDBusPendingCall object based on the error condition
454
\a error. The resulting pending call object will be in the
455
"finished" state and QDBusPendingReply<Types...>::isError() will return true.
456
457
\sa fromCompletedCall()
458
*/
459
QDBusPendingCall QDBusPendingCall::fromError(
const
QDBusError &error)
460
{
461
return
fromCompletedCall(QDBusMessage::createError(error));
462
}
463
464
/*!
465
\since 4.6
466
Creates a QDBusPendingCall object based on the message \a msg.
467
The message must be of type QDBusMessage::ErrorMessage or
468
QDBusMessage::ReplyMessage (that is, a message that is typical
469
of a completed call).
470
471
This function is useful for code that requires simulating a pending
472
call, but that has already finished.
473
474
\sa fromError()
475
*/
476
QDBusPendingCall QDBusPendingCall::fromCompletedCall(
const
QDBusMessage &msg)
477
{
478
QDBusPendingCallPrivate *d =
nullptr
;
479
if
(msg.type() == QDBusMessage::ErrorMessage ||
480
msg.type() == QDBusMessage::ReplyMessage) {
481
d =
new
QDBusPendingCallPrivate(QDBusMessage(),
nullptr
);
482
d->replyMessage = msg;
483
d->ref.storeRelaxed(1);
484
}
485
486
return
QDBusPendingCall(d);
487
}
488
489
/*!
490
Creates a QDBusPendingCallWatcher object to watch for replies on the
491
asynchronous pending call \a call and sets this object's parent
492
to \a parent.
493
*/
494
QDBusPendingCallWatcher::QDBusPendingCallWatcher(
const
QDBusPendingCall &call, QObject *parent)
495
: QObject(parent), QDBusPendingCall(call)
496
{
497
if
(d) {
// QDBusPendingCall::d
498
const
auto
locker = qt_scoped_lock(d->mutex);
499
if
(!d->watcherHelper) {
500
d->watcherHelper =
new
QDBusPendingCallWatcherHelper;
501
if
(d->replyMessage.type() != QDBusMessage::InvalidMessage) {
502
// cause a signal emission anyways
503
QMetaObject::invokeMethod(d->watcherHelper,
504
&QDBusPendingCallWatcherHelper::finished,
505
Qt::QueuedConnection);
506
}
507
}
508
d->watcherHelper->add(
this
);
509
}
510
}
511
512
/*!
513
Destroys this object. If this QDBusPendingCallWatcher object was the
514
last reference to the unfinished pending call, the call will be
515
canceled.
516
*/
517
QDBusPendingCallWatcher::~QDBusPendingCallWatcher()
518
{
519
}
520
521
/*!
522
\fn void QDBusPendingCallWatcher::waitForFinished()
523
524
Suspends the execution of the calling thread until the reply is
525
received and processed. After this function returns, isFinished()
526
should return true, indicating the reply's contents are ready to
527
be processed.
528
529
\sa QDBusPendingReply::waitForFinished()
530
*/
531
void
QDBusPendingCallWatcher::waitForFinished()
532
{
533
if
(d) {
534
d->waitForFinished();
535
536
// our signals were queued, so deliver them
537
QCoreApplication::sendPostedEvents(d->watcherHelper, QEvent::MetaCall);
538
QCoreApplication::sendPostedEvents(
this
, QEvent::MetaCall);
539
}
540
}
541
QT_END_NAMESPACE
542
543
#
include
"moc_qdbuspendingcall_p.cpp"
544
545
#
endif
// QT_NO_DBUS
546
547
#
include
"moc_qdbuspendingcall.cpp"
QDBusPendingCallPrivate
Definition
qdbuspendingcall_p.h:41
QDBusPendingCallPrivate::waitForFinished
void waitForFinished()
Definition
qdbuspendingcall.cpp:200
QDBusPendingCallPrivate::methodIdx
int methodIdx
Definition
qdbuspendingcall_p.h:51
QDBusPendingCallPrivate::watcherHelper
QDBusPendingCallWatcherHelper * watcherHelper
Definition
qdbuspendingcall_p.h:60
QDBusPendingCallPrivate::setReplyCallback
bool setReplyCallback(QObject *target, const char *member)
Definition
qdbuspendingcall.cpp:111
QDBusPendingCallPrivate::setMetaTypes
void setMetaTypes(int count, const QMetaType *types)
Definition
qdbuspendingcall.cpp:158
QDBusPendingCallPrivate::~QDBusPendingCallPrivate
~QDBusPendingCallPrivate()
Definition
qdbuspendingcall.cpp:102
QDBusPendingCallPrivate::waitForFinishedWithGui
void waitForFinishedWithGui()
Definition
qdbuspendingcall.cpp:210
QDBusPendingCallPrivate::checkReceivedSignature
void checkReceivedSignature()
Definition
qdbuspendingcall.cpp:177
QDBusPendingCallPrivate::pending
DBusPendingCall * pending
Definition
qdbuspendingcall_p.h:62
QDBusPendingCallWatcherHelper
Definition
qdbuspendingcall_p.h:78
QString
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition
qstring.h:177
QT_BEGIN_NAMESPACE
Combined button and popup list for selecting options.
Definition
qsequentialanimationgroup.cpp:47
dbus_pending_call_unref
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char return DBusMessage dbus_bool_t return DBusMessage dbus_uint32_t return DBusMessage return DBusPendingCall DBusPendingCall return dbus_pending_call_unref
Definition
qdbus_symbols_p.h:431
QT_DEFINE_QESDP_SPECIALIZATION_DTOR
#define QT_DEFINE_QESDP_SPECIALIZATION_DTOR(Class)
Definition
qshareddata.h:397
qtbase
src
dbus
qdbuspendingcall.cpp
Generated on
for Qt by
1.18.0