QtBase  v6.3.1
qobject.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2021 The Qt Company Ltd.
4 ** Copyright (C) 2016 Intel Corporation.
5 ** Copyright (C) 2013 Olivier Goffart <ogoffart@woboq.com>
6 ** Contact: https://www.qt.io/licensing/
7 **
8 ** This file is part of the QtCore module of the Qt Toolkit.
9 **
10 ** $QT_BEGIN_LICENSE:LGPL$
11 ** Commercial License Usage
12 ** Licensees holding valid commercial Qt licenses may use this file in
13 ** accordance with the commercial license agreement provided with the
14 ** Software or, alternatively, in accordance with the terms contained in
15 ** a written agreement between you and The Qt Company. For licensing terms
16 ** and conditions see https://www.qt.io/terms-conditions. For further
17 ** information use the contact form at https://www.qt.io/contact-us.
18 **
19 ** GNU Lesser General Public License Usage
20 ** Alternatively, this file may be used under the terms of the GNU Lesser
21 ** General Public License version 3 as published by the Free Software
22 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
23 ** packaging of this file. Please review the following information to
24 ** ensure the GNU Lesser General Public License version 3 requirements
25 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
26 **
27 ** GNU General Public License Usage
28 ** Alternatively, this file may be used under the terms of the GNU
29 ** General Public License version 2.0 or (at your option) the GNU General
30 ** Public license version 3 or any later version approved by the KDE Free
31 ** Qt Foundation. The licenses are as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
33 ** included in the packaging of this file. Please review the following
34 ** information to ensure the GNU General Public License requirements will
35 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
36 ** https://www.gnu.org/licenses/gpl-3.0.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include "qobject.h"
43 #include "qobject_p.h"
44 #include "qmetaobject_p.h"
45 
48 #include "qcoreapplication.h"
49 #include "qcoreapplication_p.h"
50 #include "qloggingcategory.h"
51 #include "qvariant.h"
52 #include "qmetaobject.h"
53 #if QT_CONFIG(regularexpression)
54 # include <qregularexpression.h>
55 #endif
56 #include <qthread.h>
57 #include <private/qthread_p.h>
58 #include <qdebug.h>
59 #include <qpair.h>
60 #include <qvarlengtharray.h>
61 #include <qscopeguard.h>
62 #include <qset.h>
63 #if QT_CONFIG(thread)
64 #include <qsemaphore.h>
65 #endif
66 #include <qsharedpointer.h>
67 
68 #include <private/qorderedmutexlocker_p.h>
69 #include <private/qhooks_p.h>
70 #include <qtcore_tracepoints_p.h>
71 
72 #include <new>
73 #include <mutex>
74 #include <memory>
75 
76 #include <ctype.h>
77 #include <limits.h>
78 
80 
81 static int DIRECT_CONNECTION_ONLY = 0;
82 
83 Q_LOGGING_CATEGORY(lcConnectSlotsByName, "qt.core.qmetaobject.connectslotsbyname")
84 Q_LOGGING_CATEGORY(lcConnect, "qt.core.qobject.connect")
85 
87 
89 {
90  qt_signal_spy_callback_set.storeRelease(callback_set);
91 }
92 
94 {
95 }
96 
98 {
99 }
100 
101 static int *queuedConnectionTypes(const QMetaMethod &method)
102 {
103  const auto parameterCount = method.parameterCount();
104  int *typeIds = new int[parameterCount + 1];
105  Q_CHECK_PTR(typeIds);
106  for (int i = 0; i < parameterCount; ++i) {
107  const QMetaType metaType = method.parameterMetaType(i);
108  if (metaType.flags() & QMetaType::IsPointer)
109  typeIds[i] = QMetaType::VoidStar;
110  else
111  typeIds[i] = metaType.id();
112  if (!typeIds[i]) {
113  const QByteArray typeName = method.parameterTypeName(i);
114  qCWarning(lcConnect,
115  "QObject::connect: Cannot queue arguments of type '%s'\n"
116  "(Make sure '%s' is registered using qRegisterMetaType().)",
117  typeName.constData(), typeName.constData());
118  delete[] typeIds;
119  return nullptr;
120  }
121  }
122  typeIds[parameterCount] = 0;
123 
124  return typeIds;
125 }
126 
127 static int *queuedConnectionTypes(const QArgumentType *argumentTypes, int argc)
128 {
129  auto types = std::make_unique<int[]>(argc + 1);
130  for (int i = 0; i < argc; ++i) {
131  const QArgumentType &type = argumentTypes[i];
132  if (type.type())
133  types[i] = type.type();
134  else if (type.name().endsWith('*'))
135  types[i] = QMetaType::VoidStar;
136  else
137  types[i] = QMetaType::fromName(type.name()).id();
138 
139  if (!types[i]) {
140  qCWarning(lcConnect,
141  "QObject::connect: Cannot queue arguments of type '%s'\n"
142  "(Make sure '%s' is registered using qRegisterMetaType().)",
143  type.name().constData(), type.name().constData());
144  return nullptr;
145  }
146  }
147  types[argc] = 0;
148 
149  return types.release();
150 }
151 
152 static QBasicMutex _q_ObjectMutexPool[131];
153 
158 static inline QBasicMutex *signalSlotLock(const QObject *o)
159 {
160  return &_q_ObjectMutexPool[uint(quintptr(o)) % sizeof(_q_ObjectMutexPool)/sizeof(QBasicMutex)];
161 }
162 
168 
176 
178 {
180 }
181 
183  : threadData(nullptr), currentChildBeingDeleted(nullptr)
184 {
186 
187  // QObjectData initialization
188  q_ptr = nullptr;
189  parent = nullptr; // no parent yet. It is set by setParent()
190  isWidget = false; // assume not a widget object
191  blockSig = false; // not blocking signals
192  wasDeleted = false; // double-delete catcher
193  isDeletingChildren = false; // set by deleteChildren()
194  sendChildEvents = true; // if we should send ChildAdded and ChildRemoved events to parent
195  receiveChildEvents = true;
196  postedEvents = 0;
197  extraData = nullptr;
198  metaObject = nullptr;
199  isWindow = false;
200  deleteLaterCalled = false;
201 }
202 
204 {
205  auto thisThreadData = threadData.loadRelaxed();
207  if (Q_LIKELY(thisThreadData->thread.loadAcquire() == QThread::currentThread())) {
208  // unregister pending timers
209  if (thisThreadData->hasEventDispatcher())
210  thisThreadData->eventDispatcher.loadRelaxed()->unregisterTimers(q_ptr);
211 
212  // release the timer ids back to the pool
213  for (int i = 0; i < extraData->runningTimers.size(); ++i)
215  } else {
216  qWarning("QObject::~QObject: Timers cannot be stopped from another thread");
217  }
218  }
219 
220  if (postedEvents)
222 
223  thisThreadData->deref();
224 
225  if (metaObject)
227 
228  delete extraData;
229 }
230 
235 static void computeOffsets(const QMetaObject *metaobject, int *signalOffset, int *methodOffset)
236 {
237  *signalOffset = *methodOffset = 0;
238  const QMetaObject *m = metaobject->d.superdata;
239  while (m) {
241  *methodOffset += d->methodCount;
242  Q_ASSERT(d->revision >= 4);
243  *signalOffset += d->signalCount;
244  m = m->d.superdata;
245  }
246 }
247 
248 // Used by QAccessibleWidget
249 bool QObjectPrivate::isSender(const QObject *receiver, const char *signal) const
250 {
251  Q_Q(const QObject);
252  int signal_index = signalIndex(signal);
253  ConnectionData *cd = connections.loadRelaxed();
254  if (signal_index < 0 || !cd)
255  return false;
256  QBasicMutexLocker locker(signalSlotLock(q));
257  if (signal_index < cd->signalVectorCount()) {
258  const QObjectPrivate::Connection *c = cd->signalVector.loadRelaxed()->at(signal_index).first.loadRelaxed();
259 
260  while (c) {
261  if (c->receiver.loadRelaxed() == receiver)
262  return true;
263  c = c->nextConnectionList.loadRelaxed();
264  }
265  }
266  return false;
267 }
268 
269 // Used by QAccessibleWidget
271 {
272  QObjectList returnValue;
273  int signal_index = signalIndex(signal);
274  ConnectionData *cd = connections.loadRelaxed();
275  if (signal_index < 0 || !cd)
276  return returnValue;
277  if (signal_index < cd->signalVectorCount()) {
278  const QObjectPrivate::Connection *c = cd->signalVector.loadRelaxed()->at(signal_index).first.loadRelaxed();
279 
280  while (c) {
281  QObject *r = c->receiver.loadRelaxed();
282  if (r)
283  returnValue << r;
284  c = c->nextConnectionList.loadRelaxed();
285  }
286  }
287  return returnValue;
288 }
289 
290 // Used by QAccessibleWidget
292 {
293  QObjectList returnValue;
294  ConnectionData *cd = connections.loadRelaxed();
295  if (cd) {
296  QBasicMutexLocker locker(signalSlotLock(q_func()));
297  for (Connection *c = cd->senders; c; c = c->next)
298  returnValue << c->sender;
299  }
300  return returnValue;
301 }
302 
314 {
315  Q_ASSERT(c->sender == q_ptr);
317  ConnectionData *cd = connections.loadRelaxed();
318  cd->resizeSignalVector(signal + 1);
319 
320  ConnectionList &connectionList = cd->connectionsForSignal(signal);
321  if (connectionList.last.loadRelaxed()) {
322  Q_ASSERT(connectionList.last.loadRelaxed()->receiver.loadRelaxed());
323  connectionList.last.loadRelaxed()->nextConnectionList.storeRelaxed(c);
324  } else {
325  connectionList.first.storeRelaxed(c);
326  }
327  c->id = ++cd->currentConnectionId;
328  c->prevConnectionList = connectionList.last.loadRelaxed();
329  connectionList.last.storeRelaxed(c);
330 
331  QObjectPrivate *rd = QObjectPrivate::get(c->receiver.loadRelaxed());
332  rd->ensureConnectionData();
333 
334  c->prev = &(rd->connections.loadRelaxed()->senders);
335  c->next = *c->prev;
336  *c->prev = c;
337  if (c->next)
338  c->next->prev = &c->next;
339 }
340 
342 {
343  Q_ASSERT(c->receiver.loadRelaxed());
344  ConnectionList &connections = signalVector.loadRelaxed()->at(c->signal_index);
345  c->receiver.storeRelaxed(nullptr);
346  QThreadData *td = c->receiverThreadData.loadRelaxed();
347  if (td)
348  td->deref();
349  c->receiverThreadData.storeRelaxed(nullptr);
350 
351 #ifndef QT_NO_DEBUG
352  bool found = false;
353  for (Connection *cc = connections.first.loadRelaxed(); cc; cc = cc->nextConnectionList.loadRelaxed()) {
354  if (cc == c) {
355  found = true;
356  break;
357  }
358  }
359  Q_ASSERT(found);
360 #endif
361 
362  // remove from the senders linked list
363  *c->prev = c->next;
364  if (c->next)
365  c->next->prev = c->prev;
366  c->prev = nullptr;
367 
368  if (connections.first.loadRelaxed() == c)
369  connections.first.storeRelaxed(c->nextConnectionList.loadRelaxed());
370  if (connections.last.loadRelaxed() == c)
371  connections.last.storeRelaxed(c->prevConnectionList);
372  Q_ASSERT(signalVector.loadRelaxed()->at(c->signal_index).first.loadRelaxed() != c);
373  Q_ASSERT(signalVector.loadRelaxed()->at(c->signal_index).last.loadRelaxed() != c);
374 
375  // keep c->nextConnectionList intact, as it might still get accessed by activate
376  Connection *n = c->nextConnectionList.loadRelaxed();
377  if (n)
378  n->prevConnectionList = c->prevConnectionList;
379  if (c->prevConnectionList)
380  c->prevConnectionList->nextConnectionList.storeRelaxed(n);
381  c->prevConnectionList = nullptr;
382 
383  Q_ASSERT(c != orphaned.loadRelaxed());
384  // add c to orphanedConnections
385  Connection *o = nullptr;
386  /* No ABA issue here: When adding a node, we only care about the list head, it doesn't
387  * matter if the tail changes.
388  */
389  do {
390  o = orphaned.loadRelaxed();
391  c->nextInOrphanList = o;
392  } while (!orphaned.testAndSetRelease(o, c));
393 
394 #ifndef QT_NO_DEBUG
395  found = false;
396  for (Connection *cc = connections.first.loadRelaxed(); cc; cc = cc->nextConnectionList.loadRelaxed()) {
397  if (cc == c) {
398  found = true;
399  break;
400  }
401  }
402  Q_ASSERT(!found);
403 #endif
404 
405 }
406 
408 {
409  QBasicMutex *senderMutex = signalSlotLock(sender);
410  ConnectionOrSignalVector *c = nullptr;
411  {
412  std::unique_lock<QBasicMutex> lock(*senderMutex, std::defer_lock_t{});
413  if (lockPolicy == NeedToLock)
414  lock.lock();
415  if (ref.loadAcquire() > 1)
416  return;
417 
418  // Since ref == 1, no activate() is in process since we locked the mutex. That implies,
419  // that nothing can reference the orphaned connection objects anymore and they can
420  // be safely deleted
421  c = orphaned.fetchAndStoreRelaxed(nullptr);
422  }
423  if (c) {
424  // Deleting c might run arbitrary user code, so we must not hold the lock
425  if (lockPolicy == AlreadyLockedAndTemporarilyReleasingLock) {
426  senderMutex->unlock();
427  deleteOrphaned(c);
428  senderMutex->lock();
429  } else {
430  deleteOrphaned(c);
431  }
432  }
433 }
434 
436 {
437  while (o) {
440  next = v->nextInOrphanList;
441  free(v);
442  } else {
443  QObjectPrivate::Connection *c = static_cast<Connection *>(o);
444  next = c->nextInOrphanList;
445  Q_ASSERT(!c->receiver.loadRelaxed());
446  Q_ASSERT(!c->prev);
447  c->freeSlotObject();
448  c->deref();
449  }
450  o = next;
451  }
452 }
453 
460 bool QObjectPrivate::isSignalConnected(uint signalIndex, bool checkDeclarative) const
461 {
462  if (checkDeclarative && isDeclarativeSignalConnected(signalIndex))
463  return true;
464 
465  ConnectionData *cd = connections.loadRelaxed();
466  if (!cd)
467  return false;
468  SignalVector *signalVector = cd->signalVector.loadRelaxed();
469  if (!signalVector)
470  return false;
471 
472  if (signalVector->at(-1).first.loadRelaxed())
473  return true;
474 
475  if (signalIndex < uint(cd->signalVectorCount())) {
476  const QObjectPrivate::Connection *c = signalVector->at(signalIndex).first.loadRelaxed();
477  while (c) {
478  if (c->receiver.loadRelaxed())
479  return true;
480  c = c->nextConnectionList.loadRelaxed();
481  }
482  }
483  return false;
484 }
485 
487 {
488  ConnectionData *cd = connections.loadRelaxed();
489  if (!cd)
490  return false;
491  SignalVector *signalVector = cd->signalVector.loadRelaxed();
492  if (!signalVector)
493  return false;
494 
495  if (signalVector->at(-1).first.loadAcquire())
496  return true;
497 
498  if (signalIndex < uint(cd->signalVectorCount())) {
499  const QObjectPrivate::Connection *c = signalVector->at(signalIndex).first.loadAcquire();
500  return c != nullptr;
501  }
502  return false;
503 }
504 
509 {
510 #if QT_CONFIG(thread)
511  if (semaphore_)
512  semaphore_->release();
513 #endif
514 }
515 
519 inline void QMetaCallEvent::allocArgs()
520 {
521  if (!d.nargs_)
522  return;
523 
524  constexpr size_t each = sizeof(void*) + sizeof(QMetaType);
525  void *const memory = d.nargs_ * each > sizeof(prealloc_) ?
526  calloc(d.nargs_, each) : prealloc_;
527 
529  d.args_ = static_cast<void **>(memory);
530 }
531 
538 QMetaCallEvent::QMetaCallEvent(ushort method_offset, ushort method_relative,
540  const QObject *sender, int signalId,
541  void **args, QSemaphore *semaphore)
542  : QAbstractMetaCallEvent(sender, signalId, semaphore),
543  d({nullptr, args, callFunction, 0, method_offset, method_relative}),
544  prealloc_()
545 {
546 }
547 
555  const QObject *sender, int signalId,
556  void **args, QSemaphore *semaphore)
557  : QAbstractMetaCallEvent(sender, signalId, semaphore),
558  d({slotO, args, nullptr, 0, 0, ushort(-1)}),
559  prealloc_()
560 {
561  if (d.slotObj_)
562  d.slotObj_->ref();
563 }
564 
571 QMetaCallEvent::QMetaCallEvent(ushort method_offset, ushort method_relative,
573  const QObject *sender, int signalId,
574  int nargs)
575  : QAbstractMetaCallEvent(sender, signalId),
576  d({nullptr, nullptr, callFunction, nargs, method_offset, method_relative}),
577  prealloc_()
578 {
579  allocArgs();
580 }
581 
589  const QObject *sender, int signalId,
590  int nargs)
591  : QAbstractMetaCallEvent(sender, signalId),
592  d({slotO, nullptr, nullptr, nargs, 0, ushort(-1)}),
593  prealloc_()
594 {
595  if (d.slotObj_)
596  d.slotObj_->ref();
597  allocArgs();
598 }
599 
604 {
605  if (d.nargs_) {
606  QMetaType *t = types();
607  for (int i = 0; i < d.nargs_; ++i) {
608  if (t[i].isValid() && d.args_[i])
609  t[i].destroy(d.args_[i]);
610  }
611  if (reinterpret_cast<void *>(d.args_) != reinterpret_cast<void *>(prealloc_))
612  free(d.args_);
613  }
614  if (d.slotObj_)
615  d.slotObj_->destroyIfLastRef();
616 }
617 
622 {
623  if (d.slotObj_) {
624  d.slotObj_->call(object, d.args_);
625  } else if (d.callFunction_ && d.method_offset_ <= object->metaObject()->methodOffset()) {
626  d.callFunction_(object, QMetaObject::InvokeMetaMethod, d.method_relative_, d.args_);
627  } else {
629  d.method_offset_ + d.method_relative_, d.args_);
630  }
631 }
632 
873 /*****************************************************************************
874  QObject member functions
875  *****************************************************************************/
876 
877 // check the constructor's parent thread argument
878 static bool check_parent_thread(QObject *parent,
879  QThreadData *parentThreadData,
880  QThreadData *currentThreadData)
881 {
882  if (parent && parentThreadData != currentThreadData) {
883  QThread *parentThread = parentThreadData->thread.loadAcquire();
884  QThread *currentThread = currentThreadData->thread.loadAcquire();
885  qWarning("QObject: Cannot create children for a parent that is in a different thread.\n"
886  "(Parent is %s(%p), parent's thread is %s(%p), current thread is %s(%p)",
887  parent->metaObject()->className(),
888  parent,
889  parentThread ? parentThread->metaObject()->className() : "QThread",
890  parentThread,
891  currentThread ? currentThread->metaObject()->className() : "QThread",
892  currentThread);
893  return false;
894  }
895  return true;
896 }
897 
914  : QObject(*new QObjectPrivate, parent)
915 {
916 }
917 
922  : d_ptr(&dd)
923 {
924  Q_ASSERT_X(this != parent, Q_FUNC_INFO, "Cannot parent a QObject to itself");
925 
926  Q_D(QObject);
927  d_ptr->q_ptr = this;
928  auto threadData = (parent && !parent->thread()) ? parent->d_func()->threadData.loadRelaxed() : QThreadData::current();
929  threadData->ref();
930  d->threadData.storeRelaxed(threadData);
931  if (parent) {
932  QT_TRY {
933  if (!check_parent_thread(parent, parent ? parent->d_func()->threadData.loadRelaxed() : nullptr, threadData))
934  parent = nullptr;
935  if (d->isWidget) {
936  if (parent) {
937  d->parent = parent;
938  d->parent->d_func()->children.append(this);
939  }
940  // no events sent here, this is done at the end of the QWidget constructor
941  } else {
942  setParent(parent);
943  }
944  } QT_CATCH(...) {
945  threadData->deref();
946  QT_RETHROW;
947  }
948  }
950  reinterpret_cast<QHooks::AddQObjectCallback>(qtHookData[QHooks::AddQObject])(this);
951  Q_TRACE(QObject_ctor, this);
952 }
953 
955 {
956  bindingStorage.clear();
957 }
958 
984 {
985  Q_D(QObject);
986  d->wasDeleted = true;
987  d->blockSig = 0; // unblock signals so we always emit destroyed()
988 
989  // If we reached this point, we need to clear the binding data
990  // as the corresponding properties are no longer useful
991  d->clearBindingStorage();
992 
993  QtSharedPointer::ExternalRefCountData *sharedRefcount = d->sharedRefcount.loadRelaxed();
994  if (sharedRefcount) {
995  if (sharedRefcount->strongref.loadRelaxed() > 0) {
996  qWarning("QObject: shared QObject was deleted directly. The program is malformed and may crash.");
997  // but continue deleting, it's too late to stop anyway
998  }
999 
1000  // indicate to all QWeakPointers that this QObject has now been deleted
1001  sharedRefcount->strongref.storeRelaxed(0);
1002  if (!sharedRefcount->weakref.deref())
1003  delete sharedRefcount;
1004  }
1005 
1006  if (!d->isWidget && d->isSignalConnected(0)) {
1007  emit destroyed(this);
1008  }
1009 
1010  if (d->declarativeData && QAbstractDeclarativeData::destroyed)
1011  QAbstractDeclarativeData::destroyed(d->declarativeData, this);
1012 
1013  QObjectPrivate::ConnectionData *cd = d->connections.loadRelaxed();
1014  if (cd) {
1015  if (cd->currentSender) {
1017  cd->currentSender = nullptr;
1018  }
1019 
1020  QBasicMutex *signalSlotMutex = signalSlotLock(this);
1021  QBasicMutexLocker locker(signalSlotMutex);
1022 
1023  // disconnect all receivers
1024  int receiverCount = cd->signalVectorCount();
1025  for (int signal = -1; signal < receiverCount; ++signal) {
1027 
1028  while (QObjectPrivate::Connection *c = connectionList.first.loadRelaxed()) {
1029  Q_ASSERT(c->receiver.loadAcquire());
1030 
1031  QBasicMutex *m = signalSlotLock(c->receiver.loadRelaxed());
1032  bool needToUnlock = QOrderedMutexLocker::relock(signalSlotMutex, m);
1033  if (c == connectionList.first.loadAcquire() && c->receiver.loadAcquire()) {
1034  cd->removeConnection(c);
1035  Q_ASSERT(connectionList.first.loadRelaxed() != c);
1036  }
1037  if (needToUnlock)
1038  m->unlock();
1039  }
1040  }
1041 
1042  /* Disconnect all senders:
1043  */
1044  while (QObjectPrivate::Connection *node = cd->senders) {
1045  Q_ASSERT(node->receiver.loadAcquire());
1046  QObject *sender = node->sender;
1047  // Send disconnectNotify before removing the connection from sender's connection list.
1048  // This ensures any eventual destructor of sender will block on getting receiver's lock
1049  // and not finish until we release it.
1050  sender->disconnectNotify(QMetaObjectPrivate::signal(sender->metaObject(), node->signal_index));
1051  QBasicMutex *m = signalSlotLock(sender);
1052  bool needToUnlock = QOrderedMutexLocker::relock(signalSlotMutex, m);
1053  //the node has maybe been removed while the mutex was unlocked in relock?
1054  if (node != cd->senders) {
1055  // We hold the wrong mutex
1056  Q_ASSERT(needToUnlock);
1057  m->unlock();
1058  continue;
1059  }
1060 
1061  QObjectPrivate::ConnectionData *senderData = sender->d_func()->connections.loadRelaxed();
1062  Q_ASSERT(senderData);
1063 
1064  QtPrivate::QSlotObjectBase *slotObj = nullptr;
1065  if (node->isSlotObject) {
1066  slotObj = node->slotObj;
1067  node->isSlotObject = false;
1068  }
1069 
1070  senderData->removeConnection(node);
1071  /*
1072  When we unlock, another thread has the chance to delete/modify sender data.
1073  Thus we need to call cleanOrphanedConnections before unlocking. We use the
1074  variant of the function which assumes that the lock is already held to avoid
1075  a deadlock.
1076  We need to hold m, the sender lock. Considering that we might execute arbitrary user
1077  code, we should already release the signalSlotMutex here – unless they are the same.
1078  */
1079  const bool locksAreTheSame = signalSlotMutex == m;
1080  if (!locksAreTheSame)
1081  locker.unlock();
1082  senderData->cleanOrphanedConnections(
1083  sender,
1085  );
1086  if (needToUnlock)
1087  m->unlock();
1088 
1089  if (locksAreTheSame) // otherwise already unlocked
1090  locker.unlock();
1091  if (slotObj)
1092  slotObj->destroyIfLastRef();
1093  locker.relock();
1094  }
1095 
1096  // invalidate all connections on the object and make sure
1097  // activate() will skip them
1099  }
1100  if (cd && !cd->ref.deref())
1101  delete cd;
1102  d->connections.storeRelaxed(nullptr);
1103 
1104  if (!d->children.isEmpty())
1105  d->deleteChildren();
1106 
1109 
1110  Q_TRACE(QObject_dtor, this);
1111 
1112  if (d->parent) // remove it from parent object
1113  d->setParent_helper(nullptr);
1114 }
1115 
1117 {
1118  if (ownArgumentTypes) {
1119  const int *v = argumentTypes.loadRelaxed();
1120  if (v != &DIRECT_CONNECTION_ONLY)
1121  delete[] v;
1122  }
1123  if (isSlotObject)
1125 }
1126 
1127 
1244 {
1245  Q_D(const QObject);
1246 #if QT_CONFIG(thread)
1247  if (QThread::currentThreadId() != d->threadData.loadRelaxed()->threadId.loadRelaxed()) // Unsafe code path
1248  return d->extraData ? d->extraData->objectName.valueBypassingBindings() : QString();
1249 #endif
1250  if (!d->extraData && QtPrivate::isAnyBindingEvaluating()) {
1251  QObjectPrivate *dd = const_cast<QObjectPrivate *>(d);
1252  // extraData is mutable, so this should be safe
1253  dd->extraData = new QObjectPrivate::ExtraData(dd);
1254  }
1255  return d->extraData ? d->extraData->objectName : QString();
1256 }
1257 
1258 /*
1259  Sets the object's name to \a name.
1260 */
1262 {
1263  Q_D(QObject);
1264 
1265  if (!d->extraData)
1266  d->extraData = new QObjectPrivate::ExtraData(d);
1267 
1268  d->extraData->objectName.removeBindingUnlessInWrapper();
1269 
1270  if (d->extraData->objectName != name) {
1271  d->extraData->objectName.setValueBypassingBindings(name);
1272  d->extraData->objectName.notify(); // also emits a signal
1273  }
1274 }
1275 
1277 {
1278  Q_D(QObject);
1279 
1280  if (!d->extraData)
1281  d->extraData = new QObjectPrivate::ExtraData(d);
1282 
1283  return QBindable<QString>(&d->extraData->objectName);
1284 }
1285 
1330 {
1331  switch (e->type()) {
1332  case QEvent::Timer:
1333  timerEvent((QTimerEvent *)e);
1334  break;
1335 
1336  case QEvent::ChildAdded:
1337  case QEvent::ChildPolished:
1338  case QEvent::ChildRemoved:
1339  childEvent((QChildEvent *)e);
1340  break;
1341 
1343  qDeleteInEventHandler(this);
1344  break;
1345 
1346  case QEvent::MetaCall:
1347  {
1348  QAbstractMetaCallEvent *mce = static_cast<QAbstractMetaCallEvent*>(e);
1349 
1350  if (!d_func()->connections.loadRelaxed()) {
1351  QBasicMutexLocker locker(signalSlotLock(this));
1352  d_func()->ensureConnectionData();
1353  }
1354  QObjectPrivate::Sender sender(this, const_cast<QObject*>(mce->sender()), mce->signalId());
1355 
1356  mce->placeMetaCall(this);
1357  break;
1358  }
1359 
1360  case QEvent::ThreadChange: {
1361  Q_D(QObject);
1362  QThreadData *threadData = d->threadData.loadRelaxed();
1363  QAbstractEventDispatcher *eventDispatcher = threadData->eventDispatcher.loadRelaxed();
1364  if (eventDispatcher) {
1365  QList<QAbstractEventDispatcher::TimerInfo> timers = eventDispatcher->registeredTimers(this);
1366  if (!timers.isEmpty()) {
1367  // do not to release our timer ids back to the pool (since the timer ids are moving to a new thread).
1368  eventDispatcher->unregisterTimers(this);
1369  QMetaObject::invokeMethod(this, "_q_reregisterTimers", Qt::QueuedConnection,
1370  Q_ARG(void*, (new QList<QAbstractEventDispatcher::TimerInfo>(timers))));
1371  }
1372  }
1373  break;
1374  }
1375 
1376  default:
1377  if (e->type() >= QEvent::User) {
1378  customEvent(e);
1379  break;
1380  }
1381  return false;
1382  }
1383  return true;
1384 }
1385 
1400 {
1401 }
1402 
1403 
1438 {
1439 }
1440 
1441 
1451 void QObject::customEvent(QEvent * /* event */)
1452 {
1453 }
1454 
1455 
1456 
1484 bool QObject::eventFilter(QObject * /* watched */, QEvent * /* event */)
1485 {
1486  return false;
1487 }
1488 
1514 bool QObject::blockSignals(bool block) noexcept
1515 {
1516  Q_D(QObject);
1517  bool previous = d->blockSig;
1518  d->blockSig = block;
1519  return previous;
1520 }
1521 
1528 {
1529  return d_func()->threadData.loadRelaxed()->thread.loadAcquire();
1530 }
1531 
1572 void QObject::moveToThread(QThread *targetThread)
1573 {
1574  Q_D(QObject);
1575 
1576  if (d->threadData.loadRelaxed()->thread.loadAcquire() == targetThread) {
1577  // object is already in this thread
1578  return;
1579  }
1580 
1581  if (d->parent != nullptr) {
1582  qWarning("QObject::moveToThread: Cannot move objects with a parent");
1583  return;
1584  }
1585  if (d->isWidget) {
1586  qWarning("QObject::moveToThread: Widgets cannot be moved to a new thread");
1587  return;
1588  }
1589  if (!d->bindingStorage.isEmpty()) {
1590  qWarning("QObject::moveToThread: Can not move objects that contain bindings or are used in bindings to a new thread.");
1591  return;
1592  }
1593 
1594  QThreadData *currentData = QThreadData::current();
1595  QThreadData *targetData = targetThread ? QThreadData::get2(targetThread) : nullptr;
1596  QThreadData *thisThreadData = d->threadData.loadAcquire();
1597  if (!thisThreadData->thread.loadRelaxed() && currentData == targetData) {
1598  // one exception to the rule: we allow moving objects with no thread affinity to the current thread
1599  currentData = thisThreadData;
1600  } else if (thisThreadData != currentData) {
1601  qWarning("QObject::moveToThread: Current thread (%p) is not the object's thread (%p).\n"
1602  "Cannot move to target thread (%p)\n",
1603  currentData->thread.loadRelaxed(), thisThreadData->thread.loadRelaxed(), targetData ? targetData->thread.loadRelaxed() : nullptr);
1604 
1605 #ifdef Q_OS_MAC
1606  qWarning("You might be loading two sets of Qt binaries into the same process. "
1607  "Check that all plugins are compiled against the right Qt binaries. Export "
1608  "DYLD_PRINT_LIBRARIES=1 and check that only one set of binaries are being loaded.");
1609 #endif
1610 
1611  return;
1612  }
1613 
1614  // prepare to move
1615  d->moveToThread_helper();
1616 
1617  if (!targetData)
1618  targetData = new QThreadData(0);
1619 
1620  // make sure nobody adds/removes connections to this object while we're moving it
1621  QMutexLocker l(signalSlotLock(this));
1622 
1623  QOrderedMutexLocker locker(&currentData->postEventList.mutex,
1624  &targetData->postEventList.mutex);
1625 
1626  // keep currentData alive (since we've got it locked)
1627  currentData->ref();
1628 
1629  // move the object
1630  d_func()->setThreadData_helper(currentData, targetData);
1631 
1632  locker.unlock();
1633 
1634  // now currentData can commit suicide if it wants to
1635  currentData->deref();
1636 }
1637 
1639 {
1640  Q_Q(QObject);
1643  for (int i = 0; i < children.size(); ++i) {
1644  QObject *child = children.at(i);
1645  child->d_func()->moveToThread_helper();
1646  }
1647 }
1648 
1650 {
1651  Q_Q(QObject);
1652 
1653  // move posted events
1654  int eventsMoved = 0;
1655  for (int i = 0; i < currentData->postEventList.size(); ++i) {
1656  const QPostEvent &pe = currentData->postEventList.at(i);
1657  if (!pe.event)
1658  continue;
1659  if (pe.receiver == q) {
1660  // move this post event to the targetList
1661  targetData->postEventList.addEvent(pe);
1662  const_cast<QPostEvent &>(pe).event = nullptr;
1663  ++eventsMoved;
1664  }
1665  }
1666  if (eventsMoved > 0 && targetData->hasEventDispatcher()) {
1667  targetData->canWait = false;
1668  targetData->eventDispatcher.loadRelaxed()->wakeUp();
1669  }
1670 
1671  // the current emitting thread shouldn't restore currentSender after calling moveToThread()
1672  ConnectionData *cd = connections.loadRelaxed();
1673  if (cd) {
1674  if (cd->currentSender) {
1676  cd->currentSender = nullptr;
1677  }
1678 
1679  // adjust the receiverThreadId values in the Connections
1680  if (cd) {
1681  auto *c = cd->senders;
1682  while (c) {
1683  QObject *r = c->receiver.loadRelaxed();
1684  if (r) {
1685  Q_ASSERT(r == q);
1686  targetData->ref();
1687  QThreadData *old = c->receiverThreadData.loadRelaxed();
1688  if (old)
1689  old->deref();
1690  c->receiverThreadData.storeRelaxed(targetData);
1691  }
1692  c = c->next;
1693  }
1694  }
1695 
1696  }
1697 
1698  // set new thread data
1699  targetData->ref();
1700  threadData.loadRelaxed()->deref();
1701 
1702  // synchronizes with loadAcquire e.g. in QCoreApplication::postEvent
1703  threadData.storeRelease(targetData);
1704 
1705  for (int i = 0; i < children.size(); ++i) {
1706  QObject *child = children.at(i);
1707  child->d_func()->setThreadData_helper(currentData, targetData);
1708  }
1709 }
1710 
1712 {
1713  Q_Q(QObject);
1715  QAbstractEventDispatcher *eventDispatcher = threadData.loadRelaxed()->eventDispatcher.loadRelaxed();
1716  for (int i = 0; i < timerList->size(); ++i) {
1717  const QAbstractEventDispatcher::TimerInfo &ti = timerList->at(i);
1718  eventDispatcher->registerTimer(ti.timerId, ti.interval, ti.timerType, q);
1719  }
1720  delete timerList;
1721 }
1722 
1723 
1724 //
1725 // The timer flag hasTimer is set when startTimer is called.
1726 // It is not reset when killing the timer because more than
1727 // one timer might be active.
1728 //
1729 
1765 int QObject::startTimer(int interval, Qt::TimerType timerType)
1766 {
1767  Q_D(QObject);
1768 
1769  if (Q_UNLIKELY(interval < 0)) {
1770  qWarning("QObject::startTimer: Timers cannot have negative intervals");
1771  return 0;
1772  }
1773 
1774  auto thisThreadData = d->threadData.loadRelaxed();
1775  if (Q_UNLIKELY(!thisThreadData->hasEventDispatcher())) {
1776  qWarning("QObject::startTimer: Timers can only be used with threads started with QThread");
1777  return 0;
1778  }
1779  if (Q_UNLIKELY(thread() != QThread::currentThread())) {
1780  qWarning("QObject::startTimer: Timers cannot be started from another thread");
1781  return 0;
1782  }
1783  int timerId = thisThreadData->eventDispatcher.loadRelaxed()->registerTimer(interval, timerType, this);
1784  if (!d->extraData)
1785  d->extraData = new QObjectPrivate::ExtraData(d);
1786  d->extraData->runningTimers.append(timerId);
1787  return timerId;
1788 }
1789 
1839 {
1840  Q_D(QObject);
1841  if (Q_UNLIKELY(thread() != QThread::currentThread())) {
1842  qWarning("QObject::killTimer: Timers cannot be stopped from another thread");
1843  return;
1844  }
1845  if (id) {
1846  int at = d->extraData ? d->extraData->runningTimers.indexOf(id) : -1;
1847  if (at == -1) {
1848  // timer isn't owned by this object
1849  qWarning("QObject::killTimer(): Error: timer id %d is not valid for object %p (%s, %ls), timer has not been killed",
1850  id,
1851  this,
1852  metaObject()->className(),
1853  qUtf16Printable(objectName()));
1854  return;
1855  }
1856 
1857  auto thisThreadData = d->threadData.loadRelaxed();
1858  if (thisThreadData->hasEventDispatcher())
1859  thisThreadData->eventDispatcher.loadRelaxed()->unregisterTimer(id);
1860 
1861  d->extraData->runningTimers.remove(at);
1863  }
1864 }
1865 
1866 
2020 static void qt_qFindChildren_with_name(const QObject *parent, const QString &name,
2021  const QMetaObject &mo, QList<void *> *list,
2022  Qt::FindChildOptions options)
2023 {
2024  Q_ASSERT(parent);
2025  Q_ASSERT(list);
2026  Q_ASSERT(!name.isNull());
2027  for (QObject *obj : parent->children()) {
2028  if (mo.cast(obj) && obj->objectName() == name)
2029  list->append(obj);
2030  if (options & Qt::FindChildrenRecursively)
2031  qt_qFindChildren_with_name(obj, name, mo, list, options);
2032  }
2033 }
2034 
2039  const QMetaObject &mo, QList<void*> *list, Qt::FindChildOptions options)
2040 {
2041  if (name.isNull())
2042  return qt_qFindChildren_helper(parent, mo, list, options);
2043  else
2044  return qt_qFindChildren_with_name(parent, name, mo, list, options);
2045 }
2046 
2051  QList<void*> *list, Qt::FindChildOptions options)
2052 {
2053  Q_ASSERT(parent);
2054  Q_ASSERT(list);
2055  for (QObject *obj : parent->children()) {
2056  if (mo.cast(obj))
2057  list->append(obj);
2058  if (options & Qt::FindChildrenRecursively)
2059  qt_qFindChildren_helper(obj, mo, list, options);
2060  }
2061 }
2062 
2063 #if QT_CONFIG(regularexpression)
2068  const QMetaObject &mo, QList<void*> *list, Qt::FindChildOptions options)
2069 {
2070  Q_ASSERT(parent);
2071  Q_ASSERT(list);
2072  for (QObject *obj : parent->children()) {
2073  if (mo.cast(obj)) {
2074  QRegularExpressionMatch m = re.match(obj->objectName());
2075  if (m.hasMatch())
2076  list->append(obj);
2077  }
2078  if (options & Qt::FindChildrenRecursively)
2079  qt_qFindChildren_helper(obj, re, mo, list, options);
2080  }
2081 }
2082 #endif // QT_CONFIG(regularexpression)
2083 
2087 QObject *qt_qFindChild_helper(const QObject *parent, const QString &name, const QMetaObject &mo, Qt::FindChildOptions options)
2088 {
2089  Q_ASSERT(parent);
2090  for (QObject *obj : parent->children()) {
2091  if (mo.cast(obj) && (name.isNull() || obj->objectName() == name))
2092  return obj;
2093  }
2094  if (options & Qt::FindChildrenRecursively) {
2095  for (QObject *child : parent->children()) {
2096  if (QObject *obj = qt_qFindChild_helper(child, name, mo, options))
2097  return obj;
2098  }
2099  }
2100  return nullptr;
2101 }
2102 
2109 {
2110  Q_D(QObject);
2111  Q_ASSERT(!d->isWidget);
2112  d->setParent_helper(parent);
2113 }
2114 
2116 {
2117  Q_ASSERT_X(!isDeletingChildren, "QObjectPrivate::deleteChildren()", "isDeletingChildren already set, did this function recurse?");
2118  isDeletingChildren = true;
2119  // delete children objects
2120  // don't use qDeleteAll as the destructor of the child might
2121  // delete siblings
2122  for (int i = 0; i < children.count(); ++i) {
2124  children[i] = nullptr;
2125  delete currentChildBeingDeleted;
2126  }
2127  children.clear();
2128  currentChildBeingDeleted = nullptr;
2129  isDeletingChildren = false;
2130 }
2131 
2133 {
2134  Q_Q(QObject);
2135  Q_ASSERT_X(q != o, Q_FUNC_INFO, "Cannot parent a QObject to itself");
2136 #ifdef QT_DEBUG
2137  const auto checkForParentChildLoops = qScopeGuard([&](){
2138  int depth = 0;
2139  auto p = parent;
2140  while (p) {
2141  if (++depth == CheckForParentChildLoopsWarnDepth) {
2142  qWarning("QObject %p (class: '%s', object name: '%s') may have a loop in its parent-child chain; "
2143  "this is undefined behavior",
2144  q, q->metaObject()->className(), qPrintable(q->objectName()));
2145  }
2146  p = p->parent();
2147  }
2148  });
2149 #endif
2150 
2151  if (o == parent)
2152  return;
2153 
2154  if (parent) {
2155  QObjectPrivate *parentD = parent->d_func();
2156  if (parentD->isDeletingChildren && wasDeleted
2157  && parentD->currentChildBeingDeleted == q) {
2158  // don't do anything since QObjectPrivate::deleteChildren() already
2159  // cleared our entry in parentD->children.
2160  } else {
2161  const int index = parentD->children.indexOf(q);
2162  if (index < 0) {
2163  // we're probably recursing into setParent() from a ChildRemoved event, don't do anything
2164  } else if (parentD->isDeletingChildren) {
2165  parentD->children[index] = nullptr;
2166  } else {
2167  parentD->children.removeAt(index);
2168  if (sendChildEvents && parentD->receiveChildEvents) {
2171  }
2172  }
2173  }
2174  }
2175  parent = o;
2176  if (parent) {
2177  // object hierarchies are constrained to a single thread
2178  if (threadData.loadRelaxed() != parent->d_func()->threadData.loadRelaxed()) {
2179  qWarning("QObject::setParent: Cannot set parent, new parent is in a different thread");
2180  parent = nullptr;
2181  return;
2182  }
2183  parent->d_func()->children.append(q);
2184  if (sendChildEvents && parent->d_func()->receiveChildEvents) {
2185  if (!isWidget) {
2188  }
2189  }
2190  }
2191 }
2192 
2236 {
2237  Q_D(QObject);
2238  if (!obj)
2239  return;
2240  if (d->threadData.loadRelaxed() != obj->d_func()->threadData.loadRelaxed()) {
2241  qWarning("QObject::installEventFilter(): Cannot filter events for objects in a different thread.");
2242  return;
2243  }
2244 
2245  if (!d->extraData)
2246  d->extraData = new QObjectPrivate::ExtraData(d);
2247 
2248  // clean up unused items in the list
2249  d->extraData->eventFilters.removeAll((QObject *)nullptr);
2250  d->extraData->eventFilters.removeAll(obj);
2251  d->extraData->eventFilters.prepend(obj);
2252 }
2253 
2268 {
2269  Q_D(QObject);
2270  if (d->extraData) {
2271  for (int i = 0; i < d->extraData->eventFilters.count(); ++i) {
2272  if (d->extraData->eventFilters.at(i) == obj)
2273  d->extraData->eventFilters[i] = nullptr;
2274  }
2275  }
2276 }
2277 
2320 {
2321 #ifdef QT_DEBUG
2322  if (qApp == this)
2323  qWarning("You are deferring the delete of QCoreApplication, this may not work as expected.");
2324 #endif
2326 }
2327 
2364 /*****************************************************************************
2365  Signals and slots
2366  *****************************************************************************/
2367 
2368 const char *qFlagLocation(const char *method)
2369 {
2370  QThreadData *currentThreadData = QThreadData::current(false);
2371  if (currentThreadData != nullptr)
2372  currentThreadData->flaggedSignatures.store(method);
2373  return method;
2374 }
2375 
2376 static int extract_code(const char *member)
2377 {
2378  // extract code, ensure QMETHOD_CODE <= code <= QSIGNAL_CODE
2379  return (((int)(*member) - '0') & 0x3);
2380 }
2381 
2382 static const char *extract_location(const char *member)
2383 {
2384  if (QThreadData::current()->flaggedSignatures.contains(member)) {
2385  // signature includes location information after the first null-terminator
2386  const char *location = member + qstrlen(member) + 1;
2387  if (*location != '\0')
2388  return location;
2389  }
2390  return nullptr;
2391 }
2392 
2393 static bool check_signal_macro(const QObject *sender, const char *signal,
2394  const char *func, const char *op)
2395 {
2396  int sigcode = extract_code(signal);
2397  if (sigcode != QSIGNAL_CODE) {
2398  if (sigcode == QSLOT_CODE)
2399  qCWarning(lcConnect, "QObject::%s: Attempt to %s non-signal %s::%s", func, op,
2400  sender->metaObject()->className(), signal + 1);
2401  else
2402  qCWarning(lcConnect, "QObject::%s: Use the SIGNAL macro to %s %s::%s", func, op,
2403  sender->metaObject()->className(), signal);
2404  return false;
2405  }
2406  return true;
2407 }
2408 
2409 static bool check_method_code(int code, const QObject *object, const char *method, const char *func)
2410 {
2411  if (code != QSLOT_CODE && code != QSIGNAL_CODE) {
2412  qCWarning(lcConnect,
2413  "QObject::%s: Use the SLOT or SIGNAL macro to "
2414  "%s %s::%s",
2415  func, func, object->metaObject()->className(), method);
2416  return false;
2417  }
2418  return true;
2419 }
2420 
2422 static void err_method_notfound(const QObject *object,
2423  const char *method, const char *func)
2424 {
2425  const char *type = "method";
2426  switch (extract_code(method)) {
2427  case QSLOT_CODE: type = "slot"; break;
2428  case QSIGNAL_CODE: type = "signal"; break;
2429  }
2430  const char *loc = extract_location(method);
2431  if (strchr(method, ')') == nullptr) // common typing mistake
2432  qCWarning(lcConnect, "QObject::%s: Parentheses expected, %s %s::%s%s%s", func, type,
2433  object->metaObject()->className(), method + 1, loc ? " in " : "", loc ? loc : "");
2434  else
2435  qCWarning(lcConnect, "QObject::%s: No such %s %s::%s%s%s", func, type,
2436  object->metaObject()->className(), method + 1, loc ? " in " : "", loc ? loc : "");
2437 }
2438 
2440 static void err_info_about_objects(const char *func, const QObject *sender, const QObject *receiver)
2441 {
2442  QString a = sender ? sender->objectName() : QString();
2443  QString b = receiver ? receiver->objectName() : QString();
2444  if (!a.isEmpty())
2445  qCWarning(lcConnect, "QObject::%s: (sender name: '%s')", func, a.toLocal8Bit().data());
2446  if (!b.isEmpty())
2447  qCWarning(lcConnect, "QObject::%s: (receiver name: '%s')", func, b.toLocal8Bit().data());
2448 }
2449 
2473 {
2474  Q_D(const QObject);
2475 
2476  QBasicMutexLocker locker(signalSlotLock(this));
2477  QObjectPrivate::ConnectionData *cd = d->connections.loadRelaxed();
2478  if (!cd || !cd->currentSender)
2479  return nullptr;
2480 
2481  for (QObjectPrivate::Connection *c = cd->senders; c; c = c->next) {
2482  if (c->sender == cd->currentSender->sender)
2483  return cd->currentSender->sender;
2484  }
2485 
2486  return nullptr;
2487 }
2488 
2515 {
2516  Q_D(const QObject);
2517 
2518  QBasicMutexLocker locker(signalSlotLock(this));
2519  QObjectPrivate::ConnectionData *cd = d->connections.loadRelaxed();
2520  if (!cd || !cd->currentSender)
2521  return -1;
2522 
2523  for (QObjectPrivate::Connection *c = cd->senders; c; c = c->next) {
2524  if (c->sender == cd->currentSender->sender) {
2525  // Convert from signal range to method range
2526  return QMetaObjectPrivate::signal(c->sender->metaObject(), cd->currentSender->signal).methodIndex();
2527  }
2528  }
2529 
2530  return -1;
2531 }
2532 
2554 int QObject::receivers(const char *signal) const
2555 {
2556  Q_D(const QObject);
2557  int receivers = 0;
2558  if (signal) {
2560  signal = signal_name;
2561 #ifndef QT_NO_DEBUG
2562  if (!check_signal_macro(this, signal, "receivers", "bind"))
2563  return 0;
2564 #endif
2565  signal++; // skip code
2566  int signal_index = d->signalIndex(signal);
2567  if (signal_index < 0) {
2568 #ifndef QT_NO_DEBUG
2569  err_method_notfound(this, signal - 1, "receivers");
2570 #endif
2571  return 0;
2572  }
2573 
2574  if (!d->isSignalConnected(signal_index))
2575  return receivers;
2576 
2577  if (d->declarativeData && QAbstractDeclarativeData::receivers) {
2578  receivers += QAbstractDeclarativeData::receivers(d->declarativeData, this,
2579  signal_index);
2580  }
2581 
2582  QObjectPrivate::ConnectionData *cd = d->connections.loadRelaxed();
2583  QBasicMutexLocker locker(signalSlotLock(this));
2584  if (cd && signal_index < cd->signalVectorCount()) {
2585  const QObjectPrivate::Connection *c = cd->signalVector.loadRelaxed()->at(signal_index).first.loadRelaxed();
2586  while (c) {
2587  receivers += c->receiver.loadRelaxed() ? 1 : 0;
2588  c = c->nextConnectionList.loadRelaxed();
2589  }
2590  }
2591  }
2592  return receivers;
2593 }
2594 
2614 {
2615  Q_D(const QObject);
2616  if (!signal.mobj)
2617  return false;
2618 
2619  Q_ASSERT_X(signal.mobj->cast(this) && signal.methodType() == QMetaMethod::Signal,
2620  "QObject::isSignalConnected" , "the parameter must be a signal member of the object");
2621  uint signalIndex = signal.relativeMethodIndex();
2622 
2623  if (signal.data.flags() & MethodCloned)
2625 
2627 
2628  QBasicMutexLocker locker(signalSlotLock(this));
2629  return d->isSignalConnected(signalIndex, true);
2630 }
2631 
2656  const QMetaMethod &member,
2657  int *signalIndex, int *methodIndex)
2658 {
2659  *signalIndex = -1;
2660  *methodIndex = -1;
2661  if (!obj || !member.mobj)
2662  return;
2663  const QMetaObject *m = obj->metaObject();
2664  // Check that member is member of obj class
2665  while (m != nullptr && m != member.mobj)
2666  m = m->d.superdata;
2667  if (!m)
2668  return;
2669  *signalIndex = *methodIndex = member.relativeMethodIndex();
2670 
2671  int signalOffset;
2672  int methodOffset;
2673  computeOffsets(m, &signalOffset, &methodOffset);
2674 
2675  *methodIndex += methodOffset;
2676  if (member.methodType() == QMetaMethod::Signal) {
2677  *signalIndex = originalClone(m, *signalIndex);
2678  *signalIndex += signalOffset;
2679  } else {
2680  *signalIndex = -1;
2681  }
2682 }
2683 
2684 #ifndef QT_NO_DEBUG
2685 static inline void check_and_warn_compat(const QMetaObject *sender, const QMetaMethod &signal,
2686  const QMetaObject *receiver, const QMetaMethod &method)
2687 {
2688  if (signal.attributes() & QMetaMethod::Compatibility) {
2689  if (!(method.attributes() & QMetaMethod::Compatibility))
2690  qCWarning(lcConnect, "QObject::connect: Connecting from COMPAT signal (%s::%s)",
2691  sender->className(), signal.methodSignature().constData());
2692  } else if ((method.attributes() & QMetaMethod::Compatibility)
2693  && method.methodType() == QMetaMethod::Signal) {
2694  qCWarning(lcConnect, "QObject::connect: Connecting from %s::%s to COMPAT slot (%s::%s)",
2695  sender->className(), signal.methodSignature().constData(), receiver->className(),
2696  method.methodSignature().constData());
2697  }
2698 }
2699 #endif
2700 
2773  const QObject *receiver, const char *method,
2775 {
2776  if (sender == nullptr || receiver == nullptr || signal == nullptr || method == nullptr) {
2777  qCWarning(lcConnect, "QObject::connect: Cannot connect %s::%s to %s::%s",
2778  sender ? sender->metaObject()->className() : "(nullptr)",
2779  (signal && *signal) ? signal + 1 : "(nullptr)",
2780  receiver ? receiver->metaObject()->className() : "(nullptr)",
2781  (method && *method) ? method + 1 : "(nullptr)");
2782  return QMetaObject::Connection(nullptr);
2783  }
2784  QByteArray tmp_signal_name;
2785 
2786  if (!check_signal_macro(sender, signal, "connect", "bind"))
2787  return QMetaObject::Connection(nullptr);
2788  const QMetaObject *smeta = sender->metaObject();
2789  const char *signal_arg = signal;
2790  ++signal; // skip code
2791  QArgumentTypeArray signalTypes;
2792  Q_ASSERT(QMetaObjectPrivate::get(smeta)->revision >= 7);
2793  QByteArray signalName = QMetaObjectPrivate::decodeMethodSignature(signal, signalTypes);
2794  int signal_index = QMetaObjectPrivate::indexOfSignalRelative(
2795  &smeta, signalName, signalTypes.size(), signalTypes.constData());
2796  if (signal_index < 0) {
2797  // check for normalized signatures
2798  tmp_signal_name = QMetaObject::normalizedSignature(signal - 1);
2799  signal = tmp_signal_name.constData() + 1;
2800 
2801  signalTypes.clear();
2802  signalName = QMetaObjectPrivate::decodeMethodSignature(signal, signalTypes);
2803  smeta = sender->metaObject();
2805  &smeta, signalName, signalTypes.size(), signalTypes.constData());
2806  }
2807  if (signal_index < 0) {
2808  err_method_notfound(sender, signal_arg, "connect");
2809  err_info_about_objects("connect", sender, receiver);
2810  return QMetaObject::Connection(nullptr);
2811  }
2812  signal_index = QMetaObjectPrivate::originalClone(smeta, signal_index);
2813  signal_index += QMetaObjectPrivate::signalOffset(smeta);
2814 
2815  QByteArray tmp_method_name;
2816  int membcode = extract_code(method);
2817 
2818  if (!check_method_code(membcode, receiver, method, "connect"))
2819  return QMetaObject::Connection(nullptr);
2820  const char *method_arg = method;
2821  ++method; // skip code
2822 
2823  QArgumentTypeArray methodTypes;
2824  QByteArray methodName = QMetaObjectPrivate::decodeMethodSignature(method, methodTypes);
2825  const QMetaObject *rmeta = receiver->metaObject();
2826  int method_index_relative = -1;
2827  Q_ASSERT(QMetaObjectPrivate::get(rmeta)->revision >= 7);
2828  switch (membcode) {
2829  case QSLOT_CODE:
2830  method_index_relative = QMetaObjectPrivate::indexOfSlotRelative(
2831  &rmeta, methodName, methodTypes.size(), methodTypes.constData());
2832  break;
2833  case QSIGNAL_CODE:
2834  method_index_relative = QMetaObjectPrivate::indexOfSignalRelative(
2835  &rmeta, methodName, methodTypes.size(), methodTypes.constData());
2836  break;
2837  }
2838  if (method_index_relative < 0) {
2839  // check for normalized methods
2840  tmp_method_name = QMetaObject::normalizedSignature(method);
2841  method = tmp_method_name.constData();
2842 
2843  methodTypes.clear();
2844  methodName = QMetaObjectPrivate::decodeMethodSignature(method, methodTypes);
2845  // rmeta may have been modified above
2846  rmeta = receiver->metaObject();
2847  switch (membcode) {
2848  case QSLOT_CODE:
2849  method_index_relative = QMetaObjectPrivate::indexOfSlotRelative(
2850  &rmeta, methodName, methodTypes.size(), methodTypes.constData());
2851  break;
2852  case QSIGNAL_CODE:
2853  method_index_relative = QMetaObjectPrivate::indexOfSignalRelative(
2854  &rmeta, methodName, methodTypes.size(), methodTypes.constData());
2855  break;
2856  }
2857  }
2858 
2859  if (method_index_relative < 0) {
2860  err_method_notfound(receiver, method_arg, "connect");
2861  err_info_about_objects("connect", sender, receiver);
2862  return QMetaObject::Connection(nullptr);
2863  }
2864 
2865  if (!QMetaObjectPrivate::checkConnectArgs(signalTypes.size(), signalTypes.constData(),
2866  methodTypes.size(), methodTypes.constData())) {
2867  qCWarning(lcConnect,
2868  "QObject::connect: Incompatible sender/receiver arguments"
2869  "\n %s::%s --> %s::%s",
2870  sender->metaObject()->className(), signal, receiver->metaObject()->className(),
2871  method);
2872  return QMetaObject::Connection(nullptr);
2873  }
2874 
2875  int *types = nullptr;
2876  if ((type == Qt::QueuedConnection)
2877  && !(types = queuedConnectionTypes(signalTypes.constData(), signalTypes.size()))) {
2878  return QMetaObject::Connection(nullptr);
2879  }
2880 
2881 #ifndef QT_NO_DEBUG
2882  QMetaMethod smethod = QMetaObjectPrivate::signal(smeta, signal_index);
2883  QMetaMethod rmethod = rmeta->method(method_index_relative + rmeta->methodOffset());
2884  check_and_warn_compat(smeta, smethod, rmeta, rmethod);
2885 #endif
2887  sender, signal_index, smeta, receiver, method_index_relative, rmeta ,type, types));
2888  return handle;
2889 }
2890 
2912  const QObject *receiver, const QMetaMethod &method,
2914 {
2915  if (sender == nullptr
2916  || receiver == nullptr
2917  || signal.methodType() != QMetaMethod::Signal
2918  || method.methodType() == QMetaMethod::Constructor) {
2919  qCWarning(lcConnect, "QObject::connect: Cannot connect %s::%s to %s::%s",
2920  sender ? sender->metaObject()->className() : "(nullptr)",
2921  signal.methodSignature().constData(),
2922  receiver ? receiver->metaObject()->className() : "(nullptr)",
2923  method.methodSignature().constData());
2924  return QMetaObject::Connection(nullptr);
2925  }
2926 
2927  int signal_index;
2928  int method_index;
2929  {
2930  int dummy;
2931  QMetaObjectPrivate::memberIndexes(sender, signal, &signal_index, &dummy);
2932  QMetaObjectPrivate::memberIndexes(receiver, method, &dummy, &method_index);
2933  }
2934 
2935  const QMetaObject *smeta = sender->metaObject();
2936  const QMetaObject *rmeta = receiver->metaObject();
2937  if (signal_index == -1) {
2938  qCWarning(lcConnect, "QObject::connect: Can't find signal %s on instance of class %s",
2939  signal.methodSignature().constData(), smeta->className());
2940  return QMetaObject::Connection(nullptr);
2941  }
2942  if (method_index == -1) {
2943  qCWarning(lcConnect, "QObject::connect: Can't find method %s on instance of class %s",
2944  method.methodSignature().constData(), rmeta->className());
2945  return QMetaObject::Connection(nullptr);
2946  }
2947 
2948  if (!QMetaObject::checkConnectArgs(signal.methodSignature().constData(),
2949  method.methodSignature().constData())) {
2950  qCWarning(lcConnect,
2951  "QObject::connect: Incompatible sender/receiver arguments"
2952  "\n %s::%s --> %s::%s",
2953  smeta->className(), signal.methodSignature().constData(), rmeta->className(),
2954  method.methodSignature().constData());
2955  return QMetaObject::Connection(nullptr);
2956  }
2957 
2958  int *types = nullptr;
2959  if ((type == Qt::QueuedConnection) && !(types = queuedConnectionTypes(signal)))
2960  return QMetaObject::Connection(nullptr);
2961 
2962 #ifndef QT_NO_DEBUG
2963  check_and_warn_compat(smeta, signal, rmeta, method);
2964 #endif
2966  sender, signal_index, signal.enclosingMetaObject(), receiver, method_index, nullptr, type, types));
2967  return handle;
2968 }
2969 
3048 bool QObject::disconnect(const QObject *sender, const char *signal,
3049  const QObject *receiver, const char *method)
3050 {
3051  if (sender == nullptr || (receiver == nullptr && method != nullptr)) {
3052  qCWarning(lcConnect, "QObject::disconnect: Unexpected nullptr parameter");
3053  return false;
3054  }
3055 
3056  const char *signal_arg = signal;
3057  QByteArray signal_name;
3058  bool signal_found = false;
3059  if (signal) {
3060  QT_TRY {
3062  signal = signal_name.constData();
3063  } QT_CATCH (const std::bad_alloc &) {
3064  // if the signal is already normalized, we can continue.
3065  if (sender->metaObject()->indexOfSignal(signal + 1) == -1)
3066  QT_RETHROW;
3067  }
3068 
3069  if (!check_signal_macro(sender, signal, "disconnect", "unbind"))
3070  return false;
3071  signal++; // skip code
3072  }
3073 
3074  QByteArray method_name;
3075  const char *method_arg = method;
3076  int membcode = -1;
3077  bool method_found = false;
3078  if (method) {
3079  QT_TRY {
3081  method = method_name.constData();
3082  } QT_CATCH(const std::bad_alloc &) {
3083  // if the method is already normalized, we can continue.
3084  if (receiver->metaObject()->indexOfMethod(method + 1) == -1)
3085  QT_RETHROW;
3086  }
3087 
3088  membcode = extract_code(method);
3089  if (!check_method_code(membcode, receiver, method, "disconnect"))
3090  return false;
3091  method++; // skip code
3092  }
3093 
3094  /* We now iterate through all the sender's and receiver's meta
3095  * objects in order to also disconnect possibly shadowed signals
3096  * and slots with the same signature.
3097  */
3098  bool res = false;
3099  const QMetaObject *smeta = sender->metaObject();
3100  QByteArray signalName;
3101  QArgumentTypeArray signalTypes;
3102  Q_ASSERT(QMetaObjectPrivate::get(smeta)->revision >= 7);
3103  if (signal)
3104  signalName = QMetaObjectPrivate::decodeMethodSignature(signal, signalTypes);
3105  QByteArray methodName;
3106  QArgumentTypeArray methodTypes;
3107  Q_ASSERT(!receiver || QMetaObjectPrivate::get(receiver->metaObject())->revision >= 7);
3108  if (method)
3109  methodName = QMetaObjectPrivate::decodeMethodSignature(method, methodTypes);
3110  do {
3111  int signal_index = -1;
3112  if (signal) {
3114  &smeta, signalName, signalTypes.size(), signalTypes.constData());
3115  if (signal_index < 0)
3116  break;
3117  signal_index = QMetaObjectPrivate::originalClone(smeta, signal_index);
3118  signal_index += QMetaObjectPrivate::signalOffset(smeta);
3119  signal_found = true;
3120  }
3121 
3122  if (!method) {
3123  res |= QMetaObjectPrivate::disconnect(sender, signal_index, smeta, receiver, -1, nullptr);
3124  } else {
3125  const QMetaObject *rmeta = receiver->metaObject();
3126  do {
3127  int method_index = QMetaObjectPrivate::indexOfMethod(
3128  rmeta, methodName, methodTypes.size(), methodTypes.constData());
3129  if (method_index >= 0)
3130  while (method_index < rmeta->methodOffset())
3131  rmeta = rmeta->superClass();
3132  if (method_index < 0)
3133  break;
3134  res |= QMetaObjectPrivate::disconnect(sender, signal_index, smeta, receiver, method_index, nullptr);
3135  method_found = true;
3136  } while ((rmeta = rmeta->superClass()));
3137  }
3138  } while (signal && (smeta = smeta->superClass()));
3139 
3140  if (signal && !signal_found) {
3141  err_method_notfound(sender, signal_arg, "disconnect");
3142  err_info_about_objects("disconnect", sender, receiver);
3143  } else if (method && !method_found) {
3144  err_method_notfound(receiver, method_arg, "disconnect");
3145  err_info_about_objects("disconnect", sender, receiver);
3146  }
3147  if (res) {
3148  if (!signal)
3149  const_cast<QObject *>(sender)->disconnectNotify(QMetaMethod());
3150  }
3151  return res;
3152 }
3153 
3185 bool QObject::disconnect(const QObject *sender, const QMetaMethod &signal,
3186  const QObject *receiver, const QMetaMethod &method)
3187 {
3188  if (sender == nullptr || (receiver == nullptr && method.mobj != nullptr)) {
3189  qCWarning(lcConnect, "QObject::disconnect: Unexpected nullptr parameter");
3190  return false;
3191  }
3192  if (signal.mobj) {
3193  if (signal.methodType() != QMetaMethod::Signal) {
3194  qCWarning(lcConnect, "QObject::%s: Attempt to %s non-signal %s::%s",
3195  "disconnect","unbind",
3196  sender->metaObject()->className(), signal.methodSignature().constData());
3197  return false;
3198  }
3199  }
3200  if (method.mobj) {
3201  if (method.methodType() == QMetaMethod::Constructor) {
3202  qCWarning(lcConnect, "QObject::disconnect: cannot use constructor as argument %s::%s",
3203  receiver->metaObject()->className(), method.methodSignature().constData());
3204  return false;
3205  }
3206  }
3207 
3208  int signal_index;
3209  int method_index;
3210  {
3211  int dummy;
3212  QMetaObjectPrivate::memberIndexes(sender, signal, &signal_index, &dummy);
3213  QMetaObjectPrivate::memberIndexes(receiver, method, &dummy, &method_index);
3214  }
3215  // If we are here sender is not nullptr. If signal is not nullptr while signal_index
3216  // is -1 then this signal is not a member of sender.
3217  if (signal.mobj && signal_index == -1) {
3218  qCWarning(lcConnect, "QObject::disconnect: signal %s not found on class %s",
3219  signal.methodSignature().constData(), sender->metaObject()->className());
3220  return false;
3221  }
3222  // If this condition is true then method is not a member of receiver.
3223  if (receiver && method.mobj && method_index == -1) {
3224  qCWarning(lcConnect, "QObject::disconnect: method %s not found on class %s",
3225  method.methodSignature().constData(), receiver->metaObject()->className());
3226  return false;
3227  }
3228 
3229  if (!QMetaObjectPrivate::disconnect(sender, signal_index, signal.mobj, receiver, method_index, nullptr))
3230  return false;
3231 
3232  if (!signal.isValid()) {
3233  // The signal is a wildcard, meaning all signals were disconnected.
3234  // QMetaObjectPrivate::disconnect() doesn't call disconnectNotify()
3235  // per connection in this case. Call it once now, with an invalid
3236  // QMetaMethod as argument, as documented.
3237  const_cast<QObject *>(sender)->disconnectNotify(signal);
3238  }
3239  return true;
3240 }
3241 
3292 {
3293  Q_UNUSED(signal);
3294 }
3295 
3327 {
3328  Q_UNUSED(signal);
3329 }
3330 
3331 /*
3332  \internal
3333  convert a signal index from the method range to the signal range
3334  */
3335 static int methodIndexToSignalIndex(const QMetaObject **base, int signal_index)
3336 {
3337  if (signal_index < 0)
3338  return signal_index;
3339  const QMetaObject *metaObject = *base;
3340  while (metaObject && metaObject->methodOffset() > signal_index)
3341  metaObject = metaObject->superClass();
3342 
3343  if (metaObject) {
3344  int signalOffset, methodOffset;
3345  computeOffsets(metaObject, &signalOffset, &methodOffset);
3346  if (signal_index < metaObject->methodCount())
3347  signal_index = QMetaObjectPrivate::originalClone(metaObject, signal_index - methodOffset) + signalOffset;
3348  else
3349  signal_index = signal_index - methodOffset + signalOffset;
3350  *base = metaObject;
3351  }
3352  return signal_index;
3353 }
3354 
3363 QMetaObject::Connection QMetaObject::connect(const QObject *sender, int signal_index,
3364  const QObject *receiver, int method_index, int type,
3365  int *types)
3366 {
3367  const QMetaObject *smeta = sender->metaObject();
3368  signal_index = methodIndexToSignalIndex(&smeta, signal_index);
3369  return Connection(QMetaObjectPrivate::connect(sender, signal_index, smeta,
3370  receiver, method_index,
3371  nullptr, //FIXME, we could speed this connection up by computing the relative index
3372  type, types));
3373 }
3374 
3384  int signal_index, const QMetaObject *smeta,
3385  const QObject *receiver, int method_index,
3386  const QMetaObject *rmeta, int type, int *types)
3387 {
3388  QObject *s = const_cast<QObject *>(sender);
3389  QObject *r = const_cast<QObject *>(receiver);
3390 
3391  int method_offset = rmeta ? rmeta->methodOffset() : 0;
3392  Q_ASSERT(!rmeta || QMetaObjectPrivate::get(rmeta)->revision >= 6);
3393  QObjectPrivate::StaticMetaCallFunction callFunction = rmeta ? rmeta->d.static_metacall : nullptr;
3394 
3395  QOrderedMutexLocker locker(signalSlotLock(sender),
3396  signalSlotLock(receiver));
3397 
3399  if (type & Qt::UniqueConnection && scd) {
3400  if (scd->signalVectorCount() > signal_index) {
3401  const QObjectPrivate::Connection *c2 = scd->signalVector.loadRelaxed()->at(signal_index).first.loadRelaxed();
3402 
3403  int method_index_absolute = method_index + method_offset;
3404 
3405  while (c2) {
3406  if (!c2->isSlotObject && c2->receiver.loadRelaxed() == receiver && c2->method() == method_index_absolute)
3407  return nullptr;
3408  c2 = c2->nextConnectionList.loadRelaxed();
3409  }
3410  }
3411  }
3413 
3414  const bool isSingleShot = type & Qt::SingleShotConnection;
3416 
3417  Q_ASSERT(type >= 0);
3418  Q_ASSERT(type <= 3);
3419 
3420  std::unique_ptr<QObjectPrivate::Connection> c{new QObjectPrivate::Connection};
3421  c->sender = s;
3422  c->signal_index = signal_index;
3423  c->receiver.storeRelaxed(r);
3424  QThreadData *td = r->d_func()->threadData;
3425  td->ref();
3426  c->receiverThreadData.storeRelaxed(td);
3427  c->method_relative = method_index;
3428  c->method_offset = method_offset;
3429  c->connectionType = type;
3430  c->isSlotObject = false;
3431  c->argumentTypes.storeRelaxed(types);
3432  c->callFunction = callFunction;
3433  c->isSingleShot = isSingleShot;
3434 
3435  QObjectPrivate::get(s)->addConnection(signal_index, c.get());
3436 
3437  locker.unlock();
3438  QMetaMethod smethod = QMetaObjectPrivate::signal(smeta, signal_index);
3439  if (smethod.isValid())
3440  s->connectNotify(smethod);
3441 
3442  return c.release();
3443 }
3444 
3448 bool QMetaObject::disconnect(const QObject *sender, int signal_index,
3449  const QObject *receiver, int method_index)
3450 {
3451  const QMetaObject *smeta = sender->metaObject();
3452  signal_index = methodIndexToSignalIndex(&smeta, signal_index);
3453  return QMetaObjectPrivate::disconnect(sender, signal_index, smeta,
3454  receiver, method_index, nullptr);
3455 }
3456 
3464 bool QMetaObject::disconnectOne(const QObject *sender, int signal_index,
3465  const QObject *receiver, int method_index)
3466 {
3467  const QMetaObject *smeta = sender->metaObject();
3468  signal_index = methodIndexToSignalIndex(&smeta, signal_index);
3469  return QMetaObjectPrivate::disconnect(sender, signal_index, smeta,
3470  receiver, method_index, nullptr,
3472 }
3473 
3479  const QObject *receiver, int method_index, void **slot,
3480  QBasicMutex *senderMutex, DisconnectType disconnectType)
3481 {
3482  bool success = false;
3483 
3484  auto &connectionList = connections->connectionsForSignal(signalIndex);
3485  auto *c = connectionList.first.loadRelaxed();
3486  while (c) {
3487  QObject *r = c->receiver.loadRelaxed();
3488  if (r && (receiver == nullptr || (r == receiver
3489  && (method_index < 0 || (!c->isSlotObject && c->method() == method_index))
3490  && (slot == nullptr || (c->isSlotObject && c->slotObj->compare(slot)))))) {
3491  bool needToUnlock = false;
3492  QBasicMutex *receiverMutex = nullptr;
3493  if (r) {
3494  receiverMutex = signalSlotLock(r);
3495  // need to relock this receiver and sender in the correct order
3496  needToUnlock = QOrderedMutexLocker::relock(senderMutex, receiverMutex);
3497  }
3498  if (c->receiver.loadRelaxed())
3499  connections->removeConnection(c);
3500 
3501  if (needToUnlock)
3502  receiverMutex->unlock();
3503 
3504  success = true;
3505 
3506  if (disconnectType == DisconnectOne)
3507  return success;
3508  }
3509  c = c->nextConnectionList.loadRelaxed();
3510  }
3511  return success;
3512 }
3513 
3519  int signal_index, const QMetaObject *smeta,
3520  const QObject *receiver, int method_index, void **slot,
3521  DisconnectType disconnectType)
3522 {
3523  if (!sender)
3524  return false;
3525 
3526  QObject *s = const_cast<QObject *>(sender);
3527 
3528  QBasicMutex *senderMutex = signalSlotLock(sender);
3529  QBasicMutexLocker locker(senderMutex);
3530 
3532  if (!scd)
3533  return false;
3534 
3535  bool success = false;
3536  {
3537  // prevent incoming connections changing the connections->receivers while unlocked
3539 
3540  if (signal_index < 0) {
3541  // remove from all connection lists
3542  for (int sig_index = -1; sig_index < scd->signalVectorCount(); ++sig_index) {
3543  if (disconnectHelper(connections.data(), sig_index, receiver, method_index, slot, senderMutex, disconnectType))
3544  success = true;
3545  }
3546  } else if (signal_index < scd->signalVectorCount()) {
3547  if (disconnectHelper(connections.data(), signal_index, receiver, method_index, slot, senderMutex, disconnectType))
3548  success = true;
3549  }
3550  }
3551 
3552  locker.unlock();
3553  if (success) {
3555 
3556  QMetaMethod smethod = QMetaObjectPrivate::signal(smeta, signal_index);
3557  if (smethod.isValid())
3558  s->disconnectNotify(smethod);
3559  }
3560 
3561  return success;
3562 }
3563 
3564 // Helpers for formatting the connect statements of connectSlotsByName()'s debug mode
3565 static QByteArray formatConnectionSignature(const char *className, const QMetaMethod &method)
3566 {
3567  const auto signature = method.methodSignature();
3568  Q_ASSERT(signature.endsWith(')'));
3569  const int openParen = signature.indexOf('(');
3570  const bool hasParameters = openParen >= 0 && openParen < signature.size() - 2;
3572  if (hasParameters) {
3573  result += "qOverload<"
3574  + signature.mid(openParen + 1, signature.size() - openParen - 2) + ">(";
3575  }
3576  result += '&';
3577  result += className + QByteArrayLiteral("::") + method.name();
3578  if (hasParameters)
3579  result += ')';
3580  return result;
3581 }
3582 
3583 static QByteArray msgConnect(const QMetaObject *senderMo, const QByteArray &senderName,
3584  const QMetaMethod &signal, const QObject *receiver, int receiverIndex)
3585 {
3586  const auto receiverMo = receiver->metaObject();
3587  const auto slot = receiverMo->method(receiverIndex);
3588  QByteArray message = QByteArrayLiteral("QObject::connect(")
3589  + senderName + ", " + formatConnectionSignature(senderMo->className(), signal)
3590  + ", " + receiver->objectName().toLatin1() + ", "
3591  + formatConnectionSignature(receiverMo->className(), slot) + ");";
3592  return message;
3593 }
3594 
3615 {
3616  if (!o)
3617  return;
3618  const QMetaObject *mo = o->metaObject();
3619  Q_ASSERT(mo);
3620  const QObjectList list = // list of all objects to look for matching signals including...
3621  o->findChildren<QObject *>() // all children of 'o'...
3622  << o; // and the object 'o' itself
3623 
3624  // for each method/slot of o ...
3625  for (int i = 0; i < mo->methodCount(); ++i) {
3626  const QByteArray slotSignature = mo->method(i).methodSignature();
3627  const char *slot = slotSignature.constData();
3628  Q_ASSERT(slot);
3629 
3630  // ...that starts with "on_", ...
3631  if (slot[0] != 'o' || slot[1] != 'n' || slot[2] != '_')
3632  continue;
3633 
3634  // ...we check each object in our list, ...
3635  bool foundIt = false;
3636  for (int j = 0; j < list.count(); ++j) {
3637  const QObject *co = list.at(j);
3638  const QByteArray coName = co->objectName().toLatin1();
3639 
3640  // ...discarding those whose objectName is not fitting the pattern "on_<objectName>_...", ...
3641  if (coName.isEmpty() || qstrncmp(slot + 3, coName.constData(), coName.size()) || slot[coName.size()+3] != '_')
3642  continue;
3643 
3644  const char *signal = slot + coName.size() + 4; // the 'signal' part of the slot name
3645 
3646  // ...for the presence of a matching signal "on_<objectName>_<signal>".
3647  const QMetaObject *smeta;
3648  int sigIndex = co->d_func()->signalIndex(signal, &smeta);
3649  if (sigIndex < 0) {
3650  // if no exactly fitting signal (name + complete parameter type list) could be found
3651  // look for just any signal with the correct name and at least the slot's parameter list.
3652  // Note: if more than one of those signals exist, the one that gets connected is
3653  // chosen 'at random' (order of declaration in source file)
3654  QList<QByteArray> compatibleSignals;
3655  const QMetaObject *smo = co->metaObject();
3656  int sigLen = int(qstrlen(signal)) - 1; // ignore the trailing ')'
3657  for (int k = QMetaObjectPrivate::absoluteSignalCount(smo)-1; k >= 0; --k) {
3659  if (!qstrncmp(method.methodSignature().constData(), signal, sigLen)) {
3660  smeta = method.enclosingMetaObject();
3661  sigIndex = k;
3662  compatibleSignals.prepend(method.methodSignature());
3663  }
3664  }
3665  if (compatibleSignals.size() > 1)
3666  qCWarning(lcConnectSlotsByName) << "QMetaObject::connectSlotsByName: Connecting slot" << slot
3667  << "with the first of the following compatible signals:" << compatibleSignals;
3668  }
3669 
3670  if (sigIndex < 0)
3671  continue;
3672 
3673  // we connect it...
3674  if (Connection(QMetaObjectPrivate::connect(co, sigIndex, smeta, o, i))) {
3675  foundIt = true;
3676  qCDebug(lcConnectSlotsByName, "%s",
3677  msgConnect(smeta, coName, QMetaObjectPrivate::signal(smeta, sigIndex), o, i).constData());
3678  // ...and stop looking for further objects with the same name.
3679  // Note: the Designer will make sure each object name is unique in the above
3680  // 'list' but other code may create two child objects with the same name. In
3681  // this case one is chosen 'at random'.
3682  break;
3683  }
3684  }
3685  if (foundIt) {
3686  // we found our slot, now skip all overloads
3687  while (mo->method(i + 1).attributes() & QMetaMethod::Cloned)
3688  ++i;
3689  } else if (!(mo->method(i).attributes() & QMetaMethod::Cloned)) {
3690  // check if the slot has the following signature: "on_..._...(..."
3691  int iParen = slotSignature.indexOf('(');
3692  int iLastUnderscore = slotSignature.lastIndexOf('_', iParen - 1);
3693  if (iLastUnderscore > 3)
3694  qCWarning(lcConnectSlotsByName,
3695  "QMetaObject::connectSlotsByName: No matching signal for %s", slot);
3696  }
3697  }
3698 }
3699 
3707  SlotObjectGuard() = default;
3708  // move would be fine, but we do not need it currently
3710  explicit SlotObjectGuard(QtPrivate::QSlotObjectBase *slotObject)
3711  : m_slotObject(slotObject)
3712  {
3713  if (m_slotObject)
3714  m_slotObject->ref();
3715  }
3716 
3718  { return m_slotObject; }
3719 
3721  { return m_slotObject; }
3722 
3724  if (m_slotObject)
3725  m_slotObject->destroyIfLastRef();
3726  }
3727 private:
3728  QtPrivate::QSlotObjectBase *m_slotObject = nullptr;
3729 };
3730 
3736 static void queued_activate(QObject *sender, int signal, QObjectPrivate::Connection *c, void **argv)
3737 {
3738  const int *argumentTypes = c->argumentTypes.loadRelaxed();
3739  if (!argumentTypes) {
3740  QMetaMethod m = QMetaObjectPrivate::signal(sender->metaObject(), signal);
3741  argumentTypes = queuedConnectionTypes(m);
3742  if (!argumentTypes) // cannot queue arguments
3743  argumentTypes = &DIRECT_CONNECTION_ONLY;
3744  if (!c->argumentTypes.testAndSetOrdered(nullptr, argumentTypes)) {
3745  if (argumentTypes != &DIRECT_CONNECTION_ONLY)
3746  delete[] argumentTypes;
3747  argumentTypes = c->argumentTypes.loadRelaxed();
3748  }
3749  }
3750  if (argumentTypes == &DIRECT_CONNECTION_ONLY) // cannot activate
3751  return;
3752  int nargs = 1; // include return type
3753  while (argumentTypes[nargs - 1])
3754  ++nargs;
3755 
3756  QBasicMutexLocker locker(signalSlotLock(c->receiver.loadRelaxed()));
3757  QObject *receiver = c->receiver.loadRelaxed();
3758  if (!receiver) {
3759  // the connection has been disconnected before we got the lock
3760  return;
3761  }
3762 
3763  SlotObjectGuard slotObjectGuard { c->isSlotObject ? c->slotObj : nullptr };
3764  locker.unlock();
3765 
3766  QMetaCallEvent *ev = c->isSlotObject ?
3767  new QMetaCallEvent(c->slotObj, sender, signal, nargs) :
3768  new QMetaCallEvent(c->method_offset, c->method_relative, c->callFunction, sender, signal, nargs);
3769 
3770  void **args = ev->args();
3771  QMetaType *types = ev->types();
3772 
3773  types[0] = QMetaType(); // return type
3774  args[0] = nullptr; // return value
3775 
3776  if (nargs > 1) {
3777  for (int n = 1; n < nargs; ++n)
3778  types[n] = QMetaType(argumentTypes[n - 1]);
3779 
3780  for (int n = 1; n < nargs; ++n)
3781  args[n] = types[n].create(argv[n]);
3782  }
3783 
3784  if (c->isSingleShot && !QObjectPrivate::disconnect(c)) {
3785  delete ev;
3786  return;
3787  }
3788 
3789  locker.relock();
3790  if (!c->isSingleShot && !c->receiver.loadRelaxed()) {
3791  // the connection has been disconnected while we were unlocked
3792  locker.unlock();
3793  delete ev;
3794  return;
3795  }
3796 
3797  QCoreApplication::postEvent(receiver, ev);
3798 }
3799 
3800 template <bool callbacks_enabled>
3801 void doActivate(QObject *sender, int signal_index, void **argv)
3802 {
3804 
3805  if (sp->blockSig)
3806  return;
3807 
3808  Q_TRACE_SCOPE(QMetaObject_activate, sender, signal_index);
3809 
3810  if (sp->isDeclarativeSignalConnected(signal_index)
3812  Q_TRACE_SCOPE(QMetaObject_activate_declarative_signal, sender, signal_index);
3813  QAbstractDeclarativeData::signalEmitted(sp->declarativeData, sender,
3814  signal_index, argv);
3815  }
3816 
3817  const QSignalSpyCallbackSet *signal_spy_set = callbacks_enabled ? qt_signal_spy_callback_set.loadAcquire() : nullptr;
3818 
3819  void *empty_argv[] = { nullptr };
3820  if (!argv)
3821  argv = empty_argv;
3822 
3823  if (!sp->maybeSignalConnected(signal_index)) {
3824  // The possible declarative connection is done, and nothing else is connected
3825  if (callbacks_enabled && signal_spy_set->signal_begin_callback != nullptr)
3826  signal_spy_set->signal_begin_callback(sender, signal_index, argv);
3827  if (callbacks_enabled && signal_spy_set->signal_end_callback != nullptr)
3828  signal_spy_set->signal_end_callback(sender, signal_index);
3829  return;
3830  }
3831 
3832  if (callbacks_enabled && signal_spy_set->signal_begin_callback != nullptr)
3833  signal_spy_set->signal_begin_callback(sender, signal_index, argv);
3834 
3835  bool senderDeleted = false;
3836  {
3837  Q_ASSERT(sp->connections.loadAcquire());
3838  QObjectPrivate::ConnectionDataPointer connections(sp->connections.loadRelaxed());
3839  QObjectPrivate::SignalVector *signalVector = connections->signalVector.loadRelaxed();
3840 
3842  if (signal_index < signalVector->count())
3843  list = &signalVector->at(signal_index);
3844  else
3845  list = &signalVector->at(-1);
3846 
3847  Qt::HANDLE currentThreadId = QThread::currentThreadId();
3848  bool inSenderThread = currentThreadId == QObjectPrivate::get(sender)->threadData.loadRelaxed()->threadId.loadRelaxed();
3849 
3850  // We need to check against the highest connection id to ensure that signals added
3851  // during the signal emission are not emitted in this emission.
3852  uint highestConnectionId = connections->currentConnectionId.loadRelaxed();
3853  do {
3854  QObjectPrivate::Connection *c = list->first.loadRelaxed();
3855  if (!c)
3856  continue;
3857 
3858  do {
3859  QObject * const receiver = c->receiver.loadRelaxed();
3860  if (!receiver)
3861  continue;
3862 
3863  QThreadData *td = c->receiverThreadData.loadRelaxed();
3864  if (!td)
3865  continue;
3866 
3867  bool receiverInSameThread;
3868  if (inSenderThread) {
3869  receiverInSameThread = currentThreadId == td->threadId.loadRelaxed();
3870  } else {
3871  // need to lock before reading the threadId, because moveToThread() could interfere
3872  QMutexLocker lock(signalSlotLock(receiver));
3873  receiverInSameThread = currentThreadId == td->threadId.loadRelaxed();
3874  }
3875 
3876 
3877  // determine if this connection should be sent immediately or
3878  // put into the event queue
3879  if ((c->connectionType == Qt::AutoConnection && !receiverInSameThread)
3880  || (c->connectionType == Qt::QueuedConnection)) {
3881  queued_activate(sender, signal_index, c, argv);
3882  continue;
3883 #if QT_CONFIG(thread)
3884  } else if (c->connectionType == Qt::BlockingQueuedConnection) {
3885  if (receiverInSameThread) {
3886  qWarning("Qt: Dead lock detected while activating a BlockingQueuedConnection: "
3887  "Sender is %s(%p), receiver is %s(%p)",
3888  sender->metaObject()->className(), sender,
3889  receiver->metaObject()->className(), receiver);
3890  }
3891 
3892  if (c->isSingleShot && !QObjectPrivate::disconnect(c))
3893  continue;
3894 
3895  QSemaphore semaphore;
3896  {
3897  QBasicMutexLocker locker(signalSlotLock(receiver));
3898  if (!c->isSingleShot && !c->receiver.loadAcquire())
3899  continue;
3900  QMetaCallEvent *ev = c->isSlotObject ?
3901  new QMetaCallEvent(c->slotObj, sender, signal_index, argv, &semaphore) :
3902  new QMetaCallEvent(c->method_offset, c->method_relative, c->callFunction,
3903  sender, signal_index, argv, &semaphore);
3904  QCoreApplication::postEvent(receiver, ev);
3905  }
3906  semaphore.acquire();
3907  continue;
3908 #endif
3909  }
3910 
3911  if (c->isSingleShot && !QObjectPrivate::disconnect(c))
3912  continue;
3913 
3914  QObjectPrivate::Sender senderData(receiverInSameThread ? receiver : nullptr, sender, signal_index);
3915 
3916  if (c->isSlotObject) {
3917  SlotObjectGuard obj{c->slotObj};
3918 
3919  {
3920  Q_TRACE_SCOPE(QMetaObject_activate_slot_functor, c->slotObj);
3921  obj->call(receiver, argv);
3922  }
3923  } else if (c->callFunction && c->method_offset <= receiver->metaObject()->methodOffset()) {
3924  //we compare the vtable to make sure we are not in the destructor of the object.
3925  const int method_relative = c->method_relative;
3926  const auto callFunction = c->callFunction;
3927  const int methodIndex = (Q_HAS_TRACEPOINTS || callbacks_enabled) ? c->method() : 0;
3928  if (callbacks_enabled && signal_spy_set->slot_begin_callback != nullptr)
3929  signal_spy_set->slot_begin_callback(receiver, methodIndex, argv);
3930 
3931  {
3932  Q_TRACE_SCOPE(QMetaObject_activate_slot, receiver, methodIndex);
3933  callFunction(receiver, QMetaObject::InvokeMetaMethod, method_relative, argv);
3934  }
3935 
3936  if (callbacks_enabled && signal_spy_set->slot_end_callback != nullptr)
3937  signal_spy_set->slot_end_callback(receiver, methodIndex);
3938  } else {
3939  const int method = c->method_relative + c->method_offset;
3940 
3941  if (callbacks_enabled && signal_spy_set->slot_begin_callback != nullptr) {
3942  signal_spy_set->slot_begin_callback(receiver, method, argv);
3943  }
3944 
3945  {
3946  Q_TRACE_SCOPE(QMetaObject_activate_slot, receiver, method);
3948  }
3949 
3950  if (callbacks_enabled && signal_spy_set->slot_end_callback != nullptr)
3951  signal_spy_set->slot_end_callback(receiver, method);
3952  }
3953  } while ((c = c->nextConnectionList.loadRelaxed()) != nullptr && c->id <= highestConnectionId);
3954 
3955  } while (list != &signalVector->at(-1) &&
3956  //start over for all signals;
3957  ((list = &signalVector->at(-1)), true));
3958 
3959  if (connections->currentConnectionId.loadRelaxed() == 0)
3960  senderDeleted = true;
3961  }
3962  if (!senderDeleted) {
3963  sp->connections.loadRelaxed()->cleanOrphanedConnections(sender);
3964 
3965  if (callbacks_enabled && signal_spy_set->signal_end_callback != nullptr)
3966  signal_spy_set->signal_end_callback(sender, signal_index);
3967  }
3968 }
3969 
3973 void QMetaObject::activate(QObject *sender, const QMetaObject *m, int local_signal_index,
3974  void **argv)
3975 {
3976  int signal_index = local_signal_index + QMetaObjectPrivate::signalOffset(m);
3977 
3978  if (Q_UNLIKELY(qt_signal_spy_callback_set.loadRelaxed()))
3979  doActivate<true>(sender, signal_index, argv);
3980  else
3981  doActivate<false>(sender, signal_index, argv);
3982 }
3983 
3987 void QMetaObject::activate(QObject *sender, int signalOffset, int local_signal_index, void **argv)
3988 {
3989  int signal_index = signalOffset + local_signal_index;
3990 
3991  if (Q_UNLIKELY(qt_signal_spy_callback_set.loadRelaxed()))
3992  doActivate<true>(sender, signal_index, argv);
3993  else
3994  doActivate<false>(sender, signal_index, argv);
3995 }
3996 
4001 void QMetaObject::activate(QObject *sender, int signal_index, void **argv)
4002 {
4003  const QMetaObject *mo = sender->metaObject();
4004  while (mo->methodOffset() > signal_index)
4005  mo = mo->superClass();
4006  activate(sender, mo, signal_index - mo->methodOffset(), argv);
4007 }
4008 
4018 int QObjectPrivate::signalIndex(const char *signalName,
4019  const QMetaObject **meta) const
4020 {
4021  Q_Q(const QObject);
4022  const QMetaObject *base = q->metaObject();
4023  Q_ASSERT(QMetaObjectPrivate::get(base)->revision >= 7);
4026  int relative_index = QMetaObjectPrivate::indexOfSignalRelative(
4027  &base, name, types.size(), types.constData());
4028  if (relative_index < 0)
4029  return relative_index;
4030  relative_index = QMetaObjectPrivate::originalClone(base, relative_index);
4031  if (meta)
4032  *meta = base;
4033  return relative_index + QMetaObjectPrivate::signalOffset(base);
4034 }
4035 
4036 /*****************************************************************************
4037  Properties
4038  *****************************************************************************/
4039 
4040 #ifndef QT_NO_PROPERTIES
4041 
4063 bool QObject::setProperty(const char *name, const QVariant &value)
4064 {
4065  Q_D(QObject);
4066  const QMetaObject *meta = metaObject();
4067  if (!name || !meta)
4068  return false;
4069 
4070  int id = meta->indexOfProperty(name);
4071  if (id < 0) {
4072  if (!d->extraData)
4073  d->extraData = new QObjectPrivate::ExtraData(d);
4074 
4075  const int idx = d->extraData->propertyNames.indexOf(name);
4076 
4077  if (!value.isValid()) {
4078  if (idx == -1)
4079  return false;
4080  d->extraData->propertyNames.removeAt(idx);
4081  d->extraData->propertyValues.removeAt(idx);
4082  } else {
4083  if (idx == -1) {
4084  d->extraData->propertyNames.append(name);
4085  d->extraData->propertyValues.append(value);
4086  } else {
4087  if (value.userType() == d->extraData->propertyValues.at(idx).userType()
4088  && value == d->extraData->propertyValues.at(idx))
4089  return false;
4090  d->extraData->propertyValues[idx] = value;
4091  }
4092  }
4093 
4095  QCoreApplication::sendEvent(this, &ev);
4096 
4097  return false;
4098  }
4099  QMetaProperty p = meta->property(id);
4100 #ifndef QT_NO_DEBUG
4101  if (!p.isWritable())
4102  qWarning("%s::setProperty: Property \"%s\" invalid,"
4103  " read-only or does not exist", metaObject()->className(), name);
4104 #endif
4105  return p.write(this, value);
4106 }
4107 
4118 QVariant QObject::property(const char *name) const
4119 {
4120  Q_D(const QObject);
4121  const QMetaObject *meta = metaObject();
4122  if (!name || !meta)
4123  return QVariant();
4124 
4125  int id = meta->indexOfProperty(name);
4126  if (id < 0) {
4127  if (!d->extraData)
4128  return QVariant();
4129  const int i = d->extraData->propertyNames.indexOf(name);
4130  return d->extraData->propertyValues.value(i);
4131  }
4132  QMetaProperty p = meta->property(id);
4133 #ifndef QT_NO_DEBUG
4134  if (!p.isReadable())
4135  qWarning("%s::property: Property \"%s\" invalid or does not exist",
4136  metaObject()->className(), name);
4137 #endif
4138  return p.read(this);
4139 }
4140 
4148 {
4149  Q_D(const QObject);
4150  if (d->extraData)
4151  return d->extraData->propertyNames;
4152  return QList<QByteArray>();
4153 }
4154 
4155 #endif // QT_NO_PROPERTIES
4156 
4157 
4158 /*****************************************************************************
4159  QObject debugging output routines.
4160  *****************************************************************************/
4161 
4162 static void dumpRecursive(int level, const QObject *object)
4163 {
4164  if (object) {
4165  const int indent = level * 4;
4166  const QString name = object->objectName();
4167  QString flags;
4168 #if 0
4169  if (qApp->focusWidget() == object)
4170  flags += 'F';
4171  if (object->isWidgetType()) {
4172  QWidget * w = (QWidget *)object;
4173  if (w->isVisible()) {
4174  QString t("<%1,%2,%3,%4>");
4175  flags += t.arg(w->x()).arg(w->y()).arg(w->width()).arg(w->height());
4176  } else {
4177  flags += 'I';
4178  }
4179  }
4180 #endif
4181  qDebug("%*s%s::%ls %ls", indent, "", object->metaObject()->className(),
4182  qUtf16Printable(name), qUtf16Printable(flags));
4183  for (auto child : object->children())
4184  dumpRecursive(level + 1, child);
4185  }
4186 }
4187 
4188 
4198 {
4199  dumpRecursive(0, this);
4200 }
4201 
4212 {
4213  qDebug("OBJECT %s::%s", metaObject()->className(),
4214  objectName().isEmpty() ? "unnamed" : objectName().toLocal8Bit().data());
4215 
4216  Q_D(const QObject);
4217  QBasicMutexLocker locker(signalSlotLock(this));
4218 
4219  // first, look for connections where this object is the sender
4220  qDebug(" SIGNALS OUT");
4221 
4222  QObjectPrivate::ConnectionData *cd = d->connections.loadRelaxed();
4223  if (cd && cd->signalVectorCount() > 0) {
4224  QObjectPrivate::SignalVector *signalVector = cd->signalVector.loadRelaxed();
4225  for (int signal_index = 0; signal_index < signalVector->count(); ++signal_index) {
4226  const QObjectPrivate::Connection *c = signalVector->at(signal_index).first.loadRelaxed();
4227  if (!c)
4228  continue;
4229  const QMetaMethod signal = QMetaObjectPrivate::signal(metaObject(), signal_index);
4230  qDebug(" signal: %s", signal.methodSignature().constData());
4231 
4232  // receivers
4233  while (c) {
4234  if (!c->receiver.loadRelaxed()) {
4235  qDebug(" <Disconnected receiver>");
4236  c = c->nextConnectionList.loadRelaxed();
4237  continue;
4238  }
4239  if (c->isSlotObject) {
4240  qDebug(" <functor or function pointer>");
4241  c = c->nextConnectionList.loadRelaxed();
4242  continue;
4243  }
4244  const QMetaObject *receiverMetaObject = c->receiver.loadRelaxed()->metaObject();
4245  const QMetaMethod method = receiverMetaObject->method(c->method());
4246  qDebug(" --> %s::%s %s",
4247  receiverMetaObject->className(),
4248  c->receiver.loadRelaxed()->objectName().isEmpty() ? "unnamed" : qPrintable(c->receiver.loadRelaxed()->objectName()),
4249  method.methodSignature().constData());
4250  c = c->nextConnectionList.loadRelaxed();
4251  }
4252  }
4253  } else {
4254  qDebug( " <None>" );
4255  }
4256 
4257  // now look for connections where this object is the receiver
4258  qDebug(" SIGNALS IN");
4259 
4260  if (cd && cd->senders) {
4261  for (QObjectPrivate::Connection *s = cd->senders; s; s = s->next) {
4262  QByteArray slotName = QByteArrayLiteral("<unknown>");
4263  if (!s->isSlotObject) {
4264  const QMetaMethod slot = metaObject()->method(s->method());
4265  slotName = slot.methodSignature();
4266  }
4267  qDebug(" <-- %s::%s %s",
4268  s->sender->metaObject()->className(),
4269  s->sender->objectName().isEmpty() ? "unnamed" : qPrintable(s->sender->objectName()),
4270  slotName.constData());
4271  }
4272  } else {
4273  qDebug(" <None>");
4274  }
4275 }
4276 
4277 
4278 #ifndef QT_NO_DEBUG_STREAM
4280 {
4281  QDebugStateSaver saver(dbg);
4282  if (!o)
4283  return dbg << "QObject(0x0)";
4284  dbg.nospace() << o->metaObject()->className() << '(' << (const void *)o;
4285  if (!o->objectName().isEmpty())
4286  dbg << ", name = " << o->objectName();
4287  dbg << ')';
4288  return dbg;
4289 }
4290 #endif
4291 
4807 {
4808  delete o;
4809 }
4810 
4967 QMetaObject::Connection QObject::connectImpl(const QObject *sender, void **signal,
4968  const QObject *receiver, void **slot,
4970  const int *types, const QMetaObject *senderMetaObject)
4971 {
4972  if (!signal) {
4973  qCWarning(lcConnect, "QObject::connect: invalid nullptr parameter");
4974  if (slotObj)
4975  slotObj->destroyIfLastRef();
4976  return QMetaObject::Connection();
4977  }
4978 
4979  int signal_index = -1;
4980  void *args[] = { &signal_index, signal };
4981  for (; senderMetaObject && signal_index < 0; senderMetaObject = senderMetaObject->superClass()) {
4982  senderMetaObject->static_metacall(QMetaObject::IndexOfMethod, 0, args);
4983  if (signal_index >= 0 && signal_index < QMetaObjectPrivate::get(senderMetaObject)->signalCount)
4984  break;
4985  }
4986  if (!senderMetaObject) {
4987  qCWarning(lcConnect, "QObject::connect: signal not found in %s", sender->metaObject()->className());
4988  slotObj->destroyIfLastRef();
4989  return QMetaObject::Connection(nullptr);
4990  }
4991  signal_index += QMetaObjectPrivate::signalOffset(senderMetaObject);
4992  return QObjectPrivate::connectImpl(sender, signal_index, receiver, slot, slotObj, type, types, senderMetaObject);
4993 }
4994 
4995 static void connectWarning(const QObject *sender,
4996  const QMetaObject *senderMetaObject,
4997  const QObject *receiver,
4998  const char *message)
4999 {
5000  const char *senderString = sender ? sender->metaObject()->className()
5001  : senderMetaObject ? senderMetaObject->className()
5002  : "Unknown";
5003  const char *receiverString = receiver ? receiver->metaObject()->className()
5004  : "Unknown";
5005  qCWarning(lcConnect, "QObject::connect(%s, %s): %s", senderString, receiverString, message);
5006 }
5007 
5016  const QObject *receiver, void **slot,
5017  QtPrivate::QSlotObjectBase *slotObj, int type,
5018  const int *types, const QMetaObject *senderMetaObject)
5019 {
5020  auto connectFailureGuard = qScopeGuard([&]()
5021  {
5022  if (slotObj)
5023  slotObj->destroyIfLastRef();
5024  });
5025 
5026  if (!sender || !receiver || !slotObj || !senderMetaObject) {
5027  connectWarning(sender, senderMetaObject, receiver, "invalid nullptr parameter");
5028  return QMetaObject::Connection();
5029  }
5030 
5031  if (type & Qt::UniqueConnection && !slot) {
5032  connectWarning(sender, senderMetaObject, receiver, "unique connections require a pointer to member function of a QObject subclass");
5033  return QMetaObject::Connection();
5034  }
5035 
5036  connectFailureGuard.dismiss();
5037 
5038  QObject *s = const_cast<QObject *>(sender);
5039  QObject *r = const_cast<QObject *>(receiver);
5040 
5041  QOrderedMutexLocker locker(signalSlotLock(sender),
5042  signalSlotLock(receiver));
5043 
5044  if (type & Qt::UniqueConnection && slot && QObjectPrivate::get(s)->connections.loadRelaxed()) {
5046  if (connections->signalVectorCount() > signal_index) {
5047  const QObjectPrivate::Connection *c2 = connections->signalVector.loadRelaxed()->at(signal_index).first.loadRelaxed();
5048 
5049  while (c2) {
5050  if (c2->receiver.loadRelaxed() == receiver && c2->isSlotObject && c2->slotObj->compare(slot)) {
5051  slotObj->destroyIfLastRef();
5052  return QMetaObject::Connection();
5053  }
5054  c2 = c2->nextConnectionList.loadRelaxed();
5055  }
5056  }
5057  }
5059 
5060  const bool isSingleShot = type & Qt::SingleShotConnection;
5062 
5063  Q_ASSERT(type >= 0);
5064  Q_ASSERT(type <= 3);
5065 
5066  std::unique_ptr<QObjectPrivate::Connection> c{new QObjectPrivate::Connection};
5067  c->sender = s;
5068  c->signal_index = signal_index;
5069  QThreadData *td = r->d_func()->threadData;
5070  td->ref();
5071  c->receiverThreadData.storeRelaxed(td);
5072  c->receiver.storeRelaxed(r);
5073  c->slotObj = slotObj;
5074  c->connectionType = type;
5075  c->isSlotObject = true;
5076  if (types) {
5077  c->argumentTypes.storeRelaxed(types);
5078  c->ownArgumentTypes = false;
5079  }
5080  c->isSingleShot = isSingleShot;
5081 
5082  QObjectPrivate::get(s)->addConnection(signal_index, c.get());
5083  QMetaObject::Connection ret(c.release());
5084  locker.unlock();
5085 
5086  QMetaMethod method = QMetaObjectPrivate::signal(senderMetaObject, signal_index);
5087  Q_ASSERT(method.isValid());
5088  s->connectNotify(method);
5089 
5090  return ret;
5091 }
5092 
5102 {
5104  if (!c)
5105  return false;
5106  const bool disconnected = QObjectPrivate::disconnect(c);
5107  const_cast<QMetaObject::Connection &>(connection).d_ptr = nullptr;
5108  c->deref(); // has been removed from the QMetaObject::Connection object
5109  return disconnected;
5110 }
5111 
5173 bool QObject::disconnectImpl(const QObject *sender, void **signal, const QObject *receiver, void **slot, const QMetaObject *senderMetaObject)
5174 {
5175  if (sender == nullptr || (receiver == nullptr && slot != nullptr)) {
5176  qCWarning(lcConnect, "QObject::disconnect: Unexpected nullptr parameter");
5177  return false;
5178  }
5179 
5180  int signal_index = -1;
5181  if (signal) {
5182  void *args[] = { &signal_index, signal };
5183  for (; senderMetaObject && signal_index < 0; senderMetaObject = senderMetaObject->superClass()) {
5184  senderMetaObject->static_metacall(QMetaObject::IndexOfMethod, 0, args);
5185  if (signal_index >= 0 && signal_index < QMetaObjectPrivate::get(senderMetaObject)->signalCount)
5186  break;
5187  }
5188  if (!senderMetaObject) {
5189  qCWarning(lcConnect, "QObject::disconnect: signal not found in %s", sender->metaObject()->className());
5190  return false;
5191  }
5192  signal_index += QMetaObjectPrivate::signalOffset(senderMetaObject);
5193  }
5194 
5195  return QMetaObjectPrivate::disconnect(sender, signal_index, senderMetaObject, receiver, -1, slot);
5196 }
5197 
5208 {
5209  return QObjectPrivate::connect(sender, signal_index, sender, slotObj, type);
5210 }
5211 
5223  const QObject *receiver,
5224  QtPrivate::QSlotObjectBase *slotObj,
5226 {
5227  if (!sender) {
5228  qCWarning(lcConnect, "QObject::connect: invalid nullptr parameter");
5229  if (slotObj)
5230  slotObj->destroyIfLastRef();
5231  return QMetaObject::Connection();
5232  }
5233  const QMetaObject *senderMetaObject = sender->metaObject();
5234  signal_index = methodIndexToSignalIndex(&senderMetaObject, signal_index);
5235 
5236  return QObjectPrivate::connectImpl(sender, signal_index, receiver, /*slot*/ nullptr, slotObj,
5237  type, /*types*/ nullptr, senderMetaObject);
5238 }
5239 
5248 bool QObjectPrivate::disconnect(const QObject *sender, int signal_index, void **slot)
5249 {
5250  return QObjectPrivate::disconnect(sender, signal_index, sender, slot);
5251 }
5252 
5265 bool QObjectPrivate::disconnect(const QObject *sender, int signal_index, const QObject *receiver,
5266  void **slot)
5267 {
5268  const QMetaObject *senderMetaObject = sender->metaObject();
5269  signal_index = methodIndexToSignalIndex(&senderMetaObject, signal_index);
5270 
5271  return QMetaObjectPrivate::disconnect(sender, signal_index, senderMetaObject, receiver, -1,
5272  slot);
5273 }
5274 
5280 {
5281  if (!c)
5282  return false;
5283  QObject *receiver = c->receiver.loadRelaxed();
5284  if (!receiver)
5285  return false;
5286 
5287  QBasicMutex *senderMutex = signalSlotLock(c->sender);
5288  QBasicMutex *receiverMutex = signalSlotLock(receiver);
5289 
5291  {
5292  QOrderedMutexLocker locker(senderMutex, receiverMutex);
5293 
5294  // load receiver once again and recheck to ensure nobody else has removed the connection in the meantime
5295  receiver = c->receiver.loadRelaxed();
5296  if (!receiver)
5297  return false;
5298 
5299  connections = QObjectPrivate::get(c->sender)->connections.loadRelaxed();
5301  connections->removeConnection(c);
5302 
5303  c->sender->disconnectNotify(QMetaObjectPrivate::signal(c->sender->metaObject(), c->signal_index));
5304  // We must not hold the receiver mutex, else we risk dead-locking; we also only need the sender mutex
5305  // It is however vital to hold the senderMutex before calling cleanOrphanedConnections, as otherwise
5306  // another thread might modify/delete the connection
5307  if (receiverMutex != senderMutex) {
5308  receiverMutex->unlock();
5309  }
5310  connections->cleanOrphanedConnections(c->sender, ConnectionData::AlreadyLockedAndTemporarilyReleasingLock);
5311  senderMutex->unlock(); // now both sender and receiver mutex have been manually unlocked
5312  locker.dismiss(); // so we dismiss the QOrderedMutexLocker
5313  }
5314 
5315  return true;
5316 }
5317 
5333 QMetaObject::Connection::Connection(const QMetaObject::Connection &other) : d_ptr(other.d_ptr)
5334 {
5335  if (d_ptr)
5336  static_cast<QObjectPrivate::Connection *>(d_ptr)->ref();
5337 }
5338 
5342 QMetaObject::Connection &QMetaObject::Connection::operator=(const QMetaObject::Connection &other)
5343 {
5344  if (other.d_ptr != d_ptr) {
5345  if (d_ptr)
5346  static_cast<QObjectPrivate::Connection *>(d_ptr)->deref();
5347  d_ptr = other.d_ptr;
5348  if (other.d_ptr)
5349  static_cast<QObjectPrivate::Connection *>(other.d_ptr)->ref();
5350  }
5351  return *this;
5352 }
5353 
5358 QMetaObject::Connection::Connection() : d_ptr(nullptr) {}
5359 
5363 QMetaObject::Connection::~Connection()
5364 {
5365  if (d_ptr)
5366  static_cast<QObjectPrivate::Connection *>(d_ptr)->deref();
5367 }
5368 
5370 bool QMetaObject::Connection::isConnected_helper() const
5371 {
5372  Q_ASSERT(d_ptr); // we're only called from operator RestrictedBool() const
5373  QObjectPrivate::Connection *c = static_cast<QObjectPrivate::Connection *>(d_ptr);
5374 
5375  return c->receiver.loadRelaxed();
5376 }
5377 
5378 
5390 
5391 #include "moc_qobject.cpp"
small capitals from c petite p scientific i
[1]
Definition: afcover.h:80
#define value
[5]
FT_UInt idx
Definition: cffcmap.c:135
static bool(* isSignalConnected)(QAbstractDeclarativeData *, const QObject *, int)
Definition: qobject_p.h:94
static int(* receivers)(QAbstractDeclarativeData *, const QObject *, int)
Definition: qobject_p.h:93
static void(* destroyed)(QAbstractDeclarativeData *, QObject *)
Definition: qobject_p.h:91
static void(* signalEmitted)(QAbstractDeclarativeData *, QObject *, int, void **)
Definition: qobject_p.h:92
static void(* setWidgetParent)(QObject *, QObject *)
Definition: qobject_p.h:95
The QAbstractEventDispatcher class provides an interface to manage Qt's event queue.
virtual QList< TimerInfo > registeredTimers(QObject *object) const =0
virtual bool unregisterTimers(QObject *object)=0
const QObject * sender() const
Definition: qobject_p.h:594
virtual void placeMetaCall(QObject *object)=0
int signalId() const
Definition: qobject_p.h:595
int type() const
bool deref() noexcept
Definition: qbasicatomic.h:102
void storeRelaxed(T newValue) noexcept
Definition: qbasicatomic.h:91
T loadRelaxed() const noexcept
Definition: qbasicatomic.h:90
Type loadAcquire() const noexcept
Definition: qbasicatomic.h:233
Type loadRelaxed() const noexcept
Definition: qbasicatomic.h:226
void storeRelease(Type newValue) noexcept
Definition: qbasicatomic.h:234
QBindable is a wrapper class around binding-enabled properties. It allows type-safe operations while ...
Definition: qproperty.h:753
The QByteArray class provides an array of bytes.
Definition: qbytearray.h:85
qsizetype size() const noexcept
Definition: qbytearray.h:470
const char * constData() const noexcept
Definition: qbytearray.h:144
qsizetype indexOf(char c, qsizetype from=0) const
bool isEmpty() const noexcept
Definition: qbytearray.h:129
qsizetype lastIndexOf(char c, qsizetype from=-1) const
The QChildEvent class contains event parameters for child object events.
Definition: qcoreevent.h:383
static bool sendEvent(QObject *receiver, QEvent *event)
static void removePostedEvents(QObject *receiver, int eventType=0)
static void postEvent(QObject *receiver, QEvent *event, int priority=Qt::NormalEventPriority)
The QDebug class provides an output stream for debugging information.
Definition: qdebug.h:65
QDebug & nospace()
Definition: qdebug.h:113
Convenience class for custom QDebug operators.
Definition: qdebug.h:176
The QDynamicPropertyChangeEvent class contains event parameters for dynamic property change events.
Definition: qcoreevent.h:400
The QEvent class is the base class of all event classes. Event objects contain event parameters.
Definition: qcoreevent.h:58
@ MetaCall
Definition: qcoreevent.h:110
@ ChildPolished
Definition: qcoreevent.h:120
@ ChildRemoved
Definition: qcoreevent.h:121
@ DeferredDelete
Definition: qcoreevent.h:113
@ ThreadChange
Definition: qcoreevent.h:95
@ Timer
Definition: qcoreevent.h:72
@ ChildAdded
Definition: qcoreevent.h:119
The QExplicitlySharedDataPointer class represents a pointer to an explicitly shared object.
Definition: qshareddata.h:161
qsizetype size() const noexcept
Definition: qlist.h:414
bool isEmpty() const noexcept
Definition: qlist.h:418
void removeAt(qsizetype i)
Definition: qlist.h:588
const_reference at(qsizetype i) const noexcept
Definition: qlist.h:457
qsizetype count() const noexcept
Definition: qlist.h:415
void prepend(rvalue_ref t)
Definition: qlist.h:484
void append(parameter_type t)
Definition: qlist.h:469
void clear()
Definition: qlist.h:445
const void *const * args() const
Definition: qobject_p.h:629
QMetaCallEvent(ushort method_offset, ushort method_relative, QObjectPrivate::StaticMetaCallFunction callFunction, const QObject *sender, int signalId, void **args, QSemaphore *semaphore)
Definition: qobject.cpp:538
~QMetaCallEvent() override
Definition: qobject.cpp:603
virtual void placeMetaCall(QObject *object) override
Definition: qobject.cpp:621
const QMetaType * types() const
Definition: qobject_p.h:631
The QMetaMethod class provides meta-data about a member function.
Definition: qmetaobject.h:54
int relativeMethodIndex() const
int methodIndex() const
bool isValid() const
Definition: qmetaobject.h:172
QByteArray methodSignature() const
MethodType methodType() const
The QMetaProperty class provides meta-data about a property.
Definition: qmetaobject.h:277
The QMetaType class manages named types in the meta-object system.
Definition: qmetatype.h:328
constexpr TypeFlags flags() const
Definition: qmetatype.h:2516
static QMetaType fromName(QByteArrayView name)
Definition: qmetatype.cpp:2789
int id(int=0) const
Definition: qmetatype.h:453
The QMutex class provides access serialization between threads.
Definition: qmutex.h:285
void unlock() noexcept
Definition: qmutex.h:293
void lock() noexcept
Definition: qmutex.h:290
The QMutexLocker class is a convenience class that simplifies locking and unlocking mutexes.
Definition: qmutex.h:317
void unlock() noexcept
Definition: qmutex.h:322
void relock() noexcept
Definition: qmutex.h:323
QDynamicMetaObjectData * metaObject
Definition: qobject.h:112
uint isDeletingChildren
Definition: qobject.h:105
uint isWindow
Definition: qobject.h:108
virtual ~QObjectData()=0
Definition: qobject.cpp:175
QMetaObject * dynamicMetaObject() const
Definition: qobject.cpp:177
uint receiveChildEvents
Definition: qobject.h:107
uint wasDeleted
Definition: qobject.h:104
int postedEvents
Definition: qobject.h:111
QObject * q_ptr
Definition: qobject.h:98
uint deleteLaterCalled
Definition: qobject.h:109
uint isWidget
Definition: qobject.h:102
uint sendChildEvents
Definition: qobject.h:106
QObjectList children
Definition: qobject.h:100
uint blockSig
Definition: qobject.h:103
QObject * parent
Definition: qobject.h:99
QBindingStorage bindingStorage
Definition: qobject.h:113
The QObject class is the base class of all Qt objects.
Definition: qobject.h:125
int senderSignalIndex() const
Definition: qobject.cpp:2514
int startTimer(int interval, Qt::TimerType timerType=Qt::CoarseTimer)
Definition: qobject.cpp:1765
Q_INVOKABLE QObject(QObject *parent=nullptr)
Definition: qobject.cpp:913
bool isSignalConnected(const QMetaMethod &signal) const
Definition: qobject.cpp:2613
virtual ~QObject()
Definition: qobject.cpp:983
void installEventFilter(QObject *filterObj)
Definition: qobject.cpp:2235
const QObjectList & children() const
Definition: qobject.h:206
void dumpObjectTree() const
Definition: qobject.cpp:4197
virtual void connectNotify(const QMetaMethod &signal)
Definition: qobject.cpp:3291
void dumpObjectInfo() const
Definition: qobject.cpp:4211
QObject * parent() const
Definition: qobject.h:409
void moveToThread(QThread *thread)
Definition: qobject.cpp:1572
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
Definition: qobject.cpp:2772
QObject * sender() const
Definition: qobject.cpp:2472
virtual void childEvent(QChildEvent *event)
Definition: qobject.cpp:1437
QString objectName
the name of this object
Definition: qobject.h:129
virtual bool event(QEvent *event)
Definition: qobject.cpp:1329
void setParent(QObject *parent)
Definition: qobject.cpp:2108
virtual bool eventFilter(QObject *watched, QEvent *event)
Definition: qobject.cpp:1484
static bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *member)
Definition: qobject.cpp:3048
void removeEventFilter(QObject *obj)
Definition: qobject.cpp:2267
virtual void timerEvent(QTimerEvent *event)
Definition: qobject.cpp:1399
QThread * thread() const
Definition: qobject.cpp:1527
QScopedPointer< QObjectData > d_ptr
Definition: qobject.h:436
bool blockSignals(bool b) noexcept
Definition: qobject.cpp:1514
QList< QByteArray > dynamicPropertyNames() const
Definition: qobject.cpp:4147
int receivers(const char *signal) const
Definition: qobject.cpp:2554
QVariant property(const char *name) const
Definition: qobject.cpp:4118
void setObjectName(const QString &name)
Definition: qobject.cpp:1261
bool setProperty(const char *name, const QVariant &value)
Definition: qobject.cpp:4063
QBindable< QString > bindableObjectName()
Definition: qobject.cpp:1276
void destroyed(QObject *=nullptr)
void killTimer(int id)
Definition: qobject.cpp:1838
void deleteLater()
Definition: qobject.cpp:2319
virtual void disconnectNotify(const QMetaMethod &signal)
Definition: qobject.cpp:3326
virtual void customEvent(QEvent *event)
Definition: qobject.cpp:1451
static QMetaObject::Connection connectImpl(const QObject *sender, int signal_index, const QObject *receiver, void **slot, QtPrivate::QSlotObjectBase *slotObj, int type, const int *types, const QMetaObject *senderMetaObject)
Definition: qobject.cpp:5015
ExtraData * extraData
Definition: qobject_p.h:414
bool isSignalConnected(uint signalIdx, bool checkDeclarative=true) const
Definition: qobject.cpp:460
void ensureConnectionData()
Definition: qobject_p.h:404
void moveToThread_helper()
Definition: qobject.cpp:1638
void checkForIncompatibleLibraryVersion(int version) const
Definition: qobject_p.h:444
QObjectPrivate(int version=QObjectPrivateVersion)
Definition: qobject.cpp:182
QAtomicPointer< ConnectionData > connections
Definition: qobject_p.h:423
static QMetaObject::Connection connect(const typename QtPrivate::FunctionPointer< Func1 >::Object *sender, Func1 signal, const typename QtPrivate::FunctionPointer< Func2 >::Object *receiverPrivate, Func2 slot, Qt::ConnectionType type=Qt::AutoConnection)
Definition: qobject_p.h:533
void(* StaticMetaCallFunction)(QObject *, QMetaObject::Call, int, void **)
Definition: qobject_p.h:127
void addConnection(int signal, Connection *c)
Definition: qobject.cpp:313
QObject * currentChildBeingDeleted
Definition: qobject_p.h:426
void clearBindingStorage()
Definition: qobject.cpp:954
QObjectList receiverList(const char *signal) const
Definition: qobject.cpp:270
virtual ~QObjectPrivate()
Definition: qobject.cpp:203
void setParent_helper(QObject *)
Definition: qobject.cpp:2132
static bool disconnect(const typename QtPrivate::FunctionPointer< Func1 >::Object *sender, Func1 signal, const typename QtPrivate::FunctionPointer< Func2 >::Object *receiverPrivate, Func2 slot)
Definition: qobject_p.h:562
void disconnectNotify(const QMetaMethod &signal)
Definition: qobject_p.h:470
void setThreadData_helper(QThreadData *currentData, QThreadData *targetData)
Definition: qobject.cpp:1649
void _q_reregisterTimers(void *pointer)
Definition: qobject.cpp:1711
bool maybeSignalConnected(uint signalIndex) const
Definition: qobject.cpp:486
int signalIndex(const char *signalName, const QMetaObject **meta=nullptr) const
Definition: qobject.cpp:4018
QObjectList senderList() const
Definition: qobject.cpp:291
static QObjectPrivate * get(QObject *o)
Definition: qobject_p.h:368
QAtomicPointer< QThreadData > threadData
Definition: qobject_p.h:420
void deleteChildren()
Definition: qobject.cpp:2115
bool isSender(const QObject *receiver, const char *signal) const
Definition: qobject.cpp:249
bool isDeclarativeSignalConnected(uint signalIdx) const
Definition: qobject_p.h:459
Definition: qthread_p.h:76
QObject * receiver
Definition: qthread_p.h:78
QEvent * event
Definition: qthread_p.h:79
void addEvent(const QPostEvent &ev)
Definition: qthread_p.h:112
QMutex mutex
Definition: qthread_p.h:108
The QRegularExpression class provides pattern matching using regular expressions.
QRegularExpressionMatch match(const QString &subject, qsizetype offset=0, MatchType matchType=NormalMatch, MatchOptions matchOptions=NoMatchOption) const
The QRegularExpressionMatch class provides the results of a matching a QRegularExpression against a s...
The QSemaphore class provides a general counting semaphore.
Definition: qsemaphore.h:55
void acquire(int n=1)
Definition: qsemaphore.cpp:323
The QString class provides a Unicode character string.
Definition: qstring.h:388
QByteArray toLatin1() const &
Definition: qstring.h:745
void store(const char *method)
Definition: qthread_p.h:280
static Q_AUTOTEST_EXPORT QThreadData * current(bool createIfNecessary=true)
Definition: qthread.cpp:908
QAtomicPointer< QAbstractEventDispatcher > eventDispatcher
Definition: qthread_p.h:298
bool canWait
Definition: qthread_p.h:303
void deref()
Definition: qthread.cpp:116
static QThreadData * get2(QThread *thread)
Definition: qthread_p.h:244
QAtomicPointer< void > threadId
Definition: qthread_p.h:297
FlaggedDebugSignatures flaggedSignatures
Definition: qthread_p.h:300
QPostEventList postEventList
Definition: qthread_p.h:295
bool hasEventDispatcher() const
Definition: qthread_p.h:250
void ref()
Definition: qthread.cpp:108
QAtomicPointer< QThread > thread
Definition: qthread_p.h:296
static Qt::HANDLE currentThreadId() noexcept Q_DECL_PURE_FUNCTION
Definition: qthread.h:187
static QThread * currentThread()
Definition: qthread.cpp:879
The QTimerEvent class contains parameters that describe a timer event.
Definition: qcoreevent.h:367
constexpr size_type size() const noexcept
const T * constData() const
The QVariant class acts like a union for the most common Qt data types.
Definition: qvariant.h:95
The QWidget class is the base class of all user interface objects.
Definition: qwidget.h:133
QSize size
the size of the widget excluding any window frame
Definition: qwidget.h:147
void destroyIfLastRef() noexcept
Definition: base.h:37
double e
auto signal
auto mo
[7]
int const char * version
Definition: zlib.h:814
JOCTET JCOEFPTR block
Definition: jsimd.h:109
short next
Definition: keywords.cpp:454
QPainterPath node()
Definition: paths.cpp:574
void(* AddQObjectCallback)(QObject *)
Definition: qhooks_p.h:74
void(* RemoveQObjectCallback)(QObject *)
Definition: qhooks_p.h:75
@ AddQObject
Definition: qhooks_p.h:67
@ RemoveQObject
Definition: qhooks_p.h:68
Definition: qnamespace.h:55
TimerType
Definition: qnamespace.h:1689
@ FindChildrenRecursively
Definition: qnamespace.h:1480
void * HANDLE
Definition: qnamespace.h:1561
ConnectionType
Definition: qnamespace.h:1304
@ SingleShotConnection
Definition: qnamespace.h:1310
@ AutoConnection
Definition: qnamespace.h:1305
@ BlockingQueuedConnection
Definition: qnamespace.h:1308
@ QueuedConnection
Definition: qnamespace.h:1307
@ UniqueConnection
Definition: qnamespace.h:1309
bool isAnyBindingEvaluating()
Definition: qproperty.cpp:2274
#define QString()
Definition: parse-defines.h:51
set set set set set set set macro pixldst1 op
void
Definition: png.h:1080
int loc
Definition: property.cpp:46
#define Q_BASIC_ATOMIC_INITIALIZER(a)
#define QByteArrayLiteral(str)
Definition: qbytearray.h:80
size_t qstrlen(const char *str)
int qstrncmp(const char *str1, const char *str2, size_t len)
#define Q_UNLIKELY(x)
#define Q_LIKELY(x)
#define Q_DECL_COLD_FUNCTION
#define Q_FUNC_INFO
#define qApp
DBusConnection * connection
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 * method
EGLOutputLayerEXT EGLint EGLAttrib value
#define Q_DISABLE_COPY_MOVE(Class)
Definition: qglobal.h:519
size_t quintptr
Definition: qglobal.h:310
unsigned int uint
Definition: qglobal.h:334
unsigned short ushort
Definition: qglobal.h:333
QT_BEGIN_NAMESPACE quintptr Q_CORE_EXPORT qtHookData[]
Definition: qhooks.cpp:45
#define qDebug
[1]
Definition: qlogging.h:177
#define qWarning
Definition: qlogging.h:179
#define Q_LOGGING_CATEGORY(name,...)
#define qCWarning(category,...)
#define qCDebug(category,...)
@ MethodCloned
Definition: qmetaobject_p.h:99
const char * typeName
Definition: qmetatype.cpp:869
void qt_qFindChildren_helper(const QObject *parent, const QString &name, const QMetaObject &mo, QList< void * > *list, Qt::FindChildOptions options)
Definition: qobject.cpp:2038
Q_CORE_EXPORT QBasicAtomicPointer< QSignalSpyCallbackSet > qt_signal_spy_callback_set
Definition: qobject.cpp:86
QDebug operator<<(QDebug dbg, const QObject *o)
Definition: qobject.cpp:4279
void qDeleteInEventHandler(QObject *o)
Definition: qobject.cpp:4806
const char * qFlagLocation(const char *method)
Definition: qobject.cpp:2368
void doActivate(QObject *sender, int signal_index, void **argv)
Definition: qobject.cpp:3801
void qt_register_signal_spy_callbacks(QSignalSpyCallbackSet *callback_set)
Definition: qobject.cpp:88
QObject * qt_qFindChild_helper(const QObject *parent, const QString &name, const QMetaObject &mo, Qt::FindChildOptions options)
Definition: qobject.cpp:2087
#define QSIGNAL_CODE
Definition: qobjectdefs.h:77
#define Q_ARG(type, data)
Definition: qobjectdefs.h:98
#define QSLOT_CODE
Definition: qobjectdefs.h:76
GLenum type
Definition: qopengl.h:270
GLenum GLuint GLenum GLsizei const GLchar * message
Definition: qopengl.h:270
GLint location
GLboolean GLboolean GLboolean b
GLsizei const GLfloat * v
[13]
GLuint64 GLenum void * handle
GLint GLenum GLsizei GLsizei GLsizei depth
const GLfloat * m
GLenum GLuint GLint level
GLboolean r
[2]
GLfloat GLfloat GLfloat w
[0]
GLboolean GLboolean GLboolean GLboolean a
[7]
GLuint index
[2]
GLsizei GLenum GLenum * types
GLenum GLenum GLsizei count
GLuint object
[3]
GLbitfield flags
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLint ref
GLuint name
GLfloat n
GLsizei GLenum GLsizei GLsizei GLuint memory
struct _cl_event * event
Definition: qopenglext.h:2998
GLhandleARB obj
[2]
Definition: qopenglext.h:4164
GLenum func
Definition: qopenglext.h:663
GLuint res
Definition: qopenglext.h:8867
const GLubyte * c
Definition: qopenglext.h:12701
GLdouble GLdouble t
[9]
Definition: qopenglext.h:243
GLsizei const void * pointer
Definition: qopenglext.h:384
GLdouble GLdouble GLdouble GLdouble q
Definition: qopenglext.h:259
GLuint64EXT * result
[6]
Definition: qopenglext.h:10932
GLdouble s
[6]
Definition: qopenglext.h:235
GLfloat GLfloat p
[1]
Definition: qopenglext.h:12698
#define Q_ASSERT(cond)
Definition: qrandom.cpp:84
#define Q_ASSERT_X(cond, x, msg)
Definition: qrandom.cpp:85
QScopeGuard< typename std::decay< F >::type > qScopeGuard(F &&f)
[qScopeGuard]
Definition: qscopeguard.h:93
#define sp
#define emit
Definition: qtmetamacros.h:85
#define Q_HAS_TRACEPOINTS
Definition: qtrace_p.h:135
#define Q_TRACE_SCOPE(x,...)
Definition: qtrace_p.h:138
#define Q_TRACE(x,...)
Definition: qtrace_p.h:136
const char className[16]
[1]
Definition: qwizard.cpp:135
#define explicit
Q_UNUSED(salary)
[21]
QT_BEGIN_NAMESPACE void dumpRecursive(const QDir &dir, QTextStream &out)
Definition: main.cpp:52
Q_CHECK_PTR(a=new int[80])
QRandomGenerator64 rd
[10]
QString base
connect(quitButton, &QPushButton::clicked, &app, &QCoreApplication::quit, Qt::QueuedConnection)
QObject::connect nullptr
MyCustomStruct c2
QReadWriteLock lock
[0]
QSharedPointer< T > other(t)
[5]
QLayoutItem * child
[0]
QAction * at
view create()
QStringList list
[0]
virtual QMetaObject * toDynamicMetaObject(QObject *)=0
virtual void objectDestroyed(QObject *)
Definition: qobject_p.h:669
virtual ~QDynamicMetaObjectData()
Definition: qobject.cpp:93
qsizetype indexOf(const AT &t, qsizetype from=0) const noexcept
Definition: qlist.h:966
StaticMetacallFunction static_metacall
Definition: qobjectdefs.h:435
SuperData superdata
Definition: qobjectdefs.h:431
The QMetaObject class contains meta-information about Qt objects.
Definition: qobjectdefs.h:165
QMetaProperty property(int index) const
const char * className() const
static bool disconnectOne(const QObject *sender, int signal_index, const QObject *receiver, int method_index)
Definition: qobject.cpp:3464
static bool disconnect(const QObject *sender, int signal_index, const QObject *receiver, int method_index)
Definition: qobject.cpp:3448
static int metacall(QObject *, Call, int, void **)
static bool invokeMethod(QObject *obj, const char *member, Qt::ConnectionType, QGenericReturnArgument ret, QGenericArgument val0=QGenericArgument(nullptr), 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())
static QByteArray normalizedSignature(const char *method)
static void connectSlotsByName(QObject *o)
Definition: qobject.cpp:3614
static Connection connect(const QObject *sender, int signal_index, const QObject *receiver, int method_index, int type=0, int *types=nullptr)
Definition: qobject.cpp:3363
int static_metacall(Call, int, void **) const
int indexOfProperty(const char *name) const
int methodOffset() const
const QMetaObject * superClass() const
Definition: qobjectdefs.h:477
struct QMetaObject::Data d
QMetaMethod method(int index) const
static bool checkConnectArgs(const char *signal, const char *method)
static void activate(QObject *sender, int signal_index, void **argv)
Definition: qobject.cpp:4001
static int signalOffset(const QMetaObject *m)
static QObjectPrivate::Connection * connect(const QObject *sender, int signal_index, const QMetaObject *smeta, const QObject *receiver, int method_index_relative, const QMetaObject *rmeta=nullptr, int type=0, int *types=nullptr)
Definition: qobject.cpp:3383
static const QMetaObjectPrivate * get(const QMetaObject *metaobject)
static bool disconnect(const QObject *sender, int signal_index, const QMetaObject *smeta, const QObject *receiver, int method_index, void **slot, DisconnectType=DisconnectAll)
Definition: qobject.cpp:3518
static Q_CORE_EXPORT QMetaMethod signal(const QMetaObject *m, int signal_index)
static int indexOfMethod(const QMetaObject *m, const QByteArray &name, int argc, const QArgumentType *types)
static void memberIndexes(const QObject *obj, const QMetaMethod &member, int *signalIndex, int *methodIndex)
Definition: qobject.cpp:2655
static QByteArray decodeMethodSignature(const char *signature, QArgumentTypeArray &types)
static Q_CORE_EXPORT int absoluteSignalCount(const QMetaObject *m)
static bool disconnectHelper(QObjectPrivate::ConnectionData *connections, int signalIndex, const QObject *receiver, int method_index, void **slot, QBasicMutex *senderMutex, DisconnectType=DisconnectAll)
Definition: qobject.cpp:3478
static int indexOfSignalRelative(const QMetaObject **baseObject, const QByteArray &name, int argc, const QArgumentType *types)
static int originalClone(const QMetaObject *obj, int local_method_index)
static bool checkConnectArgs(int signalArgc, const QArgumentType *signalTypes, int methodArgc, const QArgumentType *methodTypes)
static int indexOfSlotRelative(const QMetaObject **m, const QByteArray &name, int argc, const QArgumentType *types)
QAtomicInteger< uint > currentConnectionId
Definition: qobject_p.h:264
QAtomicPointer< Connection > orphaned
Definition: qobject_p.h:269
void removeConnection(Connection *c)
Definition: qobject.cpp:341
ConnectionList & connectionsForSignal(int signal)
Definition: qobject_p.h:301
void resizeSignalVector(uint size)
Definition: qobject_p.h:306
void cleanOrphanedConnections(QObject *sender, LockPolicy lockPolicy=NeedToLock)
Definition: qobject_p.h:294
static void deleteOrphaned(ConnectionOrSignalVector *c)
Definition: qobject.cpp:435
void cleanOrphanedConnectionsImpl(QObject *sender, LockPolicy lockPolicy)
Definition: qobject.cpp:407
QAtomicPointer< SignalVector > signalVector
Definition: qobject_p.h:266
QAtomicPointer< const int > argumentTypes
Definition: qobject_p.h:165
QAtomicPointer< Connection > nextConnectionList
Definition: qobject_p.h:155
QAtomicPointer< QObject > receiver
Definition: qobject_p.h:159
QtPrivate::QSlotObjectBase * slotObj
Definition: qobject_p.h:163
QAtomicPointer< Connection > last
Definition: qobject_p.h:200
QAtomicPointer< Connection > first
Definition: qobject_p.h:199
static SignalVector * asSignalVector(ConnectionOrSignalVector *c)
Definition: qobject_p.h:139
QList< int > runningTimers
Definition: qobject_p.h:119
ConnectionList & at(int i)
Definition: qobject_p.h:236
BeginCallback slot_begin_callback
Definition: qobject_p.h:78
EndCallback slot_end_callback
Definition: qobject_p.h:80
EndCallback signal_end_callback
Definition: qobject_p.h:79
BeginCallback signal_begin_callback
Definition: qobject_p.h:77
QtPrivate::QSlotObjectBase const * operator->() const
Definition: qobject.cpp:3717
QtPrivate::QSlotObjectBase * operator->()
Definition: qobject.cpp:3720
SlotObjectGuard()=default
Definition: inftrees.h:24
QThreadStorage< int * > dummy[8]
const char * signature
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent