Implemented WaitForInputIdle.

diff --git a/if1632/thunk.c b/if1632/thunk.c
index 5501e7d..51cfa2a 100644
--- a/if1632/thunk.c
+++ b/if1632/thunk.c
@@ -375,6 +375,7 @@
         GETADDR( DispatchMessageW, "DispatchMessageW" );
         GETADDR( DispatchMessageA, "DispatchMessageA" );
         GETADDR( RedrawWindow, "RedrawWindow" );
+        GETADDR( WaitForInputIdle, "WaitForInputIdle" );
 
 #undef GETADDR
     }
diff --git a/include/callback.h b/include/callback.h
index 44a49a0..7bf4343 100644
--- a/include/callback.h
+++ b/include/callback.h
@@ -103,6 +103,7 @@
     HQUEUE16 WINAPI (*InitThreadInput16)( WORD unknown, WORD flags );
     void WINAPI (*UserYield16)( void );
     WORD WINAPI (*DestroyIcon32)( HGLOBAL16 handle, UINT16 flags );
+    DWORD WINAPI (*WaitForInputIdle)( HANDLE hProcess, DWORD dwTimeOut );
     
 }  CALLOUT_TABLE;
 
diff --git a/include/process.h b/include/process.h
index b1d9236..54665c1 100644
--- a/include/process.h
+++ b/include/process.h
@@ -96,6 +96,8 @@
     struct _PDB     *next;             /*    List reference - list of PDB's */
     WORD            winver;            /*    Windows version figured out by VERSION_GetVersion */
     struct _SERVICETABLE *service_table; /*  Service table for service thread */
+    HANDLE           idle_event;       /* event to signal, when the process is idle */
+    HANDLE16         main_queue;       /* main message queue of the process */ 
 } PDB;
 
 /* Process flags */
@@ -146,6 +148,7 @@
 
 extern DWORD WINAPI GetProcessDword( DWORD dwProcessID, INT offset );
 void WINAPI SetProcessDword( DWORD dwProcessID, INT offset, DWORD value );
+extern DWORD WINAPI MapProcessHandle( HANDLE handle );
 
 /* scheduler/environ.c */
 extern BOOL ENV_InheritEnvironment( PDB *pdb, LPCSTR env );
diff --git a/loader/module.c b/loader/module.c
index 89916f9..5813d3b 100644
--- a/loader/module.c
+++ b/loader/module.c
@@ -834,6 +834,10 @@
         return 11;
     }
     
+    /* Give 30 seconds to the app to come up */
+    if ( Callout.WaitForInputIdle ( info.hProcess, 30000 ) ==  0xFFFFFFFF ) 
+      WARN("WaitForInputIdle failed: Error %ld\n", GetLastError() );
+    
     /* Get 16-bit hInstance/hTask from process */
     pdb = PROCESS_IdToPDB( info.dwProcessId );
     tdb = pdb? (TDB *)GlobalLock16( pdb->task ) : NULL;
@@ -1289,7 +1293,7 @@
 
 
 /***********************************************************************
- *              GetModuleFileName32A      (KERNEL32.235)
+ *              GetModuleFileNameA      (KERNEL32.235)
  */
 DWORD WINAPI GetModuleFileNameA( 
 	HMODULE hModule,	/* [in] module handle (32bit) */
diff --git a/scheduler/process.c b/scheduler/process.c
index b30e24d..d9ff8fd 100644
--- a/scheduler/process.c
+++ b/scheduler/process.c
@@ -313,6 +313,7 @@
     pdb->heap            = pdb->system_heap;  /* will be changed later on */
     pdb->next            = PROCESS_First;
     pdb->winver          = 0xffff; /* to be determined */
+    pdb->main_queue      = INVALID_HANDLE_VALUE16;
     PROCESS_First = pdb;
     return pdb;
 }
@@ -338,6 +339,7 @@
     initial_pdb.priority        = 8;  /* Normal */
     initial_pdb.flags           = PDB32_WIN16_PROC;
     initial_pdb.winver          = 0xffff; /* to be determined */
