Use SERVICES callback to implement Windows timers.
Timer expiration handling removed from EVENT_WaitNetEvent loop.

diff --git a/include/message.h b/include/message.h
index ffe942e..b8dcc10 100644
--- a/include/message.h
+++ b/include/message.h
@@ -22,8 +22,6 @@
 extern void TIMER_RemoveWindowTimers( HWND hwnd );
 extern void TIMER_RemoveQueueTimers( HQUEUE16 hqueue );
 extern void TIMER_SwitchQueue( HQUEUE16 hOldQueue, HQUEUE16 hNewQueue );
-extern LONG TIMER_GetNextExpiration(void);
-extern void TIMER_ExpireTimers(void);
 extern BOOL TIMER_GetTimerMsg( MSG *msg, HWND hwnd,
                                  HQUEUE16 hQueue, BOOL remove );
 
diff --git a/windows/timer.c b/windows/timer.c
index 2163101..89dd416 100644
--- a/windows/timer.c
+++ b/windows/timer.c
@@ -8,6 +8,7 @@
 #include "queue.h"
 #include "task.h"
 #include "winproc.h"
+#include "services.h"
 #include "debug.h"
 
 DEFAULT_DEBUG_CHANNEL(timer)
@@ -189,47 +190,22 @@
     TIMER_InsertTimer( pTimer );
 }
 
-			       
 /***********************************************************************
- *           TIMER_GetNextExpiration
- *
- * Return next timer expiration time, or -1 if none.
- */
-LONG TIMER_GetNextExpiration(void)
-{
-    TIMER *pTimer;
-    LONG retValue;
-    
-    EnterCriticalSection( &csTimer );
-
-    pTimer = pNextTimer;
-
-    while (pTimer && !pTimer->expires)  /* Skip already expired timers */
-        pTimer = pTimer->next;
-
-    if (pTimer)
-    {
-        DWORD now = GetTickCount();
-        retValue = (pTimer->expires <= now) ? 0 : (pTimer->expires - now);
-    }
-    else retValue = -1;
-
-    LeaveCriticalSection( &csTimer );
-    return retValue;
-}
-
-
-/***********************************************************************
- *           TIMER_ExpireTimers
+ *           TIMER_CheckTimers
  *
  * Mark expired timers and wake the appropriate queues.
  */
-void TIMER_ExpireTimers(void)
+static void CALLBACK TIMER_CheckTimers( ULONG_PTR forceTimer )
 {
+    static HANDLE ServiceHandle  = INVALID_HANDLE_VALUE;
+    static LONG   ServiceTimeout = 0;
+
     TIMER *pTimer;
     DWORD curTime = GetTickCount();
 
     EnterCriticalSection( &csTimer );
+
+    TRACE(timer, "Called at %ld (%s)\n", curTime, forceTimer? "manual" : "auto" );
     
     pTimer = pNextTimer;
     
@@ -241,6 +217,37 @@
         QUEUE_IncTimerCount( pTimer->hq );
         pTimer = pTimer->next;
     }
+
+    /* Install service callback with appropriate timeout, so that
+       we get called again once the next timer has expired */
+
+    if (pTimer)
+    {
+        LONG timeout = pTimer->expires - curTime;
+
+        if ( forceTimer || timeout != ServiceTimeout )
+        {
+            if ( ServiceHandle != INVALID_HANDLE_VALUE ) 
+              SERVICE_Delete( ServiceHandle );
+
+            ServiceHandle = SERVICE_AddTimer( timeout * 1000L, 
+                                              TIMER_CheckTimers, FALSE );
+            ServiceTimeout = timeout;
+
+            TRACE(timer, "Installed service callback with timeout %ld\n", timeout );
+        }
+    }
+    else
+    {
+        if ( ServiceHandle != INVALID_HANDLE_VALUE )
+        {
+            SERVICE_Delete( ServiceHandle );
+            ServiceHandle = INVALID_HANDLE_VALUE;
+            ServiceTimeout = 0;
+
+            TRACE(timer, "Deleted service callback\n" );
+        }
+    }
     
     LeaveCriticalSection( &csTimer );
 }
@@ -272,11 +279,15 @@
         return FALSE; /* No timer */
     }
     
