Index: trunk/src/kernel/qeventloop_pm.cpp
===================================================================
--- trunk/src/kernel/qeventloop_pm.cpp	(revision 175)
+++ trunk/src/kernel/qeventloop_pm.cpp	(revision 176)
@@ -63,9 +63,11 @@
 static HMQ qt_gui_queue = 0;
 
+#ifdef QT_PM_NO_DOSTIMERS
+static bool	dispatchTimer( uint, QMSG * );
+#endif
+static void	activateZeroTimers();
+
 static void	initTimers();
 static void	cleanupTimers();
-static bool	dispatchTimer( uint, QMSG * );
-static bool	activateTimer( uint );
-static void	activateZeroTimers();
 
 static int	 numZeroTimers	= 0;		// number of full-speed timers
@@ -111,5 +113,5 @@
 /*!
   \class QPMObjectWindow qwindowdefs.h
-    
+
   The QPMObjectWindow class is an auxiliary class for dedicated message
   processing. Its functionality is based on PM object windows. Once an instance
@@ -119,14 +121,14 @@
   window handle of this object window is necessary to be passed as a HWND
   argument to other calls and/or messages.
-  
+
   Instances of this class must be created on the main GUI thread only or on a
   thread that has created a PM message queue and runs the PM message loop
   \b itself. If you create an instance on a thread other than main, make sure
   you destroy it before destroying the thread's message queue.
-  
+
   \note WM_CREATE and WM_DESTROY messages are processed internally and not
   delivered do the message() method. Instead, you can use the constructor and
   the destructor of the subclasses, respectively.
-  
+
   \note This class is non-portable!
 */
@@ -158,5 +160,5 @@
 /*!
   Destroys this object window.
-  This method calls destroy() to free the PM object window. 
+  This method calls destroy() to free the PM object window.
 */
 QPMObjectWindow::~QPMObjectWindow()
@@ -171,5 +173,5 @@
   already created. The handle of the successfully created object window can
   be obtained using the hwnd() method.
-  
+
   \note Must be called on the same thread that cosnstructed this instance.
 */
@@ -178,8 +180,8 @@
     if ( w != NULLHANDLE )
         return FALSE;
-    
+
     static const char *ClassName = "QPMObjectWindow";
     static bool classRegistered = FALSE;
-    
+
     if ( !classRegistered ) {
         WinRegisterClass( 0, ClassName, windowProc, 0, QWL_USER + sizeof(PVOID) );
@@ -193,5 +195,5 @@
     if ( w == NULLHANDLE )
         qSystemWarning( "QPMObjectWindow: Failed to create object window" );
-#endif    
+#endif
 
     if ( w != NULLHANDLE && qt_gui_queue &&
@@ -200,5 +202,5 @@
             qt_objWindows.append( &w );
     }
-    
+
     return w != NULLHANDLE;
 }
@@ -209,5 +211,5 @@
   The method does nothing but returns \c FALSE  if the window has been
   already destroyed (or never created).
-  
+
   \note Must be called on the same thread that cosnstructed this instance.
 */
@@ -216,5 +218,5 @@
     if ( w == NULLHANDLE )
         return FALSE;
-    
+
     if ( qt_gui_queue && qt_WinQueryQueue( 0 ) == qt_gui_queue ) {
         // remove the handle from the 'clean destruction' list
@@ -225,5 +227,5 @@
     w = 0; // tell windowProc() we're unsafe
     WinDestroyWindow( h );
-    
+
     return TRUE;
 }
@@ -244,5 +246,5 @@
         static_cast< QPMObjectWindow * >( WinQueryWindowPtr( hwnd, QWL_USER ) );
     Q_ASSERT( that );
-    
+
     // Note: before WinCreateWindow() returns to the constructor or after the
     // destructor has been called, w is 0. We use this to determine that the
@@ -251,5 +253,5 @@
     if ( !that || !that->w )
         return (MRESULT) FALSE;