+    initial_pdb.main_queue      = INVALID_HANDLE_VALUE16;
 
     /* Initialize virtual memory management */
     if (!VIRTUAL_Init()) return FALSE;
@@ -352,6 +354,14 @@
     if (!(SystemHeap = HeapCreate( HEAP_GROWABLE, 0x10000, 0 ))) return FALSE;
     initial_pdb.system_heap = initial_pdb.heap = SystemHeap;
 
+    /* Create the idle event for the initial process
+       FIXME 1: Shouldn't we call UserSignalProc for the initial process too?
+       FIXME 2: It seems to me that the initial pdb becomes never freed, so I don't now
+                where to release the idle event for the initial process.
+    */
+    initial_pdb.idle_event = CreateEventA ( NULL, TRUE, FALSE, NULL );
+    initial_pdb.idle_event = ConvertToGlobalHandle ( initial_pdb.idle_event );
+
     /* Initialize signal handling */
     if (!SIGNAL_Init()) return FALSE;
 
@@ -485,8 +495,9 @@
     if ( Options.debug && TASK_AddTaskEntryBreakpoint )
         TASK_AddTaskEntryBreakpoint( pdb->task );
 
-    /* Now call the entry point */
-    PROCESS_CallUserSignalProc( USIG_PROCESS_RUNNING, 0, 0 );
+    /* Call UserSignalProc ( USIG_PROCESS_RUNNING ... ) only for non-GUI win32 apps */
+    if ( type != PROC_WIN16 && (pdb->flags & PDB32_CONSOLE_PROC))
+        PROCESS_CallUserSignalProc( USIG_PROCESS_RUNNING, 0, 0 );
 
     switch ( type )
     {
diff --git a/windows/message.c b/windows/message.c
index b21f809..91dc327 100644
--- a/windows/message.c
+++ b/windows/message.c
@@ -1933,6 +1933,7 @@
     DWORD i;
     HANDLE handles[MAXIMUM_WAIT_OBJECTS];
     DWORD ret;
+    PDB * pdb = PROCESS_Current();
 
     HQUEUE16 hQueue = GetFastQueue16();
     MESSAGEQUEUE *msgQueue = (MESSAGEQUEUE *)QUEUE_Lock( hQueue );
@@ -1968,6 +1969,7 @@
 	/*
 	 * Check the handles in the list.
 	 */
+	SetEvent ( pdb->idle_event );
 	ret = WaitForMultipleObjects(nCount, pHandles, fWaitAll, 5L);
 
 	/*
@@ -2000,9 +2002,13 @@
     /* Add the thread event to the handle list */
       for (i = 0; i < nCount; i++)
 	handles[i] = pHandles[i];
-    handles[nCount] = msgQueue->hEvent;
+      handles[nCount] = msgQueue->hEvent;
 
-    ret = WaitForMultipleObjects( nCount+1, handles, fWaitAll, dwMilliseconds );
+      if ( pdb->main_queue == INVALID_HANDLE_VALUE16 ) pdb->main_queue = hQueue;
+      if ( pdb->main_queue == hQueue ) SetEvent ( pdb->idle_event );
+      ret = WaitForMultipleObjects( nCount+1, handles, fWaitAll, dwMilliseconds );
+      if ( pdb->main_queue == hQueue ) ResetEvent ( pdb->idle_event );
+
     } 
 
     QUEUE_Unlock( msgQueue );
@@ -2488,8 +2494,7 @@
 {
     struct timeval t;
     gettimeofday( &t, NULL );
-    /* make extremely compatible: granularity is 25 msec */
-    return ((t.tv_sec * 1000) + (t.tv_usec / 25000) * 25) - MSG_WineStartTicks;
+    return ((t.tv_sec * 1000) + (t.tv_usec / 1000)) - MSG_WineStartTicks;
 }
 
 
diff --git a/windows/queue.c b/windows/queue.c
index cc71032..3b88261 100644
--- a/windows/queue.c
+++ b/windows/queue.c
@@ -5,6 +5,7 @@
 
 #include <string.h>
 #include <signal.h>
+#include <assert.h>
 #include "wine/winbase16.h"
 #include "wine/winuser16.h"
 #include "miscemu.h"
