@ -50,22 +50,107 @@
# include "qptrvector.h"
# ifdef QT_THREAD_SUPPORT
# include <qmutex.h>
# include "qmutex.h"
# include <private/qmutexpool_p.h>
# include "qthread.h"
# endif
# include <ctype.h>
# include <stdlib.h>
# ifndef QT_NO_USERDATA
class QObjectPrivate : public QPtrVector < QObjectUserData >
# else
class QObjectPrivate {
# endif
{
public :
# ifndef QT_NO_USERDATA
QObjectPrivate ( uint s ) : QPtrVector < QObjectUserData > ( s ) { setAutoDelete ( TRUE ) ; }
# endif
QThread * ownThread ;
} ;
# else
class QObjectPrivate {
# if defined(QT_THREAD_SUPPORT)
void QObject : : moveToThread_helper ( QThread * targetThread )
{
QEvent e ( QEvent : : ThreadChange ) ;
QApplication : : sendEvent ( this , & e ) ;
if ( childObjects ) {
QObject * child ;
QObjectListIt it ( * childObjects ) ;
while ( ( child = it . current ( ) ) ) {
+ + it ;
child - > moveToThread_helper ( targetThread ) ;
}
}
}
void QObject : : setThreadObject_helper ( QThread * targetThread )
{
d - > ownThread = targetThread ;
if ( childObjects ) {
QObject * child ;
QObjectListIt it ( * childObjects ) ;
while ( ( child = it . current ( ) ) ) {
+ + it ;
child - > moveToThread_helper ( targetThread ) ;
}
}
}
/*!
Changes the thread affinity for this object and its children . The
object cannot be moved if it has a parent . Event processing will
continue in the \ a targetThread . To move an object to the main
thread , pass QApplication : : guiThread ( ) as the \ a targetThread .
Note that all active timers for the object will be reset . The
timers are first stopped in the current thread and restarted ( with
the same interval ) in the \ a targetThread . As a result , constantly
moving an object between threads can postpone timer events
indefinitely .
\ sa contextThreadObject ( )
*/
void QObject : : moveToThread ( QThread * targetThread )
{
QMutexLocker locker ( QApplication : : qt_mutex ) ;
if ( parentObj ) {
# if defined(QT_DEBUG)
qWarning ( " QObject::moveToThread: Cannot move objects with a parent " ) ;
# endif
return ;
}
if ( isWidget ) {
# if defined(QT_DEBUG)
qWarning ( " QObject::moveToThread: Widgets cannot be moved to a new thread " ) ;
# endif
return ;
}
QThread * objectThread = contextThreadObject ( ) ;
QThread * currentThread = QThread : : currentThreadObject ( ) ;
if ( objectThread ! = currentThread ) {
# if defined(QT_DEBUG)
qWarning ( " QObject::moveToThread: Current thread is not the object's thread " ) ;
# endif
return ;
}
if ( objectThread = = targetThread ) {
return ;
}
moveToThread_helper ( targetThread ) ;
setThreadObject_helper ( targetThread ) ;
}
# endif
class QSenderObjectList : public QObjectList , public QShared
@ -75,6 +160,41 @@ public:
QObject * currentSender ;
} ;
class Q_EXPORT QMetaCallEvent : public QEvent
{
public :
enum MetaCallType {
MetaCallEmit = 0 ,
MetaCallInvoke = 1
} ;
public :
QMetaCallEvent ( int id , QObject * sender , QUObject * data , MetaCallType type ) ;
~ QMetaCallEvent ( ) ;
inline int id ( ) const { return id_ ; }
inline QObject * sender ( ) const { return sender_ ; }
inline QUObject * data ( ) const { return data_ ; }
inline MetaCallType type ( ) const { return type_ ; }
private :
const int id_ ;
QObject * sender_ ;
QUObject * data_ ;
const MetaCallType type_ ;
} ;
/*! \internal
*/
QMetaCallEvent : : QMetaCallEvent ( int id , QObject * sender , QUObject * data , MetaCallType type )
: QEvent ( MetaCall ) , id_ ( id ) , sender_ ( sender ) , data_ ( data ) , type_ ( type )
{ }
/*! \internal
*/
QMetaCallEvent : : ~ QMetaCallEvent ( )
{ }
/*!
\ class Qt qnamespace . h
@ -269,7 +389,21 @@ void *qt_find_obj_child( QObject *parent, const char *type, const char *name )
return 0 ;
}
# ifdef QT_THREAD_SUPPORT
/*!
Returns a pointer to the QThread * associated with
the current thread affinity of this object .
\ sa moveToThread ( )
*/
QThread * QObject : : contextThreadObject ( ) const
{
return d - > ownThread ;
}
# endif
# ifndef QT_NO_PRELIMINARY_SIGNAL_SPY
/*
@ -436,6 +570,11 @@ QObject::QObject( QObject *parent, const char *name )
insert_tree ( this ) ;
isTree = TRUE ;
}
if ( ! d )
d = new QObjectPrivate ( 0 ) ;
d - > ownThread = QThread : : currentThreadObject ( ) ;
}
@ -720,6 +859,36 @@ QObject* QObject::child( const char *objName, const char *inheritsClass,
return obj ;
}
/*! \internal */
QUObject * deepCopyQUObjectArray ( QUObject * origArray )
{
QUObject * newArray ;
int count = 0 ;
while ( ! ( ( origArray + count ) - > isLastObject ) ) {
count + + ;
}
count + + ;
newArray = ( QUObject * ) malloc ( sizeof ( QUObject ) * count ) ;
for ( int i = 0 ; i < count ; i + + ) {
( origArray + i ) - > deepCopy ( newArray + i ) ;
}
return newArray ;
}
/*! \internal */
void destroyDeepCopiedQUObjectArray ( QUObject * uArray )
{
int count = 0 ;
while ( ! ( ( uArray + count ) - > isLastObject ) ) {
count + + ;
}
count + + ;
for ( int i = 0 ; i < count ; i + + ) {
( uArray + i ) - > ~ QUObject ( ) ;
}
free ( uArray ) ;
}
/*!
\ fn bool QObject : : isWidgetType ( ) const
@ -777,6 +946,40 @@ bool QObject::event( QEvent *e )
delete this ;
return TRUE ;
case QEvent : : MetaCall :
{
QMetaCallEvent * metaEvent = dynamic_cast < QMetaCallEvent * > ( e ) ;
if ( metaEvent ) {
if ( d - > ownThread = = QThread : : currentThreadObject ( ) ) {
QSenderObjectList * sol ;
QObject * oldSender = 0 ;
sol = senderObjects ;
if ( sol ) {
oldSender = sol - > currentSender ;
sol - > ref ( ) ;
sol - > currentSender = metaEvent - > sender ( ) ;
}
QUObject * o = metaEvent - > data ( ) ;
if ( metaEvent - > type ( ) = = QMetaCallEvent : : MetaCallEmit ) {
qt_emit ( metaEvent - > id ( ) , o ) ;
}
if ( metaEvent - > type ( ) = = QMetaCallEvent : : MetaCallInvoke ) {
qt_invoke ( metaEvent - > id ( ) , o ) ;
}
if ( sol ) {
sol - > currentSender = oldSender ;
if ( sol - > deref ( ) ) {
delete sol ;
}
}
}
else {
qWarning ( " QObject: Ignoring metacall event from non-owning thread " ) ;
}
destroyDeepCopiedQUObjectArray ( metaEvent - > data ( ) ) ;
}
}
default :
if ( e - > type ( ) > = QEvent : : User ) {
customEvent ( ( QCustomEvent * ) e ) ;
@ -2337,6 +2540,7 @@ void QObject::activate_signal( int signal )
if ( ! signalsBlocked ( ) & & signal > = 0 & &
( ! connections | | ! connections - > at ( signal ) ) ) {
QUObject o [ 1 ] ;
o [ 0 ] . isLastObject = true ;
qt_spy_signal ( this , signal , o ) ;
return ;
}
@ -2349,6 +2553,7 @@ void QObject::activate_signal( int signal )
if ( ! clist )
return ;
QUObject o [ 1 ] ;
o [ 0 ] . isLastObject = true ;
activate_signal ( clist , o ) ;
}
@ -2364,6 +2569,8 @@ void QObject::activate_signal( QConnectionList *clist, QUObject *o )
qt_spy_signal ( this , connections - > findRef ( clist ) , o ) ;
# endif
const QThread * currentThread = QThread : : currentThreadObject ( ) ;
QObject * object ;
QSenderObjectList * sol ;
QObject * oldSender = 0 ;
@ -2377,10 +2584,26 @@ void QObject::activate_signal( QConnectionList *clist, QUObject *o )
sol - > ref ( ) ;
sol - > currentSender = this ;
}
if ( c - > memberType ( ) = = QSIGNAL_CODE )
if ( c - > memberType ( ) = = QSIGNAL_CODE ) {
if ( object - > d - > ownThread = = currentThread ) {
object - > qt_emit ( c - > member ( ) , o ) ;
else
}
else {
if ( object - > d - > ownThread & & ! object - > d - > ownThread - > finished ( ) ) {
QApplication : : postEvent ( object , new QMetaCallEvent ( c - > member ( ) , this , deepCopyQUObjectArray ( o ) , QMetaCallEvent : : MetaCallEmit ) ) ;
}
}
}
else {
if ( object - > d - > ownThread = = currentThread ) {
object - > qt_invoke ( c - > member ( ) , o ) ;
}
else {
if ( object - > d - > ownThread & & ! object - > d - > ownThread - > finished ( ) ) {
QApplication : : postEvent ( object , new QMetaCallEvent ( c - > member ( ) , this , deepCopyQUObjectArray ( o ) , QMetaCallEvent : : MetaCallInvoke ) ) ;
}
}
}
if ( sol ) {
sol - > currentSender = oldSender ;
if ( sol - > deref ( ) )
@ -2401,10 +2624,26 @@ void QObject::activate_signal( QConnectionList *clist, QUObject *o )
sol - > ref ( ) ;
sol - > currentSender = this ;
}
if ( c - > memberType ( ) = = QSIGNAL_CODE )
if ( c - > memberType ( ) = = QSIGNAL_CODE ) {
if ( object - > d - > ownThread = = currentThread ) {
object - > qt_emit ( c - > member ( ) , o ) ;
else
}
else {
if ( object - > d - > ownThread & & ! object - > d - > ownThread - > finished ( ) ) {
QApplication : : postEvent ( object , new QMetaCallEvent ( c - > member ( ) , this , deepCopyQUObjectArray ( o ) , QMetaCallEvent : : MetaCallEmit ) ) ;
}
}
}
else {
if ( object - > d - > ownThread = = currentThread ) {
object - > qt_invoke ( c - > member ( ) , o ) ;
}
else {
if ( object - > d - > ownThread & & ! object - > d - > ownThread - > finished ( ) ) {
QApplication : : postEvent ( object , new QMetaCallEvent ( c - > member ( ) , this , deepCopyQUObjectArray ( o ) , QMetaCallEvent : : MetaCallInvoke ) ) ;
}
}
}
if ( sol ) {
sol - > currentSender = oldSender ;
if ( sol - > deref ( ) )
@ -2442,6 +2681,7 @@ void QObject::FNAME( int signal, TYPE param ) \
if ( ! signalsBlocked ( ) & & signal > = 0 & & \
( ! connections | | ! connections - > at ( signal ) ) ) { \
QUObject o [ 2 ] ; \
o [ 1 ] . isLastObject = true ; \
static_QUType_ # # TYPE . set ( o + 1 , param ) ; \
qt_spy_signal ( this , signal , o ) ; \
return ; \
@ -2453,6 +2693,7 @@ void QObject::FNAME( int signal, TYPE param ) \
if ( ! clist ) \
return ; \
QUObject o [ 2 ] ; \
o [ 1 ] . isLastObject = true ; \
static_QUType_ # # TYPE . set ( o + 1 , param ) ; \
activate_signal ( clist , o ) ; \
}
@ -2466,6 +2707,7 @@ void QObject::FNAME( int signal, TYPE param ) \
if ( ! clist ) \
return ; \
QUObject o [ 2 ] ; \
o [ 1 ] . isLastObject = true ; \
static_QUType_ # # TYPE . set ( o + 1 , param ) ; \
activate_signal ( clist , o ) ; \
}