99 static QBasicAtomicInt objectCount = Q_BASIC_ATOMIC_INITIALIZER(0); |
99 static QBasicAtomicInt objectCount = Q_BASIC_ATOMIC_INITIALIZER(0); |
100 |
100 |
101 /** \internal |
101 /** \internal |
102 * mutex to be locked when accessing the connectionlists or the senders list |
102 * mutex to be locked when accessing the connectionlists or the senders list |
103 */ |
103 */ |
104 static QMutex *signalSlotLock(const QObject *o) |
104 static inline QMutex *signalSlotLock(const QObject *o) |
105 { |
105 { |
106 if (!signalSlotMutexes) { |
106 if (!signalSlotMutexes) { |
107 QMutexPool *mp = new QMutexPool; |
107 QMutexPool *mp = new QMutexPool; |
108 if (!signalSlotMutexes.testAndSetOrdered(0, mp)) { |
108 if (!signalSlotMutexes.testAndSetOrdered(0, mp)) { |
109 delete mp; |
109 delete mp; |
123 QMutexPool *old = signalSlotMutexes.fetchAndStoreAcquire(0); |
123 QMutexPool *old = signalSlotMutexes.fetchAndStoreAcquire(0); |
124 delete old; |
124 delete old; |
125 } |
125 } |
126 } |
126 } |
127 |
127 |
|
128 void (*QAbstractDeclarativeData::destroyed)(QAbstractDeclarativeData *, QObject *) = 0; |
|
129 void (*QAbstractDeclarativeData::parentChanged)(QAbstractDeclarativeData *, QObject *, QObject *) = 0; |
|
130 |
128 QObjectData::~QObjectData() {} |
131 QObjectData::~QObjectData() {} |
129 QDeclarativeData::~QDeclarativeData() {} |
|
130 |
132 |
131 QObjectPrivate::QObjectPrivate(int version) |
133 QObjectPrivate::QObjectPrivate(int version) |
132 : threadData(0), connectionLists(0), senders(0), currentSender(0), currentChildBeingDeleted(0) |
134 : threadData(0), connectionLists(0), senders(0), currentSender(0), currentChildBeingDeleted(0) |
133 { |
135 { |
134 if (version != QObjectPrivateVersion) |
136 if (version != QObjectPrivateVersion) |
135 qFatal("Cannot mix incompatible Qt libraries"); |
137 qFatal("Cannot mix incompatible Qt library (version 0x%x) with this library (version 0x%x)", |
|
138 version, QObjectPrivateVersion); |
136 |
139 |
137 // QObjectData initialization |
140 // QObjectData initialization |
138 q_ptr = 0; |
141 q_ptr = 0; |
139 parent = 0; // no parent yet. It is set by setParent() |
142 parent = 0; // no parent yet. It is set by setParent() |
140 isWidget = false; // assume not a widget object |
143 isWidget = false; // assume not a widget object |
388 } |
391 } |
389 connectionLists->dirty = false; |
392 connectionLists->dirty = false; |
390 } |
393 } |
391 } |
394 } |
392 |
395 |
393 QObjectPrivate::Sender *QObjectPrivate::setCurrentSender(QObject *receiver, |
|
394 Sender *sender) |
|
395 { |
|
396 Sender *previousSender = receiver->d_func()->currentSender; |
|
397 receiver->d_func()->currentSender = sender; |
|
398 return previousSender; |
|
399 } |
|
400 |
|
401 void QObjectPrivate::resetCurrentSender(QObject *receiver, |
|
402 Sender *currentSender, |
|
403 Sender *previousSender) |
|
404 { |
|
405 // ref is set to zero when this object is deleted during the metacall |
|
406 if (currentSender->ref == 1) |
|
407 receiver->d_func()->currentSender = previousSender; |
|
408 // if we've recursed, we need to tell the caller about the objects deletion |
|
409 if (previousSender) |
|
410 previousSender->ref = currentSender->ref; |
|
411 } |
|
412 |
|
413 |
|
414 typedef QMultiHash<QObject *, QObject **> GuardHash; |
396 typedef QMultiHash<QObject *, QObject **> GuardHash; |
415 Q_GLOBAL_STATIC(GuardHash, guardHash) |
397 Q_GLOBAL_STATIC(GuardHash, guardHash) |
416 Q_GLOBAL_STATIC(QMutex, guardHashLock) |
398 Q_GLOBAL_STATIC(QMutex, guardHashLock) |
417 |
399 |
418 /*!\internal |
400 /*!\internal |
567 |
540 |
568 \ingroup objectmodel |
541 \ingroup objectmodel |
569 |
542 |
570 \reentrant |
543 \reentrant |
571 |
544 |
572 QObject is the heart of the \l{Qt object model}. The central |
545 QObject is the heart of the Qt \l{Object Model}. The central |
573 feature in this model is a very powerful mechanism for seamless |
546 feature in this model is a very powerful mechanism for seamless |
574 object communication called \l{signals and slots}. You can |
547 object communication called \l{signals and slots}. You can |
575 connect a signal to a slot with connect() and destroy the |
548 connect a signal to a slot with connect() and destroy the |
576 connection with disconnect(). To avoid never ending notification |
549 connection with disconnect(). To avoid never ending notification |
577 loops you can temporarily block signals with blockSignals(). The |
550 loops you can temporarily block signals with blockSignals(). The |
578 protected functions connectNotify() and disconnectNotify() make |
551 protected functions connectNotify() and disconnectNotify() make |
579 it possible to track connections. |
552 it possible to track connections. |
580 |
553 |
581 QObjects organize themselves in \l {Object Trees and Object |
554 QObjects organize themselves in \l {Object Trees & Ownership} |
582 Ownership} {object trees}. When you create a QObject with another |
555 {object trees}. When you create a QObject with another object as |
583 object as parent, the object will automatically add itself to the |
556 parent, the object will automatically add itself to the parent's |
584 parent's children() list. The parent takes ownership of the |
557 children() list. The parent takes ownership of the object; i.e., |
585 object; i.e., it will automatically delete its children in its |
558 it will automatically delete its children in its destructor. You |
586 destructor. You can look for an object by name and optionally type |
559 can look for an object by name and optionally type using |
587 using findChild() or findChildren(). |
560 findChild() or findChildren(). |
588 |
561 |
589 Every object has an objectName() and its class name can be found |
562 Every object has an objectName() and its class name can be found |
590 via the corresponding metaObject() (see QMetaObject::className()). |
563 via the corresponding metaObject() (see QMetaObject::className()). |
591 You can determine whether the object's class inherits another |
564 You can determine whether the object's class inherits another |
592 class in the QObject inheritance hierarchy by using the |
565 class in the QObject inheritance hierarchy by using the |
634 This is by design. Actually, they are declared, but in a |
607 This is by design. Actually, they are declared, but in a |
635 \c{private} section with the macro Q_DISABLE_COPY(). In fact, all |
608 \c{private} section with the macro Q_DISABLE_COPY(). In fact, all |
636 Qt classes derived from QObject (direct or indirect) use this |
609 Qt classes derived from QObject (direct or indirect) use this |
637 macro to declare their copy constructor and assignment operator to |
610 macro to declare their copy constructor and assignment operator to |
638 be private. The reasoning is found in the discussion on |
611 be private. The reasoning is found in the discussion on |
639 \l{Identity vs Value} {Identity vs Value} on the \l{Qt Object |
612 \l{Identity vs Value} {Identity vs Value} on the Qt \l{Object |
640 Model} page. |
613 Model} page. |
641 |
614 |
642 The main consequence is that you should use pointers to QObject |
615 The main consequence is that you should use pointers to QObject |
643 (or to your QObject subclass) where you might otherwise be tempted |
616 (or to your QObject subclass) where you might otherwise be tempted |
644 to use your QObject subclass as a value. For example, without a |
617 to use your QObject subclass as a value. For example, without a |
681 To make user-visible text translatable, it must be wrapped in calls to |
654 To make user-visible text translatable, it must be wrapped in calls to |
682 the tr() function. This is explained in detail in the |
655 the tr() function. This is explained in detail in the |
683 \l{Writing Source Code for Translation} document. |
656 \l{Writing Source Code for Translation} document. |
684 |
657 |
685 \sa QMetaObject, QPointer, QObjectCleanupHandler, Q_DISABLE_COPY() |
658 \sa QMetaObject, QPointer, QObjectCleanupHandler, Q_DISABLE_COPY() |
686 \sa {Object Trees and Object Ownership} |
659 \sa {Object Trees & Ownership} |
687 */ |
660 */ |
688 |
661 |
689 /*! |
662 /*! |
690 \relates QObject |
663 \relates QObject |
691 |
664 |
869 emit destroyed(this); |
842 emit destroyed(this); |
870 } QT_CATCH(...) { |
843 } QT_CATCH(...) { |
871 // all the signal/slots connections are still in place - if we don't |
844 // all the signal/slots connections are still in place - if we don't |
872 // quit now, we will crash pretty soon. |
845 // quit now, we will crash pretty soon. |
873 qWarning("Detected an unexpected exception in ~QObject while emitting destroyed()."); |
846 qWarning("Detected an unexpected exception in ~QObject while emitting destroyed()."); |
874 #if defined(Q_AUTOTEST_EXPORT) && !defined(QT_NO_EXCEPTIONS) |
847 #if defined(Q_BUILD_INTERNAL) && !defined(QT_NO_EXCEPTIONS) |
875 struct AutotestException : public std::exception |
848 struct AutotestException : public std::exception |
876 { |
849 { |
877 const char *what() const throw() { return "autotest swallow"; } |
850 const char *what() const throw() { return "autotest swallow"; } |
878 } autotestException; |
851 } autotestException; |
879 // throw autotestException; |
852 // throw autotestException; |
882 QT_RETHROW; |
855 QT_RETHROW; |
883 #endif |
856 #endif |
884 } |
857 } |
885 |
858 |
886 if (d->declarativeData) |
859 if (d->declarativeData) |
887 d->declarativeData->destroyed(this); |
860 QAbstractDeclarativeData::destroyed(d->declarativeData, this); |
888 |
861 |
889 { |
862 // set ref to zero to indicate that this object has been deleted |
890 QMutex *signalSlotMutex = 0; |
863 if (d->currentSender != 0) |
891 QT_TRY { |
864 d->currentSender->ref = 0; |
892 signalSlotMutex = signalSlotLock(this); |
865 d->currentSender = 0; |
893 } QT_CATCH(const std::bad_alloc &) { |
866 |
894 // out of memory - swallow to prevent a crash |
867 if (d->connectionLists || d->senders) { |
895 } |
868 QMutex *signalSlotMutex = signalSlotLock(this); |
896 QMutexLocker locker(signalSlotMutex); |
869 QMutexLocker locker(signalSlotMutex); |
897 |
|
898 // set ref to zero to indicate that this object has been deleted |
|
899 if (d->currentSender != 0) |
|
900 d->currentSender->ref = 0; |
|
901 d->currentSender = 0; |
|
902 |
870 |
903 // disconnect all receivers |
871 // disconnect all receivers |
904 if (d->connectionLists) { |
872 if (d->connectionLists) { |
905 ++d->connectionLists->inUse; |
873 ++d->connectionLists->inUse; |
906 for (int signal = -1; signal < d->connectionLists->count(); ++signal) { |
874 int connectionListsCount = d->connectionLists->count(); |
|
875 for (int signal = -1; signal < connectionListsCount; ++signal) { |
907 QObjectPrivate::ConnectionList &connectionList = |
876 QObjectPrivate::ConnectionList &connectionList = |
908 (*d->connectionLists)[signal]; |
877 (*d->connectionLists)[signal]; |
909 |
878 |
910 while (QObjectPrivate::Connection *c = connectionList.first) { |
879 while (QObjectPrivate::Connection *c = connectionList.first) { |
911 if (!c->receiver) { |
880 if (!c->receiver) { |
938 } |
907 } |
939 |
908 |
940 // disconnect all senders |
909 // disconnect all senders |
941 QObjectPrivate::Connection *node = d->senders; |
910 QObjectPrivate::Connection *node = d->senders; |
942 while (node) { |
911 while (node) { |
943 QMutex *m = signalSlotLock(node->sender); |
912 QObject *sender = node->sender; |
|
913 QMutex *m = signalSlotLock(sender); |
944 node->prev = &node; |
914 node->prev = &node; |
945 bool needToUnlock = QOrderedMutexLocker::relock(locker.mutex(), m); |
915 bool needToUnlock = QOrderedMutexLocker::relock(signalSlotMutex, m); |
946 //the node has maybe been removed while the mutex was unlocked in relock? |
916 //the node has maybe been removed while the mutex was unlocked in relock? |
947 if (!node || signalSlotLock(node->sender) != m) { |
917 if (!node || node->sender != sender) { |
948 m->unlock(); |
918 m->unlock(); |
949 continue; |
919 continue; |
950 } |
920 } |
951 node->receiver = 0; |
921 node->receiver = 0; |
952 QObjectConnectionListVector *senderLists = node->sender->d_func()->connectionLists; |
922 QObjectConnectionListVector *senderLists = sender->d_func()->connectionLists; |
953 if (senderLists) |
923 if (senderLists) |
954 senderLists->dirty = true; |
924 senderLists->dirty = true; |
955 |
925 |
956 node = node->next; |
926 node = node->next; |
957 if (needToUnlock) |
927 if (needToUnlock) |
974 if (!d->children.isEmpty()) |
944 if (!d->children.isEmpty()) |
975 d->deleteChildren(); |
945 d->deleteChildren(); |
976 |
946 |
977 qt_removeObject(this); |
947 qt_removeObject(this); |
978 |
948 |
979 QCoreApplication::removePostedEvents(this); |
949 if (d->postedEvents) |
|
950 QCoreApplication::removePostedEvents(this, 0); |
980 |
951 |
981 if (d->parent) // remove it from parent object |
952 if (d->parent) // remove it from parent object |
982 d->setParent_helper(0); |
953 d->setParent_helper(0); |
983 |
954 |
984 d->threadData->deref(); |
955 d->threadData->deref(); |
1474 // one exception to the rule: we allow moving objects with no thread affinity to the current thread |
1445 // one exception to the rule: we allow moving objects with no thread affinity to the current thread |
1475 currentData = d->threadData; |
1446 currentData = d->threadData; |
1476 } else if (d->threadData != currentData) { |
1447 } else if (d->threadData != currentData) { |
1477 qWarning("QObject::moveToThread: Current thread (%p) is not the object's thread (%p).\n" |
1448 qWarning("QObject::moveToThread: Current thread (%p) is not the object's thread (%p).\n" |
1478 "Cannot move to target thread (%p)\n", |
1449 "Cannot move to target thread (%p)\n", |
1479 d->threadData->thread, currentData->thread, targetData->thread); |
1450 currentData->thread, d->threadData->thread, targetData->thread); |
1480 |
1451 |
1481 #ifdef Q_WS_MAC |
1452 #ifdef Q_WS_MAC |
1482 qWarning("On Mac OS X, you might be loading two sets of Qt binaries into the same process. " |
1453 qWarning("On Mac OS X, you might be loading two sets of Qt binaries into the same process. " |
1483 "Check that all plugins are compiled against the right Qt binaries. Export " |
1454 "Check that all plugins are compiled against the right Qt binaries. Export " |
1484 "DYLD_PRINT_LIBRARIES=1 and check that only one set of binaries are being loaded."); |
1455 "DYLD_PRINT_LIBRARIES=1 and check that only one set of binaries are being loaded."); |
2508 if (!check_signal_macro(sender, signal, "connect", "bind")) |
2481 if (!check_signal_macro(sender, signal, "connect", "bind")) |
2509 return false; |
2482 return false; |
2510 const QMetaObject *smeta = sender->metaObject(); |
2483 const QMetaObject *smeta = sender->metaObject(); |
2511 const char *signal_arg = signal; |
2484 const char *signal_arg = signal; |
2512 ++signal; //skip code |
2485 ++signal; //skip code |
2513 int signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signal); |
2486 int signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signal, false); |
2514 if (signal_index < 0) { |
2487 if (signal_index < 0) { |
2515 // check for normalized signatures |
2488 // check for normalized signatures |
2516 tmp_signal_name = QMetaObject::normalizedSignature(signal - 1); |
2489 tmp_signal_name = QMetaObject::normalizedSignature(signal - 1); |
2517 signal = tmp_signal_name.constData() + 1; |
2490 signal = tmp_signal_name.constData() + 1; |
2518 |
2491 |
2519 smeta = sender->metaObject(); |
2492 smeta = sender->metaObject(); |
2520 signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signal); |
2493 signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signal, false); |
2521 |
2494 } |
2522 if (signal_index < 0) { |
2495 if (signal_index < 0) { |
2523 err_method_notfound(sender, signal_arg, "connect"); |
2496 // re-use tmp_signal_name and signal from above |
2524 err_info_about_objects("connect", sender, receiver); |
2497 |
2525 return false; |
2498 smeta = sender->metaObject(); |
2526 } |
2499 signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signal, true); |
|
2500 } |
|
2501 if (signal_index < 0) { |
|
2502 err_method_notfound(sender, signal_arg, "connect"); |
|
2503 err_info_about_objects("connect", sender, receiver); |
|
2504 return false; |
2527 } |
2505 } |
2528 signal_index = QMetaObjectPrivate::originalClone(smeta, signal_index); |
2506 signal_index = QMetaObjectPrivate::originalClone(smeta, signal_index); |
2529 int signalOffset, methodOffset; |
2507 int signalOffset, methodOffset; |
2530 computeOffsets(smeta, &signalOffset, &methodOffset); |
2508 computeOffsets(smeta, &signalOffset, &methodOffset); |
2531 int signal_absolute_index = signal_index + methodOffset; |
2509 int signal_absolute_index = signal_index + methodOffset; |
2541 |
2519 |
2542 const QMetaObject *rmeta = receiver->metaObject(); |
2520 const QMetaObject *rmeta = receiver->metaObject(); |
2543 int method_index = -1; |
2521 int method_index = -1; |
2544 switch (membcode) { |
2522 switch (membcode) { |
2545 case QSLOT_CODE: |
2523 case QSLOT_CODE: |
2546 method_index = rmeta->indexOfSlot(method); |
2524 method_index = QMetaObjectPrivate::indexOfSlot(rmeta, method, false); |
2547 break; |
2525 break; |
2548 case QSIGNAL_CODE: |
2526 case QSIGNAL_CODE: |
2549 method_index = rmeta->indexOfSignal(method); |
2527 method_index = QMetaObjectPrivate::indexOfSignalRelative(&rmeta, method, false); |
|
2528 if (method_index >= 0) |
|
2529 method_index += rmeta->methodOffset(); |
2550 break; |
2530 break; |
2551 } |
2531 } |
2552 if (method_index < 0) { |
2532 if (method_index < 0) { |
2553 // check for normalized methods |
2533 // check for normalized methods |
2554 tmp_method_name = QMetaObject::normalizedSignature(method); |
2534 tmp_method_name = QMetaObject::normalizedSignature(method); |
2555 method = tmp_method_name.constData(); |
2535 method = tmp_method_name.constData(); |
|
2536 |
|
2537 // rmeta may have been modified above |
|
2538 rmeta = receiver->metaObject(); |
2556 switch (membcode) { |
2539 switch (membcode) { |
2557 case QSLOT_CODE: |
2540 case QSLOT_CODE: |
2558 method_index = rmeta->indexOfSlot(method); |
2541 method_index = rmeta->indexOfSlot(method); |
2559 break; |
2542 break; |
2560 case QSIGNAL_CODE: |
2543 case QSIGNAL_CODE: |
2738 bool res = false; |
2721 bool res = false; |
2739 const QMetaObject *smeta = sender->metaObject(); |
2722 const QMetaObject *smeta = sender->metaObject(); |
2740 do { |
2723 do { |
2741 int signal_index = -1; |
2724 int signal_index = -1; |
2742 if (signal) { |
2725 if (signal) { |
2743 signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signal); |
2726 signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signal, false); |
|
2727 if (signal_index < 0) |
|
2728 signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signal, true); |
2744 if (signal_index < 0) |
2729 if (signal_index < 0) |
2745 break; |
2730 break; |
2746 signal_index = QMetaObjectPrivate::originalClone(smeta, signal_index); |
2731 signal_index = QMetaObjectPrivate::originalClone(smeta, signal_index); |
2747 int signalOffset, methodOffset; |
2732 int signalOffset, methodOffset; |
2748 computeOffsets(smeta, &signalOffset, &methodOffset); |
2733 computeOffsets(smeta, &signalOffset, &methodOffset); |
3219 if (qt_signal_spy_callback_set.signal_begin_callback != 0) { |
3204 if (qt_signal_spy_callback_set.signal_begin_callback != 0) { |
3220 qt_signal_spy_callback_set.signal_begin_callback(sender, signal_absolute_index, |
3205 qt_signal_spy_callback_set.signal_begin_callback(sender, signal_absolute_index, |
3221 argv ? argv : empty_argv); |
3206 argv ? argv : empty_argv); |
3222 } |
3207 } |
3223 |
3208 |
|
3209 QThreadData *currentThreadData = QThreadData::current(); |
|
3210 |
3224 QMutexLocker locker(signalSlotLock(sender)); |
3211 QMutexLocker locker(signalSlotLock(sender)); |
3225 QThreadData *currentThreadData = QThreadData::current(); |
|
3226 |
|
3227 QObjectConnectionListVector *connectionLists = sender->d_func()->connectionLists; |
3212 QObjectConnectionListVector *connectionLists = sender->d_func()->connectionLists; |
3228 if (!connectionLists) { |
3213 if (!connectionLists) { |
3229 locker.unlock(); |
3214 locker.unlock(); |
3230 if (qt_signal_spy_callback_set.signal_end_callback != 0) |
3215 if (qt_signal_spy_callback_set.signal_end_callback != 0) |
3231 qt_signal_spy_callback_set.signal_end_callback(sender, signal_absolute_index); |
3216 qt_signal_spy_callback_set.signal_end_callback(sender, signal_absolute_index); |
3317 --connectionLists->inUse; |
3302 --connectionLists->inUse; |
3318 Q_ASSERT(connectionLists->inUse >= 0); |
3303 Q_ASSERT(connectionLists->inUse >= 0); |
3319 if (connectionLists->orphaned) { |
3304 if (connectionLists->orphaned) { |
3320 if (!connectionLists->inUse) |
3305 if (!connectionLists->inUse) |
3321 delete connectionLists; |
3306 delete connectionLists; |
3322 } else { |
3307 } else if (connectionLists->dirty) { |
3323 sender->d_func()->cleanConnectionLists(); |
3308 sender->d_func()->cleanConnectionLists(); |
3324 } |
3309 } |
3325 |
3310 |
3326 locker.unlock(); |
3311 locker.unlock(); |
3327 |
3312 |
3361 */ |
3346 */ |
3362 int QObjectPrivate::signalIndex(const char *signalName) const |
3347 int QObjectPrivate::signalIndex(const char *signalName) const |
3363 { |
3348 { |
3364 Q_Q(const QObject); |
3349 Q_Q(const QObject); |
3365 const QMetaObject *base = q->metaObject(); |
3350 const QMetaObject *base = q->metaObject(); |
3366 int relative_index = QMetaObjectPrivate::indexOfSignalRelative(&base, signalName); |
3351 int relative_index = QMetaObjectPrivate::indexOfSignalRelative(&base, signalName, false); |
|
3352 if (relative_index < 0) |
|
3353 relative_index = QMetaObjectPrivate::indexOfSignalRelative(&base, signalName, true); |
3367 if (relative_index < 0) |
3354 if (relative_index < 0) |
3368 return relative_index; |
3355 return relative_index; |
3369 relative_index = QMetaObjectPrivate::originalClone(base, relative_index); |
3356 relative_index = QMetaObjectPrivate::originalClone(base, relative_index); |
3370 int signalOffset, methodOffset; |
3357 int signalOffset, methodOffset; |
3371 computeOffsets(base, &signalOffset, &methodOffset); |
3358 computeOffsets(base, &signalOffset, &methodOffset); |