-    
+
     return that->message( msg, mp1, mp2 );
 }
@@ -257,8 +259,8 @@
 /*!
   \fn QPMObjectWindow::send( ULONG msg, MPARAM mp1, MPARAM mp2 ) const
-  
+
   Synchronously sends a message \a msg with the given parameters \a mp1 and
   \a mp2 to this window handle and returns a reply from the message() function.
-  
+
   \note Must be called on the same thread that cosnstructed this instance.
 */
@@ -266,9 +268,9 @@
 /*!
   \fn QPMObjectWindow::post( ULONG msg, MPARAM mp1, MPARAM mp2 ) const
-  
+
   Asynchronously posts a message \a msg with the given parameters \a mp1 and
   \a mp2 to this window handle. Returns \c TRUE on success and \c FALSE
   otherwise.
-  
+
   \note Can be called on any thread.
 */
@@ -310,11 +312,16 @@
         }
         case WM_TIMER: {
+#ifndef QT_PM_NO_DOSTIMERS
+            QApplication::sendPostedEvents( NULL, QEvent::Timer );
+            break;
+#else // ifndef QT_PM_NO_DOSTIMERS
             USHORT id = SHORT1FROMMP( mp1 );
             QMSG qmsg = { hwnd(), msg, mp1, mp2 };
             dispatchTimer( (uint) id, &qmsg );
             break;
+#endif // ifndef QT_PM_NO_DOSTIMERS
         }
     }
-    
+
     return FALSE;
 }
@@ -382,7 +389,18 @@
   need some extra handling to activate objects at timeout.
 
-  Implementation note: There are two types of timer identifiers. PM
-  timer ids (internal use) are stored in TimerInfo.  Qt timer ids are
-  indexes (+1) into the timerVec vector.
+  There are two implemetations of Qt timers. When QT_PM_NO_DOSTIMERS is defined
+  (NOT by default), Qt uses PM timers. In this case, there are two types of
+  timer identifiers. PM timer ids (internal use) are stored in TimerInfo. Qt
+  timer ids are indexes (+1) into the timerVec vector. Note that this PM timer
+  based implementation is error-prone due to stupid PM limitations: there are
+  only several dozens of PM timers per the whole system and this number is
+  shared across all processes (e.g. if you create too many timers, other
+  applications that also need them will suck).
+
+  When QT_PM_NO_DOSTIMERS is not defined (by default), Qt uses its own timer
+  implementation based on a signle DosAsyncTimer() and a dedicated timer thread.
+  This implementation allows virtually unlimited number of Qt timers. In this
+  case, there is only one type of type identifiers: Qt timer identifiers are
+  indexes (+1) into the timeDict dictionary.
 
   NOTE: These functions are for internal use. QObject::startTimer() and
@@ -418,22 +436,12 @@
 //
 
