Add real threading support, including per-thread event loops, to QThread

pull/2/head
Timothy Pearson 12 years ago
parent 7aa5ac7f0e
commit 78125ea2f0

@ -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;

@ -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

@ -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
};

@ -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
}
/*!

@ -40,6 +40,7 @@
#include "qeventloop.h"
#include "qapplication.h"
#include "qbitarray.h"
#include "qmutex.h"
#include <stdlib.h>
#include <sys/types.h>

@ -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;

@ -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 );

@ -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;
}

@ -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

@ -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
};

@ -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

@ -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

@ -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

@ -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

@ -3193,6 +3193,7 @@ void generateClass() // generate C++ source code for a class
offset++;
}
}
fprintf( out, " o[%d].isLastObject = true;\n", f->args->count() + 0 );
fprintf( out, " activate_signal( clist, o );\n" );
// get return values from inOut parameters

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -1,58 +1,166 @@
#define CHAR_VAL 257
#define INT_VAL 258
#define DOUBLE_VAL 259
#define STRING 260
#define IDENTIFIER 261
#define FRIEND 262
#define TYPEDEF 263
#define AUTO 264
#define REGISTER 265
#define STATIC 266
#define EXTERN 267
#define INLINE 268
#define VIRTUAL 269
#define CONST 270
#define VOLATILE 271
#define CHAR 272
#define SHORT 273
#define INT 274
#define LONG 275
#define SIGNED 276
#define UNSIGNED 277
#define FLOAT 278
#define DOUBLE 279
#define VOID 280
#define ENUM 281
#define CLASS 282
#define STRUCT 283
#define UNION 284
#define ASM 285
#define PRIVATE 286
#define PROTECTED 287
#define PUBLIC 288
#define OPERATOR 289
#define DBL_COLON 290
#define TRIPLE_DOT 291
#define TEMPLATE 292
#define NAMESPACE 293
#define USING 294
#define MUTABLE 295
#define THROW 296
#define SIGNALS 297
#define SLOTS 298
#define Q_OBJECT 299
#define Q_PROPERTY 300
#define Q_OVERRIDE 301
#define Q_CLASSINFO 302
#define Q_ENUMS 303
#define Q_SETS 304
#define READ 305
#define WRITE 306
#define STORED 307
#define DESIGNABLE 308
#define SCRIPTABLE 309
#define RESET 310
typedef union {
/* A Bison parser, made by GNU Bison 2.4.1. */
/* Skeleton interface for Bison's Yacc-like parsers in C
Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* As a special exception, you may create a larger work that contains
part or all of the Bison parser skeleton and distribute that work
under terms of your choice, so long as that work isn't itself a
parser generator using the skeleton or a modified version thereof
as a parser skeleton. Alternatively, if you modify or redistribute
the parser skeleton itself, you may (at your option) remove this
special exception, which will cause the skeleton and the resulting
Bison output files to be licensed under the GNU General Public
License without this special exception.
This special exception was added by the Free Software Foundation in
version 2.2 of Bison. */
/* Tokens. */
#ifndef YYTOKENTYPE
# define YYTOKENTYPE
/* Put the tokens into the symbol table, so that GDB and other debuggers
know about them. */
enum yytokentype {
CHAR_VAL = 258,
INT_VAL = 259,
DOUBLE_VAL = 260,
STRING = 261,
IDENTIFIER = 262,
FRIEND = 263,
TYPEDEF = 264,
AUTO = 265,
REGISTER = 266,
STATIC = 267,
EXTERN = 268,
INLINE = 269,
VIRTUAL = 270,
CONST = 271,
VOLATILE = 272,
CHAR = 273,
SHORT = 274,
INT = 275,
LONG = 276,
SIGNED = 277,
UNSIGNED = 278,
FLOAT = 279,
DOUBLE = 280,
VOID = 281,
ENUM = 282,
CLASS = 283,
STRUCT = 284,
UNION = 285,
ASM = 286,
PRIVATE = 287,
PROTECTED = 288,
PUBLIC = 289,
OPERATOR = 290,
DBL_COLON = 291,
TRIPLE_DOT = 292,
TEMPLATE = 293,
NAMESPACE = 294,
USING = 295,
MUTABLE = 296,
THROW = 297,
SIGNALS = 298,
SLOTS = 299,
Q_OBJECT = 300,
Q_PROPERTY = 301,
Q_OVERRIDE = 302,
Q_CLASSINFO = 303,
Q_ENUMS = 304,
Q_SETS = 305,
READ = 306,
WRITE = 307,
STORED = 308,
DESIGNABLE = 309,
SCRIPTABLE = 310,
RESET = 311
};
#endif
/* Tokens. */
#define CHAR_VAL 258
#define INT_VAL 259
#define DOUBLE_VAL 260
#define STRING 261
#define IDENTIFIER 262
#define FRIEND 263
#define TYPEDEF 264
#define AUTO 265
#define REGISTER 266
#define STATIC 267
#define EXTERN 268
#define INLINE 269
#define VIRTUAL 270
#define CONST 271
#define VOLATILE 272
#define CHAR 273
#define SHORT 274
#define INT 275
#define LONG 276
#define SIGNED 277
#define UNSIGNED 278
#define FLOAT 279
#define DOUBLE 280
#define VOID 281
#define ENUM 282
#define CLASS 283
#define STRUCT 284
#define UNION 285
#define ASM 286
#define PRIVATE 287
#define PROTECTED 288
#define PUBLIC 289
#define OPERATOR 290
#define DBL_COLON 291
#define TRIPLE_DOT 292
#define TEMPLATE 293
#define NAMESPACE 294
#define USING 295
#define MUTABLE 296
#define THROW 297
#define SIGNALS 298
#define SLOTS 299
#define Q_OBJECT 300
#define Q_PROPERTY 301
#define Q_OVERRIDE 302
#define Q_CLASSINFO 303
#define Q_ENUMS 304
#define Q_SETS 305
#define READ 306
#define WRITE 307
#define STORED 308
#define DESIGNABLE 309
#define SCRIPTABLE 310
#define RESET 311
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
typedef union YYSTYPE
{
/* Line 1676 of yacc.c */
#line 692 "moc.y"
char char_val;
int int_val;
double double_val;
@ -61,5 +169,17 @@ typedef union {
Function *function;
ArgList *arg_list;
Argument *arg;
/* Line 1676 of yacc.c */
#line 177 "moc_yacc.h"
} YYSTYPE;
# define YYSTYPE_IS_TRIVIAL 1
# define yystype YYSTYPE /* obsolescent; will be withdrawn */
# define YYSTYPE_IS_DECLARED 1
#endif
extern YYSTYPE yylval;

@ -74,7 +74,6 @@ typedef pthread_mutex_t Q_MUTEX_T;
#include <errno.h>
#include <string.h>
// Private class declarations
class QRealMutexPrivate : public QMutexPrivate {

@ -62,8 +62,12 @@
#include <pthread.h>
#endif
class QThread;
class QEventLoop;
class QThreadInstance {
public:
static void setCurrentThread(QThread *thread);
static QThreadInstance *current();
void init(unsigned int stackSize);
@ -95,6 +99,8 @@ public:
static unsigned int __stdcall start( void * );
static void finish( QThreadInstance * );
#endif // Q_OS_WIN32
QEventLoop* eventLoop;
};
#endif // QT_THREAD_SUPPORT

@ -39,6 +39,9 @@
**********************************************************************/
#include "qucom_p.h"
#include "qucomextra_p.h"
#include "qvariant.h"
// Standard types
@ -545,3 +548,24 @@ void QUType_QString::clear( QUObject *o )
delete (QString*)o->payload.ptr;
o->payload.ptr = 0;
}
QUObject* QUObject::deepCopy(QUObject* newLocation) {
QUObject* ret;
if (newLocation) {
ret = new(newLocation) QUObject(*this);
}
else {
ret = new QUObject(*this);
}
// Any type that has a clear() method must be copied here!
if (*(type->uuid()) == TID_QUType_charstar) {
static_QUType_charstar.set( ret, (const char *)static_QUType_charstar.get(this), true );
}
if (*(type->uuid()) == TID_QUType_QString) {
static_QUType_QString.set( ret, (QString)static_QUType_QString.get(this) );
}
if (*(type->uuid()) == TID_QUType_QVariant) {
static_QUType_QVariant.set( ret, (QVariant)static_QUType_QVariant.get(this) );
}
return ret;
}

@ -127,7 +127,7 @@ extern Q_EXPORT QUType_Null static_QUType_Null;
struct Q_EXPORT QUObject
{
public: // scary MSVC bug makes this necessary
QUObject() : type( &static_QUType_Null ) {}
QUObject() : type( &static_QUType_Null ), isLastObject(false) {}
~QUObject() { type->clear( this ); }
QUType *type;
@ -184,6 +184,8 @@ public: // scary MSVC bug makes this necessary
} payload;
QUObject* deepCopy(QUObject*);
bool isLastObject;
};

Loading…
Cancel
Save