summaryrefslogtreecommitdiffstats
path: root/src/kernel/qobject.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/kernel/qobject.cpp')
-rw-r--r--src/kernel/qobject.cpp328
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