-    if (remove)	TIMER_RestartTimer( pTimer, curTime );  /* Restart it */
-
     TRACE(timer, "Timer expired: %04x, %04x, %04x, %08lx\n", 
 		   pTimer->hwnd, pTimer->msg, pTimer->id, (DWORD)pTimer->proc);
 
+    if (remove)	
+    {
+        TIMER_RestartTimer( pTimer, curTime );  /* Restart it */
+        TIMER_CheckTimers( TRUE );
+    }
+
       /* Build the message */
     msg->hwnd    = pTimer->hwnd;
     msg->message = pTimer->msg;
@@ -318,6 +329,7 @@
                                        type, WIN_PROC_TIMER );
             pTimer->expires = GetTickCount() + timeout;
             TIMER_InsertTimer( pTimer );
+            TIMER_CheckTimers( TRUE );
             LeaveCriticalSection( &csTimer );
             return id;
         }
@@ -351,6 +363,7 @@
 		   pTimer, pTimer->hwnd, pTimer->msg, pTimer->id,
                    (DWORD)pTimer->proc );
     TIMER_InsertTimer( pTimer );
+    TIMER_CheckTimers( TRUE );
     
     LeaveCriticalSection( &csTimer );
     
diff --git a/windows/x11drv/event.c b/windows/x11drv/event.c
index 5c65024..91c0e7b 100644
--- a/windows/x11drv/event.c
+++ b/windows/x11drv/event.c
@@ -205,26 +205,15 @@
 BOOL X11DRV_EVENT_WaitNetEvent( BOOL sleep, BOOL peek )
 {
   XEvent event;
-  LONG maxWait = sleep ? TIMER_GetNextExpiration() : 0;
   int pending = TSXPending(display);
   
-  /* Wait for an event or a timeout. If maxWait is -1, we have no timeout;
-   * in this case, we fall through directly to the XNextEvent loop.
-   */
-  
-  if (!pending)
+  if (!pending && sleep)
     {
       int num_pending;
-      struct timeval timeout;
       fd_set io_set[3];
       
       memcpy( io_set, __event_io_set, sizeof(io_set) );
       
-      if(maxWait != -1) {
-	timeout.tv_usec = (maxWait % 1000) * 1000;
-	timeout.tv_sec = maxWait / 1000;
-      }
-      
 #ifdef CONFIG_IPC
       sigsetjmp(env_wait_x, 1);
       stop_wait_op= CONT;
@@ -238,37 +227,24 @@
       /* The code up to the next "stop_wait_op = CONT" must be reentrant */
       num_pending = select( __event_max_fd, &io_set[EVENT_IO_READ], 
 			    &io_set[EVENT_IO_WRITE], 
-			    &io_set[EVENT_IO_EXCEPT], (maxWait == -1) ? 0 : &timeout );
+			    &io_set[EVENT_IO_EXCEPT], NULL );
       if ( num_pending == -1 )
 	{
 	  /* Error - signal, invalid arguments, out of memory */
 	  stop_wait_op = CONT;
 	  return FALSE;
 	}
-      if ( num_pending == 0 )
-        {
-	  /* Timeout */
-	  stop_wait_op = CONT;
-	  TIMER_ExpireTimers(); /* FIXME: should this be done even if sleep == 0? */
-	  return FALSE;
-	}
-      else stop_wait_op = CONT;
+      stop_wait_op = CONT;
 #else  /* CONFIG_IPC */
       num_pending = select( __event_max_fd, &io_set[EVENT_IO_READ],
 			    &io_set[EVENT_IO_WRITE],
-			    &io_set[EVENT_IO_EXCEPT], (maxWait == -1) ? 0 : &timeout );
+			    &io_set[EVENT_IO_EXCEPT], NULL );
       
       if ( num_pending == -1 )
 	{
 	  /* Error - signal, invalid arguments, out of memory */
 	  return FALSE;
 	}
-      if ( num_pending == 0 )
-        {
-	  /* Timeout */
-	  TIMER_ExpireTimers(); /* FIXME: should this be done even if sleep == 0? */
-	  return FALSE;
-        }
 #endif  /* CONFIG_IPC */
       
       /* Flush the wake-up pipe, it's just dummy data for waking-up this