@@ -18,7 +19,6 @@
 #include "heap.h"
 #include "thread.h"
 #include "process.h"
-#include <assert.h>
 #include "debugtools.h"
 #include "spy.h"
 
@@ -467,7 +467,7 @@
 
         if (msgQueue->hEvent == 0)
         {
-            WARN_(msg)("CreateEvent32A is not able to create an event object");
+            WARN_(msg)("CreateEventA is not able to create an event object");
             return 0;
         }
         msgQueue->hEvent = ConvertToGlobalHandle( msgQueue->hEvent );
@@ -672,14 +672,19 @@
 {
     MESSAGEQUEUE *queue;
     DWORD curTime = 0;
+    HQUEUE16 hQueue;
+    PDB * pdb;
 
     TRACE_(msg)("q %04x waiting for %04x\n", GetFastQueue16(), bits);
 
     if ( THREAD_IsWin16( NtCurrentTeb() ) && (timeout != INFINITE) )
         curTime = GetTickCount();
 
-    if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() ))) return 0;
+    hQueue = GetFastQueue16();
+    if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( hQueue ))) return 0;
     
+    pdb = PROCESS_Current();
+
     for (;;)
     {
         if (queue->changeBits & bits)
@@ -716,7 +721,24 @@
 	        TRACE_(msg)("bHasWin16Lock=TRUE\n");
 	        ReleaseThunkLock( &dwlc );
 	    }
+
+
+	    if ( pdb->main_queue == INVALID_HANDLE_VALUE16 ) 
+	    {
+	        pdb->main_queue = hQueue;
+	    }
+	    if ( pdb->main_queue == hQueue ) 
+	    {
+	        SetEvent ( pdb->idle_event );
+	    }
+
 	    WaitForSingleObject( queue->hEvent, timeout );
+
+	    if ( pdb->main_queue == hQueue ) 
+	    {
+	        ResetEvent ( pdb->idle_event );
+	    }
+
 	    if ( bHasWin16Lock ) 
 	    {
 	        RestoreThunkLock( dwlc );
@@ -724,6 +746,8 @@
         }
         else
         {
+	    SetEvent ( pdb->idle_event );
+
             if ( timeout == INFINITE )
                 WaitEvent16( 0 );  /* win 16 thread, use WaitEvent */
             else
@@ -1395,7 +1419,7 @@
 
 
 /***********************************************************************
- *           SetMessageQueue32   (USER32.494)
+ *           SetMessageQueue   (USER32.494)
  */
 BOOL WINAPI SetMessageQueue( INT size )
 {
@@ -1409,7 +1433,7 @@
 }
 
 /***********************************************************************
- *           InitThreadInput   (USER.409)
+ *           InitThreadInput16   (USER.409)
  */
 HQUEUE16 WINAPI InitThreadInput16( WORD unknown, WORD flags )
 {
@@ -1430,7 +1454,7 @@
         {
             WARN_(msg)("failed!\n");
             return FALSE;
-    }
+	}
         
         /* Link new queue into list */
         queuePtr = (MESSAGEQUEUE *)QUEUE_Lock( hQueue );
@@ -1496,12 +1520,54 @@
  */
 DWORD WINAPI WaitForInputIdle (HANDLE hProcess, DWORD dwTimeOut)
 {
-  FIXME_(msg)("(hProcess=%d, dwTimeOut=%ld): stub\n", hProcess, dwTimeOut);
+  PDB * pdb;
+  DWORD cur_time, ret, pid = MapProcessHandle ( hProcess );
 
+  /* Check whether the calling process is a command line application */
+  if (!THREAD_IsWin16(NtCurrentTeb() ) &&
+      (PROCESS_Current()->flags & PDB32_CONSOLE_PROC))
+  {
+    TRACE_(msg)("not a win32 GUI application!\n" );
+    return 0; 
+  }
+  
+  pdb = PROCESS_IdToPDB( pid );
+
+  /* check whether we are waiting for a win32 process or the win16 subsystem */
+  if ( pdb->flags & PDB32_WIN16_PROC ) {
+    if ( THREAD_IsWin16(NtCurrentTeb()) ) return 0;
+  }
+    else { /* target is win32 */
+    if ( pdb->flags & PDB32_CONSOLE_PROC ) return 0;
+    if ( GetFastQueue16() == pdb->main_queue ) return 0;
+  }
+
+  cur_time = GetTickCount();
+  
+  TRACE_(msg)("waiting for %x\n", pdb->idle_event );
+  while ( dwTimeOut > GetTickCount() - cur_time || dwTimeOut == INFINITE ) {
+
+    ret = MsgWaitForMultipleObjects ( 1, &pdb->idle_event, FALSE, dwTimeOut, QS_SENDMESSAGE );
+    if ( ret == ( WAIT_OBJECT_0 + 1 )) {
+      MESSAGEQUEUE * queue;
+      if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() ))) return 0xFFFFFFFF;
+      QUEUE_ReceiveMessage ( queue );
+      QUEUE_Unlock ( queue );
+      continue; 
+    }
+    if ( ret == WAIT_TIMEOUT || ret == 0xFFFFFFFF ) {
+      TRACE_(msg)("timeout or error\n");
+      return ret;
+    }
+    else {
+      TRACE_(msg)("finished\n");
+      return 0;
+    }
+    
+  }
   return WAIT_TIMEOUT;
 }
 
