Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qsignalspy.cpp
Go to the documentation of this file.
1// Copyright (C) 2019 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qsignalspy.h"
5
7
145bool QSignalSpy::wait(std::chrono::milliseconds timeout)
146{
147 QMutexLocker locker(&m_mutex);
148 Q_ASSERT(!m_waiting);
149 const qsizetype origCount = size();
150 m_waiting = true;
151 locker.unlock();
152
153 m_loop.enterLoop(timeout);
154
155 locker.relock();
156 m_waiting = false;
157 return size() > origCount;
158}
159
161{
162 if (!signal.isValid()) {
163 qWarning("QSignalSpy: Null signal is not valid");
164 return false;
165 }
166
167 if (signal.methodType() != QMetaMethod::Signal) {
168 qWarning("QSignalSpy: Not a signal: '%s'", signal.methodSignature().constData());
169 return false;
170 }
171
172 return true;
173}
174
175static bool isObjectValid(const QObject *object)
176{
177 const bool valid = !!object;
178
179 if (!valid)
180 qWarning("QSignalSpy: Cannot spy on a null object");
181
182 return valid;
183}
184
185QSignalSpy::ObjectSignal QSignalSpy::verify(const QObject *obj, const char *aSignal)
186{
187 if (!isObjectValid(obj))
188 return {};
189
190 if (!aSignal) {
191 qWarning("QSignalSpy: Null signal name is not valid");
192 return {};
193 }
194
195 if (((aSignal[0] - '0') & 0x03) != QSIGNAL_CODE) {
196 qWarning("QSignalSpy: Not a valid signal, use the SIGNAL macro");
197 return {};
198 }
199
201 const QMetaObject * const mo = obj->metaObject();
202 const int sigIndex = mo->indexOfMethod(ba.constData());
203 if (sigIndex < 0) {
204 qWarning("QSignalSpy: No such signal: '%s'", ba.constData());
205 return {};
206 }
207
208 return verify(obj, mo->method(sigIndex));
209}
210
211QSignalSpy::ObjectSignal QSignalSpy::verify(const QObject *obj, QMetaMethod signal)
212{
214 return {obj, signal};
215 else
216 return {};
217}
218
219static QList<int> makeArgs(QMetaMethod member, const QObject *obj)
220{
221 QList<int> result;
222 result.reserve(member.parameterCount());
223 for (int i = 0; i < member.parameterCount(); ++i) {
224 QMetaType tp = member.parameterMetaType(i);
225 if (!tp.isValid() && obj) {
226 void *argv[] = { &tp, &i };
227 QMetaObject::metacall(const_cast<QObject*>(obj),
229 member.methodIndex(), argv);
230 }
231 if (!tp.isValid()) {
232 qWarning("QSignalSpy: Unable to handle parameter '%s' of type '%s' of method '%s',"
233 " use qRegisterMetaType to register it.",
234 member.parameterNames().at(i).constData(),
235 member.parameterTypes().at(i).constData(),
236 member.name().constData());
237 }
238 result.append(tp.id());
239 }
240 return result;
241}
242
244{
245 QSignalSpy * const q;
246public:
247 explicit QSignalSpyPrivate(QSignalSpy *qq) : q(qq) {}
248
249 int qt_metacall(QMetaObject::Call call, int methodId, void **a) override;
250};
251
252QSignalSpy::QSignalSpy(ObjectSignal os)
253 : sig(os.sig.methodSignature()),
254 args(os.obj ? makeArgs(os.sig, os.obj) : QList<int>{})
255{
256 if (!os.obj)
257 return;
258
259 auto i = std::make_unique<QSignalSpyPrivate>(this);
260
261 const auto signalIndex = os.sig.methodIndex();
262 const auto slotIndex = QObject::staticMetaObject.methodCount();
264 i.get(), slotIndex, Qt::DirectConnection)) {
265 qWarning("QSignalSpy: QMetaObject::connect returned false. Unable to connect.");
266 return;
267 }
268
269 d_ptr = std::move(i);
270}
271
276 = default;
277
278void QSignalSpy::appendArgs(void **a)
279{
280 QList<QVariant> list;
281 list.reserve(args.size());
282 for (qsizetype i = 0; i < args.size(); ++i) {
283 const QMetaType::Type type = static_cast<QMetaType::Type>(args.at(i));
285 list << *reinterpret_cast<QVariant *>(a[i + 1]);
286 else
287 list << QVariant(QMetaType(type), a[i + 1]);
288 }
289 QMutexLocker locker(&m_mutex);
290 append(std::move(list));
291
292 if (m_waiting) {
293 locker.unlock();
294 m_loop.exitLoop();
295 }
296}
297
303{
304 methodId = QObject::qt_metacall(call, methodId, a);
305 if (methodId < 0)
306 return methodId;
307
308 if (call == QMetaObject::InvokeMetaMethod) {
309 if (methodId == 0) {
310 q->appendArgs(a);
311 }
312 --methodId;
313 }
314 return methodId;
315}
316
\inmodule QtCore
Definition qbytearray.h:57
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
Definition qbytearray.h:124
Definition qlist.h:75
qsizetype size() const noexcept
Definition qlist.h:397
const_reference at(qsizetype i) const noexcept
Definition qlist.h:446
void reserve(qsizetype size)
Definition qlist.h:753
void append(parameter_type t)
Definition qlist.h:458
\inmodule QtCore
Definition qmetaobject.h:19
int parameterCount() const
int methodIndex() const
QList< QByteArray > parameterTypes() const
Returns a list of parameter types.
QMetaType parameterMetaType(int index) const
QByteArray name() const
QList< QByteArray > parameterNames() const
Returns a list of parameter names.
\inmodule QtCore
Definition qmetatype.h:341
bool isValid() const
int id(int=0) const
Definition qmetatype.h:475
Type
\macro Q_DECLARE_OPAQUE_POINTER(PointerType)
Definition qmetatype.h:345
friend class QVariant
Definition qmetatype.h:796
\inmodule QtCore
Definition qmutex.h:313
void unlock() noexcept
Unlocks this mutex locker.
Definition qmutex.h:319
void relock() noexcept
Relocks an unlocked mutex locker.
Definition qmutex.h:320
\inmodule QtCore
Definition qobject.h:103
QSignalSpyPrivate(QSignalSpy *qq)
int qt_metacall(QMetaObject::Call call, int methodId, void **a) override
\reimp
\inmodule QtTest
Definition qsignalspy.h:22
bool wait(int timeout)
Definition qsignalspy.h:47
QSignalSpy(const QObject *obj, const char *aSignal)
Constructs a new QSignalSpy that listens for emissions of the signal from the QObject object.
Definition qsignalspy.h:30
QByteArray signal() const
Returns the normalized signal the spy is currently listening to.
Definition qsignalspy.h:45
Q_TESTLIB_EXPORT ~QSignalSpy()
Destructor.
void enterLoop(int secs)
\inmodule QtCore
Definition qvariant.h:65
auto signalIndex
auto signal
auto mo
[7]
Combined button and popup list for selecting options.
@ DirectConnection
#define qWarning
Definition qlogging.h:166
#define QSIGNAL_CODE
Definition qobjectdefs.h:42
GLboolean GLboolean GLboolean GLboolean a
[7]
GLuint object
[3]
GLbitfield GLuint64 timeout
[4]
GLenum type
GLhandleARB obj
[2]
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLuint64EXT * result
[6]
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
static bool isSignalMetaMethodValid(QMetaMethod signal)
static QList< int > makeArgs(QMetaMethod member, const QObject *obj)
static bool isObjectValid(const QObject *object)
ptrdiff_t qsizetype
Definition qtypes.h:165
QList< int > list
[14]
QByteArray ba
[0]
QJSValueList args
\inmodule QtCore
static int metacall(QObject *, Call, int, void **)
static QByteArray normalizedSignature(const char *method)
Normalizes the signature of the given method.
static Connection connect(const QObject *sender, int signal_index, const QObject *receiver, int method_index, int type=0, int *types=nullptr)
Definition qobject.cpp:3556
@ RegisterMethodArgumentMetaType