diff --git a/src/kernel/ntqapplication.h b/src/kernel/ntqapplication.h index cdb7fdfc..557658ae 100644 --- a/src/kernel/ntqapplication.h +++ b/src/kernel/ntqapplication.h @@ -63,6 +63,7 @@ class TQWSDecoration; #ifdef QT_THREAD_SUPPORT class TQMutex; +class TQThread; #endif // QT_THREAD_SUPPORT @@ -369,7 +370,9 @@ private: #ifndef QT_NO_CURSOR static TQCursor *app_cursor; #endif +#ifndef QT_THREAD_SUPPORT static TQEventLoop* eventloop; +#endif static int app_tracking; static bool is_app_running; static bool is_app_closing; @@ -425,6 +428,7 @@ private: static void removePostedEvent( TQEvent * ); static void removePostedEvents( TQObject *receiver, int event_type ); + friend class TQObject; friend class TQWidget; friend class TQETWidget; friend class TQDialog; @@ -444,6 +448,15 @@ private: // Disabled copy constructor and operator= TQApplication( const TQApplication & ); TQApplication &operator=( const TQApplication & ); #endif + +private: + static TQEventLoop* currentEventLoop(); + +public: +#ifdef QT_THREAD_SUPPORT + static TQThread* guiThread(); +#endif + static bool isGuiThread(); }; inline int TQApplication::argc() const diff --git a/src/kernel/ntqevent.h b/src/kernel/ntqevent.h index 08dc69b6..566575ca 100644 --- a/src/kernel/ntqevent.h +++ b/src/kernel/ntqevent.h @@ -137,6 +137,8 @@ public: HelpRequest = 95, // CE (?) button pressed WindowStateChange = 96, // window state has changed IconDrag = 97, // proxy icon dragged + MetaCall = 98, // meta method call (internal) + ThreadChange = 99, // thread changed User = 1000, // first user event id MaxUser = 65535 // last user event id }; diff --git a/src/kernel/ntqobject.h b/src/kernel/ntqobject.h index 5b64e2d0..943e8319 100644 --- a/src/kernel/ntqobject.h +++ b/src/kernel/ntqobject.h @@ -63,6 +63,10 @@ class TQObjectUserData; #endif struct TQUObject; +#ifdef QT_THREAD_SUPPORT +class TQThread; +#endif + class Q_EXPORT TQObject: public TQt { TQ_OBJECT @@ -217,6 +221,18 @@ private: // Disabled copy constructor and operator= TQObject( const TQObject & ); TQObject &operator=( const TQObject & ); #endif + +public: +#ifdef QT_THREAD_SUPPORT + TQThread* contextThreadObject() const; + void moveToThread(TQThread *targetThread); +#endif + +private: +#ifdef QT_THREAD_SUPPORT + void moveToThread_helper(TQThread *targetThread); + void setThreadObject_helper(TQThread *targetThread); +#endif }; diff --git a/src/kernel/ntqthread.h b/src/kernel/ntqthread.h index c3679fbc..824578c2 100644 --- a/src/kernel/ntqthread.h +++ b/src/kernel/ntqthread.h @@ -118,11 +118,25 @@ protected: private: TQThreadInstance * d; friend class TQThreadInstance; + friend class TQCoreApplicationThread; + friend class TQApplication; + friend class TQEventLoop; #if defined(TQ_DISABLE_COPY) TQThread( const TQThread & ); TQThread &operator=( const TQThread & ); #endif // TQ_DISABLE_COPY + +public: + static TQThread* currentThreadObject(); +}; + +class Q_EXPORT TQEventLoopThread : public TQThread +{ + public: + TQEventLoopThread(); + ~TQEventLoopThread(); + virtual void run(); }; #endif // QT_THREAD_SUPPORT diff --git a/src/kernel/qapplication.cpp b/src/kernel/qapplication.cpp index a552c236..5b57bd24 100644 --- a/src/kernel/qapplication.cpp +++ b/src/kernel/qapplication.cpp @@ -68,6 +68,7 @@ #if defined(QT_THREAD_SUPPORT) # include "ntqmutex.h" # include "ntqthread.h" +# include #endif // QT_THREAD_SUPPORT #include @@ -383,7 +384,25 @@ Q_EXPORT TQt::HANDLE tqt_get_application_thread_id() } #endif // QT_THREAD_SUPPORT +#ifndef QT_THREAD_SUPPORT TQEventLoop *TQApplication::eventloop = 0; // application event loop +#endif + +#ifdef QT_THREAD_SUPPORT +TQEventLoop* TQApplication::currentEventLoop() { + TQThread* thread = TQThread::currentThreadObject(); + if (thread) { + if (thread->d) { + return thread->d->eventLoop; + } + } + return NULL; +} +#else +TQEventLoop* TQApplication::currentEventLoop() { + return TQApplication::eventloop; +} +#endif #ifndef QT_NO_ACCEL extern bool tqt_dispatchAccelEvent( TQWidget*, TQKeyEvent* ); // def in qaccel.cpp @@ -516,6 +535,41 @@ TQClipboard *tqt_clipboard = 0; // global clipboard object #endif TQWidgetList * tqt_modal_stack=0; // stack of modal widgets +#ifdef QT_THREAD_SUPPORT +// thread wrapper for the main() thread +class TQCoreApplicationThread : public TQThread +{ +public: + inline TQCoreApplicationThread() + { + TQThreadInstance::setCurrentThread(this); + + // thread should be running and not finished for the lifetime + // of the application (even if QCoreApplication goes away) + d->running = true; + d->finished = false; + d->eventLoop = NULL; + } + inline ~TQCoreApplicationThread() + { + // avoid warning from TQThread + d->running = false; + } +private: + inline void run() + { + // this function should never be called, it is implemented + // only so that we can instantiate the object + tqFatal("TQCoreApplicationThread: internal error"); + } +}; + +static TQCoreApplicationThread tqt_main_thread; +static TQThread *mainThread() { return &tqt_main_thread; } +#else +static TQThread* mainThread() { return TQThread::currentThread(); } +#endif + // Definitions for posted events struct TQPostEvent { TQPostEvent( TQObject *r, TQEvent *e ): receiver( r ), event( e ) {} @@ -818,8 +872,8 @@ void TQApplication::construct( int &argc, char **argv, Type type ) initialize( argc, argv ); if ( tqt_is_gui_used ) tqt_maxWindowRect = desktop()->rect(); - if ( eventloop ) - eventloop->appStartingUp(); + if ( currentEventLoop() ) + currentEventLoop()->appStartingUp(); } /*! @@ -874,8 +928,8 @@ TQApplication::TQApplication( Display* dpy, HANDLE visual, HANDLE colormap ) if ( tqt_is_gui_used ) tqt_maxWindowRect = desktop()->rect(); - if ( eventloop ) - eventloop->appStartingUp(); + if ( currentEventLoop() ) + currentEventLoop()->appStartingUp(); } /*! @@ -916,13 +970,26 @@ TQApplication::TQApplication(Display *dpy, int argc, char **argv, if ( tqt_is_gui_used ) tqt_maxWindowRect = desktop()->rect(); - if ( eventloop ) - eventloop->appStartingUp(); + if ( currentEventLoop() ) + currentEventLoop()->appStartingUp(); } #endif // Q_WS_X11 +#ifdef QT_THREAD_SUPPORT +TQThread* TQApplication::guiThread() { + return mainThread(); +} + +bool TQApplication::isGuiThread() { + return (TQThread::currentThreadObject() == guiThread()); +} +#else +bool TQApplication::isGuiThread() { + return true; +} +#endif void TQApplication::init_precmdline() { @@ -1030,8 +1097,8 @@ TQApplication::~TQApplication() } #endif - if ( eventloop ) - eventloop->appClosingDown(); + if ( currentEventLoop() ) + currentEventLoop()->appClosingDown(); if ( postRList ) { TQVFuncList::Iterator it = postRList->begin(); while ( it != postRList->end() ) { // call post routines @@ -2698,8 +2765,20 @@ bool TQApplication::internalNotify( TQObject *receiver, TQEvent * e) } - if (!handled) + if (!handled) { +#if defined(QT_THREAD_SUPPORT) + bool locked = TQApplication::tqt_mutex->locked(); + if (locked) { + TQApplication::tqt_mutex->unlock(); + } +#endif consumed = receiver->event( e ); +#if defined(QT_THREAD_SUPPORT) + if (locked) { + TQApplication::tqt_mutex->lock(); + } +#endif + } e->spont = FALSE; return consumed; } @@ -2793,9 +2872,10 @@ void TQApplication::processOneEvent() */ TQEventLoop *TQApplication::eventLoop() { - if ( !eventloop && !is_app_closing ) + if ( !currentEventLoop() && !is_app_closing ) { (void) new TQEventLoop( tqApp, "default event loop" ); - return eventloop; + } + return currentEventLoop(); } @@ -3263,8 +3343,23 @@ void TQApplication::postEvent( TQObject *receiver, TQEvent *event ) l->append( pe ); globalPostedEvents->append( pe ); - if (eventloop) - eventloop->wakeUp(); +#ifdef QT_THREAD_SUPPORT + if ( event->type() == TQEvent::MetaCall ) { + // Wake up the receiver thread event loop + TQThread* thread = receiver->contextThreadObject(); + if (thread) { + if (thread->d) { + if (thread->d->eventLoop) { + thread->d->eventLoop->wakeUp(); + } + } + } + return; + } +#endif + + if (currentEventLoop()) + currentEventLoop()->wakeUp(); } @@ -3326,7 +3421,8 @@ void TQApplication::sendPostedEvents( TQObject *receiver, int event_type ) && ( receiver == 0 // we send to all receivers || receiver == pe->receiver ) // we send to THAT receiver && ( event_type == 0 // we send all types - || event_type == pe->event->type() ) ) { // we send THAT type + || event_type == pe->event->type() ) // we send THAT type + && ( (!pe->receiver) || (pe->receiver->contextThreadObject() == TQThread::currentThreadObject()) ) ) { // only send if active thread is receiver object owning thread // first, we diddle the event so that we can deliver // it, and that noone will try to touch it later. pe->event->posted = FALSE; diff --git a/src/kernel/qeventloop.cpp b/src/kernel/qeventloop.cpp index 4824f571..e13a0e92 100644 --- a/src/kernel/qeventloop.cpp +++ b/src/kernel/qeventloop.cpp @@ -41,6 +41,11 @@ #include "ntqapplication.h" #include "ntqdatetime.h" +#ifdef QT_THREAD_SUPPORT +# include "ntqthread.h" +# include "qthreadinstance_p.h" +#endif + /*! \class TQEventLoop \brief The TQEventLoop class manages the event queue. @@ -100,15 +105,27 @@ TQEventLoop::TQEventLoop( TQObject *parent, const char *name ) : TQObject( parent, name ) { #if defined(QT_CHECK_STATE) - if ( TQApplication::eventloop ) - tqFatal( "TQEventLoop: there must be only one event loop object. \nConstruct it before TQApplication." ); - // for now ;) + if ( TQApplication::currentEventLoop() ) + tqFatal( "TQEventLoop: there must be only one event loop object per thread. \nIf this is supposed to be the main GUI event loop, construct it before TQApplication." ); + if (!TQThread::currentThreadObject()) { + tqFatal( "TQEventLoop: this object can only be used in threads constructed via TQThread." ); + } #endif // QT_CHECK_STATE d = new TQEventLoopPrivate; init(); + +#ifdef QT_THREAD_SUPPORT + TQThread* thread = TQThread::currentThreadObject(); + if (thread) { + if (thread->d) { + thread->d->eventLoop = this; + } + } +#else TQApplication::eventloop = this; +#endif } /*! @@ -118,7 +135,16 @@ TQEventLoop::~TQEventLoop() { cleanup(); delete d; +#ifdef QT_THREAD_SUPPORT + TQThread* thread = TQThread::currentThreadObject(); + if (thread) { + if (thread->d) { + thread->d->eventLoop = 0; + } + } +#else TQApplication::eventloop = 0; +#endif } /*! diff --git a/src/kernel/qeventloop_unix.cpp b/src/kernel/qeventloop_unix.cpp index aa13ef8b..ccdbb4b8 100644 --- a/src/kernel/qeventloop_unix.cpp +++ b/src/kernel/qeventloop_unix.cpp @@ -40,6 +40,7 @@ #include "ntqeventloop.h" #include "ntqapplication.h" #include "ntqbitarray.h" +#include "ntqmutex.h" #include #include diff --git a/src/kernel/qeventloop_unix_glib.cpp b/src/kernel/qeventloop_unix_glib.cpp index cdf9f03c..9f89332e 100644 --- a/src/kernel/qeventloop_unix_glib.cpp +++ b/src/kernel/qeventloop_unix_glib.cpp @@ -44,6 +44,7 @@ #include "ntqeventloop.h" #include "ntqapplication.h" #include "ntqbitarray.h" +#include "ntqmutex.h" #include #include @@ -578,17 +579,14 @@ int TQEventLoop::activateSocketNotifiers() while ( (sn=it.current()) ) { ++it; d->sn_pending_list.removeRef( sn ); - if ( sn->pending ) { - - #ifdef DEBUG_QT_GLIBMAINLOOP - printf("activate sn : send event fd=%d\n", sn->gPollFD.fd ); - #endif - - - sn->pending = FALSE; - TQApplication::sendEvent( sn->obj, &event ); - n_act++; - } + if ( sn->pending ) { +#ifdef DEBUG_QT_GLIBMAINLOOP + printf("activate sn : send event fd=%d\n", sn->gPollFD.fd ); +#endif + sn->pending = FALSE; + TQApplication::sendEvent( sn->obj, &event ); + n_act++; + } } return n_act; diff --git a/src/kernel/qeventloop_x11.cpp b/src/kernel/qeventloop_x11.cpp index 56542710..a2d8590f 100644 --- a/src/kernel/qeventloop_x11.cpp +++ b/src/kernel/qeventloop_x11.cpp @@ -146,55 +146,57 @@ bool TQEventLoop::processEvents( ProcessEventsFlags flags ) if ( tqt_is_gui_used ) { TQApplication::sendPostedEvents(); - // Two loops so that posted events accumulate - while ( XPending( TQPaintDevice::x11AppDisplay() ) ) { - // also flushes output buffer - while ( XPending( TQPaintDevice::x11AppDisplay() ) ) { - if ( d->shortcut ) { - return FALSE; - } - - XNextEvent( TQPaintDevice::x11AppDisplay(), &event ); - - if ( flags & ExcludeUserInput ) { - switch ( event.type ) { - case ButtonPress: - case ButtonRelease: - case MotionNotify: - case XKeyPress: - case XKeyRelease: - case EnterNotify: - case LeaveNotify: - continue; - - case ClientMessage: - { - // from qapplication_x11.cpp - extern Atom tqt_wm_protocols; - extern Atom tqt_wm_take_focus; - extern Atom qt_qt_scrolldone; - - // only keep the wm_take_focus and - // qt_qt_scrolldone protocols, discard all - // other client messages - if ( event.xclient.format != 32 ) - continue; - - if ( event.xclient.message_type == tqt_wm_protocols || - (Atom) event.xclient.data.l[0] == tqt_wm_take_focus ) - break; - if ( event.xclient.message_type == qt_qt_scrolldone ) - break; + if (TQApplication::isGuiThread()) { + // Two loops so that posted events accumulate + while ( XPending( TQPaintDevice::x11AppDisplay() ) ) { + // also flushes output buffer + while ( XPending( TQPaintDevice::x11AppDisplay() ) ) { + if ( d->shortcut ) { + return FALSE; + } + + XNextEvent( TQPaintDevice::x11AppDisplay(), &event ); + + if ( flags & ExcludeUserInput ) { + switch ( event.type ) { + case ButtonPress: + case ButtonRelease: + case MotionNotify: + case XKeyPress: + case XKeyRelease: + case EnterNotify: + case LeaveNotify: + continue; + + case ClientMessage: + { + // from qapplication_x11.cpp + extern Atom tqt_wm_protocols; + extern Atom tqt_wm_take_focus; + extern Atom qt_qt_scrolldone; + + // only keep the wm_take_focus and + // qt_qt_scrolldone protocols, discard all + // other client messages + if ( event.xclient.format != 32 ) + continue; + + if ( event.xclient.message_type == tqt_wm_protocols || + (Atom) event.xclient.data.l[0] == tqt_wm_take_focus ) + break; + if ( event.xclient.message_type == qt_qt_scrolldone ) + break; + } + + default: break; + } + } + + nevents++; + if ( tqApp->x11ProcessEvent( &event ) == 1 ) + return TRUE; } - - default: break; - } } - - nevents++; - if ( tqApp->x11ProcessEvent( &event ) == 1 ) - return TRUE; - } } } @@ -261,7 +263,7 @@ bool TQEventLoop::processEvents( ProcessEventsFlags flags ) FD_ZERO( &d->sn_vec[2].select_fds ); } - if ( tqt_is_gui_used ) { + if ( tqt_is_gui_used && TQApplication::isGuiThread() ) { // select for events on the event socket - only on X11 FD_SET( d->xfd, &d->sn_vec[0].select_fds ); highest = TQMAX( highest, d->xfd ); diff --git a/src/kernel/qeventloop_x11_glib.cpp b/src/kernel/qeventloop_x11_glib.cpp index 11141a3a..bb702b82 100644 --- a/src/kernel/qeventloop_x11_glib.cpp +++ b/src/kernel/qeventloop_x11_glib.cpp @@ -39,7 +39,6 @@ ** **********************************************************************/ - #include "qeventloop_glib_p.h" // includes qplatformdefs.h #include "ntqeventloop.h" #include "ntqapplication.h" @@ -58,23 +57,21 @@ // TQt-GSource Structure and Callbacks typedef struct { - GSource source; - TQEventLoop * qeventLoop; + GSource source; + TQEventLoop * qeventLoop; } TQtGSource; -static gboolean qt_gsource_prepare ( GSource *source, - gint *timeout ); +static gboolean qt_gsource_prepare ( GSource *source, gint *timeout ); static gboolean qt_gsource_check ( GSource *source ); -static gboolean qt_gsource_dispatch ( GSource *source, - GSourceFunc callback, gpointer user_data ); +static gboolean qt_gsource_dispatch ( GSource *source, GSourceFunc callback, gpointer user_data ); static GSourceFuncs qt_gsource_funcs = { - qt_gsource_prepare, - qt_gsource_check, - qt_gsource_dispatch, - NULL, - NULL, - NULL + qt_gsource_prepare, + qt_gsource_check, + qt_gsource_dispatch, + NULL, + NULL, + NULL }; // forward main loop callbacks to TQEventLoop methods! @@ -82,25 +79,25 @@ static GSourceFuncs qt_gsource_funcs = { static gboolean qt_gsource_prepare ( GSource *source, gint *timeout ) { - TQtGSource * qtGSource; + TQtGSource * qtGSource; qtGSource = (TQtGSource*) source; - return qtGSource->qeventLoop->gsourcePrepare(source, timeout); + return qtGSource->qeventLoop->gsourcePrepare(source, timeout); } static gboolean qt_gsource_check ( GSource *source ) { - TQtGSource * qtGSource = (TQtGSource*) source; - return qtGSource->qeventLoop->gsourceCheck(source); + TQtGSource * qtGSource = (TQtGSource*) source; + return qtGSource->qeventLoop->gsourceCheck(source); } static gboolean qt_gsource_dispatch ( GSource *source, GSourceFunc callback, gpointer user_data ) { - Q_UNUSED(callback); - Q_UNUSED(user_data); - - TQtGSource * qtGSource = (TQtGSource*) source; - return qtGSource->qeventLoop->gsourceDispatch(source); + Q_UNUSED(callback); + Q_UNUSED(user_data); + + TQtGSource * qtGSource = (TQtGSource*) source; + return qtGSource->qeventLoop->gsourceDispatch(source); } @@ -134,82 +131,84 @@ static TQVFuncList *qt_postselect_handler = 0; void qt_install_preselect_handler( VFPTR handler ) { - if ( !qt_preselect_handler ) - qt_preselect_handler = new TQVFuncList; - qt_preselect_handler->append( handler ); + if ( !qt_preselect_handler ) { + qt_preselect_handler = new TQVFuncList; + } + qt_preselect_handler->append( handler ); } + void qt_remove_preselect_handler( VFPTR handler ) { - if ( qt_preselect_handler ) { - TQVFuncList::Iterator it = qt_preselect_handler->find( handler ); - if ( it != qt_preselect_handler->end() ) - qt_preselect_handler->remove( it ); - } + if ( qt_preselect_handler ) { + TQVFuncList::Iterator it = qt_preselect_handler->find( handler ); + if ( it != qt_preselect_handler->end() ) { + qt_preselect_handler->remove( it ); + } + } } + void qt_install_postselect_handler( VFPTR handler ) { - if ( !qt_postselect_handler ) - qt_postselect_handler = new TQVFuncList; - qt_postselect_handler->prepend( handler ); + if ( !qt_postselect_handler ) { + qt_postselect_handler = new TQVFuncList; + } + qt_postselect_handler->prepend( handler ); } + void qt_remove_postselect_handler( VFPTR handler ) { - if ( qt_postselect_handler ) { - TQVFuncList::Iterator it = qt_postselect_handler->find( handler ); - if ( it != qt_postselect_handler->end() ) - qt_postselect_handler->remove( it ); - } + if ( qt_postselect_handler ) { + TQVFuncList::Iterator it = qt_postselect_handler->find( handler ); + if ( it != qt_postselect_handler->end() ) { + qt_postselect_handler->remove( it ); + } + } } - void TQEventLoop::init() { // initialize ProcessEventFlags (all events & wait for more) - d->pev_flags = AllEvents | WaitForMore; - // initialize the common parts of the event loop - if (pipe( d->thread_pipe ) < 0) { - // Error! - } - fcntl(d->thread_pipe[0], F_SETFD, FD_CLOEXEC); - fcntl(d->thread_pipe[1], F_SETFD, FD_CLOEXEC); + // initialize the common parts of the event loop + if (pipe( d->thread_pipe ) < 0) { + // Error! + } + fcntl(d->thread_pipe[0], F_SETFD, FD_CLOEXEC); + fcntl(d->thread_pipe[1], F_SETFD, FD_CLOEXEC); - // intitialize the X11 parts of the event loop - d->xfd = -1; - if ( tqt_is_gui_used ) - d->xfd = XConnectionNumber( TQPaintDevice::x11AppDisplay() ); + // intitialize the X11 parts of the event loop + d->xfd = -1; + if ( tqt_is_gui_used && TQApplication::isGuiThread() ) { + d->xfd = XConnectionNumber( TQPaintDevice::x11AppDisplay() ); + } - // new GSource + // new GSource + TQtGSource * qtGSource = (TQtGSource*) g_source_new(&qt_gsource_funcs, sizeof(TQtGSource)); - TQtGSource * qtGSource = (TQtGSource*) g_source_new(&qt_gsource_funcs, - sizeof(TQtGSource)); - - g_source_set_can_recurse ((GSource*)qtGSource, TRUE); + g_source_set_can_recurse ((GSource*)qtGSource, TRUE); + + qtGSource->qeventLoop = this; - qtGSource->qeventLoop = this; - // init main loop and attach gsource - - #ifdef DEBUG_QT_GLIBMAINLOOP - printf("inside init(1)\n"); - #endif - - g_main_loop_new (NULL, 1); - - g_source_attach( (GSource*)qtGSource, NULL ); + +#ifdef DEBUG_QT_GLIBMAINLOOP + printf("inside init(1)\n"); +#endif + + g_main_loop_new (NULL, 1); + + g_source_attach( (GSource*)qtGSource, NULL ); d->gSource = (GSource*) qtGSource; // poll for X11 events - if ( tqt_is_gui_used ) { - - + if ( tqt_is_gui_used && TQApplication::isGuiThread() ) { d->x_gPollFD.fd = d->xfd; d->x_gPollFD.events = G_IO_IN | G_IO_HUP; g_source_add_poll(d->gSource, &d->x_gPollFD); - } + } // poll thread-pipe @@ -218,21 +217,21 @@ void TQEventLoop::init() g_source_add_poll(d->gSource, &d->threadPipe_gPollFD); - #ifdef DEBUG_QT_GLIBMAINLOOP - printf("inside init(2)\n"); - #endif +#ifdef DEBUG_QT_GLIBMAINLOOP + printf("inside init(2)\n"); +#endif } void TQEventLoop::cleanup() { - // cleanup the common parts of the event loop - close( d->thread_pipe[0] ); - close( d->thread_pipe[1] ); - cleanupTimers(); - - // cleanup the X11 parts of the event loop - d->xfd = -1; + // cleanup the common parts of the event loop + close( d->thread_pipe[0] ); + close( d->thread_pipe[1] ); + cleanupTimers(); + + // cleanup the X11 parts of the event loop + d->xfd = -1; // todo: destroy gsource } @@ -240,186 +239,189 @@ void TQEventLoop::cleanup() bool TQEventLoop::processEvents( ProcessEventsFlags flags ) { - #ifdef DEBUG_QT_GLIBMAINLOOP - printf("inside processEvents(1) looplevel=%d\n", d->looplevel ); - #endif - ProcessEventsFlags save_flags; - int rval; - save_flags = d->pev_flags; +#ifdef DEBUG_QT_GLIBMAINLOOP + printf("inside processEvents(1) looplevel=%d\n", d->looplevel ); +#endif - d->pev_flags = flags; - - rval = g_main_context_iteration(NULL, flags & WaitForMore ? TRUE : FALSE); - - d->pev_flags = save_flags; + ProcessEventsFlags save_flags; + int rval; + save_flags = d->pev_flags; - #ifdef DEBUG_QT_GLIBMAINLOOP - printf("inside processEvents(2) looplevel=%d rval=%d\n", d->looplevel, rval ); - #endif + d->pev_flags = flags; - return rval; // were events processed? + rval = g_main_context_iteration(NULL, flags & WaitForMore ? TRUE : FALSE); + + d->pev_flags = save_flags; + +#ifdef DEBUG_QT_GLIBMAINLOOP + printf("inside processEvents(2) looplevel=%d rval=%d\n", d->looplevel, rval ); +#endif + + return rval; // were events processed? } bool TQEventLoop::processX11Events() { ProcessEventsFlags flags = d->pev_flags; - // process events from the X server - XEvent event; - int nevents = 0; + // process events from the X server + XEvent event; + int nevents = 0; #if defined(QT_THREAD_SUPPORT) - TQMutexLocker locker( TQApplication::tqt_mutex ); + TQMutexLocker locker( TQApplication::tqt_mutex ); #endif - // handle gui and posted events - if ( tqt_is_gui_used ) { - TQApplication::sendPostedEvents(); - - // Two loops so that posted events accumulate - while ( XPending( TQPaintDevice::x11AppDisplay() ) ) { - // also flushes output buffer - while ( XPending( TQPaintDevice::x11AppDisplay() ) ) { - if ( d->shortcut ) { - return FALSE; - } - - XNextEvent( TQPaintDevice::x11AppDisplay(), &event ); - - if ( flags & ExcludeUserInput ) { - switch ( event.type ) { - case ButtonPress: - case ButtonRelease: - case MotionNotify: - case XKeyPress: - case XKeyRelease: - case EnterNotify: - case LeaveNotify: - continue; - - case ClientMessage: - { - // from qapplication_x11.cpp - extern Atom tqt_wm_protocols; - extern Atom tqt_wm_take_focus; - extern Atom qt_qt_scrolldone; - - // only keep the wm_take_focus and - // qt_qt_scrolldone protocols, discard all - // other client messages - if ( event.xclient.format != 32 ) - continue; - - if ( event.xclient.message_type == tqt_wm_protocols || - (Atom) event.xclient.data.l[0] == tqt_wm_take_focus ) - break; - if ( event.xclient.message_type == qt_qt_scrolldone ) - break; + // handle gui and posted events + if ( tqt_is_gui_used ) { + TQApplication::sendPostedEvents(); + + if (TQApplication::isGuiThread()) { + // Two loops so that posted events accumulate + while ( XPending( TQPaintDevice::x11AppDisplay() ) ) { + // also flushes output buffer + while ( XPending( TQPaintDevice::x11AppDisplay() ) ) { + if ( d->shortcut ) { + return FALSE; + } + + XNextEvent( TQPaintDevice::x11AppDisplay(), &event ); + + if ( flags & ExcludeUserInput ) { + switch ( event.type ) { + case ButtonPress: + case ButtonRelease: + case MotionNotify: + case XKeyPress: + case XKeyRelease: + case EnterNotify: + case LeaveNotify: + continue; + + case ClientMessage: + { + // from qapplication_x11.cpp + extern Atom tqt_wm_protocols; + extern Atom tqt_wm_take_focus; + extern Atom qt_qt_scrolldone; + + // only keep the wm_take_focus and + // qt_qt_scrolldone protocols, discard all + // other client messages + if ( event.xclient.format != 32 ) + continue; + + if ( event.xclient.message_type == tqt_wm_protocols || + (Atom) event.xclient.data.l[0] == tqt_wm_take_focus ) + break; + if ( event.xclient.message_type == qt_qt_scrolldone ) + break; + } + + default: break; + } + } + + nevents++; + if ( tqApp->x11ProcessEvent( &event ) == 1 ) + return TRUE; + } } - - default: break; - } } - - nevents++; - if ( tqApp->x11ProcessEvent( &event ) == 1 ) - return TRUE; - } } - } - - if ( d->shortcut ) { + + if ( d->shortcut ) { + return FALSE; + } + + TQApplication::sendPostedEvents(); + + const uint exclude_all = ExcludeSocketNotifiers | 0x08; + // 0x08 == ExcludeTimers for X11 only + if ( nevents > 0 && ( flags & exclude_all ) == exclude_all && ( flags & WaitForMore ) ) { + return TRUE; + } return FALSE; - } - - TQApplication::sendPostedEvents(); - - const uint exclude_all = ExcludeSocketNotifiers | 0x08; - // 0x08 == ExcludeTimers for X11 only - if ( nevents > 0 && ( flags & exclude_all ) == exclude_all && - ( flags & WaitForMore ) ) { - return TRUE; - } - return FALSE; } - - + + bool TQEventLoop::gsourcePrepare(GSource *gs, int * timeout) { Q_UNUSED(gs); - #ifdef DEBUG_QT_GLIBMAINLOOP - printf("inside gsourcePrepare(1)\n"); - #endif +#ifdef DEBUG_QT_GLIBMAINLOOP + printf("inside gsourcePrepare(1)\n"); +#endif ProcessEventsFlags flags = d->pev_flags; - + #if defined(QT_THREAD_SUPPORT) - TQMutexLocker locker( TQApplication::tqt_mutex ); + TQMutexLocker locker( TQApplication::tqt_mutex ); #endif - - // don't block if exitLoop() or exit()/quit() has been called. - bool canWait = d->exitloop || d->quitnow ? FALSE : (flags & WaitForMore); - - // Process timers and socket notifiers - the common UNIX stuff - - // return the maximum time we can wait for an event. - static timeval zerotm; - timeval *tm = 0; - if ( ! ( flags & 0x08 ) ) { // 0x08 == ExcludeTimers for X11 only - tm = qt_wait_timer(); // wait for timer or X event - if ( !canWait ) { - if ( !tm ) - tm = &zerotm; - tm->tv_sec = 0; // no time to wait - tm->tv_usec = 0; - } - } - - // include or exclude SocketNotifiers (by setting or cleaning poll events) - - if ( ! ( flags & ExcludeSocketNotifiers ) ) { - TQPtrListIterator it( d->sn_list ); - TQSockNotGPollFD *sn; - while ( (sn=it.current()) ) { - ++it; - sn->gPollFD.events = sn->events; // restore poll events + + // don't block if exitLoop() or exit()/quit() has been called. + bool canWait = d->exitloop || d->quitnow ? FALSE : (flags & WaitForMore); + + // Process timers and socket notifiers - the common UNIX stuff + + // return the maximum time we can wait for an event. + static timeval zerotm; + timeval *tm = 0; + if ( ! ( flags & 0x08 ) ) { // 0x08 == ExcludeTimers for X11 only + tm = qt_wait_timer(); // wait for timer or X event + if ( !canWait ) { + if ( !tm ) { + tm = &zerotm; + } + tm->tv_sec = 0; // no time to wait + tm->tv_usec = 0; } - } else { - TQPtrListIterator it( d->sn_list ); - TQSockNotGPollFD *sn; - while ( (sn=it.current()) ) { - ++it; - sn->gPollFD.events = 0; // delete poll events + } + + // include or exclude SocketNotifiers (by setting or cleaning poll events) + if ( ! ( flags & ExcludeSocketNotifiers ) ) { + TQPtrListIterator it( d->sn_list ); + TQSockNotGPollFD *sn; + while ( (sn=it.current()) ) { + ++it; + sn->gPollFD.events = sn->events; // restore poll events + } + } + else { + TQPtrListIterator it( d->sn_list ); + TQSockNotGPollFD *sn; + while ( (sn=it.current()) ) { + ++it; + sn->gPollFD.events = 0; // delete poll events } } - #ifdef DEBUG_QT_GLIBMAINLOOP - printf("inside gsourcePrepare(2) canwait=%d\n", canWait); - #endif - - if ( canWait ) - emit aboutToBlock(); - +#ifdef DEBUG_QT_GLIBMAINLOOP + printf("inside gsourcePrepare(2) canwait=%d\n", canWait); +#endif - if ( qt_preselect_handler ) { - TQVFuncList::Iterator it, end = qt_preselect_handler->end(); - for ( it = qt_preselect_handler->begin(); it != end; ++it ) - (**it)(); - } + if ( canWait ) { + emit aboutToBlock(); + } - // unlock the GUI mutex and select. when we return from this function, there is - // something for us to do + if ( qt_preselect_handler ) { + TQVFuncList::Iterator it, end = qt_preselect_handler->end(); + for ( it = qt_preselect_handler->begin(); it != end; ++it ) + (**it)(); + } + + // unlock the GUI mutex and select. when we return from this function, there is + // something for us to do #if defined(QT_THREAD_SUPPORT) - locker.mutex()->unlock(); + locker.mutex()->unlock(); #endif - - #ifdef DEBUG_QT_GLIBMAINLOOP - printf("inside gsourcePrepare(2.1) canwait=%d\n", canWait); - #endif - + +#ifdef DEBUG_QT_GLIBMAINLOOP + printf("inside gsourcePrepare(2.1) canwait=%d\n", canWait); +#endif + // do we have to dispatch events? - if (hasPendingEvents()) { + if (hasPendingEvents()) { *timeout = 0; // no time to stay in poll #ifdef DEBUG_QT_GLIBMAINLOOP @@ -427,8 +429,8 @@ bool TQEventLoop::gsourcePrepare(GSource *gs, int * timeout) #endif return FALSE; - } - + } + // stay in poll until something happens? if (!tm) { // fixme *timeout = -1; // wait forever @@ -439,25 +441,24 @@ bool TQEventLoop::gsourcePrepare(GSource *gs, int * timeout) return FALSE; } - + // else timeout >=0 *timeout = tm->tv_sec * 1000 + tm->tv_usec/1000; - #ifdef DEBUG_QT_GLIBMAINLOOP - printf("inside gsourcePrepare(3c) timeout=%d \n", *timeout); - #endif - +#ifdef DEBUG_QT_GLIBMAINLOOP + printf("inside gsourcePrepare(3c) timeout=%d \n", *timeout); +#endif - return FALSE; + return FALSE; } bool TQEventLoop::gsourceCheck(GSource *gs) { Q_UNUSED(gs); - #ifdef DEBUG_QT_GLIBMAINLOOP - printf("inside gsourceCheck(1)\n"); - #endif +#ifdef DEBUG_QT_GLIBMAINLOOP + printf("inside gsourceCheck(1)\n"); +#endif // Socketnotifier events? @@ -476,45 +477,45 @@ bool TQEventLoop::gsourceCheck(GSource *gs) { //} if (d->x_gPollFD.revents) { - #ifdef DEBUG_QT_GLIBMAINLOOP - printf("inside gsourceCheck(2) xfd!\n"); - #endif +#ifdef DEBUG_QT_GLIBMAINLOOP + printf("inside gsourceCheck(2) xfd!\n"); +#endif return TRUE; // we got events! } - if (d->threadPipe_gPollFD.revents) { - #ifdef DEBUG_QT_GLIBMAINLOOP - printf("inside gsourceCheck(2) threadpipe!!\n"); - #endif + if (d->threadPipe_gPollFD.revents) { +#ifdef DEBUG_QT_GLIBMAINLOOP + printf("inside gsourceCheck(2) threadpipe!!\n"); +#endif return TRUE; // we got events! } - if (hasPendingEvents()) { - #ifdef DEBUG_QT_GLIBMAINLOOP - printf("inside gsourceCheck(2) pendingEvents!\n"); - #endif + if (hasPendingEvents()) { +#ifdef DEBUG_QT_GLIBMAINLOOP + printf("inside gsourceCheck(2) pendingEvents!\n"); +#endif return TRUE; // we got more X11 events! } - // check if we have timers to activate? + // check if we have timers to activate? timeval * tm =qt_wait_timer(); - if (tm && (tm->tv_sec == 0 && tm->tv_usec == 0 )) { - #ifdef DEBUG_QT_GLIBMAINLOOP - printf("inside gsourceCheck(2) qtwaittimer!\n"); - #endif - - return TRUE; - } + if (tm && (tm->tv_sec == 0 && tm->tv_usec == 0 )) { +#ifdef DEBUG_QT_GLIBMAINLOOP + printf("inside gsourceCheck(2) qtwaittimer!\n"); +#endif + + return TRUE; + } - // nothing to dispatch + // nothing to dispatch - #ifdef DEBUG_QT_GLIBMAINLOOP - printf("inside gsourceCheck(2) nothing to dispatch!\n"); - #endif +#ifdef DEBUG_QT_GLIBMAINLOOP + printf("inside gsourceCheck(2) nothing to dispatch!\n"); +#endif - return FALSE; + return FALSE; } @@ -533,37 +534,35 @@ bool TQEventLoop::gsourceDispatch(GSource *gs) { ProcessEventsFlags flags = d->pev_flags; - #ifdef DEBUG_QT_GLIBMAINLOOP - printf("inside gsourceDispatch(1)\n"); - #endif - - // we are awake, broadcast it - emit awake(); - emit tqApp->guiThreadAwake(); - - // some other thread woke us up... consume the data on the thread pipe so that - // select doesn't immediately return next time +#ifdef DEBUG_QT_GLIBMAINLOOP + printf("inside gsourceDispatch(1)\n"); +#endif + // we are awake, broadcast it + emit awake(); + emit tqApp->guiThreadAwake(); + + // some other thread woke us up... consume the data on the thread pipe so that + // select doesn't immediately return next time + if ( d->threadPipe_gPollFD.revents) { - char c; - if (::read( d->thread_pipe[0], &c, 1 ) < 0) { - // Error! - } - } + char c; + if (::read( d->thread_pipe[0], &c, 1 ) < 0) { + // Error! + } + } - if ( qt_postselect_handler ) { - TQVFuncList::Iterator it, end = qt_postselect_handler->end(); - for ( it = qt_postselect_handler->begin(); it != end; ++it ) - (**it)(); - } + if ( qt_postselect_handler ) { + TQVFuncList::Iterator it, end = qt_postselect_handler->end(); + for ( it = qt_postselect_handler->begin(); it != end; ++it ) + (**it)(); + } - // activate socket notifiers - if ( ! ( flags & ExcludeSocketNotifiers )) { + // activate socket notifiers + if ( ! ( flags & ExcludeSocketNotifiers )) { // if select says data is ready on any socket, then set the socket notifier // to pending // if ( &d->sn_list ) { - - TQPtrList *list = &d->sn_list; TQSockNotGPollFD *sn = list->first(); while ( sn ) { @@ -572,39 +571,35 @@ bool TQEventLoop::gsourceDispatch(GSource *gs) { sn = list->next(); } // } - + nevents += activateSocketNotifiers(); - } + } - // activate timers - if ( ! ( flags & 0x08 ) ) { + // activate timers + if ( ! ( flags & 0x08 ) ) { // 0x08 == ExcludeTimers for X11 only nevents += activateTimers(); - } - - + } // return true if we handled events, false otherwise //return (nevents > 0); // now process x11 events! - #ifdef DEBUG_QT_GLIBMAINLOOP - printf("inside gsourceDispatch(2) hasPendingEvents=%d\n", hasPendingEvents()); - #endif +#ifdef DEBUG_QT_GLIBMAINLOOP + printf("inside gsourceDispatch(2) hasPendingEvents=%d\n", hasPendingEvents()); +#endif if (hasPendingEvents()) { - // color approx. optimization - only on X11 qt_reset_color_avail(); processX11Events(); - } #if defined(QT_THREAD_SUPPORT) - locker.mutex()->unlock(); + locker.mutex()->unlock(); #endif if (d->singletoolkit) { @@ -617,21 +612,22 @@ bool TQEventLoop::gsourceDispatch(GSource *gs) { bool TQEventLoop::hasPendingEvents() const { - extern uint qGlobalPostedEventsCount(); // from qapplication.cpp - return ( qGlobalPostedEventsCount() || ( tqt_is_gui_used ? XPending( TQPaintDevice::x11AppDisplay() ) : 0)); + extern uint qGlobalPostedEventsCount(); // from qapplication.cpp + return ( qGlobalPostedEventsCount() || ( (tqt_is_gui_used && TQApplication::isGuiThread()) ? XPending( TQPaintDevice::x11AppDisplay() ) : 0)); } void TQEventLoop::appStartingUp() { - if ( tqt_is_gui_used ) - d->xfd = XConnectionNumber( TQPaintDevice::x11AppDisplay() ); + if ( tqt_is_gui_used ) { + d->xfd = XConnectionNumber( TQPaintDevice::x11AppDisplay() ); + } } void TQEventLoop::appClosingDown() { - d->xfd = -1; + d->xfd = -1; } void TQEventLoop::setSingleToolkitEventHandling(bool enabled) { - d->singletoolkit = enabled; + d->singletoolkit = enabled; } \ No newline at end of file diff --git a/src/kernel/qobject.cpp b/src/kernel/qobject.cpp index 61ed4e7e..3d9ef0b1 100644 --- a/src/kernel/qobject.cpp +++ b/src/kernel/qobject.cpp @@ -50,22 +50,107 @@ #include "ntqptrvector.h" #ifdef QT_THREAD_SUPPORT -#include +#include "ntqmutex.h" #include +#include "ntqthread.h" #endif #include - +#include #ifndef QT_NO_USERDATA class TQObjectPrivate : public TQPtrVector +#else +class TQObjectPrivate { +#endif { public: +#ifndef QT_NO_USERDATA TQObjectPrivate( uint s ) : TQPtrVector(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; ideepCopy(newArray+i); + } + return newArray; +} + +/*! \internal */ +void destroyDeepCopiedTQUObjectArray(TQUObject* uArray) +{ + int count = 0; + while (!((uArray+count)->isLastObject)) { + count++; + } + count++; + for (int i=0; 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(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 diff --git a/src/kernel/qthread.cpp b/src/kernel/qthread.cpp index a1719313..fe03ce06 100644 --- a/src/kernel/qthread.cpp +++ b/src/kernel/qthread.cpp @@ -41,6 +41,7 @@ #include "qplatformdefs.h" #include "ntqthread.h" +#include "ntqeventloop.h" #include #ifndef QT_H @@ -238,4 +239,20 @@ void TQThread::postEvent( TQObject * receiver, TQEvent * event ) } #endif +TQEventLoopThread::TQEventLoopThread() : TQThread() +{ + // +} + +TQEventLoopThread::~TQEventLoopThread() +{ + // +} + +void TQEventLoopThread::run() +{ + TQEventLoop* eventLoop = TQApplication::eventLoop(); + if (eventLoop) eventLoop->exec(); +} + #endif // QT_THREAD_SUPPORT diff --git a/src/kernel/qthread_unix.cpp b/src/kernel/qthread_unix.cpp index 73319b64..8cb39a7f 100644 --- a/src/kernel/qthread_unix.cpp +++ b/src/kernel/qthread_unix.cpp @@ -52,11 +52,6 @@ typedef pthread_mutex_t Q_MUTEX_T; #include -static TQThreadInstance main_instance = { - 0, { 0, &main_instance }, 0, 0, 1, 0, PTHREAD_COND_INITIALIZER, 0 -}; - - static TQMutexPool *qt_thread_mutexpool = 0; @@ -82,10 +77,20 @@ static void create_storage_key() ** TQThreadInstance *************************************************************************/ +void TQThreadInstance::setCurrentThread(TQThread *thread) +{ + pthread_once(&storage_key_once, create_storage_key); + pthread_setspecific(storage_key, thread); +} + TQThreadInstance *TQThreadInstance::current() { + TQThreadInstance *ret = NULL; pthread_once( &storage_key_once, create_storage_key ); - TQThreadInstance *ret = (TQThreadInstance *) pthread_getspecific( storage_key ); + TQThread *thread = (TQThread *) pthread_getspecific( storage_key ); + if (thread) { + ret = thread->d; + } return ret; } @@ -101,6 +106,8 @@ void TQThreadInstance::init(unsigned int stackSize) pthread_cond_init(&thread_done, NULL); thread_id = 0; + eventLoop = 0; + // threads have not been initialized yet, do it now if (! qt_thread_mutexpool) TQThread::initialize(); } @@ -114,8 +121,8 @@ void *TQThreadInstance::start( void *_arg ) { void **arg = (void **) _arg; - pthread_once( &storage_key_once, create_storage_key ); - pthread_setspecific( storage_key, arg[1] ); + setCurrentThread( (TQThread *) arg[0] ); + pthread_cleanup_push( TQThreadInstance::finish, arg[1] ); pthread_testcancel(); @@ -192,9 +199,6 @@ void TQThread::initialize() tqt_global_mutexpool = new TQMutexPool( TRUE, 73 ); if ( ! qt_thread_mutexpool ) qt_thread_mutexpool = new TQMutexPool( FALSE, 127 ); - - pthread_once( &storage_key_once, create_storage_key ); - pthread_setspecific( storage_key, &main_instance ); } /*! \internal @@ -206,11 +210,6 @@ void TQThread::cleanup() delete qt_thread_mutexpool; tqt_global_mutexpool = 0; qt_thread_mutexpool = 0; - - TQThreadInstance::finish(&main_instance); - - pthread_once( &storage_key_once, create_storage_key ); - pthread_setspecific( storage_key, 0 ); } /*! @@ -470,5 +469,20 @@ bool TQThread::wait( unsigned long time ) return (ret == 0); } +/*! + Returns a pointer to the currently executing TQThread. If the + current thread was not started using the TQThread API, this + function returns zero. + + Note that TQApplication creates a TQThread object to represent the + main thread; calling this function from main() after creating + TQApplication will return a valid pointer. +*/ +TQThread *TQThread::currentThreadObject() +{ + pthread_once(&storage_key_once, create_storage_key); + return reinterpret_cast(pthread_getspecific(storage_key)); +} + #endif // QT_THREAD_SUPPORT diff --git a/src/kernel/qwidget.cpp b/src/kernel/qwidget.cpp index f7ed299f..f0ff3ed5 100644 --- a/src/kernel/qwidget.cpp +++ b/src/kernel/qwidget.cpp @@ -56,6 +56,9 @@ #include "ntqstyle.h" #include "ntqmetaobject.h" #include "ntqguardedptr.h" +#if defined(QT_THREAD_SUPPORT) +#include "ntqthread.h" +#endif #if defined(QT_ACCESSIBILITY_SUPPORT) #include "ntqaccessible.h" #endif @@ -887,6 +890,12 @@ TQWidget::TQWidget( TQWidget *parent, const char *name, WFlags f, NFlags n ) } #endif +#if defined(QT_THREAD_SUPPORT) && defined(QT_CHECK_STATE) + if (TQThread::currentThreadObject() != TQApplication::guiThread()) { + tqFatal( "TQWidget: Cannot create a TQWidget outside of the main GUI thread" ); + } +#endif + fstrut_dirty = 1; isWidget = TRUE; // is a widget diff --git a/src/moc/moc.y b/src/moc/moc.y index 2826274c..6f773449 100644 --- a/src/moc/moc.y +++ b/src/moc/moc.y @@ -3193,6 +3193,7 @@ void generateClass() // generate C++ source code for a class offset++; } } + fprintf( out, " o[%d].isLastObject = true;\n", f->args->count() + 0 ); fprintf( out, " activate_signal( clist, o );\n" ); // get return values from inOut parameters diff --git a/src/moc/moc_yacc.cpp b/src/moc/moc_yacc.cpp index 83caffeb..8f655dad 100644 --- a/src/moc/moc_yacc.cpp +++ b/src/moc/moc_yacc.cpp @@ -6019,6 +6019,7 @@ void generateClass() // generate C++ source code for a class offset++; } } + fprintf( out, " o[%d].isLastObject = true;\n", f->args->count() + 0 ); fprintf( out, " activate_signal( clist, o );\n" ); // get return values from inOut parameters diff --git a/src/tools/qmutex_unix.cpp b/src/tools/qmutex_unix.cpp index b69661ad..7d22798c 100644 --- a/src/tools/qmutex_unix.cpp +++ b/src/tools/qmutex_unix.cpp @@ -74,7 +74,6 @@ typedef pthread_mutex_t Q_MUTEX_T; #include #include - // Private class declarations class TQRealMutexPrivate : public TQMutexPrivate { diff --git a/src/tools/qthreadinstance_p.h b/src/tools/qthreadinstance_p.h index 62c569c4..98ef3d95 100644 --- a/src/tools/qthreadinstance_p.h +++ b/src/tools/qthreadinstance_p.h @@ -62,8 +62,12 @@ #include #endif +class TQThread; +class TQEventLoop; + class TQThreadInstance { public: + static void setCurrentThread(TQThread *thread); static TQThreadInstance *current(); void init(unsigned int stackSize); @@ -95,6 +99,8 @@ public: static unsigned int __stdcall start( void * ); static void finish( TQThreadInstance * ); #endif // Q_OS_WIN32 + + TQEventLoop* eventLoop; }; #endif // QT_THREAD_SUPPORT diff --git a/src/tools/qucom.cpp b/src/tools/qucom.cpp index 6035d662..d3b26c3f 100644 --- a/src/tools/qucom.cpp +++ b/src/tools/qucom.cpp @@ -39,6 +39,9 @@ **********************************************************************/ #include "qucom_p.h" +#include "qucomextra_p.h" + +#include "ntqvariant.h" // Standard types @@ -545,3 +548,24 @@ void TQUType_TQString::clear( TQUObject *o ) delete (TQString*)o->payload.ptr; o->payload.ptr = 0; } + +TQUObject* TQUObject::deepCopy(TQUObject* newLocation) { + TQUObject* ret; + if (newLocation) { + ret = new(newLocation) TQUObject(*this); + } + else { + ret = new TQUObject(*this); + } + // Any type that has a clear() method must be copied here! + if (*(type->uuid()) == TID_QUType_charstar) { + static_QUType_charstar.set( ret, (const char *)static_QUType_charstar.get(this), true ); + } + if (*(type->uuid()) == TID_QUType_TQString) { + static_QUType_TQString.set( ret, (TQString)static_QUType_TQString.get(this) ); + } + if (*(type->uuid()) == TID_QUType_TQVariant) { + static_QUType_TQVariant.set( ret, (TQVariant)static_QUType_TQVariant.get(this) ); + } + return ret; +} diff --git a/src/tools/qucom_p.h b/src/tools/qucom_p.h index 0814e18d..f4f7ea81 100644 --- a/src/tools/qucom_p.h +++ b/src/tools/qucom_p.h @@ -127,7 +127,7 @@ extern Q_EXPORT TQUType_Null static_QUType_Null; struct Q_EXPORT TQUObject { public: // scary MSVC bug makes this necessary - TQUObject() : type( &static_QUType_Null ) {} + TQUObject() : type( &static_QUType_Null ), isLastObject(false) {} ~TQUObject() { type->clear( this ); } TQUType *type; @@ -184,6 +184,8 @@ public: // scary MSVC bug makes this necessary } payload; + TQUObject* deepCopy(TQUObject*); + bool isLastObject; };