-
 /***********************************************************************
  *           GetInputState32   (USER32.244)
  */
diff --git a/windows/user.c b/windows/user.c
index fc3e1b6..68f380e 100644
--- a/windows/user.c
+++ b/windows/user.c
@@ -207,7 +207,9 @@
 WORD WINAPI UserSignalProc( UINT uCode, DWORD dwThreadOrProcessID,
                             DWORD dwFlags, HMODULE16 hModule )
 {
+    static HANDLE win16_idle_event;
     HINSTANCE16 hInst;
+    PDB * pdb;
 
     /* FIXME: Proper reaction to most signals still missing. */
 
@@ -234,18 +236,48 @@
         break;
 
     case USIG_PROCESS_CREATE:
+      pdb = PROCESS_IdToPDB( dwThreadOrProcessID );
+
+      /* Create the idle event for the process. We have just one idle_event for all
+	 win16 processes, while each win32 process has its own */
+
+      if ( pdb->flags & PDB32_WIN16_PROC )
+      {
+          if (!win16_idle_event)
+          {
+              win16_idle_event = CreateEventA ( NULL, TRUE, FALSE, NULL );
+              win16_idle_event = ConvertToGlobalHandle ( win16_idle_event );
+          }
+          pdb->idle_event = win16_idle_event;
+      }
+      else { /* win32 process */
+	pdb->idle_event = CreateEventA ( NULL, TRUE, FALSE, NULL );
+        pdb->idle_event = ConvertToGlobalHandle ( pdb->idle_event );
+	TRACE_(win)("created win32 idle event: %x\n", pdb->idle_event );
+      }
+      break;
+
     case USIG_PROCESS_INIT:
     case USIG_PROCESS_LOADED:
+      break;
     case USIG_PROCESS_RUNNING:
+        pdb = PROCESS_IdToPDB ( dwThreadOrProcessID );
+	SetEvent ( pdb->idle_event );
         break;
 
     case USIG_PROCESS_EXIT:
         break;
 
-    case USIG_PROCESS_DESTROY:
-        hInst = GetProcessDword( dwThreadOrProcessID, GPD_HINSTANCE16 );
-        USER_AppExit( hInst );
-        break;
+    case USIG_PROCESS_DESTROY:      
+      hInst = GetProcessDword( dwThreadOrProcessID, GPD_HINSTANCE16 );
+      USER_AppExit( hInst );
+
+      pdb = PROCESS_IdToPDB( dwThreadOrProcessID );
+      if ( ! (pdb->flags & PDB32_WIN16_PROC) ) {
+	TRACE_(win)("destroying win32 idle event: %x\n", pdb->idle_event );
+	CloseHandle ( pdb->idle_event );	
+      }
+      break;
 
     default:
         FIXME_(win)("(%04x, %08lx, %04lx, %04x)\n",