-#include "qptrvector.h"
-#include "qintdict.h"
-
-struct TimerInfo {				// internal timer info
-    uint     ind;				// - Qt timer identifier - 1
-    ULONG    id;				// - PM timer identifier
-    bool     zero;				// - zero timing
-    QObject *obj;				// - object to receive events
-};
-typedef QPtrVector<TimerInfo>  TimerVec;	// vector of TimerInfo structs
-typedef QIntDict<TimerInfo> TimerDict;		// fast dict of timers
-
-static TimerVec  *timerVec  = 0;		// timer vector
-static TimerDict *timerDict = 0;		// timer dict
-
-template <typename T>                           // template to track availability 
-class QFreeValueList                            // of free (unused) integer
-{                                               // values within some interval
+//
+// Template to track availability of free (unused) integer values within some
+// interval. Note that take() and give() maintain spans sorted in ascending
+// order.
+//
+template <typename T>
+class QFreeValueList
+{
 public:
     QFreeValueList( T min, T max ) : intMin( min ), intMax( max ) {
@@ -450,8 +458,10 @@
     void give( T val ) {
         Q_ASSERT( val >= intMin && val <= intMax );
+        // look for the span to join
         typename FreeList::iterator it = freeValues.begin();
         for ( ; it != freeValues.end(); ++ it ) {
             Span &span = (*it);
             if ( val == span.min - 1 ) {
+                // join the less end of span
                 span.min --;
                 typename FreeList::iterator it2 = it;
@@ -462,4 +472,5 @@
                 return;
             } else if ( val == span.max + 1 ) {
+                // join the greater end of span
                 span.max ++;
                 typename FreeList::iterator it2 = it;
@@ -469,7 +480,9 @@
                 }
                 return;
+            } else if ( val < span.min ) {
+                // all the following spans are too "far" to join
+                break;
             }
-            else if ( val < span.min )
-                break;
+            // span must not include val (contradicts take())
             Q_ASSERT( val > span.max );
         }
@@ -493,4 +506,152 @@
 };
 
+#ifndef QT_PM_NO_DOSTIMERS
+
+#include "qintdict.h"
+
+struct TimerInfo {              // internal timer info
+    uint     ind;               // - Qt timer identifier - 1 (= index in vector)
+    ULONG    interval;          // - timeout interval, milliseconds
+    ULONG    last;              // - last shot timestamp
+    QObject *obj;               // - object to receive events
+};
+
+typedef QIntDict<TimerInfo> TimerDict;          // dict of TimerInfo structs
+static TimerDict *timerDict = NULL;
+
+static QMutex timerMutex;                       // mutex protecting timerDict
+
+typedef QFreeValueList<int> FreeQtTIDList;      // list of free Qt timer IDs
+static FreeQtTIDList *freeQtTIDs = NULL;
+
+//
+// Auxiliary timer thread to wait for Dos timer events and post Qt timer events.
+//
+static class QTimerThread : public QThread
+{
+public:
+    QTimerThread();
+    virtual ~QTimerThread();
+    void run();
+    void signalQuit();
+    void ensureShot( int ival );
+private:
+    HEV hev;                        // OS/2 timer event semaphore
+    HTIMER htimer;                  // OS/2 timer
+    ULONG interval;                 // OS/2 timer interval
+    bool quit : 1;                  // quit flag
+} *timerThread = NULL;
+
+QTimerThread::QTimerThread()
+    : hev( NULLHANDLE ), htimer( NULLHANDLE )
+    , interval( 0 ), quit( false )
+{
+    APIRET rc;
+    rc = DosCreateEventSem( NULL, &hev, DC_SEM_SHARED, 0 /* reset */);
+    Q_ASSERT( rc == NO_ERROR );
+}
+
+QTimerThread::~QTimerThread()
+{
+    if ( hev != NULLHANDLE ) {
+        DosCloseEventSem( hev );
+        hev = NULLHANDLE;
+    }
+}
+
+void QTimerThread::run()
+{
+    APIRET rc;
+    ULONG now = 0;
+
+    do {
+        rc = DosWaitEventSem( hev, SEM_INDEFINITE_WAIT );
+        Q_ASSERT( rc == NO_ERROR );
+        if ( quit )
+            break;
+
+        // get current time again and calculate the interval
+        DosQuerySysInfo( QSV_MS_COUNT, QSV_MS_COUNT, &now, sizeof(now) );
+
+        // go through all timers and see which were shot
+
+        QMutexLocker lock( &timerMutex );
+
+        ULONG minLeft = ULONG_MAX;
+
+        QIntDictIterator<TimerInfo> it( *timerDict );
+        for ( register TimerInfo *t; (t = it.current()); ++it ) {
+            ULONG spent = now - t->last;
+            if ( spent >= t->interval ) {
+                // the timer iterval has expired, post the timer event
+                QTimerEvent *e = new QTimerEvent( t->ind + 1 );
+                QApplication::postEvent( t->obj, e );
+                // set the new last stamp
+                t->last += t->interval * (spent / t->interval);
+            }
+            // calculate minimal time to the next shot
+            minLeft = QMIN( minLeft, t->interval - (spent % t->interval) );
+        }
+
+        if ( timerDict->count() > 0 ) {
+            // post a spare WM_TIMER message to make sure timers run even when
+            // the message loop is not controlled by QEventLoop::processEvents()
+            // (e.g. when moving or resizing a window using the mouse)
+            WinPostMsg( qt_aux_win.hwnd(), WM_TIMER, 0, 0 );
+            // restart the OS/2 timer
+            interval = minLeft;
+            ULONG postCnt;
+            DosResetEventSem( hev, &postCnt );
+            // check for quit (cancelQuit() could post the semaphore just before
+            // we reset it above)
+            if ( quit )
+                break;
+            rc = DosAsyncTimer( minLeft, (HSEM) hev, &htimer );
+            Q_ASSERT( rc == NO_ERROR );
+        } else {
+            htimer = NULLHANDLE;
+            interval = 0;
+        }
+
+    } while (1);
+}
+
+void QTimerThread::signalQuit()
+{
+    quit = true;
+    DosPostEventSem( hev );
+    wait();
+}
+
+// Note: must be called from under timerMutex!
+void QTimerThread::ensureShot( int ival )
+{
+    Q_ASSERT( timerMutex.locked() );
+    Q_ASSERT( ival > 0 );
+    if ( interval == 0 || interval > (ULONG) ival ) {
+        // start another timer to make sure the new Qt timer is fired off in time
+        interval = (ULONG) ival;
+        APIRET rc = DosAsyncTimer( interval, (HSEM) hev, &htimer );
+        Q_ASSERT( rc == NO_ERROR );
+    }
+}
+
+#else // ifndef QT_PM_NO_DOSTIMERS
+
+#include "qptrvector.h"
+#include "qintdict.h"
+
+struct TimerInfo {				// internal timer info
+    uint     ind;				// - Qt timer identifier - 1
+    ULONG    id;				// - PM timer identifier
+    bool     zero;				// - zero timing
+    QObject *obj;				// - object to receive events
+};
+typedef QPtrVector<TimerInfo>  TimerVec;	// vector of TimerInfo structs
+typedef QIntDict<TimerInfo> TimerDict;		// fast dict of timers
+
+static TimerVec  *timerVec  = 0;		// timer vector
+static TimerDict *timerDict = 0;		// timer dict
+
 typedef QFreeValueList<int> FreeQtTIDList;      // list of free Qt timer IDs
 static FreeQtTIDList *freeQtTIDs = 0;
@@ -498,49 +659,67 @@
 static FreePMTIDList *freePMTIDs = 0;
 
-// Activate a timer, used by both event-loop based and simple timers.
-
-static bool dispatchTimer( uint timerId, QMSG *msg )
-{
-    MRESULT res = NULL;
-    if ( !msg || !qApp || !qt_pmEventFilter(msg,res) )
-	return activateTimer( timerId );
-    return TRUE;
-}
-
-
 //
 // Timer activation (called from the event loop when WM_TIMER arrives)
 //
-
-static bool activateTimer( uint id )		// activate timer
-{
-    if ( !timerVec )				// should never happen
-	return FALSE;
-    register TimerInfo *t = timerDict->find( id );
-    if ( !t )					// no such timer id
-	return FALSE;
-    QTimerEvent e( t->ind + 1 );
-    QApplication::sendEvent( t->obj, &e );	// send event
-    return TRUE;				// timer event was processed
-}
-
-static void activateZeroTimers()		// activate full-speed timers
-{
+static bool dispatchTimer( uint timerId, QMSG *msg )
+{
+    MRESULT res = NULL;
+    if ( !msg || !qApp || !qt_pmEventFilter(msg,res) )
+    {
+        if ( !timerVec )            // should never happen
+            return FALSE;
+        register TimerInfo *t = timerDict->find( timerId );
+        if ( !t )                   // no such timer id
+            return FALSE;
+        QTimerEvent e( t->ind + 1 );
+        QApplication::sendEvent( t->obj, &e );  // send event
+        return TRUE;                // timer event was processed
+    }
+    return TRUE;
+}
+
+#endif // ifndef QT_PM_NO_DOSTIMERS
+
+//
+// activate full-speed timers
+//
+static void activateZeroTimers()
+{
+#ifndef QT_PM_NO_DOSTIMERS
+    if ( !timerDict )
+        return;
+    QIntDictIterator<TimerInfo> it( *timerDict );
+    register TimerInfo *t = 0;
+    int n = numZeroTimers;
+    while ( n-- ) {
+        for ( ;; ) {
+            t = it();
+            Q_ASSERT( t );
+            if ( !t )
+                return;
+            if ( t->interval == 0 )
+                break;
+        }
+        QTimerEvent e( t->ind + 1 );
+        QApplication::sendEvent( t->obj, &e );
+    }
+#else
     if ( !timerVec )
-	return;
+        return;
     uint i=0;
     register TimerInfo *t = 0;
     int n = numZeroTimers;
     while ( n-- ) {
-	for ( ;; ) {
-	    t = timerVec->at(i++);
-	    if ( t && t->zero )
-		break;
-	    else if ( i == timerVec->size() )		// should not happen
-		return;
-	}
-	QTimerEvent e( t->ind + 1 );
-	QApplication::sendEvent( t->obj, &e );
-    }
+        for ( ;; ) {
+            t = timerVec->at(i++);
+            if ( t && t->zero )
+                break;
+            else if ( i == timerVec->size() )		// should not happen
+                return;
+        }
+        QTimerEvent e( t->ind + 1 );
+        QApplication::sendEvent( t->obj, &e );
+    }
+#endif
 }
 
@@ -552,4 +731,14 @@
 static void initTimers()			// initialize timers
 {
+#ifndef QT_PM_NO_DOSTIMERS
+    timerDict = new TimerDict( 29 );
+    Q_CHECK_PTR( timerDict );
+    timerDict->setAutoDelete( TRUE );
+    freeQtTIDs = new FreeQtTIDList( 0, 1023 );  // resonable max amount of timers
+    Q_CHECK_PTR( freeQtTIDs );
+    timerThread = new QTimerThread();
+    Q_CHECK_PTR( timerThread );
+    timerThread->start();
+#else // ifndef QT_PM_NO_DOSTIMERS
     timerVec = new TimerVec( 128 );
     Q_CHECK_PTR( timerVec );
@@ -557,8 +746,9 @@
     timerDict = new TimerDict( 29 );
     Q_CHECK_PTR( timerDict );
-    freeQtTIDs = new FreeQtTIDList( 0, INT_MAX );
+    freeQtTIDs = new FreeQtTIDList( 0, 1023 );  // resonable max amount of timers
     Q_CHECK_PTR( freeQtTIDs );
     freePMTIDs = new FreePMTIDList( 1, TID_USERMAX - 1 );
     Q_CHECK_PTR( freePMTIDs );
+#endif // ifndef QT_PM_NO_DOSTIMERS
 }
 
@@ -573,4 +763,15 @@
 static void cleanupTimers()			// remove pending timers
 {
+#ifndef QT_PM_NO_DOSTIMERS
+    if ( !timerDict )               // no timers were used
+        return;
+    timerThread->signalQuit();
+    delete timerThread;
+    timerThread = NULL;
+    delete freeQtTIDs;
+    freeQtTIDs = NULL;
+    delete timerDict;
+    timerDict = NULL;
+#else // ifndef QT_PM_NO_DOSTIMERS
     register TimerInfo *t;
     if ( !timerVec )				// no timers were used
@@ -589,4 +790,5 @@
     delete timerVec;
     timerVec  = 0;
+#endif // ifndef QT_PM_NO_DOSTIMERS
 }
 
@@ -600,15 +802,20 @@
 {
     Q_ASSERT( obj );
-    if ( !obj )
+    if ( !obj || interval < 0 )
         return 0;
-    
-    // lazily create the auxiliary window to process WM_TIMER messages
+
+    // lazily create the auxiliary window to process WM_TIMER and
+    // WM_U_SEM_ZEROTIMER messages
     if ( !qt_aux_win.hwnd() )
         if ( !qt_aux_win.create() )
             return 0;
-    
-    register TimerInfo *t;
+
+#ifndef QT_PM_NO_DOSTIMERS
+    if ( !timerDict )				// initialize timer data
+        initTimers();
+#else  // ifndef QT_PM_NO_DOSTIMERS
     if ( !timerVec )				// initialize timer data
-	initTimers();
+        initTimers();
+#endif // ifndef QT_PM_NO_DOSTIMERS
 
     if ( freeQtTIDs->isEmpty() ) {
@@ -619,5 +826,6 @@
         return 0;
     }
-    
+
+#ifdef QT_PM_NO_DOSTIMERS
     if ( freePMTIDs->isEmpty() ) {
 #if defined(QT_CHECK_STATE)
@@ -627,13 +835,37 @@
         return 0;
     }
-    
-    int ind = freeQtTIDs->take();		// get free timer
+#endif
+
+    int ind = freeQtTIDs->take();		        // get free timer
+
+#ifndef QT_PM_NO_DOSTIMERS
+    register TimerInfo *t = new TimerInfo;      // create timer entry
+    Q_CHECK_PTR( t );
+    t->ind  = ind;
+    t->obj  = obj;
+
+    t->interval = interval;
+    if ( t->interval == 0 ) {                   // add zero timer
+        numZeroTimers++;
+        // indicate there is a new zero timer
+        WinPostMsg( qt_aux_win.hwnd(), WM_U_SEM_ZEROTIMER, 0, 0 );
+    } else {
+        // set the initial last shot timestamp value to now
+        DosQuerySysInfo( QSV_MS_COUNT, QSV_MS_COUNT, &t->last, sizeof(t->last) );
+    }
+
+    QMutexLocker lock( &timerMutex );
+    timerDict->insert( ind, t );                // store in timer dict
+    if ( t->interval != 0 )
+        timerThread->ensureShot( t->interval );
+#else // ifndef QT_PM_NO_DOSTIMERS
     if ( (uint) ind >= timerVec->size() ) {
         uint newSize = timerVec->size() * 4;	// increase the size
         if ( newSize <= (uint) ind )
             newSize = (uint) ind + 1;
-	timerVec->resize( newSize );
-    }
-    t = new TimerInfo;				// create timer entry
+        timerVec->resize( newSize );
+    }
+
+    register TimerInfo *t = new TimerInfo;      // create timer entry
     Q_CHECK_PTR( t );
     t->ind  = ind;
@@ -659,21 +891,37 @@
         }
     }
