summaryrefslogtreecommitdiffstats
path: root/src/kernel
diff options
context:
space:
mode:
authorTimothy Pearson <[email protected]>2012-12-06 16:47:27 -0600
committerTimothy Pearson <[email protected]>2012-12-06 16:47:27 -0600
commit78125ea2f051107b84fdc0354acdedb7885308ee (patch)
treec162d7f55467f81a01e2e669ce297acce06b3947 /src/kernel
parent7aa5ac7f0e76c5b87e4ca837b75b3edd522a3372 (diff)
downloadqt3-78125ea2f051107b84fdc0354acdedb7885308ee.tar.gz
qt3-78125ea2f051107b84fdc0354acdedb7885308ee.zip
Add real threading support, including per-thread event loops, to QThread
Diffstat (limited to 'src/kernel')
-rw-r--r--src/kernel/qapplication.cpp124
-rw-r--r--src/kernel/qapplication.h13
-rw-r--r--src/kernel/qevent.h2
-rw-r--r--src/kernel/qeventloop.cpp32
-rw-r--r--src/kernel/qeventloop_unix.cpp1
-rw-r--r--src/kernel/qeventloop_unix_glib.cpp20
-rw-r--r--src/kernel/qeventloop_x11.cpp98
-rw-r--r--src/kernel/qeventloop_x11_glib.cpp600
-rw-r--r--src/kernel/qobject.cpp328
-rw-r--r--src/kernel/qobject.h16
-rw-r--r--src/kernel/qthread.cpp17
-rw-r--r--src/kernel/qthread.h14
-rw-r--r--src/kernel/qthread_unix.cpp46
-rw-r--r--src/kernel/qwidget.cpp9
14 files changed, 883 insertions, 437 deletions
diff --git a/src/kernel/qapplication.cpp b/src/kernel/qapplication.cpp
index 51aa247..a9c9fb8 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,20 @@ bool QApplication::internalNotify( QObject *receiver, QEvent * e)
}
- if (!handled)
+ if (!handled) {
+#if defined(QT_THREAD_SUPPORT)
+ bool locked = QApplication::qt_mutex->locked();
+ if (locked) {
+ QApplication::qt_mutex->unlock();
+ }
+#endif
consumed = receiver->event( e );
+#if defined(QT_THREAD_SUPPORT)
+ if (locked) {
+ QApplication::qt_mutex->lock();
+ }
+#endif
+ }
e->spont = FALSE;
return consumed;
}
@@ -2793,9 +2872,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 +3343,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 +3421,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/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_unix.cpp b/src/kernel/qeventloop_unix.cpp
index b0ad8b9..202ef12 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>
diff --git a/src/kernel/qeventloop_unix_glib.cpp b/src/kernel/qeventloop_unix_glib.cpp
index e607447..9d3ce27 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>
@@ -578,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..cd3e865 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 );
diff --git a/src/kernel/qeventloop_x11_glib.cpp b/src/kernel/qeventloop_x11_glib.cpp
index 59ab8a1..b3d881a 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"
@@ -58,23 +57,21 @@
// 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!
@@ -82,25 +79,25 @@ static GSourceFuncs qt_gsource_funcs = {
static gboolean qt_gsource_prepare ( GSource *source,
gint *timeout )
{
- QtGSource * qtGSource;
+ QtGSource * qtGSource;
qtGSource = (QtGSource*) source;
- return qtGSource->qeventLoop->gsourcePrepare(source, timeout);
+ return qtGSource->qeventLoop->gsourcePrepare(source, timeout);
}
static gboolean qt_gsource_check ( GSource *source )
{
- QtGSource * qtGSource = (QtGSource*) source;
- return qtGSource->qeventLoop->gsourceCheck(source);
+ QtGSource * qtGSource = (QtGSource*) 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);
-
- QtGSource * qtGSource = (QtGSource*) source;
- return qtGSource->qeventLoop->gsourceDispatch(source);
+ Q_UNUSED(callback);
+ Q_UNUSED(user_data);
+
+ QtGSource * qtGSource = (QtGSource*) source;
+ return qtGSource->qeventLoop->gsourceDispatch(source);
}
@@ -134,82 +131,84 @@ 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);
+ // 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() );
+ // intitialize the X11 parts of the event loop
+ d->xfd = -1;
+ if ( qt_is_gui_used && QApplication::isGuiThread() ) {
+ d->xfd = XConnectionNumber( QPaintDevice::x11AppDisplay() );
+ }
- // new GSource
+ // new GSource
+ QtGSource * qtGSource = (QtGSource*) g_source_new(&qt_gsource_funcs, sizeof(QtGSource));
- QtGSource * qtGSource = (QtGSource*) g_source_new(&qt_gsource_funcs,
- sizeof(QtGSource));
-
- 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 ( 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);
- }
+ }
// poll thread-pipe
@@ -218,21 +217,21 @@ void QEventLoop::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 QEventLoop::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 QEventLoop::cleanup()
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;
- #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 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 ) {
+
+ if ( d->shortcut ) {
+ 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;
- }
-
- 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)();
- }
+ 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 ) {
+ 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();
+ 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 QEventLoop::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 QEventLoop::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 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?
@@ -476,45 +477,45 @@ 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
+ // 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 QEventLoop::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 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,39 +571,35 @@ 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();
processX11Events();
-
}
#if defined(QT_THREAD_SUPPORT)
- locker.mutex()->unlock();
+ locker.mutex()->unlock();
#endif
if (d->singletoolkit) {
@@ -617,21 +612,22 @@ 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() );
+ }
}
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/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/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