diff options
Diffstat (limited to 'src/kernel/qobject.cpp')
-rw-r--r-- | src/kernel/qobject.cpp | 328 |
1 files changed, 285 insertions, 43 deletions
diff --git a/src/kernel/qobject.cpp b/src/kernel/qobject.cpp index 61ed4e7e7..3d9ef0b1c 100644 --- a/src/kernel/qobject.cpp +++ b/src/kernel/qobject.cpp @@ -50,22 +50,107 @@ #include "ntqptrvector.h" #ifdef QT_THREAD_SUPPORT -#include <ntqmutex.h> +#include "ntqmutex.h" #include <private/qmutexpool_p.h> +#include "ntqthread.h" #endif #include <ctype.h> - +#include <stdlib.h> #ifndef QT_NO_USERDATA class TQObjectPrivate : public TQPtrVector<TQObjectUserData> +#else +class TQObjectPrivate { +#endif { public: +#ifndef QT_NO_USERDATA TQObjectPrivate( uint s ) : TQPtrVector<TQObjectUserData>(s){ setAutoDelete( TRUE ); } +#endif + TQThread* ownThread; }; -#else -class TQObjectPrivate { + +#if defined(QT_THREAD_SUPPORT) + +void TQObject::moveToThread_helper(TQThread *targetThread) +{ + TQEvent e(TQEvent::ThreadChange); + TQApplication::sendEvent(this, &e); + + if (childObjects) { + TQObject *child; + TQObjectListIt it(*childObjects); + while ( (child=it.current()) ) { + ++it; + child->moveToThread_helper(targetThread); + } + } +} + +void TQObject::setThreadObject_helper(TQThread *targetThread) +{ + d->ownThread = targetThread; + + if (childObjects) { + TQObject *child; + TQObjectListIt 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 TQApplication::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 TQObject::moveToThread(TQThread *targetThread) +{ + TQMutexLocker locker( TQApplication::tqt_mutex ); + + if (parentObj) { +#if defined(QT_DEBUG) + tqWarning( "TQObject::moveToThread: Cannot move objects with a parent" ); +#endif + return; + } + if (isWidget) { +#if defined(QT_DEBUG) + tqWarning( "TQObject::moveToThread: Widgets cannot be moved to a new thread" ); +#endif + return; + } + + TQThread *objectThread = contextThreadObject(); + TQThread *currentThread = TQThread::currentThreadObject(); + + if (objectThread != currentThread) { +#if defined(QT_DEBUG) + tqWarning( "TQObject::moveToThread: Current thread is not the object's thread" ); +#endif + return; + } + + if (objectThread == targetThread) { + return; + } + + moveToThread_helper(targetThread); + setThreadObject_helper(targetThread); } + #endif class TQSenderObjectList : public TQObjectList, public TQShared @@ -75,6 +160,41 @@ public: TQObject *currentSender; }; +class Q_EXPORT TQMetaCallEvent : public TQEvent +{ +public: + enum MetaCallType { + MetaCallEmit = 0, + MetaCallInvoke = 1 + }; + +public: + TQMetaCallEvent(int id, TQObject *sender, TQUObject *data, MetaCallType type); + ~TQMetaCallEvent(); + + inline int id() const { return id_; } + inline TQObject *sender() const { return sender_; } + inline TQUObject *data() const { return data_; } + inline MetaCallType type() const { return type_; } + +private: + const int id_; + TQObject *sender_; + TQUObject *data_; + const MetaCallType type_; +}; + +/*! \internal + */ +TQMetaCallEvent::TQMetaCallEvent(int id, TQObject *sender, TQUObject *data, MetaCallType type) + :TQEvent(MetaCall), id_(id), sender_(sender), data_(data), type_(type) +{ } + +/*! \internal + */ +TQMetaCallEvent::~TQMetaCallEvent() +{ } + /*! \class TQt ntqnamespace.h @@ -269,7 +389,21 @@ void *tqt_find_obj_child( TQObject *parent, const char *type, const char *name ) return 0; } +#ifdef QT_THREAD_SUPPORT +/*! + Returns a pointer to the TQThread* associated with + the current thread affinity of this object. + + \sa moveToThread() + */ + +TQThread* TQObject::contextThreadObject() const +{ + return d->ownThread; +} + +#endif #ifndef QT_NO_PRELIMINARY_SIGNAL_SPY /* @@ -436,6 +570,11 @@ TQObject::TQObject( TQObject *parent, const char *name ) insert_tree( this ); isTree = TRUE; } + + if ( !d ) + d = new TQObjectPrivate(0); + + d->ownThread = TQThread::currentThreadObject(); } @@ -720,6 +859,36 @@ TQObject* TQObject::child( const char *objName, const char *inheritsClass, return obj; } +/*! \internal */ +TQUObject* deepCopyTQUObjectArray(TQUObject* origArray) +{ + TQUObject* newArray; + int count = 0; + while (!((origArray+count)->isLastObject)) { + count++; + } + count++; + newArray = (TQUObject*)malloc(sizeof(TQUObject)*count); + for (int i=0; i<count; i++) { + (origArray+i)->deepCopy(newArray+i); + } + return newArray; +} + +/*! \internal */ +void destroyDeepCopiedTQUObjectArray(TQUObject* uArray) +{ + int count = 0; + while (!((uArray+count)->isLastObject)) { + count++; + } + count++; + for (int i=0; i<count; i++) { + (uArray+i)->~TQUObject(); + } + free(uArray); +} + /*! \fn bool TQObject::isWidgetType() const @@ -777,6 +946,40 @@ bool TQObject::event( TQEvent *e ) delete this; return TRUE; + case TQEvent::MetaCall: + { + TQMetaCallEvent* metaEvent = dynamic_cast<TQMetaCallEvent*>(e); + if (metaEvent) { + if (d->ownThread == TQThread::currentThreadObject()) { + TQSenderObjectList* sol; + TQObject* oldSender = 0; + sol = senderObjects; + if ( sol ) { + oldSender = sol->currentSender; + sol->ref(); + sol->currentSender = metaEvent->sender(); + } + TQUObject *o = metaEvent->data(); + if (metaEvent->type() == TQMetaCallEvent::MetaCallEmit) { + tqt_emit( metaEvent->id(), o ); + } + if (metaEvent->type() == TQMetaCallEvent::MetaCallInvoke) { + tqt_invoke( metaEvent->id(), o ); + } + if (sol ) { + sol->currentSender = oldSender; + if ( sol->deref() ) { + delete sol; + } + } + } + else { + tqWarning("TQObject: Ignoring metacall event from non-owning thread"); + } + destroyDeepCopiedTQUObjectArray(metaEvent->data()); + } + } + default: if ( e->type() >= TQEvent::User ) { customEvent( (TQCustomEvent*) e ); @@ -2337,6 +2540,7 @@ void TQObject::activate_signal( int signal ) if ( !signalsBlocked() && signal >= 0 && ( !connections || !connections->at( signal ) ) ) { TQUObject o[1]; + o[0].isLastObject = true; qt_spy_signal( this, signal, o ); return; } @@ -2349,6 +2553,7 @@ void TQObject::activate_signal( int signal ) if ( !clist ) return; TQUObject o[1]; + o[0].isLastObject = true; activate_signal( clist, o ); } @@ -2364,6 +2569,8 @@ void TQObject::activate_signal( TQConnectionList *clist, TQUObject *o ) qt_spy_signal( this, connections->findRef( clist), o ); #endif + const TQThread *currentThread = TQThread::currentThreadObject(); + TQObject *object; TQSenderObjectList* sol; TQObject* oldSender = 0; @@ -2377,10 +2584,26 @@ void TQObject::activate_signal( TQConnectionList *clist, TQUObject *o ) sol->ref(); sol->currentSender = this; } - if ( c->memberType() == TQSIGNAL_CODE ) - object->tqt_emit( c->member(), o ); - else - object->tqt_invoke( c->member(), o ); + if ( c->memberType() == TQSIGNAL_CODE ) { + if (object->d->ownThread == currentThread) { + object->tqt_emit( c->member(), o ); + } + else { + if (object->d->ownThread && !object->d->ownThread->finished()) { + TQApplication::postEvent(object, new TQMetaCallEvent(c->member(), this, deepCopyTQUObjectArray(o), TQMetaCallEvent::MetaCallEmit)); + } + } + } + else { + if (object->d->ownThread == currentThread) { + object->tqt_invoke( c->member(), o ); + } + else { + if (object->d->ownThread && !object->d->ownThread->finished()) { + TQApplication::postEvent(object, new TQMetaCallEvent(c->member(), this, deepCopyTQUObjectArray(o), TQMetaCallEvent::MetaCallInvoke)); + } + } + } if ( sol ) { sol->currentSender = oldSender; if ( sol->deref() ) @@ -2401,10 +2624,26 @@ void TQObject::activate_signal( TQConnectionList *clist, TQUObject *o ) sol->ref(); sol->currentSender = this; } - if ( c->memberType() == TQSIGNAL_CODE ) - object->tqt_emit( c->member(), o ); - else - object->tqt_invoke( c->member(), o ); + if ( c->memberType() == TQSIGNAL_CODE ) { + if (object->d->ownThread == currentThread) { + object->tqt_emit( c->member(), o ); + } + else { + if (object->d->ownThread && !object->d->ownThread->finished()) { + TQApplication::postEvent(object, new TQMetaCallEvent(c->member(), this, deepCopyTQUObjectArray(o), TQMetaCallEvent::MetaCallEmit)); + } + } + } + else { + if (object->d->ownThread == currentThread) { + object->tqt_invoke( c->member(), o ); + } + else { + if (object->d->ownThread && !object->d->ownThread->finished()) { + TQApplication::postEvent(object, new TQMetaCallEvent(c->member(), this, deepCopyTQUObjectArray(o), TQMetaCallEvent::MetaCallInvoke)); + } + } + } if (sol ) { sol->currentSender = oldSender; if ( sol->deref() ) @@ -2435,39 +2674,42 @@ void TQObject::activate_signal( TQConnectionList *clist, TQUObject *o ) */ #ifndef QT_NO_PRELIMINARY_SIGNAL_SPY -#define ACTIVATE_SIGNAL_WITH_PARAM(FNAME,TYPE) \ -void TQObject::FNAME( int signal, TYPE param ) \ -{ \ - if ( tqt_preliminary_signal_spy ) { \ - if ( !signalsBlocked() && signal >= 0 && \ - ( !connections || !connections->at( signal ) ) ) { \ - TQUObject o[2]; \ - static_QUType_##TYPE.set( o+1, param ); \ - qt_spy_signal( this, signal, o ); \ - return; \ - } \ - } \ - if ( !connections || signalsBlocked() || signal < 0 ) \ - return; \ - TQConnectionList *clist = connections->at( signal ); \ - if ( !clist ) \ - return; \ - TQUObject o[2]; \ - static_QUType_##TYPE.set( o+1, param ); \ - activate_signal( clist, o ); \ +#define ACTIVATE_SIGNAL_WITH_PARAM(FNAME,TYPE) \ +void TQObject::FNAME( int signal, TYPE param ) \ +{ \ + if ( tqt_preliminary_signal_spy ) { \ + if ( !signalsBlocked() && signal >= 0 && \ + ( !connections || !connections->at( signal ) ) ) { \ + TQUObject o[2]; \ + o[1].isLastObject = true; \ + static_QUType_##TYPE.set( o+1, param ); \ + qt_spy_signal( this, signal, o ); \ + return; \ + } \ + } \ + if ( !connections || signalsBlocked() || signal < 0 ) \ + return; \ + TQConnectionList *clist = connections->at( signal ); \ + if ( !clist ) \ + return; \ + TQUObject o[2]; \ + o[1].isLastObject = true; \ + static_QUType_##TYPE.set( o+1, param ); \ + activate_signal( clist, o ); \ } #else -#define ACTIVATE_SIGNAL_WITH_PARAM(FNAME,TYPE) \ -void TQObject::FNAME( int signal, TYPE param ) \ -{ \ - if ( !connections || signalsBlocked() || signal < 0 ) \ - return; \ - TQConnectionList *clist = connections->at( signal ); \ - if ( !clist ) \ - return; \ - TQUObject o[2]; \ - static_QUType_##TYPE.set( o+1, param ); \ - activate_signal( clist, o ); \ +#define ACTIVATE_SIGNAL_WITH_PARAM(FNAME,TYPE) \ +void TQObject::FNAME( int signal, TYPE param ) \ +{ \ + if ( !connections || signalsBlocked() || signal < 0 ) \ + return; \ + TQConnectionList *clist = connections->at( signal ); \ + if ( !clist ) \ + return; \ + TQUObject o[2]; \ + o[1].isLastObject = true; \ + static_QUType_##TYPE.set( o+1, param ); \ + activate_signal( clist, o ); \ } #endif |