diff options
author | Darrell Anderson <[email protected]> | 2012-12-19 14:03:09 -0600 |
---|---|---|
committer | Darrell Anderson <[email protected]> | 2012-12-19 14:03:09 -0600 |
commit | 35202ed0d899a9ff3c77dad72b501fb30e4dcf93 (patch) | |
tree | 683787f69d937483b860973ce17f0c5d430a142d /src/kernel | |
parent | 8d5add0e87ad913bdf0362a83f431995115f3bfa (diff) | |
parent | f19aa203c934d0f85862fdf810a87fe7c5777d17 (diff) | |
download | qt3-35202ed0d899a9ff3c77dad72b501fb30e4dcf93.tar.gz qt3-35202ed0d899a9ff3c77dad72b501fb30e4dcf93.zip |
Merge branch 'master' of http://scm.trinitydesktop.org/scm/git/qt3
Diffstat (limited to 'src/kernel')
28 files changed, 1078 insertions, 560 deletions
diff --git a/src/kernel/qapplication.cpp b/src/kernel/qapplication.cpp index 51aa247..5b43301 100644 --- a/src/kernel/qapplication.cpp +++ b/src/kernel/qapplication.cpp @@ -68,6 +68,7 @@ #if defined(QT_THREAD_SUPPORT) # include "qmutex.h" # include "qthread.h" +# include <private/qthreadinstance_p.h> #endif // QT_THREAD_SUPPORT #include <stdlib.h> @@ -383,7 +384,25 @@ Q_EXPORT Qt::HANDLE qt_get_application_thread_id() } #endif // QT_THREAD_SUPPORT +#ifndef QT_THREAD_SUPPORT QEventLoop *QApplication::eventloop = 0; // application event loop +#endif + +#ifdef QT_THREAD_SUPPORT +QEventLoop* QApplication::currentEventLoop() { + QThread* thread = QThread::currentThreadObject(); + if (thread) { + if (thread->d) { + return thread->d->eventLoop; + } + } + return NULL; +} +#else +QEventLoop* QApplication::currentEventLoop() { + return QApplication::eventloop; +} +#endif #ifndef QT_NO_ACCEL extern bool qt_dispatchAccelEvent( QWidget*, QKeyEvent* ); // def in qaccel.cpp @@ -516,6 +535,41 @@ QClipboard *qt_clipboard = 0; // global clipboard object #endif QWidgetList * qt_modal_stack=0; // stack of modal widgets +#ifdef QT_THREAD_SUPPORT +// thread wrapper for the main() thread +class QCoreApplicationThread : public QThread +{ +public: + inline QCoreApplicationThread() + { + QThreadInstance::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 ~QCoreApplicationThread() + { + // avoid warning from QThread + d->running = false; + } +private: + inline void run() + { + // this function should never be called, it is implemented + // only so that we can instantiate the object + qFatal("QCoreApplicationThread: internal error"); + } +}; + +static QCoreApplicationThread qt_main_thread; +static QThread *mainThread() { return &qt_main_thread; } +#else +static QThread* mainThread() { return QThread::currentThread(); } +#endif + // Definitions for posted events struct QPostEvent { QPostEvent( QObject *r, QEvent *e ): receiver( r ), event( e ) {} @@ -818,8 +872,8 @@ void QApplication::construct( int &argc, char **argv, Type type ) initialize( argc, argv ); if ( qt_is_gui_used ) qt_maxWindowRect = desktop()->rect(); - if ( eventloop ) - eventloop->appStartingUp(); + if ( currentEventLoop() ) + currentEventLoop()->appStartingUp(); } /*! @@ -874,8 +928,8 @@ QApplication::QApplication( Display* dpy, HANDLE visual, HANDLE colormap ) if ( qt_is_gui_used ) qt_maxWindowRect = desktop()->rect(); - if ( eventloop ) - eventloop->appStartingUp(); + if ( currentEventLoop() ) + currentEventLoop()->appStartingUp(); } /*! @@ -916,13 +970,26 @@ QApplication::QApplication(Display *dpy, int argc, char **argv, if ( qt_is_gui_used ) qt_maxWindowRect = desktop()->rect(); - if ( eventloop ) - eventloop->appStartingUp(); + if ( currentEventLoop() ) + currentEventLoop()->appStartingUp(); } #endif // Q_WS_X11 +#ifdef QT_THREAD_SUPPORT +QThread* QApplication::guiThread() { + return mainThread(); +} + +bool QApplication::isGuiThread() { + return (QThread::currentThreadObject() == guiThread()); +} +#else +bool QApplication::isGuiThread() { + return true; +} +#endif void QApplication::init_precmdline() { @@ -1030,8 +1097,8 @@ QApplication::~QApplication() } #endif - if ( eventloop ) - eventloop->appClosingDown(); + if ( currentEventLoop() ) + currentEventLoop()->appClosingDown(); if ( postRList ) { QVFuncList::Iterator it = postRList->begin(); while ( it != postRList->end() ) { // call post routines @@ -2698,8 +2765,28 @@ bool QApplication::internalNotify( QObject *receiver, QEvent * e) } - if (!handled) + if (!handled) { +#if defined(QT_THREAD_SUPPORT) + int locklevel = 0; + int llcount; + if (QApplication::qt_mutex) { + QApplication::qt_mutex->lock(); // 1 of 2 + locklevel = qt_mutex->level() - 1; + for (llcount=0; llcount<locklevel; llcount++) { + QApplication::qt_mutex->unlock(); + } + QApplication::qt_mutex->unlock(); // 2 of 2 + } +#endif consumed = receiver->event( e ); +#if defined(QT_THREAD_SUPPORT) + if (QApplication::qt_mutex) { + for (llcount=0; llcount<locklevel; llcount++) { + QApplication::qt_mutex->lock(); + } + } +#endif + } e->spont = FALSE; return consumed; } @@ -2793,9 +2880,10 @@ void QApplication::processOneEvent() */ QEventLoop *QApplication::eventLoop() { - if ( !eventloop && !is_app_closing ) + if ( !currentEventLoop() && !is_app_closing ) { (void) new QEventLoop( qApp, "default event loop" ); - return eventloop; + } + return currentEventLoop(); } @@ -3263,8 +3351,23 @@ void QApplication::postEvent( QObject *receiver, QEvent *event ) l->append( pe ); globalPostedEvents->append( pe ); - if (eventloop) - eventloop->wakeUp(); +#ifdef QT_THREAD_SUPPORT + if ( event->type() == QEvent::MetaCall ) { + // Wake up the receiver thread event loop + QThread* thread = receiver->contextThreadObject(); + if (thread) { + if (thread->d) { + if (thread->d->eventLoop) { + thread->d->eventLoop->wakeUp(); + } + } + } + return; + } +#endif + + if (currentEventLoop()) + currentEventLoop()->wakeUp(); } @@ -3326,7 +3429,8 @@ void QApplication::sendPostedEvents( QObject *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() == QThread::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/qapplication.h b/src/kernel/qapplication.h index c34ff45..5611164 100644 --- a/src/kernel/qapplication.h +++ b/src/kernel/qapplication.h @@ -63,6 +63,7 @@ class QWSDecoration; #ifdef QT_THREAD_SUPPORT class QMutex; +class QThread; #endif // QT_THREAD_SUPPORT @@ -369,7 +370,9 @@ private: #ifndef QT_NO_CURSOR static QCursor *app_cursor; #endif +#ifndef QT_THREAD_SUPPORT static QEventLoop* eventloop; +#endif static int app_tracking; static bool is_app_running; static bool is_app_closing; @@ -425,6 +428,7 @@ private: static void removePostedEvent( QEvent * ); static void removePostedEvents( QObject *receiver, int event_type ); + friend class QObject; friend class QWidget; friend class QETWidget; friend class QDialog; @@ -444,6 +448,15 @@ private: // Disabled copy constructor and operator= QApplication( const QApplication & ); QApplication &operator=( const QApplication & ); #endif + +private: + static QEventLoop* currentEventLoop(); + +public: +#ifdef QT_THREAD_SUPPORT + static QThread* guiThread(); +#endif + static bool isGuiThread(); }; inline int QApplication::argc() const diff --git a/src/kernel/qapplication_x11.cpp b/src/kernel/qapplication_x11.cpp index 2873b9e..c2c0288 100644 --- a/src/kernel/qapplication_x11.cpp +++ b/src/kernel/qapplication_x11.cpp @@ -430,7 +430,7 @@ static bool qt_x11EventFilter( XEvent* ev ) //XIM qt_xim = 0; Q_EXPORT XIMStyle qt_xim_style = 0; Q_EXPORT XIMStyle qt_xim_preferred_style = 0; -Q_EXPORT static XIMStyle xim_default_style = XIMPreeditCallbacks | XIMStatusNothing; +static XIMStyle xim_default_style = XIMPreeditCallbacks | XIMStatusNothing; #endif Q_EXPORT int qt_ximComposingKeycode=0; @@ -5889,7 +5889,7 @@ static Bool qt_net_wm_sync_request_scanner(Display*, XEvent* event, XPointer arg { return (event->type == ClientMessage && event->xclient.window == *(Window*)arg && event->xclient.message_type == qt_wm_protocols - && event->xclient.data.l[ 0 ] == qt_net_wm_sync_request ); + && ((unsigned int)event->xclient.data.l[ 0 ]) == qt_net_wm_sync_request ); } #endif diff --git a/src/kernel/qdragobject.cpp b/src/kernel/qdragobject.cpp index 4f3353b..d48d79f 100644 --- a/src/kernel/qdragobject.cpp +++ b/src/kernel/qdragobject.cpp @@ -1749,9 +1749,9 @@ QColorDrag::QColorDrag( QWidget *dragsource, const char *name ) void QColorDrag::setColor( const QColor &col ) { - short r = (col.red() << 8) | col.red(); - short g = (col.green() << 8) | col.green(); - short b = (col.blue() << 8) | col.blue(); + unsigned short r = (col.red() << 8) | col.red(); + unsigned short g = (col.green() << 8) | col.green(); + unsigned short b = (col.blue() << 8) | col.blue(); // make sure we transmit data in network order r = htons(r); diff --git a/src/kernel/qevent.h b/src/kernel/qevent.h index 6512b9a..9587b8f 100644 --- a/src/kernel/qevent.h +++ b/src/kernel/qevent.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/qeventloop.cpp b/src/kernel/qeventloop.cpp index 1f6a130..5eadb9e 100644 --- a/src/kernel/qeventloop.cpp +++ b/src/kernel/qeventloop.cpp @@ -41,6 +41,11 @@ #include "qapplication.h" #include "qdatetime.h" +#ifdef QT_THREAD_SUPPORT +# include "qthread.h" +# include "qthreadinstance_p.h" +#endif + /*! \class QEventLoop \brief The QEventLoop class manages the event queue. @@ -100,15 +105,27 @@ QEventLoop::QEventLoop( QObject *parent, const char *name ) : QObject( parent, name ) { #if defined(QT_CHECK_STATE) - if ( QApplication::eventloop ) - qFatal( "QEventLoop: there must be only one event loop object. \nConstruct it before QApplication." ); - // for now ;) + if ( QApplication::currentEventLoop() ) + qFatal( "QEventLoop: there must be only one event loop object per thread. \nIf this is supposed to be the main GUI event loop, construct it before QApplication." ); + if (!QThread::currentThreadObject()) { + qFatal( "QEventLoop: this object can only be used in threads constructed via QThread." ); + } #endif // QT_CHECK_STATE d = new QEventLoopPrivate; init(); + +#ifdef QT_THREAD_SUPPORT + QThread* thread = QThread::currentThreadObject(); + if (thread) { + if (thread->d) { + thread->d->eventLoop = this; + } + } +#else QApplication::eventloop = this; +#endif } /*! @@ -118,7 +135,16 @@ QEventLoop::~QEventLoop() { cleanup(); delete d; +#ifdef QT_THREAD_SUPPORT + QThread* thread = QThread::currentThreadObject(); + if (thread) { + if (thread->d) { + thread->d->eventLoop = 0; + } + } +#else QApplication::eventloop = 0; +#endif } /*! diff --git a/src/kernel/qeventloop.h b/src/kernel/qeventloop.h index 25f80cd..a3ee01d 100644 --- a/src/kernel/qeventloop.h +++ b/src/kernel/qeventloop.h @@ -102,25 +102,6 @@ public: virtual void wakeUp(); -#ifdef Q_QDOC -#else // Q_QDOC -#if defined(QT_USE_GLIBMAINLOOP) - - // glib main loop support - - /* internal: used to fit glib-main-loop gsource concept */ - - bool gsourcePrepare(GSource *gs, int * timeout); - bool gsourceCheck(GSource * gs); - bool gsourceDispatch(GSource * gs); - - bool processX11Events(); - - // end glib main loop support - -#endif //QT_USE_GLIBMAINLOOP -#endif // Q_QDOC - void setSingleToolkitEventHandling(bool enabled); signals: @@ -145,6 +126,24 @@ private: QEventLoopPrivate *d; friend class QApplication; + +#ifdef Q_QDOC +#else // Q_QDOC +#if defined(QT_USE_GLIBMAINLOOP) + + // glib main loop support + /* internal: used to fit glib-main-loop gsource concept */ +public: + bool gsourcePrepare(GSource *gs, int * timeout); + bool gsourceCheck(GSource * gs); + bool gsourceDispatch(GSource * gs); + + bool processX11Events(); + + // end glib main loop support + +#endif //QT_USE_GLIBMAINLOOP +#endif // Q_QDOC }; #endif // QEVENTLOOP_H diff --git a/src/kernel/qeventloop_glib_p.h b/src/kernel/qeventloop_glib_p.h index 7de324d..663f20e 100644 --- a/src/kernel/qeventloop_glib_p.h +++ b/src/kernel/qeventloop_glib_p.h @@ -84,49 +84,51 @@ struct QSockNotGPollFD class QEventLoopPrivate { public: - QEventLoopPrivate() - { - reset(); - } - - void reset() { - looplevel = 0; - quitcode = 0; - quitnow = FALSE; - exitloop = FALSE; - shortcut = FALSE; - singletoolkit = TRUE; - } - - int looplevel; - int quitcode; - unsigned int quitnow : 1; - unsigned int exitloop : 1; - unsigned int shortcut : 1; - + QEventLoopPrivate() + { #if defined(Q_WS_X11) - int xfd; - - GPollFD x_gPollFD; - + xfd = -1; + x_gPollFD.fd = -1; #endif // Q_WS_X11 + reset(); + } + + void reset() { + looplevel = 0; + quitcode = 0; + quitnow = FALSE; + exitloop = FALSE; + shortcut = FALSE; + singletoolkit = TRUE; + } + + int looplevel; + int quitcode; + unsigned int quitnow : 1; + unsigned int exitloop : 1; + unsigned int shortcut : 1; - int thread_pipe[2]; +#if defined(Q_WS_X11) + int xfd; + GPollFD x_gPollFD; +#endif // Q_WS_X11 + int thread_pipe[2]; GPollFD threadPipe_gPollFD; - - QPtrList<QSockNotGPollFD> sn_list; - // pending socket notifiers list - QPtrList<QSockNotGPollFD> sn_pending_list; - + QPtrList<QSockNotGPollFD> sn_list; + + // pending socket notifiers list + QPtrList<QSockNotGPollFD> sn_pending_list; + // store flags for one iteration - uint pev_flags; - + uint pev_flags; + // My GSource - GSource * gSource; bool singletoolkit; + // main context + GMainContext *ctx; }; #endif // QEVENTLOOP_GLIB_P_H diff --git a/src/kernel/qeventloop_unix.cpp b/src/kernel/qeventloop_unix.cpp index b0ad8b9..80c8f29 100644 --- a/src/kernel/qeventloop_unix.cpp +++ b/src/kernel/qeventloop_unix.cpp @@ -40,6 +40,7 @@ #include "qeventloop.h" #include "qapplication.h" #include "qbitarray.h" +#include "qmutex.h" #include <stdlib.h> #include <sys/types.h> @@ -561,6 +562,8 @@ int QEventLoop::activateTimers() n_act++; QTimerEvent e( t->id ); QApplication::sendEvent( t->obj, &e ); // send event + if ( !timerList ) // sendEvent allows other threads to execute, therefore we must check for list existence when it returns! + return 0; if ( timerList->findRef( begin ) == -1 ) begin = 0; } diff --git a/src/kernel/qeventloop_unix_glib.cpp b/src/kernel/qeventloop_unix_glib.cpp index 6852f6b..6a890ce 100644 --- a/src/kernel/qeventloop_unix_glib.cpp +++ b/src/kernel/qeventloop_unix_glib.cpp @@ -44,6 +44,7 @@ #include "qeventloop.h" #include "qapplication.h" #include "qbitarray.h" +#include "qmutex.h" #include <stdlib.h> #include <sys/types.h> @@ -369,9 +370,9 @@ void QEventLoop::registerSocketNotifier( QSocketNotifier *notifier ) return; } - #ifdef DEBUG_QT_GLIBMAINLOOP - printf("register socket notifier %d\n", sockfd); - #endif +#ifdef DEBUG_QT_GLIBMAINLOOP + printf("register socket notifier %d\n", sockfd); +#endif QPtrList<QSockNotGPollFD> *list = &d->sn_list; QSockNotGPollFD *sn; @@ -424,9 +425,9 @@ void QEventLoop::unregisterSocketNotifier( QSocketNotifier *notifier ) return; } - #ifdef DEBUG_QT_GLIBMAINLOOP - printf("unregister socket notifier %d\n", sockfd); - #endif +#ifdef DEBUG_QT_GLIBMAINLOOP + printf("unregister socket notifier %d\n", sockfd); +#endif QPtrList<QSockNotGPollFD> *list = &d->sn_list; QSockNotGPollFD *sn; @@ -457,9 +458,9 @@ void QEventLoop::setSocketNotifierPending( QSocketNotifier *notifier ) return; } - #ifdef DEBUG_QT_GLIBMAINLOOP - printf("set socket notifier pending %d\n", sockfd); - #endif +#ifdef DEBUG_QT_GLIBMAINLOOP + printf("set socket notifier pending %d\n", sockfd); +#endif QPtrList<QSockNotGPollFD> *list = &d->sn_list; QSockNotGPollFD *sn; @@ -505,7 +506,9 @@ void QEventLoop::wakeUp() size_t nbytes = 0; char c = 0; if ( ::ioctl( d->thread_pipe[0], FIONREAD, (char*)&nbytes ) >= 0 && nbytes == 0 ) { - ::write( d->thread_pipe[1], &c, 1 ); + if (::write( d->thread_pipe[1], &c, 1 ) < 0) { + // Failed! + } } } @@ -576,17 +579,14 @@ int QEventLoop::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; - QApplication::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; + QApplication::sendEvent( sn->obj, &event ); + n_act++; + } } return n_act; diff --git a/src/kernel/qeventloop_x11.cpp b/src/kernel/qeventloop_x11.cpp index 833be69..5ee41ca 100644 --- a/src/kernel/qeventloop_x11.cpp +++ b/src/kernel/qeventloop_x11.cpp @@ -146,55 +146,57 @@ bool QEventLoop::processEvents( ProcessEventsFlags flags ) if ( qt_is_gui_used ) { QApplication::sendPostedEvents(); - // Two loops so that posted events accumulate - while ( XPending( QPaintDevice::x11AppDisplay() ) ) { - // also flushes output buffer - while ( XPending( QPaintDevice::x11AppDisplay() ) ) { - if ( d->shortcut ) { - return FALSE; - } - - XNextEvent( QPaintDevice::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 qt_wm_protocols; - extern Atom qt_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 == qt_wm_protocols || - (Atom) event.xclient.data.l[0] == qt_wm_take_focus ) - break; - if ( event.xclient.message_type == qt_qt_scrolldone ) - break; + if (QApplication::isGuiThread()) { + // Two loops so that posted events accumulate + while ( XPending( QPaintDevice::x11AppDisplay() ) ) { + // also flushes output buffer + while ( XPending( QPaintDevice::x11AppDisplay() ) ) { + if ( d->shortcut ) { + return FALSE; + } + + XNextEvent( QPaintDevice::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 qt_wm_protocols; + extern Atom qt_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 == qt_wm_protocols || + (Atom) event.xclient.data.l[0] == qt_wm_take_focus ) + break; + if ( event.xclient.message_type == qt_qt_scrolldone ) + break; + } + + default: break; + } + } + + nevents++; + if ( qApp->x11ProcessEvent( &event ) == 1 ) + return TRUE; } - - default: break; - } } - - nevents++; - if ( qApp->x11ProcessEvent( &event ) == 1 ) - return TRUE; - } } } @@ -261,7 +263,7 @@ bool QEventLoop::processEvents( ProcessEventsFlags flags ) FD_ZERO( &d->sn_vec[2].select_fds ); } - if ( qt_is_gui_used ) { + if ( qt_is_gui_used && QApplication::isGuiThread() ) { // select for events on the event socket - only on X11 FD_SET( d->xfd, &d->sn_vec[0].select_fds ); highest = QMAX( highest, d->xfd ); @@ -282,7 +284,8 @@ bool QEventLoop::processEvents( ProcessEventsFlags flags ) // 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(); + if ( locker.mutex() ) locker.mutex()->unlock(); + else return false; #endif int nsel; @@ -296,7 +299,8 @@ bool QEventLoop::processEvents( ProcessEventsFlags flags ) // relock the GUI mutex before processing any pending events #if defined(QT_THREAD_SUPPORT) - locker.mutex()->lock(); + if ( locker.mutex() ) locker.mutex()->lock(); + else return false; #endif // we are awake, broadcast it diff --git a/src/kernel/qeventloop_x11_glib.cpp b/src/kernel/qeventloop_x11_glib.cpp index 59ab8a1..877ff44 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 "qeventloop.h" #include "qapplication.h" @@ -49,58 +48,85 @@ #if defined(QT_THREAD_SUPPORT) # include "qmutex.h" +# include "qthread.h" #endif // QT_THREAD_SUPPORT #include <errno.h> #include <glib.h> +// #define DEBUG_QT_GLIBMAINLOOP 1 + // Qt-GSource Structure and Callbacks typedef struct { - GSource source; - QEventLoop * qeventLoop; + GSource source; + QEventLoop * qeventLoop; } QtGSource; -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 QEventLoop methods! static gboolean qt_gsource_prepare ( GSource *source, - gint *timeout ) + gint *timeout ) { - QtGSource * qtGSource; - qtGSource = (QtGSource*) source; - return qtGSource->qeventLoop->gsourcePrepare(source, timeout); + QtGSource * qtGSource = (QtGSource*) source; + QEventLoop* candidateEventLoop = qtGSource->qeventLoop; + QEventLoop* activeThreadEventLoop = QApplication::eventLoop(); + + if (candidateEventLoop == activeThreadEventLoop) { + return candidateEventLoop->gsourcePrepare(source, timeout); + } + else { + // Prepare failed + return FALSE; + } } static gboolean qt_gsource_check ( GSource *source ) { - QtGSource * qtGSource = (QtGSource*) source; - return qtGSource->qeventLoop->gsourceCheck(source); + QtGSource * qtGSource = (QtGSource*) source; + QEventLoop* candidateEventLoop = qtGSource->qeventLoop; + QEventLoop* activeThreadEventLoop = QApplication::eventLoop(); + + if (candidateEventLoop == activeThreadEventLoop) { + return candidateEventLoop->gsourceCheck(source); + } + else { + // Check failed + return FALSE; + } } static gboolean qt_gsource_dispatch ( GSource *source, GSourceFunc callback, gpointer user_data ) { - Q_UNUSED(callback); - Q_UNUSED(user_data); + Q_UNUSED(callback); + Q_UNUSED(user_data); - QtGSource * qtGSource = (QtGSource*) source; - return qtGSource->qeventLoop->gsourceDispatch(source); + QtGSource * qtGSource = (QtGSource*) source; + QEventLoop* candidateEventLoop = qtGSource->qeventLoop; + QEventLoop* activeThreadEventLoop = QApplication::eventLoop(); + + if (candidateEventLoop == activeThreadEventLoop) { + return candidateEventLoop->gsourceDispatch(source); + } + else { + // Dispatch failed + return FALSE; + } } @@ -134,339 +160,329 @@ static QVFuncList *qt_postselect_handler = 0; void qt_install_preselect_handler( VFPTR handler ) { - if ( !qt_preselect_handler ) - qt_preselect_handler = new QVFuncList; - qt_preselect_handler->append( handler ); + if ( !qt_preselect_handler ) { + qt_preselect_handler = new QVFuncList; + } + qt_preselect_handler->append( handler ); } + void qt_remove_preselect_handler( VFPTR handler ) { - if ( qt_preselect_handler ) { - QVFuncList::Iterator it = qt_preselect_handler->find( handler ); - if ( it != qt_preselect_handler->end() ) - qt_preselect_handler->remove( it ); - } + if ( qt_preselect_handler ) { + QVFuncList::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 QVFuncList; - qt_postselect_handler->prepend( handler ); + if ( !qt_postselect_handler ) { + qt_postselect_handler = new QVFuncList; + } + qt_postselect_handler->prepend( handler ); } + void qt_remove_postselect_handler( VFPTR handler ) { - if ( qt_postselect_handler ) { - QVFuncList::Iterator it = qt_postselect_handler->find( handler ); - if ( it != qt_postselect_handler->end() ) - qt_postselect_handler->remove( it ); - } + if ( qt_postselect_handler ) { + QVFuncList::Iterator it = qt_postselect_handler->find( handler ); + if ( it != qt_postselect_handler->end() ) { + qt_postselect_handler->remove( it ); + } + } } - void QEventLoop::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); - - // intitialize the X11 parts of the event loop - d->xfd = -1; - if ( qt_is_gui_used ) - d->xfd = XConnectionNumber( QPaintDevice::x11AppDisplay() ); - - // new GSource - - QtGSource * qtGSource = (QtGSource*) g_source_new(&qt_gsource_funcs, - sizeof(QtGSource)); - - g_source_set_can_recurse ((GSource*)qtGSource, TRUE); - - 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 ); - d->gSource = (GSource*) qtGSource; - + // 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 ( qt_is_gui_used && QApplication::isGuiThread() ) { + d->xfd = XConnectionNumber( QPaintDevice::x11AppDisplay() ); + } + + // new main context for thread + d->ctx = g_main_context_new(); + g_main_context_push_thread_default(d->ctx); + + // new GSource + QtGSource * qtGSource = (QtGSource*) g_source_new(&qt_gsource_funcs, sizeof(QtGSource)); + g_source_set_can_recurse ((GSource*)qtGSource, TRUE); + qtGSource->qeventLoop = this; + + // init main loop and attach gsource +#ifdef DEBUG_QT_GLIBMAINLOOP + printf("inside init(1)\n"); +#endif + + g_main_loop_new (d->ctx, 1); + g_source_attach( (GSource*)qtGSource, d->ctx ); + d->gSource = (GSource*)qtGSource; + // poll for X11 events - - if ( qt_is_gui_used ) { - - + if ( qt_is_gui_used && QApplication::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); - } + d->x_gPollFD.events = G_IO_IN | G_IO_HUP | G_IO_ERR; + g_source_add_poll(d->gSource, &d->x_gPollFD); + } // poll thread-pipe - d->threadPipe_gPollFD.fd = d->thread_pipe[0]; - d->threadPipe_gPollFD.events = G_IO_IN | G_IO_HUP; + d->threadPipe_gPollFD.events = G_IO_IN | G_IO_HUP | G_IO_ERR; 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 QEventLoop::cleanup() { - // cleanup the common parts of the event loop - close( d->thread_pipe[0] ); - close( d->thread_pipe[1] ); - cleanupTimers(); + // 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; + + // unref the main context + g_main_context_unref(d->ctx); - // cleanup the X11 parts of the event loop - d->xfd = -1; - // todo: destroy gsource } bool QEventLoop::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; + + d->pev_flags = flags; + + rval = g_main_context_iteration(d->ctx, flags & WaitForMore ? TRUE : FALSE); - #ifdef DEBUG_QT_GLIBMAINLOOP - printf("inside processEvents(2) looplevel=%d rval=%d\n", d->looplevel, rval ); - #endif + d->pev_flags = save_flags; - return rval; // were events processed? +#ifdef DEBUG_QT_GLIBMAINLOOP + printf("inside processEvents(2) looplevel=%d rval=%d\n", d->looplevel, rval ); +#endif + + return rval; // were events processed? } bool QEventLoop::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) - QMutexLocker locker( QApplication::qt_mutex ); + QMutexLocker locker( QApplication::qt_mutex ); #endif - // handle gui and posted events - if ( qt_is_gui_used ) { - QApplication::sendPostedEvents(); - - // Two loops so that posted events accumulate - while ( XPending( QPaintDevice::x11AppDisplay() ) ) { - // also flushes output buffer - while ( XPending( QPaintDevice::x11AppDisplay() ) ) { - if ( d->shortcut ) { - return FALSE; - } - - XNextEvent( QPaintDevice::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 qt_wm_protocols; - extern Atom qt_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 == qt_wm_protocols || - (Atom) event.xclient.data.l[0] == qt_wm_take_focus ) - break; - if ( event.xclient.message_type == qt_qt_scrolldone ) - break; + // handle gui and posted events + if ( qt_is_gui_used ) { + QApplication::sendPostedEvents(); + + if (QApplication::isGuiThread()) { + // Two loops so that posted events accumulate + while ( XPending( QPaintDevice::x11AppDisplay() ) ) { + // also flushes output buffer + while ( XPending( QPaintDevice::x11AppDisplay() ) ) { + if ( d->shortcut ) { + return FALSE; + } + + XNextEvent( QPaintDevice::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 qt_wm_protocols; + extern Atom qt_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 == qt_wm_protocols || + (Atom) event.xclient.data.l[0] == qt_wm_take_focus ) + break; + if ( event.xclient.message_type == qt_qt_scrolldone ) + break; + } + + default: break; + } + } + + nevents++; + if ( qApp->x11ProcessEvent( &event ) == 1 ) { + return TRUE; + } + } } - - default: break; - } } - - nevents++; - if ( qApp->x11ProcessEvent( &event ) == 1 ) - return TRUE; - } } - } + + if ( d->shortcut ) { + return FALSE; + } - if ( d->shortcut ) { + QApplication::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; - } - - QApplication::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 QEventLoop::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) - QMutexLocker locker( QApplication::qt_mutex ); + QMutexLocker locker( QApplication::qt_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 ) ) { - QPtrListIterator<QSockNotGPollFD> it( d->sn_list ); - QSockNotGPollFD *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 { - QPtrListIterator<QSockNotGPollFD> it( d->sn_list ); - QSockNotGPollFD *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 ) ) { + QPtrListIterator<QSockNotGPollFD> it( d->sn_list ); + QSockNotGPollFD *sn; + while ( (sn=it.current()) ) { + ++it; + sn->gPollFD.events = sn->events; // restore poll events + } + } + else { + QPtrListIterator<QSockNotGPollFD> it( d->sn_list ); + QSockNotGPollFD *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 ) { - QVFuncList::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(); -#endif + if ( canWait ) { + emit aboutToBlock(); + } - #ifdef DEBUG_QT_GLIBMAINLOOP - printf("inside gsourcePrepare(2.1) canwait=%d\n", canWait); - #endif + if ( qt_preselect_handler ) { + QVFuncList::Iterator it, end = qt_preselect_handler->end(); + for ( it = qt_preselect_handler->begin(); it != end; ++it ) + (**it)(); + } +#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 - printf("inside gsourcePrepare(3a)\n"); - #endif - +#ifdef DEBUG_QT_GLIBMAINLOOP + printf("inside gsourcePrepare(3a)\n"); +#endif return FALSE; - } - + } + // stay in poll until something happens? if (!tm) { // fixme *timeout = -1; // wait forever - #ifdef DEBUG_QT_GLIBMAINLOOP - printf("inside gsourcePrepare(3b) timeout=%d \n", *timeout); - #endif - - +#ifdef DEBUG_QT_GLIBMAINLOOP + printf("inside gsourcePrepare(3b) timeout=%d \n", *timeout); +#endif return FALSE; } - - // else timeout >=0 + + // 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 QEventLoop::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? - QPtrList<QSockNotGPollFD> *list = &d->sn_list; - //if ( list ) { - - QSockNotGPollFD *sn = list->first(); while ( sn ) { if ( sn->gPollFD.revents ) @@ -476,45 +492,43 @@ bool QEventLoop::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 - - #ifdef DEBUG_QT_GLIBMAINLOOP - printf("inside gsourceCheck(2) nothing to dispatch!\n"); - #endif + // nothing to dispatch +#ifdef DEBUG_QT_GLIBMAINLOOP + printf("inside gsourceCheck(2) nothing to dispatch!\n"); +#endif - return FALSE; + return FALSE; } @@ -526,44 +540,41 @@ bool QEventLoop::gsourceDispatch(GSource *gs) { QMutexLocker locker( QApplication::qt_mutex ); #endif #if defined(QT_THREAD_SUPPORT) - locker.mutex()->lock(); + if (locker.mutex()) locker.mutex()->lock(); #endif int nevents=0; - ProcessEventsFlags flags = d->pev_flags; - #ifdef DEBUG_QT_GLIBMAINLOOP - printf("inside gsourceDispatch(1)\n"); - #endif - - // we are awake, broadcast it - emit awake(); - emit qApp->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 qApp->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 ) { - QVFuncList::Iterator it, end = qt_postselect_handler->end(); - for ( it = qt_postselect_handler->begin(); it != end; ++it ) - (**it)(); - } + if ( qt_postselect_handler ) { + QVFuncList::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 ) { - - QPtrList<QSockNotGPollFD> *list = &d->sn_list; QSockNotGPollFD *sn = list->first(); while ( sn ) { @@ -572,40 +583,38 @@ bool QEventLoop::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(); +#if defined(QT_THREAD_SUPPORT) + if (locker.mutex()) locker.mutex()->unlock(); +#endif processX11Events(); - } - + else { #if defined(QT_THREAD_SUPPORT) - locker.mutex()->unlock(); + if (locker.mutex()) locker.mutex()->unlock(); #endif + } if (d->singletoolkit) { return TRUE; // Eat the event @@ -617,21 +626,27 @@ bool QEventLoop::gsourceDispatch(GSource *gs) { bool QEventLoop::hasPendingEvents() const { - extern uint qGlobalPostedEventsCount(); // from qapplication.cpp - return ( qGlobalPostedEventsCount() || ( qt_is_gui_used ? XPending( QPaintDevice::x11AppDisplay() ) : 0)); + extern uint qGlobalPostedEventsCount(); // from qapplication.cpp + return ( qGlobalPostedEventsCount() || ( (qt_is_gui_used && QApplication::isGuiThread()) ? XPending( QPaintDevice::x11AppDisplay() ) : 0)); } void QEventLoop::appStartingUp() { - if ( qt_is_gui_used ) - d->xfd = XConnectionNumber( QPaintDevice::x11AppDisplay() ); + if ( qt_is_gui_used ) { + d->xfd = XConnectionNumber( QPaintDevice::x11AppDisplay() ); + if ( (d->x_gPollFD.fd == -1) && QApplication::isGuiThread() ) { + d->x_gPollFD.fd = d->xfd; + d->x_gPollFD.events = G_IO_IN | G_IO_HUP | G_IO_ERR; + g_source_add_poll(d->gSource, &d->x_gPollFD); + } + } } void QEventLoop::appClosingDown() { - d->xfd = -1; + d->xfd = -1; } void QEventLoop::setSingleToolkitEventHandling(bool enabled) { - d->singletoolkit = enabled; + d->singletoolkit = enabled; }
\ No newline at end of file diff --git a/src/kernel/qimage.cpp b/src/kernel/qimage.cpp index b55a0e7..214fc85 100644 --- a/src/kernel/qimage.cpp +++ b/src/kernel/qimage.cpp @@ -5424,6 +5424,7 @@ static void write_pbm_image( QImageIO *iio ) class QImageIOFrameGrabber : public QImageConsumer { public: QImageIOFrameGrabber() : framecount(0) { } + virtual ~QImageIOFrameGrabber() { } QImageDecoder *decoder; int framecount; diff --git a/src/kernel/qinputcontext.cpp b/src/kernel/qinputcontext.cpp index 5433ae4..3b2d476 100644 --- a/src/kernel/qinputcontext.cpp +++ b/src/kernel/qinputcontext.cpp @@ -477,6 +477,7 @@ bool QInputContext::isComposing() const */ bool QInputContext::filterEvent( const QEvent *event ) { + Q_UNUSED(event); return FALSE; } @@ -679,6 +680,11 @@ void QInputContext::unsetFocus() */ void QInputContext::setMicroFocus( int x, int y, int w, int h, QFont *f ) { + Q_UNUSED(x); + Q_UNUSED(y); + Q_UNUSED(w); + Q_UNUSED(h); + Q_UNUSED(f); } @@ -705,6 +711,9 @@ void QInputContext::mouseHandler( int x, QEvent::Type type, Qt::ButtonState button, Qt::ButtonState state ) { + Q_UNUSED(x); + Q_UNUSED(button); + Q_UNUSED(state); // Default behavior for simple ephemeral input contexts. Some // complex input contexts should not be reset here. if ( type == QEvent::MouseButtonPress || diff --git a/src/kernel/qinputcontext_x11.cpp b/src/kernel/qinputcontext_x11.cpp index 8bdfa5e..e7c82c1 100644 --- a/src/kernel/qinputcontext_x11.cpp +++ b/src/kernel/qinputcontext_x11.cpp @@ -67,6 +67,8 @@ */ bool QInputContext::x11FilterEvent( QWidget *keywidget, XEvent *event ) { + Q_UNUSED(keywidget); + Q_UNUSED(event); return FALSE; } diff --git a/src/kernel/qjpegio.cpp b/src/kernel/qjpegio.cpp index 5d2a1b1..bdb4c27 100644 --- a/src/kernel/qjpegio.cpp +++ b/src/kernel/qjpegio.cpp @@ -80,7 +80,7 @@ void my_error_exit (j_common_ptr cinfo) my_error_mgr* myerr = (my_error_mgr*) cinfo->err; char buffer[JMSG_LENGTH_MAX]; (*cinfo->err->format_message)(cinfo, buffer); - qWarning(buffer); + qWarning("%s", buffer); longjmp(myerr->setjmp_buffer, 1); } diff --git a/src/kernel/qnetworkprotocol.cpp b/src/kernel/qnetworkprotocol.cpp index 4173584..e6c4a6a 100644 --- a/src/kernel/qnetworkprotocol.cpp +++ b/src/kernel/qnetworkprotocol.cpp @@ -381,6 +381,14 @@ public: of these values. */ +QNetworkProtocolFactoryBase::QNetworkProtocolFactoryBase() { + // +} + +QNetworkProtocolFactoryBase::~QNetworkProtocolFactoryBase() { + // +} + /*! Constructor of the network protocol base class. Does some initialization and connecting of signals and slots. diff --git a/src/kernel/qnetworkprotocol.h b/src/kernel/qnetworkprotocol.h index 096a9ad..fa350e3 100644 --- a/src/kernel/qnetworkprotocol.h +++ b/src/kernel/qnetworkprotocol.h @@ -64,6 +64,10 @@ template <class T> class QValueList; class Q_EXPORT QNetworkProtocolFactoryBase { public: + QNetworkProtocolFactoryBase(); + virtual ~QNetworkProtocolFactoryBase(); + +public: virtual QNetworkProtocol *createObject() = 0; }; diff --git a/src/kernel/qobject.cpp b/src/kernel/qobject.cpp index 7e01dec..13486f4 100644 --- a/src/kernel/qobject.cpp +++ b/src/kernel/qobject.cpp @@ -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 ) - object->qt_emit( c->member(), o ); - else - object->qt_invoke( c->member(), o ); + if ( c->memberType() == QSIGNAL_CODE ) { + if (object->d->ownThread == currentThread) { + object->qt_emit( c->member(), o ); + } + 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 ) - object->qt_emit( c->member(), o ); - else - object->qt_invoke( c->member(), o ); + if ( c->memberType() == QSIGNAL_CODE ) { + if (object->d->ownThread == currentThread) { + object->qt_emit( c->member(), o ); + } + 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() ) @@ -2435,39 +2674,42 @@ void QObject::activate_signal( QConnectionList *clist, QUObject *o ) */ #ifndef QT_NO_PRELIMINARY_SIGNAL_SPY -#define ACTIVATE_SIGNAL_WITH_PARAM(FNAME,TYPE) \ -void QObject::FNAME( int signal, TYPE param ) \ -{ \ - if ( qt_preliminary_signal_spy ) { \ - if ( !signalsBlocked() && signal >= 0 && \ - ( !connections || !connections->at( signal ) ) ) { \ - QUObject o[2]; \ - static_QUType_##TYPE.set( o+1, param ); \ - qt_spy_signal( this, signal, o ); \ - return; \ - } \ - } \ - if ( !connections || signalsBlocked() || signal < 0 ) \ - return; \ - QConnectionList *clist = connections->at( signal ); \ - if ( !clist ) \ - return; \ - QUObject o[2]; \ - static_QUType_##TYPE.set( o+1, param ); \ - activate_signal( clist, o ); \ +#define ACTIVATE_SIGNAL_WITH_PARAM(FNAME,TYPE) \ +void QObject::FNAME( int signal, TYPE param ) \ +{ \ + if ( qt_preliminary_signal_spy ) { \ + 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; \ + } \ + } \ + if ( !connections || signalsBlocked() || signal < 0 ) \ + return; \ + QConnectionList *clist = connections->at( signal ); \ + if ( !clist ) \ + return; \ + QUObject 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 QObject::FNAME( int signal, TYPE param ) \ -{ \ - if ( !connections || signalsBlocked() || signal < 0 ) \ - return; \ - QConnectionList *clist = connections->at( signal ); \ - if ( !clist ) \ - return; \ - QUObject o[2]; \ - static_QUType_##TYPE.set( o+1, param ); \ - activate_signal( clist, o ); \ +#define ACTIVATE_SIGNAL_WITH_PARAM(FNAME,TYPE) \ +void QObject::FNAME( int signal, TYPE param ) \ +{ \ + if ( !connections || signalsBlocked() || signal < 0 ) \ + return; \ + QConnectionList *clist = connections->at( signal ); \ + if ( !clist ) \ + return; \ + QUObject o[2]; \ + o[1].isLastObject = true; \ + static_QUType_##TYPE.set( o+1, param ); \ + activate_signal( clist, o ); \ } #endif diff --git a/src/kernel/qobject.h b/src/kernel/qobject.h index 6de28db..2f469ba 100644 --- a/src/kernel/qobject.h +++ b/src/kernel/qobject.h @@ -63,6 +63,10 @@ class QObjectUserData; #endif struct QUObject; +#ifdef QT_THREAD_SUPPORT +class QThread; +#endif + class Q_EXPORT QObject: public Qt { Q_OBJECT @@ -217,6 +221,18 @@ private: // Disabled copy constructor and operator= QObject( const QObject & ); QObject &operator=( const QObject & ); #endif + +public: +#ifdef QT_THREAD_SUPPORT + QThread* contextThreadObject() const; + void moveToThread(QThread *targetThread); +#endif + +private: +#ifdef QT_THREAD_SUPPORT + void moveToThread_helper(QThread *targetThread); + void setThreadObject_helper(QThread *targetThread); +#endif }; diff --git a/src/kernel/qpaintdevice_x11.cpp b/src/kernel/qpaintdevice_x11.cpp index a755c01..5941657 100644 --- a/src/kernel/qpaintdevice_x11.cpp +++ b/src/kernel/qpaintdevice_x11.cpp @@ -529,11 +529,16 @@ static void create_dpis() Q_CHECK_PTR( dpisX ); Q_CHECK_PTR( dpisY ); for ( i = 0; i < screens; i++ ) { - dpisX[ i ] = (DisplayWidth(dpy,i) * 254 + DisplayWidthMM(dpy,i)*5) - - / (DisplayWidthMM(dpy,i)*10); - dpisY[ i ] = (DisplayHeight(dpy,i) * 254 + DisplayHeightMM(dpy,i)*5) - / (DisplayHeightMM(dpy,i)*10); + if (DisplayWidthMM(dpy,i) < 1) + dpisX[ i ] = 75; // default the dpi to 75. + else + dpisX[ i ] = (DisplayWidth(dpy,i) * 254 + DisplayWidthMM(dpy,i)*5) + / (DisplayWidthMM(dpy,i)*10); + if (DisplayHeightMM(dpy,i) < 1) + dpisY[ i ] = 75; // default the dpi to 75. + else + dpisY[ i ] = (DisplayHeight(dpy,i) * 254 + DisplayHeightMM(dpy,i)*5) + / (DisplayHeightMM(dpy,i)*10); } } diff --git a/src/kernel/qprocess_unix.cpp b/src/kernel/qprocess_unix.cpp index 2a4a2fd..c6066d4 100644 --- a/src/kernel/qprocess_unix.cpp +++ b/src/kernel/qprocess_unix.cpp @@ -379,7 +379,9 @@ void QProcessManager::sigchldHnd( int fd ) } char tmp; - ::read( fd, &tmp, sizeof(tmp) ); + if (::read( fd, &tmp, sizeof(tmp) ) < 0) { + qWarning( "Could not read from file descriptor" ); + } #if defined(QT_QPROCESS_DEBUG) qDebug( "QProcessManager::sigchldHnd()" ); #endif @@ -562,7 +564,9 @@ QT_SIGNAL_RETTYPE qt_C_sigchldHnd( QT_SIGNAL_ARGS ) return; char a = 1; - ::write( QProcessPrivate::procManager->sigchldFd[0], &a, sizeof(a) ); + if (::write( QProcessPrivate::procManager->sigchldFd[0], &a, sizeof(a) ) < 0) { + qWarning( "Could not write to file descriptor" ); + } } diff --git a/src/kernel/qscriptengine_x11.cpp b/src/kernel/qscriptengine_x11.cpp index 7d2b77d..b87680b 100644 --- a/src/kernel/qscriptengine_x11.cpp +++ b/src/kernel/qscriptengine_x11.cpp @@ -2725,11 +2725,7 @@ static bool khmer_shape_syllable(QOpenType *openType, QShaperItem *item) #ifndef QT_NO_XFTFREETYPE if (openType) { - unsigned short logClusters[16]; - for (int i = 0; i < len; ++i) - logClusters[i] = i; - - uint where[16]; + uint where[16]; for (int i = 0; i < len; ++i) { where[i] = ~(PreSubstProperty @@ -3236,11 +3232,7 @@ static bool myanmar_shape_syllable(QOpenType *openType, QShaperItem *item, bool #ifndef QT_NO_XFTFREETYPE if (openType) { - unsigned short logClusters[32]; - for (int i = 0; i < len; ++i) - logClusters[i] = i; - - uint where[32]; + uint where[32]; for (int i = 0; i < len; ++i) { where[i] = ~(PreSubstProperty diff --git a/src/kernel/qstyle.h b/src/kernel/qstyle.h index cf7a235..0efc386 100644 --- a/src/kernel/qstyle.h +++ b/src/kernel/qstyle.h @@ -290,6 +290,7 @@ class Q_EXPORT QStyleControlElementData { QString caption; QStyleControlElementGenericWidgetData topLevelWidgetData; Q_UINT32 topLevelWidgetFlags; + QPixmap paletteBgPixmap; }; class Q_EXPORT QStyleWidgetActionRequestData { @@ -1070,6 +1071,18 @@ public: // bool - whether or not the upper two button drawing areas should be combined into one SH_ScrollBar_CombineSubLineRegionDrawingAreas, + // Qt::QRgb - color of the popup menu arrow (active, menuitem enabled) + SH_PopupMenu_SubMenuArrowColorActiveEnabled, + + // Qt::QRgb - color of the popup menu arrow (active, menuitem disabled) + SH_PopupMenu_SubMenuArrowColorActiveDisabled, + + // Qt::QRgb - color of the popup menu arrow (inactive, menuitem enabled) + SH_PopupMenu_SubMenuArrowColorInactiveEnabled, + + // Qt::QRgb - color of the popup menu arrow (active, menuitem disabled) + SH_PopupMenu_SubMenuArrowColorInactiveDisabled, + // do not add any values below/greater than this SH_CustomBase = 0xf0000000 }; diff --git a/src/kernel/qthread.cpp b/src/kernel/qthread.cpp index 1653a51..cfe8c56 100644 --- a/src/kernel/qthread.cpp +++ b/src/kernel/qthread.cpp @@ -41,6 +41,7 @@ #include "qplatformdefs.h" #include "qthread.h" +#include "qeventloop.h" #include <private/qthreadinstance_p.h> #ifndef QT_H @@ -238,4 +239,20 @@ void QThread::postEvent( QObject * receiver, QEvent * event ) } #endif +QEventLoopThread::QEventLoopThread() : QThread() +{ + // +} + +QEventLoopThread::~QEventLoopThread() +{ + // +} + +void QEventLoopThread::run() +{ + QEventLoop* eventLoop = QApplication::eventLoop(); + if (eventLoop) eventLoop->exec(); +} + #endif // QT_THREAD_SUPPORT diff --git a/src/kernel/qthread.h b/src/kernel/qthread.h index 160919f..0188ea6 100644 --- a/src/kernel/qthread.h +++ b/src/kernel/qthread.h @@ -118,11 +118,25 @@ protected: private: QThreadInstance * d; friend class QThreadInstance; + friend class QCoreApplicationThread; + friend class QApplication; + friend class QEventLoop; #if defined(Q_DISABLE_COPY) QThread( const QThread & ); QThread &operator=( const QThread & ); #endif // Q_DISABLE_COPY + +public: + static QThread* currentThreadObject(); +}; + +class Q_EXPORT QEventLoopThread : public QThread +{ + public: + QEventLoopThread(); + ~QEventLoopThread(); + virtual void run(); }; #endif // QT_THREAD_SUPPORT diff --git a/src/kernel/qthread_unix.cpp b/src/kernel/qthread_unix.cpp index e4d6625..52b070e 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 <sched.h> -static QThreadInstance main_instance = { - 0, { 0, &main_instance }, 0, 0, 1, 0, PTHREAD_COND_INITIALIZER, 0 -}; - - static QMutexPool *qt_thread_mutexpool = 0; @@ -82,10 +77,20 @@ static void create_storage_key() ** QThreadInstance *************************************************************************/ +void QThreadInstance::setCurrentThread(QThread *thread) +{ + pthread_once(&storage_key_once, create_storage_key); + pthread_setspecific(storage_key, thread); +} + QThreadInstance *QThreadInstance::current() { + QThreadInstance *ret = NULL; pthread_once( &storage_key_once, create_storage_key ); - QThreadInstance *ret = (QThreadInstance *) pthread_getspecific( storage_key ); + QThread *thread = (QThread *) pthread_getspecific( storage_key ); + if (thread) { + ret = thread->d; + } return ret; } @@ -101,6 +106,8 @@ void QThreadInstance::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) QThread::initialize(); } @@ -114,8 +121,8 @@ void *QThreadInstance::start( void *_arg ) { void **arg = (void **) _arg; - pthread_once( &storage_key_once, create_storage_key ); - pthread_setspecific( storage_key, arg[1] ); + setCurrentThread( (QThread *) arg[0] ); + pthread_cleanup_push( QThreadInstance::finish, arg[1] ); pthread_testcancel(); @@ -192,9 +199,6 @@ void QThread::initialize() qt_global_mutexpool = new QMutexPool( TRUE, 73 ); if ( ! qt_thread_mutexpool ) qt_thread_mutexpool = new QMutexPool( FALSE, 127 ); - - pthread_once( &storage_key_once, create_storage_key ); - pthread_setspecific( storage_key, &main_instance ); } /*! \internal @@ -206,11 +210,6 @@ void QThread::cleanup() delete qt_thread_mutexpool; qt_global_mutexpool = 0; qt_thread_mutexpool = 0; - - QThreadInstance::finish(&main_instance); - - pthread_once( &storage_key_once, create_storage_key ); - pthread_setspecific( storage_key, 0 ); } /*! @@ -470,5 +469,20 @@ bool QThread::wait( unsigned long time ) return (ret == 0); } +/*! + Returns a pointer to the currently executing QThread. If the + current thread was not started using the QThread API, this + function returns zero. + + Note that QApplication creates a QThread object to represent the + main thread; calling this function from main() after creating + QApplication will return a valid pointer. +*/ +QThread *QThread::currentThreadObject() +{ + pthread_once(&storage_key_once, create_storage_key); + return reinterpret_cast<QThread *>(pthread_getspecific(storage_key)); +} + #endif // QT_THREAD_SUPPORT diff --git a/src/kernel/qwidget.cpp b/src/kernel/qwidget.cpp index 704681d..5ad69a0 100644 --- a/src/kernel/qwidget.cpp +++ b/src/kernel/qwidget.cpp @@ -56,6 +56,9 @@ #include "qstyle.h" #include "qmetaobject.h" #include "qguardedptr.h" +#if defined(QT_THREAD_SUPPORT) +#include "qthread.h" +#endif #if defined(QT_ACCESSIBILITY_SUPPORT) #include "qaccessible.h" #endif @@ -887,6 +890,12 @@ QWidget::QWidget( QWidget *parent, const char *name, WFlags f, NFlags n ) } #endif +#if defined(QT_THREAD_SUPPORT) && defined(QT_CHECK_STATE) + if (QThread::currentThreadObject() != QApplication::guiThread()) { + qFatal( "QWidget: Cannot create a QWidget outside of the main GUI thread" ); + } +#endif + fstrut_dirty = 1; isWidget = TRUE; // is a widget |