-    timerVec->insert( ind, t );			// store in timer vector
+    timerVec->insert( ind, t );         // store in timer vector
     if ( !t->zero )
-        timerDict->insert( t->id, t );		// store in dict
-    return ind + 1;				// return index in vector
+        timerDict->insert( t->id, t );  // store in dict
+#endif // ifndef QT_PM_NO_DOSTIMERS
+
+    return ind + 1;                     // return index in vector
 }
 
 bool qKillTimer( int ind )
 {
+#ifndef QT_PM_NO_DOSTIMERS
+    if ( !timerDict )
+        return FALSE;
+    register TimerInfo *t = timerDict->find( ind-1 );
+    if ( !t )
+        return FALSE;
+    if ( t->interval == 0 ) {
+        numZeroTimers--;
+    }
+    freeQtTIDs->give( t->ind );
+    QMutexLocker lock( &timerMutex );
+    timerDict->remove( ind-1 );
+    return TRUE;
+#else // ifndef QT_PM_NO_DOSTIMERS
     if ( !timerVec || ind <= 0 || (uint)ind > timerVec->size() )
-	return FALSE;
+        return FALSE;
     register TimerInfo *t = timerVec->at(ind-1);
     if ( !t )
-	return FALSE;
+        return FALSE;
     if ( t->zero ) {
-	numZeroTimers--;
+        numZeroTimers--;
     } else {
-	WinStopTimer( 0, qt_aux_win.hwnd(), t->id );
+        WinStopTimer( 0, qt_aux_win.hwnd(), t->id );
         freePMTIDs->give( t->id );
         timerDict->remove( t->id );
@@ -682,26 +930,46 @@
     timerVec->remove( ind-1 );
     return TRUE;
+#endif // ifndef QT_PM_NO_DOSTIMERS
 }
 
 bool qKillTimer( QObject *obj )
 {
+#ifndef QT_PM_NO_DOSTIMERS
+    if ( !timerDict )
+        return FALSE;
+    QIntDictIterator<TimerInfo> it ( *timerDict );
+    for ( register TimerInfo *t; (t = it.current()); ) {
+        if ( t->obj == obj ) {		// object found
+            if ( t->interval == 0 ) {
+                numZeroTimers--;
+            }
+            freeQtTIDs->give( t->ind );
+            QMutexLocker lock( &timerMutex );
+            timerDict->remove( it.currentKey() );
+        } else {
+            ++it;
+        }
+    }
+    return TRUE;
+#else // ifndef QT_PM_NO_DOSTIMERS
     if ( !timerVec )
-	return FALSE;
+        return FALSE;
     register TimerInfo *t;
     for ( uint i=0; i<timerVec->size(); i++ ) {
-	t = timerVec->at( i );
-	if ( t && t->obj == obj ) {		// object found
-	    if ( t->zero ) {
-		numZeroTimers--;
-	    } else {
-		WinStopTimer( 0, qt_aux_win.hwnd(), t->id );
+        t = timerVec->at( i );
+        if ( t && t->obj == obj ) {		// object found
+            if ( t->zero ) {
+                numZeroTimers--;
+            } else {
+                WinStopTimer( 0, qt_aux_win.hwnd(), t->id );
                 freePMTIDs->give( t->id );
                 timerDict->remove( t->id );
             }
             freeQtTIDs->give( t->ind );
-	    timerVec->remove( i );
-	}
+            timerVec->remove( i );
+        }
     }
     return TRUE;
+#endif // ifndef QT_PM_NO_DOSTIMERS
 }
 
@@ -895,5 +1163,5 @@
     qt_gui_queue = d->hmq;
 
-    qt_aux_win.setEventLoop( this ); 
+    qt_aux_win.setEventLoop( this );
 
 #if defined(QT_THREAD_SUPPORT)
@@ -910,11 +1178,16 @@
 void QEventLoop::cleanup()
 {
-    cleanupTimers();
-
-    // ss_thread should have been stopped already in appClosingDown()
+    // timers should have been already uninitialized in appClosingDown()
+#ifndef QT_PM_NO_DOSTIMERS
+    Q_ASSERT( timerDict == 0 );
+#else
+    Q_ASSERT( timerVec == 0 );
+#endif
+
+    // ss_thread should have been already stopped in appClosingDown()
     Q_ASSERT( ss_thread == 0 );
-    
-    qt_aux_win.setEventLoop( 0 ); 
-    
+
+    qt_aux_win.setEventLoop( 0 );
+
     // destroy all windows created by QPMObjectWindow instances
     for ( HWND *w = qt_objWindows.first(); w; w = qt_objWindows.next() ) {
@@ -922,7 +1195,7 @@
         WinDestroyWindow( *w );
         // tell QPMObjectWindow the window has been destroyed
-        *w = 0; 
-    }
-    
+        *w = 0;
+    }
+
     WinDestroyMsgQueue( d->hmq );
     WinTerminate( d->hab );
@@ -937,8 +1210,10 @@
 void QEventLoop::appClosingDown()
 {
-    // ensure the thread is terminated before QApplication calls
+    // ensure the socket thread is terminated before QApplication calls
     // QThread::cleanup()
     if ( ss_thread )
         ss_cleanup();
+    // the same applies to the timer thread
+    cleanupTimers();
 }
 
@@ -975,5 +1250,5 @@
     QMutexLocker locker( &ss_mutex );
     ss_thread->cancelSelectOrIdle();
-    
+
     QPtrList<QSockNot>  *list = d->sn_vec[type].list;
     QSockNot *sn;
@@ -1039,5 +1314,5 @@
     if ( !ss_thread )
         return; // definitely not found
-    
+
     QMutexLocker locker( &ss_mutex );
     ss_thread->cancelSelectOrIdle();
@@ -1094,5 +1369,5 @@
     if ( !ss_thread )
         return; // definitely not found
-    
+
     QMutexLocker locker( &ss_mutex );
     ss_thread->cancelSelectOrIdle();
@@ -1145,4 +1420,12 @@
     QApplication::sendPostedEvents();
 
+#ifndef QT_PM_NO_DOSTIMERS
+    // we've just processed all pending events above, including QEvent::Timer
+    // events, so remove spare WM_TIMER messages posted to qt_aux_win for the
+    // cases when the message loop is run bypassing this method
+    if ( qt_aux_win.hwnd() )
+        WinPeekMsg( 0, &msg, qt_aux_win.hwnd(), WM_TIMER, WM_TIMER, PM_REMOVE );
+#endif // ifndef QT_PM_NO_DOSTIMERS
+
     if ( flags & ExcludeUserInput ) {
         while ( WinPeekMsg( 0, &msg, 0, 0, 0, PM_NOREMOVE ) ) {
@@ -1163,5 +1446,5 @@
 
     bool canWait = d->exitloop || d->quitnow ? FALSE : (flags & WaitForMore);
-    
+
     if ( canWait ) {
         // can wait if necessary
@@ -1184,10 +1467,10 @@
 	}
     }
-    
+
     if ( msg.msg == WM_QUIT ) {
         // process the quit request
 #if !defined (QT_NO_SESSIONMANAGER)
         if ( qt_app_canQuit() ) {
-#endif                    
+#endif
             exit( 0 );
             return TRUE;
@@ -1197,5 +1480,5 @@
             return TRUE;
         }
-#endif                    
+#endif
     }
 
@@ -1211,5 +1494,5 @@
             flags |= ExcludeSocketNotifiers;
     }
-    
+
     if ( !handled && msg.msg && (!msg.hwnd || !QWidget::find( msg.hwnd )) ) {
 	handled = qt_pmEventFilter( &msg, res );
@@ -1224,5 +1507,5 @@
 	activateSocketNotifiers();
 
-    // any pending configs?    
+    // any pending configs?
     if ( configRequests )
 	qPMProcessConfigRequests();
@@ -1260,5 +1543,5 @@
     if ( !ss_thread )
         return 0;
-    
+
     // postpone activation if ss_thread is working with the list
     if ( !ss_mutex.tryLock() ) {
@@ -1279,5 +1562,5 @@
 	if ( FD_ISSET(sn->fd, sn->queue) ) {
 	    FD_CLR( sn->fd, sn->queue );
-            // reenable the socket to let it participate in the next select() 
+            // reenable the socket to let it participate in the next select()
             FD_SET( sn->fd, sn->active );
             d->sn_highest = QMAX( d->sn_highest, sn->fd );
