summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorTimothy Pearson <[email protected]>2012-11-26 22:38:07 -0600
committerTimothy Pearson <[email protected]>2012-11-26 22:38:07 -0600
commitde67a2b84b0d8b8ef994e91c108af3273e2ac37f (patch)
tree62758d4b374f0c6c0f5acf6cf99c27ff1a1fbf15 /src
parentb5d6591054de1d4f66280207023c43e9e191146c (diff)
downloadqt3-de67a2b84b0d8b8ef994e91c108af3273e2ac37f.tar.gz
qt3-de67a2b84b0d8b8ef994e91c108af3273e2ac37f.zip
Add glib main loop support patches
Diffstat (limited to 'src')
-rw-r--r--src/kernel/qeventloop.h20
-rw-r--r--src/kernel/qeventloop_glib_p.h130
-rw-r--r--src/kernel/qeventloop_p.h6
-rw-r--r--src/kernel/qeventloop_unix_glib.cpp593
-rw-r--r--src/kernel/qeventloop_x11_glib.cpp618
-rw-r--r--src/kernel/qt_kernel.pri22
-rw-r--r--src/qt.pro8
7 files changed, 1393 insertions, 4 deletions
diff --git a/src/kernel/qeventloop.h b/src/kernel/qeventloop.h
index 8d45c43..9a79f6c 100644
--- a/src/kernel/qeventloop.h
+++ b/src/kernel/qeventloop.h
@@ -44,6 +44,10 @@
#include "qsocketnotifier.h"
#endif // QT_H
+#if defined(QT_USE_GLIBMAINLOOP)
+#include <glib.h>
+#endif // QT_USE_GLIBMAINLOOP
+
class QEventLoopPrivate;
class QSocketNotifier;
class QTimer;
@@ -95,6 +99,22 @@ public:
virtual void wakeUp();
+#if defined(QT_USE_GLIBMAINLOOP)
+
+ // glib main loop support
+
+ /* internal: used to fit glib-main-loop gsource concept */
+
+ bool gsourcePrepare(GSource *gs, int * timeout);
+ bool gsourceCheck(GSource * gs);
+ bool gsourceDispatch(GSource * gs);
+
+ bool processX11Events();
+
+ // end glib main loop support
+
+#endif //QT_USE_GLIBMAINLOOP
+
signals:
void awake();
void aboutToBlock();
diff --git a/src/kernel/qeventloop_glib_p.h b/src/kernel/qeventloop_glib_p.h
new file mode 100644
index 0000000..8d1ead9
--- /dev/null
+++ b/src/kernel/qeventloop_glib_p.h
@@ -0,0 +1,130 @@
+/**
+** Qt->glib main event loop integration by Norbert Frese 2005
+** code based on qeventloop_p.h 3.3.5
+**
+*/
+
+/****************************************************************************
+** $Id: qt/qeventloop_glib_p.h
+**
+** Definition of QEventLoop class
+**
+** Copyright (C) 1992-2005 Trolltech AS. All rights reserved.
+**
+** This file is part of the kernel module of the Qt GUI Toolkit.
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
+** licenses for Qt/Embedded may use this file in accordance with the
+** Qt Embedded Commercial License Agreement provided with the Software.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+** See http://www.trolltech.com/pricing.html or email [email protected] for
+** information about Qt Commercial License Agreements.
+** See http://www.trolltech.com/gpl/ for GPL licensing information.
+**
+** Contact [email protected] if any conditions of this licensing are
+** not clear to you.
+**
+**********************************************************************/
+
+#ifndef QEVENTLOOP_GLIB_P_H
+#define QEVENTLOOP_GLIB_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. This header file may
+// change from version to version without notice, or even be
+// removed.
+//
+// We mean it.
+//
+//
+
+#ifndef QT_H
+#include "qplatformdefs.h"
+#endif // QT_H
+
+// SCO OpenServer redefines raise -> kill
+#if defined(raise)
+# undef raise
+#endif
+
+#include "qeventloop.h"
+#include "qwindowdefs.h"
+
+class QSocketNotifier;
+
+#include "qptrlist.h"
+
+#include <glib.h>
+
+// uncomment this for main loop related debug-output
+
+// #define DEBUG_QT_GLIBMAINLOOP 1
+
+// Wrapper for QSocketNotifier Object and GPollFD
+
+struct QSockNotGPollFD
+{
+ QSocketNotifier *obj;
+ GPollFD gPollFD;
+ gushort events; // save events
+ bool pending;
+};
+
+class QEventLoopPrivate
+{
+public:
+ QEventLoopPrivate()
+ {
+ reset();
+ }
+
+ void reset() {
+ looplevel = 0;
+ quitcode = 0;
+ quitnow = FALSE;
+ exitloop = FALSE;
+ shortcut = FALSE;
+ }
+
+ int looplevel;
+ int quitcode;
+ unsigned int quitnow : 1;
+ unsigned int exitloop : 1;
+ unsigned int shortcut : 1;
+
+#if defined(Q_WS_X11)
+ int xfd;
+
+ GPollFD x_gPollFD;
+
+#endif // Q_WS_X11
+
+ int thread_pipe[2];
+
+ GPollFD threadPipe_gPollFD;
+
+ QPtrList<QSockNotGPollFD> sn_list;
+ // pending socket notifiers list
+ QPtrList<QSockNotGPollFD> sn_pending_list;
+
+ // store flags for one iteration
+ uint pev_flags;
+
+ // My GSource
+
+ GSource * gSource;
+
+};
+
+#endif // QEVENTLOOP_GLIB_P_H
diff --git a/src/kernel/qeventloop_p.h b/src/kernel/qeventloop_p.h
index 4e7e365..7935d73 100644
--- a/src/kernel/qeventloop_p.h
+++ b/src/kernel/qeventloop_p.h
@@ -49,6 +49,10 @@
//
//
+#if defined(QT_USE_GLIBMAINLOOP)
+#include "qeventloop_glib_p.h" // use a different header file!!!
+#else
+
#ifndef QT_H
#include "qplatformdefs.h"
#endif // QT_H
@@ -147,4 +151,6 @@ public:
};
+#endif // !QT_USE_GLIBMAINLOOP
+
#endif // QEVENTLOOP_P_H
diff --git a/src/kernel/qeventloop_unix_glib.cpp b/src/kernel/qeventloop_unix_glib.cpp
new file mode 100644
index 0000000..6852f6b
--- /dev/null
+++ b/src/kernel/qeventloop_unix_glib.cpp
@@ -0,0 +1,593 @@
+/**
+** Qt->glib main event loop integration by Norbert Frese 2005
+** code based on qeventloop_unix.cpp 3.3.5
+**
+*/
+
+/****************************************************************************
+** $Id: qt/qeventloop_unix_glib.cpp
+**
+** Implementation of QEventLoop class
+**
+** Copyright (C) 2000-2005 Trolltech AS. All rights reserved.
+**
+** This file is part of the kernel module of the Qt GUI Toolkit.
+**
+** This file may be distributed under the terms of the Q Public License
+** as defined by Trolltech AS of Norway and appearing in the file
+** LICENSE.QPL included in the packaging of this file.
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
+** licenses for Unix/X11 or for Qt/Embedded may use this file in accordance
+** with the Qt Commercial License Agreement provided with the Software.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+** See http://www.trolltech.com/pricing.html or email [email protected] for
+** information about Qt Commercial License Agreements.
+** See http://www.trolltech.com/qpl/ for QPL licensing information.
+** See http://www.trolltech.com/gpl/ for GPL licensing information.
+**
+** Contact [email protected] if any conditions of this licensing are
+** not clear to you.
+**
+**********************************************************************/
+
+
+#include "qeventloop_glib_p.h" // includes qplatformdefs.h
+#include "qeventloop.h"
+#include "qapplication.h"
+#include "qbitarray.h"
+#include <stdlib.h>
+#include <sys/types.h>
+
+#include <glib.h>
+
+/*****************************************************************************
+ Timer handling; UNIX has no application timer support so we'll have to
+ make our own from scratch.
+
+ NOTE: These functions are for internal use. QObject::startTimer() and
+ QObject::killTimer() are for public use.
+ The QTimer class provides a high-level interface which translates
+ timer events into signals.
+
+ qStartTimer( interval, obj )
+ Starts a timer which will run until it is killed with qKillTimer()
+ Arguments:
+ int interval timer interval in milliseconds
+ QObject *obj where to send the timer event
+ Returns:
+ int timer identifier, or zero if not successful
+
+ qKillTimer( timerId )
+ Stops a timer specified by a timer identifier.
+ Arguments:
+ int timerId timer identifier
+ Returns:
+ bool TRUE if successful
+
+ qKillTimer( obj )
+ Stops all timers that are sent to the specified object.
+ Arguments:
+ QObject *obj object receiving timer events
+ Returns:
+ bool TRUE if successful
+ *****************************************************************************/
+
+//
+// Internal data structure for timers
+//
+
+struct TimerInfo { // internal timer info
+ int id; // - timer identifier
+ timeval interval; // - timer interval
+ timeval timeout; // - when to sent event
+ QObject *obj; // - object to receive event
+};
+
+typedef QPtrList<TimerInfo> TimerList; // list of TimerInfo structs
+
+static QBitArray *timerBitVec; // timer bit vector
+static TimerList *timerList = 0; // timer list
+
+static void initTimers();
+void cleanupTimers();
+static timeval watchtime; // watch if time is turned back
+timeval *qt_wait_timer();
+timeval *qt_wait_timer_max = 0;
+
+//
+// Internal operator functions for timevals
+//
+
+static inline bool operator<( const timeval &t1, const timeval &t2 )
+{
+ return t1.tv_sec < t2.tv_sec ||
+ (t1.tv_sec == t2.tv_sec && t1.tv_usec < t2.tv_usec);
+}
+
+static inline bool operator==( const timeval &t1, const timeval &t2 )
+{
+ return t1.tv_sec == t2.tv_sec && t1.tv_usec == t2.tv_usec;
+}
+
+static inline timeval &operator+=( timeval &t1, const timeval &t2 )
+{
+ t1.tv_sec += t2.tv_sec;
+ if ( (t1.tv_usec += t2.tv_usec) >= 1000000 ) {
+ t1.tv_sec++;
+ t1.tv_usec -= 1000000;
+ }
+ return t1;
+}
+
+static inline timeval operator+( const timeval &t1, const timeval &t2 )
+{
+ timeval tmp;
+ tmp.tv_sec = t1.tv_sec + t2.tv_sec;
+ if ( (tmp.tv_usec = t1.tv_usec + t2.tv_usec) >= 1000000 ) {
+ tmp.tv_sec++;
+ tmp.tv_usec -= 1000000;
+ }
+ return tmp;
+}
+
+static inline timeval operator-( const timeval &t1, const timeval &t2 )
+{
+ timeval tmp;
+ tmp.tv_sec = t1.tv_sec - t2.tv_sec;
+ if ( (tmp.tv_usec = t1.tv_usec - t2.tv_usec) < 0 ) {
+ tmp.tv_sec--;
+ tmp.tv_usec += 1000000;
+ }
+ return tmp;
+}
+
+
+//
+// Internal functions for manipulating timer data structures.
+// The timerBitVec array is used for keeping track of timer identifiers.
+//
+
+static int allocTimerId() // find avail timer identifier
+{
+ int i = timerBitVec->size()-1;
+ while ( i >= 0 && (*timerBitVec)[i] )
+ i--;
+ if ( i < 0 ) {
+ i = timerBitVec->size();
+ timerBitVec->resize( 4 * i );
+ for( int j=timerBitVec->size()-1; j > i; j-- )
+ timerBitVec->clearBit( j );
+ }
+ timerBitVec->setBit( i );
+ return i+1;
+}
+
+static void insertTimer( const TimerInfo *ti ) // insert timer info into list
+{
+ TimerInfo *t = timerList->first();
+ int index = 0;
+#if defined(QT_DEBUG)
+ int dangerCount = 0;
+#endif
+ while ( t && t->timeout < ti->timeout ) { // list is sorted by timeout
+#if defined(QT_DEBUG)
+ if ( t->obj == ti->obj )
+ dangerCount++;
+#endif
+ t = timerList->next();
+ index++;
+ }
+ timerList->insert( index, ti ); // inserts sorted
+#if defined(QT_DEBUG)
+ if ( dangerCount > 16 )
+ qDebug( "QObject: %d timers now exist for object %s::%s",
+ dangerCount, ti->obj->className(), ti->obj->name() );
+#endif
+}
+
+static inline void getTime( timeval &t ) // get time of day
+{
+ gettimeofday( &t, 0 );
+ while ( t.tv_usec >= 1000000 ) { // NTP-related fix
+ t.tv_usec -= 1000000;
+ t.tv_sec++;
+ }
+ while ( t.tv_usec < 0 ) {
+ if ( t.tv_sec > 0 ) {
+ t.tv_usec += 1000000;
+ t.tv_sec--;
+ } else {
+ t.tv_usec = 0;
+ break;
+ }
+ }
+}
+
+static void repairTimer( const timeval &time ) // repair broken timer
+{
+ timeval diff = watchtime - time;
+ register TimerInfo *t = timerList->first();
+ while ( t ) { // repair all timers
+ t->timeout = t->timeout - diff;
+ t = timerList->next();
+ }
+}
+
+//
+// Timer activation functions (called from the event loop)
+//
+
+/*
+ Returns the time to wait for the next timer, or null if no timers are
+ waiting.
+
+ The result is bounded to qt_wait_timer_max if this exists.
+*/
+
+timeval *qt_wait_timer()
+{
+ static timeval tm;
+ bool first = TRUE;
+ timeval currentTime;
+ if ( timerList && timerList->count() ) { // there are waiting timers
+ getTime( currentTime );
+ if ( first ) {
+ if ( currentTime < watchtime ) // clock was turned back
+ repairTimer( currentTime );
+ first = FALSE;
+ watchtime = currentTime;
+ }
+ TimerInfo *t = timerList->first(); // first waiting timer
+ if ( currentTime < t->timeout ) { // time to wait
+ tm = t->timeout - currentTime;
+ } else {
+ tm.tv_sec = 0; // no time to wait
+ tm.tv_usec = 0;
+ }
+ if ( qt_wait_timer_max && *qt_wait_timer_max < tm )
+ tm = *qt_wait_timer_max;
+ return &tm;
+ }
+ if ( qt_wait_timer_max ) {
+ tm = *qt_wait_timer_max;
+ return &tm;
+ }
+ return 0; // no timers
+}
+
+// Timer initialization
+static void initTimers() // initialize timers
+{
+ timerBitVec = new QBitArray( 128 );
+ Q_CHECK_PTR( timerBitVec );
+ int i = timerBitVec->size();
+ while( i-- > 0 )
+ timerBitVec->clearBit( i );
+ timerList = new TimerList;
+ Q_CHECK_PTR( timerList );
+ timerList->setAutoDelete( TRUE );
+ gettimeofday( &watchtime, 0 );
+}
+
+// Timer cleanup
+void cleanupTimers()
+{
+ delete timerList;
+ timerList = 0;
+ delete timerBitVec;
+ timerBitVec = 0;
+}
+
+// Main timer functions for starting and killing timers
+int qStartTimer( int interval, QObject *obj )
+{
+ if ( !timerList ) // initialize timer data
+ initTimers();
+ int id = allocTimerId(); // get free timer id
+ if ( id <= 0 ||
+ id > (int)timerBitVec->size() || !obj )// cannot create timer
+ return 0;
+ timerBitVec->setBit( id-1 ); // set timer active
+ TimerInfo *t = new TimerInfo; // create timer
+ Q_CHECK_PTR( t );
+ t->id = id;
+ t->interval.tv_sec = interval/1000;
+ t->interval.tv_usec = (interval%1000)*1000;
+ timeval currentTime;
+ getTime( currentTime );
+ t->timeout = currentTime + t->interval;
+ t->obj = obj;
+ insertTimer( t ); // put timer in list
+ return id;
+}
+
+bool qKillTimer( int id )
+{
+ register TimerInfo *t;
+ if ( !timerList || id <= 0 ||
+ id > (int)timerBitVec->size() || !timerBitVec->testBit( id-1 ) )
+ return FALSE; // not init'd or invalid timer
+ t = timerList->first();
+ while ( t && t->id != id ) // find timer info in list
+ t = timerList->next();
+ if ( t ) { // id found
+ timerBitVec->clearBit( id-1 ); // set timer inactive
+ return timerList->remove();
+ }
+ else // id not found
+ return FALSE;
+}
+
+bool qKillTimer( QObject *obj )
+{
+ register TimerInfo *t;
+ if ( !timerList ) // not initialized
+ return FALSE;
+ t = timerList->first();
+ while ( t ) { // check all timers
+ if ( t->obj == obj ) { // object found
+ timerBitVec->clearBit( t->id-1 );
+ timerList->remove();
+ t = timerList->current();
+ } else {
+ t = timerList->next();
+ }
+ }
+ return TRUE;
+}
+
+
+
+
+/*****************************************************************************
+ QEventLoop implementations for Glib-Main-Loop
+ *****************************************************************************/
+
+
+
+
+void QEventLoop::registerSocketNotifier( QSocketNotifier *notifier )
+{
+
+
+
+ int sockfd = notifier->socket();
+ int type = notifier->type();
+ if ( sockfd < 0 || type < 0 || type > 2 || notifier == 0 ) {
+#if defined(QT_CHECK_RANGE)
+ qWarning( "QSocketNotifier: Internal error" );
+#endif
+ return;
+ }
+
+ #ifdef DEBUG_QT_GLIBMAINLOOP
+ printf("register socket notifier %d\n", sockfd);
+ #endif
+
+ QPtrList<QSockNotGPollFD> *list = &d->sn_list;
+ QSockNotGPollFD *sn;
+
+ /*
+ if ( ! list ) {
+ // create new list, the QSockNotType destructor will delete it for us
+ list = new QPtrList<QSockNot>;
+ Q_CHECK_PTR( list );
+ list->setAutoDelete( TRUE );
+ d->sn_list = list;
+ }
+ */
+
+ gushort events=0;
+ switch (type) {
+ case 0:
+ events = G_IO_IN | G_IO_HUP;
+ break;
+ case 1:
+ events = G_IO_OUT;
+ break;
+ case 2:
+ events = G_IO_PRI | G_IO_ERR | G_IO_NVAL;
+ break;
+ }
+
+ sn = new QSockNotGPollFD;
+ Q_CHECK_PTR( sn );
+ sn->obj = notifier;
+ sn->gPollFD.fd = sockfd;
+ sn->gPollFD.events = events;
+ sn->events = events; // save events!
+ sn->pending = FALSE;
+
+ list->append( sn );
+
+ g_source_add_poll(d->gSource, &sn->gPollFD);
+
+}
+
+void QEventLoop::unregisterSocketNotifier( QSocketNotifier *notifier )
+{
+ int sockfd = notifier->socket();
+ int type = notifier->type();
+ if ( sockfd < 0 || type < 0 || type > 2 || notifier == 0 ) {
+#if defined(QT_CHECK_RANGE)
+ qWarning( "QSocketNotifier: Internal error" );
+#endif
+ return;
+ }
+
+ #ifdef DEBUG_QT_GLIBMAINLOOP
+ printf("unregister socket notifier %d\n", sockfd);
+ #endif
+
+ QPtrList<QSockNotGPollFD> *list = &d->sn_list;
+ QSockNotGPollFD *sn;
+ if ( ! list )
+ return;
+ sn = list->first();
+ while ( sn && !(sn->obj == notifier) )
+ sn = list->next();
+ if ( !sn ) // not found
+ return;
+
+ d->sn_pending_list.removeRef( sn );
+ list->remove(); // remove notifier found above
+ g_source_remove_poll(d->gSource, &sn->gPollFD);
+
+ delete sn; // we don't autodelete - lets do it manually
+
+}
+
+void QEventLoop::setSocketNotifierPending( QSocketNotifier *notifier )
+{
+ int sockfd = notifier->socket();
+ int type = notifier->type();
+ if ( sockfd < 0 || type < 0 || type > 2 || notifier == 0 ) {
+#if defined(QT_CHECK_RANGE)
+ qWarning( "QSocketNotifier: Internal error" );
+#endif
+ return;
+ }
+
+ #ifdef DEBUG_QT_GLIBMAINLOOP
+ printf("set socket notifier pending %d\n", sockfd);
+ #endif
+
+ QPtrList<QSockNotGPollFD> *list = &d->sn_list;
+ QSockNotGPollFD *sn;
+ if ( ! list )
+ return;
+ sn = list->first();
+ while ( sn && !(sn->obj == notifier) )
+ sn = list->next();
+ if ( ! sn ) { // not found
+ return;
+ }
+
+ // We choose a random activation order to be more fair under high load.
+ // If a constant order is used and a peer early in the list can
+ // saturate the IO, it might grab our attention completely.
+ // Also, if we're using a straight list, the callback routines may
+ // delete other entries from the list before those other entries are
+ // processed.
+ if ( !sn->pending ) {
+ d->sn_pending_list.insert( (rand() & 0xff) %
+ (d->sn_pending_list.count()+1), sn );
+ sn->pending = TRUE; // add it only once!
+ }
+}
+
+void QEventLoop::wakeUp()
+{
+ /*
+ Apparently, there is not consistency among different operating
+ systems on how to use FIONREAD.
+
+ FreeBSD, Linux and Solaris all expect the 3rd argument to
+ ioctl() to be an int, which is normally 32-bit even on 64-bit
+ machines.
+
+ IRIX, on the other hand, expects a size_t, which is 64-bit on
+ 64-bit machines.
+
+ So, the solution is to use size_t initialized to zero to make
+ sure all bits are set to zero, preventing underflow with the
+ FreeBSD/Linux/Solaris ioctls.
+ */
+ size_t nbytes = 0;
+ char c = 0;
+ if ( ::ioctl( d->thread_pipe[0], FIONREAD, (char*)&nbytes ) >= 0 && nbytes == 0 ) {
+ ::write( d->thread_pipe[1], &c, 1 );
+ }
+}
+
+int QEventLoop::timeToWait() const
+{
+ timeval *tm = qt_wait_timer();
+ if ( ! tm ) // no active timers
+ return -1;
+ return (tm->tv_sec*1000) + (tm->tv_usec/1000);
+}
+
+int QEventLoop::activateTimers()
+{
+ if ( !timerList || !timerList->count() ) // no timers
+ return 0;
+ bool first = TRUE;
+ timeval currentTime;
+ int n_act = 0, maxCount = timerList->count();
+ TimerInfo *begin = 0;
+ register TimerInfo *t;
+
+ for ( ;; ) {
+ if ( ! maxCount-- )
+ break;
+ getTime( currentTime ); // get current time
+ if ( first ) {
+ if ( currentTime < watchtime ) // clock was turned back
+ repairTimer( currentTime );
+ first = FALSE;
+ watchtime = currentTime;
+ }
+ t = timerList->first();
+ if ( !t || currentTime < t->timeout ) // no timer has expired
+ break;
+ if ( ! begin ) {
+ begin = t;
+ } else if ( begin == t ) {
+ // avoid sending the same timer multiple times
+ break;
+ } else if ( t->interval < begin->interval || t->interval == begin->interval ) {
+ begin = t;
+ }
+ timerList->take(); // unlink from list
+ t->timeout += t->interval;
+ if ( t->timeout < currentTime )
+ t->timeout = currentTime + t->interval;
+ insertTimer( t ); // relink timer
+ if ( t->interval.tv_usec > 0 || t->interval.tv_sec > 0 )
+ n_act++;
+ QTimerEvent e( t->id );
+ QApplication::sendEvent( t->obj, &e ); // send event
+ if ( timerList->findRef( begin ) == -1 )
+ begin = 0;
+ }
+ return n_act;
+}
+
+int QEventLoop::activateSocketNotifiers()
+{
+ if ( d->sn_pending_list.isEmpty() )
+ return 0;
+
+ // activate entries
+ int n_act = 0;
+ QEvent event( QEvent::SockAct );
+ QPtrListIterator<QSockNotGPollFD> it( d->sn_pending_list );
+ QSockNotGPollFD *sn;
+ 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++;
+ }
+ }
+
+ return n_act;
+}
diff --git a/src/kernel/qeventloop_x11_glib.cpp b/src/kernel/qeventloop_x11_glib.cpp
new file mode 100644
index 0000000..10ee007
--- /dev/null
+++ b/src/kernel/qeventloop_x11_glib.cpp
@@ -0,0 +1,618 @@
+/**
+** Qt->glib main event loop integration by Norbert Frese 2005
+** code based on qeventloop_x11.cpp 3.3.5
+**
+*/
+
+/****************************************************************************
+** $Id: qt/qeventloop_x11_glib.cpp
+**
+** Implementation of QEventLoop class
+**
+** Copyright (C) 2000-2005 Trolltech AS. All rights reserved.
+**
+** This file is part of the kernel module of the Qt GUI Toolkit.
+**
+** This file may be distributed under the terms of the Q Public License
+** as defined by Trolltech AS of Norway and appearing in the file
+** LICENSE.QPL included in the packaging of this file.
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
+** licenses for Unix/X11 may use this file in accordance with the Qt Commercial
+** License Agreement provided with the Software.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+** See http://www.trolltech.com/pricing.html or email [email protected] for
+** information about Qt Commercial License Agreements.
+** See http://www.trolltech.com/qpl/ for QPL licensing information.
+** See http://www.trolltech.com/gpl/ for GPL licensing information.
+**
+** Contact [email protected] if any conditions of this licensing are
+** not clear to you.
+**
+**********************************************************************/
+
+
+#include "qeventloop_glib_p.h" // includes qplatformdefs.h
+#include "qeventloop.h"
+#include "qapplication.h"
+#include "qbitarray.h"
+#include "qcolor_p.h"
+#include "qt_x11_p.h"
+
+#if defined(QT_THREAD_SUPPORT)
+# include "qmutex.h"
+#endif // QT_THREAD_SUPPORT
+
+#include <errno.h>
+
+#include <glib.h>
+
+// Qt-GSource Structure and Callbacks
+
+typedef struct {
+ GSource source;
+ QEventLoop * qeventLoop;
+} QtGSource;
+
+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 GSourceFuncs qt_gsource_funcs = {
+ qt_gsource_prepare,
+ qt_gsource_check,
+ qt_gsource_dispatch,
+ NULL,
+ NULL,
+ NULL
+};
+
+// forward main loop callbacks to QEventLoop methods!
+
+static gboolean qt_gsource_prepare ( GSource *source,
+ gint *timeout )
+{
+ QtGSource * qtGSource;
+ qtGSource = (QtGSource*) source;
+ return qtGSource->qeventLoop->gsourcePrepare(source, timeout);
+}
+
+static gboolean qt_gsource_check ( GSource *source )
+{
+ QtGSource * qtGSource = (QtGSource*) source;
+ return qtGSource->qeventLoop->gsourceCheck(source);
+}
+
+static gboolean qt_gsource_dispatch ( GSource *source,
+ GSourceFunc callback, gpointer user_data )
+{
+ QtGSource * qtGSource = (QtGSource*) source;
+ return qtGSource->qeventLoop->gsourceDispatch(source);
+}
+
+
+// -------------------------------------------------
+
+// resolve the conflict between X11's FocusIn and QEvent::FocusIn
+#undef FocusOut
+#undef FocusIn
+
+static const int XKeyPress = KeyPress;
+static const int XKeyRelease = KeyRelease;
+#undef KeyPress
+#undef KeyRelease
+
+// from qapplication.cpp
+extern bool qt_is_gui_used;
+
+// from qeventloop_unix.cpp
+extern timeval *qt_wait_timer();
+extern void cleanupTimers();
+
+// ### this needs to go away at some point...
+typedef void (*VFPTR)();
+typedef QValueList<VFPTR> QVFuncList;
+void qt_install_preselect_handler( VFPTR );
+void qt_remove_preselect_handler( VFPTR );
+static QVFuncList *qt_preselect_handler = 0;
+void qt_install_postselect_handler( VFPTR );
+void qt_remove_postselect_handler( VFPTR );
+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 );
+}
+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 );
+ }
+}
+void qt_install_postselect_handler( VFPTR 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 );
+ }
+}
+
+
+void QEventLoop::init()
+{
+ // initialize ProcessEventFlags (all events & wait for more)
+
+ d->pev_flags = AllEvents | WaitForMore;
+
+ // initialize the common parts of the event loop
+ pipe( d->thread_pipe );
+ fcntl(d->thread_pipe[0], F_SETFD, FD_CLOEXEC);
+ fcntl(d->thread_pipe[1], F_SETFD, FD_CLOEXEC);
+
+ // intitialize the X11 parts of the event loop
+ d->xfd = -1;
+ if ( qt_is_gui_used )
+ d->xfd = XConnectionNumber( QPaintDevice::x11AppDisplay() );
+
+ // new GSource
+
+ QtGSource * qtGSource = (QtGSource*) g_source_new(&qt_gsource_funcs,
+ sizeof(QtGSource));
+
+ g_source_set_can_recurse ((GSource*)qtGSource, TRUE);
+
+ qtGSource->qeventLoop = this;
+
+ // init main loop and attach gsource
+
+ #ifdef DEBUG_QT_GLIBMAINLOOP
+ printf("inside init(1)\n");
+ #endif
+
+ g_main_loop_new (NULL, 1);
+
+ g_source_attach( (GSource*)qtGSource, NULL );
+
+ d->gSource = (GSource*) qtGSource;
+
+ // poll for X11 events
+
+ if ( qt_is_gui_used ) {
+
+
+ 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
+
+ d->threadPipe_gPollFD.fd = d->thread_pipe[0];
+ d->threadPipe_gPollFD.events = G_IO_IN | G_IO_HUP;
+
+ g_source_add_poll(d->gSource, &d->threadPipe_gPollFD);
+
+ #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;
+
+ // todo: destroy gsource
+}
+
+bool QEventLoop::processEvents( ProcessEventsFlags flags )
+{
+
+ #ifdef DEBUG_QT_GLIBMAINLOOP
+ printf("inside processEvents(1) looplevel=%d\n", d->looplevel );
+ #endif
+ ProcessEventsFlags save_flags;
+ int rval;
+ save_flags = d->pev_flags;
+
+ d->pev_flags = flags;
+
+ 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;
+
+#if defined(QT_THREAD_SUPPORT)
+ 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;
+ }
+
+ default: break;
+ }
+ }
+
+ nevents++;
+ if ( qApp->x11ProcessEvent( &event ) == 1 )
+ return TRUE;
+ }
+ }
+ }
+
+ 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;
+}
+
+
+bool QEventLoop::gsourcePrepare(GSource *gs, int * timeout)
+{
+
+ #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 );
+#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
+ }
+ } 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();
+
+
+ if ( qt_preselect_handler ) {
+ QVFuncList::Iterator it, end = qt_preselect_handler->end();
+ for ( it = qt_preselect_handler->begin(); it != end; ++it )
+ (**it)();
+ }
+
+ // unlock the GUI mutex and select. when we return from this function, there is
+ // something for us to do
+#if defined(QT_THREAD_SUPPORT)
+ locker.mutex()->unlock();
+#endif
+
+ #ifdef DEBUG_QT_GLIBMAINLOOP
+ printf("inside gsourcePrepare(2.1) canwait=%d\n", canWait);
+ #endif
+
+ // do we have to dispatch events?
+ if (hasPendingEvents()) {
+ *timeout = 0; // no time to stay in poll
+
+ #ifdef DEBUG_QT_GLIBMAINLOOP
+ printf("inside gsourcePrepare(3a)\n");
+ #endif
+
+ return FALSE;
+ }
+
+ // stay in poll until something happens?
+ if (!tm) { // fixme
+ *timeout = -1; // wait forever
+ #ifdef DEBUG_QT_GLIBMAINLOOP
+ printf("inside gsourcePrepare(3b) timeout=%d \n", *timeout);
+ #endif
+
+
+ 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
+
+
+ return FALSE;
+}
+
+
+bool QEventLoop::gsourceCheck(GSource *gs) {
+
+ #ifdef DEBUG_QT_GLIBMAINLOOP
+ printf("inside gsourceCheck(1)\n");
+ #endif
+
+
+ // Socketnotifier events?
+
+ QPtrList<QSockNotGPollFD> *list = &d->sn_list;
+
+ //if ( list ) {
+
+
+ QSockNotGPollFD *sn = list->first();
+ while ( sn ) {
+ if ( sn->gPollFD.revents )
+ return TRUE;
+ sn = list->next();
+ }
+ //}
+
+ if (d->x_gPollFD.revents) {
+ #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
+
+ return TRUE; // we got events!
+ }
+ 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?
+
+ 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;
+ }
+
+ // nothing to dispatch
+
+ #ifdef DEBUG_QT_GLIBMAINLOOP
+ printf("inside gsourceCheck(2) nothing to dispatch!\n");
+ #endif
+
+ return FALSE;
+}
+
+
+bool QEventLoop::gsourceDispatch(GSource *gs) {
+
+ // relock the GUI mutex before processing any pending events
+#if defined(QT_THREAD_SUPPORT)
+ QMutexLocker locker( QApplication::qt_mutex );
+#endif
+#if defined(QT_THREAD_SUPPORT)
+ locker.mutex()->lock();
+#endif
+
+ int nevents=0;
+
+ ProcessEventsFlags flags = d->pev_flags;
+
+ #ifdef DEBUG_QT_GLIBMAINLOOP
+ printf("inside gsourceDispatch(1)\n");
+ #endif
+
+ // we are awake, broadcast it
+ emit awake();
+ emit qApp->guiThreadAwake();
+
+ // some other thread woke us up... consume the data on the thread pipe so that
+ // select doesn't immediately return next time
+
+ if ( d->threadPipe_gPollFD.revents) {
+ char c;
+ ::read( d->thread_pipe[0], &c, 1 );
+ }
+
+ 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 )) {
+ // 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 ) {
+ if ( sn->gPollFD.revents )
+ setSocketNotifierPending( sn->obj );
+ sn = list->next();
+ }
+ // }
+
+ nevents += activateSocketNotifiers();
+ }
+
+ // 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
+
+ if (hasPendingEvents()) {
+
+ // color approx. optimization - only on X11
+ qt_reset_color_avail();
+
+ processX11Events();
+
+ }
+
+#if defined(QT_THREAD_SUPPORT)
+ locker.mutex()->unlock();
+#endif
+
+ return TRUE;
+
+}
+
+bool QEventLoop::hasPendingEvents() const
+{
+ extern uint qGlobalPostedEventsCount(); // from qapplication.cpp
+ return ( qGlobalPostedEventsCount() || ( qt_is_gui_used ? XPending( QPaintDevice::x11AppDisplay() ) : 0));
+}
+
+void QEventLoop::appStartingUp()
+{
+ if ( qt_is_gui_used )
+ d->xfd = XConnectionNumber( QPaintDevice::x11AppDisplay() );
+}
+
+void QEventLoop::appClosingDown()
+{
+ d->xfd = -1;
+}
diff --git a/src/kernel/qt_kernel.pri b/src/kernel/qt_kernel.pri
index 5a89e08..b72220f 100644
--- a/src/kernel/qt_kernel.pri
+++ b/src/kernel/qt_kernel.pri
@@ -21,7 +21,7 @@ kernel {
$$KERNEL_H/qdrawutil.h \
$$KERNEL_H/qdropsite.h \
$$KERNEL_H/qevent.h \
- $$KERNEL_H/qeventloop.h\
+ $$KERNEL_H/qeventloop.h \
$$KERNEL_P/qeventloop_p.h \
$$KERNEL_H/qfocusdata.h \
$$KERNEL_H/qfont.h \
@@ -104,6 +104,10 @@ kernel {
HEADERS += $$KERNEL_P/qinputcontext_p.h
}
+ glibmainloop {
+ HEADERS+=$$KERNEL_P/qeventloop_glib_p.h
+ }
+
win32:SOURCES += $$KERNEL_CPP/qapplication_win.cpp \
$$KERNEL_CPP/qclipboard_win.cpp \
$$KERNEL_CPP/qcolor_win.cpp \
@@ -133,7 +137,6 @@ kernel {
$$KERNEL_CPP/qcursor_x11.cpp \
$$KERNEL_CPP/qdnd_x11.cpp \
$$KERNEL_CPP/qdesktopwidget_x11.cpp \
- $$KERNEL_CPP/qeventloop_x11.cpp \
$$KERNEL_CPP/qfont_x11.cpp \
$$KERNEL_CPP/qinputcontext.cpp \
$$KERNEL_CPP/qinputcontext_x11.cpp \
@@ -146,6 +149,12 @@ kernel {
$$KERNEL_CPP/qwidget_x11.cpp \
$$KERNEL_CPP/qwidgetcreate_x11.cpp \
$$KERNEL_CPP/qfontengine_x11.cpp
+ glibmainloop {
+ SOURCES += $$KERNEL_CPP/qeventloop_x11_glib.cpp
+ } else {
+ SOURCES += $$KERNEL_CPP/qeventloop_x11.cpp
+ }
+
}
!x11:mac {
@@ -172,8 +181,13 @@ kernel {
DEFINES += QMAC_ONE_PIXEL_LOCK
} else:unix {
SOURCES += $$KERNEL_CPP/qprinter_unix.cpp \
- $$KERNEL_CPP/qpsprinter.cpp \
- $$KERNEL_CPP/qeventloop_unix.cpp
+ $$KERNEL_CPP/qpsprinter.cpp
+ glibmainloop {
+ SOURCES += $$KERNEL_CPP/qeventloop_unix_glib.cpp
+ } else {
+ SOURCES += $$KERNEL_CPP/qeventloop_unix.cpp
+ }
+
}
unix:SOURCES += $$KERNEL_CPP/qprocess_unix.cpp \
$$KERNEL_CPP/qthread_unix.cpp
diff --git a/src/qt.pro b/src/qt.pro
index 2cc70cf..6f5037b 100644
--- a/src/qt.pro
+++ b/src/qt.pro
@@ -196,3 +196,11 @@ wince-* {
$$CODECS_CPP/qtextcodecplugin.cpp \
$$WIDGETS_CPP/qwidgetplugin.cpp
}
+
+glibmainloop {
+ DEFINES += QT_USE_GLIBMAINLOOP
+ QMAKE_CFLAGS += $$QMAKE_CFLAGS_GLIB
+ QMAKE_CXXFLAGS += $$QMAKE_CFLAGS_GLIB
+ LIBS += $$QMAKE_LIBS_GLIB
+}
+