Release 960528

Tue May 28 19:36:36 1996  Alexandre Julliard  <julliard@lrc.epfl.ch>

	* [controls/combo.c]
	Destroy the listbox and edit control when destroying the
	combo. This should prevent crashes on application exit.

	* [misc/system.c] [if1632/system.spec]
	Implemented InquireSystem().

	* [loader/task.c] [windows/message.c] [windows/queue.c]
	First attempt at inter-task SendMessage(). Still has a lot of
	problems.

Tue May 28 14:26:04 1996  Peter Bajusz  <hyp-x@inf.bme.hu>

	* [windows/mdi.c]
	Fixed MDITile with iconic children.

Mon May 27 20:28:18 1996  Albrecht Kleine  <kleine@ak.sax.de>

	* [misc/commdlg.c]
	ChooseFont dialog:
	- complete rewrite of FontFamilyEnumProc() and FontStyleEnumProc()
	  not real available font types (e.g. "Bold") can not selected
	- supporting more CF_LIMITSIZE- and CF_...ONLY- flags

	* [objects/font.c]
	In FONT_MatchFont perform check if "lfFaceName" is family from X11
	only if "lfFaceName" is a windows font family then do a call of
	FONT_TranslateName() : this results in better font selections in 
	ChooseFont() or applications like charmap.exe or write.exe.
	Added a ParseFontParms() call if necessary in function 
	FONT_MatchFont(): we need a font name as basis for GetTextFace() 
	even if there isn't one...

	* [resources/TODO]
	Inventory of resource translations in sysres_??.rc

Fri May 24 16:33:28 1996  Marcus Meissner <msmeissn@cip.informatik.uni-erlangen.de>

	* [misc/registry.c]
	_w95_loadreg: use offset to determine next RGDB position too.

Thu May 23 19:35:38 1996  Greg Kreider <kreider@natlab.research.philips.com>

	* [controls/combo.c]
	Fixed size of combo, lbox, and button (lb sometimes off by 2 pixels).

	* [misc/main.c]
	Result of option "-fixedmap" is to turn flag on.

Thu May 23 19:15:41 1996  Ronan Waide  <root@waider.ie>

	* [misc/shell.c]
	ShellExecute and FindExecutable now both use common code to
	determine the required executable file.
diff --git a/windows/event.c b/windows/event.c
index be015bf..53beabe 100644
--- a/windows/event.c
+++ b/windows/event.c
@@ -9,11 +9,15 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <unistd.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <errno.h>
 #include <X11/keysym.h>
 #include <X11/Xlib.h>
 #include <X11/Xresource.h>
 #include <X11/Xutil.h>
 #include <X11/Xatom.h>
+
 #include "windows.h"
 #include "gdi.h"
 #include "heap.h"
@@ -260,6 +264,91 @@
 
 
 /***********************************************************************
+ *           EVENT_WaitXEvent
+ *
+ * Wait for an X event, but at most maxWait milliseconds (-1 for no timeout).
+ * Return TRUE if an event is pending, FALSE on timeout or error
+ * (for instance lost connection with the server).
+ */
+BOOL EVENT_WaitXEvent( LONG maxWait )
+{
+    fd_set read_set;
+    struct timeval timeout;
+    XEvent event;
+    int fd = ConnectionNumber(display);
+
+    if (!XPending(display) && (maxWait != -1))
+    {
+        FD_ZERO( &read_set );
+        FD_SET( fd, &read_set );
+
+	timeout.tv_usec = (maxWait % 1000) * 1000;
+	timeout.tv_sec = maxWait / 1000;
+
+#ifdef CONFIG_IPC
+	sigsetjmp(env_wait_x, 1);
+	stop_wait_op= CONT;
+	    
+	if (DDE_GetRemoteMessage()) {
+	    while(DDE_GetRemoteMessage())
+		;
+	    return TRUE;
+	}
+	stop_wait_op= STOP_WAIT_X;
+	/* The code up to the next "stop_wait_op= CONT" must be reentrant  */
+	if (select( fd+1, &read_set, NULL, NULL, &timeout ) != 1 &&
+	    !XPending(display)) {
+	    stop_wait_op= CONT;
+	    return FALSE;
+	} else {
+	    stop_wait_op= CONT;
+	}
+#else  /* CONFIG_IPC */
+	if (select( fd+1, &read_set, NULL, NULL, &timeout ) != 1)
+            return FALSE;  /* Timeout or error */
+#endif  /* CONFIG_IPC */
+
+    }
+
+    /* Process the event (and possibly others that occurred in the meantime) */
+    do
+    {
+
+#ifdef CONFIG_IPC
+        if (DDE_GetRemoteMessage())
+        {
+            while(DDE_GetRemoteMessage()) ;
+            return TRUE;
+        }
+#endif  /* CONFIG_IPC */
+
+        XNextEvent( display, &event );
+        EVENT_ProcessEvent( &event );
+    }
+    while (XPending( display ));
+    return TRUE;
+}
+
+
+/***********************************************************************
+ *           EVENT_Synchronize
+ *
+ * Synchronize with the X server. Should not be used too often.
+ */
+void EVENT_Synchronize()
+{
+    XEvent event;
+
+    XSync( display, False );
+    while (XPending( display ))
+    {
+	XNextEvent( display, &event );
+	EVENT_ProcessEvent( &event );
+    }    
+}
+
+
+/***********************************************************************
  *           EVENT_XStateToKeyState
  *
  * Translate a X event state (Button1Mask, ShiftMask, etc...) to
diff --git a/windows/mdi.c b/windows/mdi.c
index 22efc97..b515e58 100644
--- a/windows/mdi.c
+++ b/windows/mdi.c
@@ -773,12 +773,16 @@
                 if( !listTop )
                     break;
                 
-                if( listTop->hChild )
+                /* skip iconized childs from tiling */
+                while (!listTop->hChild)
                 {
-                    SetWindowPos(listTop->hChild, 0, x, y, xsize, ysize, 
-				 SWP_DRAWFRAME | SWP_NOACTIVATE | SWP_NOZORDER);
-		    y += ysize;
-                }
+    	            listPrev = listTop->prev;
+    	            free(listTop);
+    	            listTop = listPrev;
+    	        }                
+                SetWindowPos(listTop->hChild, 0, x, y, xsize, ysize, 
+                             SWP_DRAWFRAME | SWP_NOACTIVATE | SWP_NOZORDER);
+                y += ysize;
     	        listPrev = listTop->prev;
     	        free(listTop);
     	        listTop = listPrev;
diff --git a/windows/message.c b/windows/message.c
index 7e1799b..aef426c 100644
--- a/windows/message.c
+++ b/windows/message.c
@@ -8,14 +8,12 @@
 #include <string.h>
 #include <sys/time.h>
 #include <sys/types.h>
-#include <errno.h>
 
 #include "message.h"
 #include "win.h"
 #include "gdi.h"
 #include "sysmetrics.h"
 #include "hook.h"
-#include "event.h"
 #include "spy.h"
 #include "winpos.h"
 #include "atom.h"
@@ -204,7 +202,7 @@
     int i, pos = sysMsgQueue->nextMessage;
 
     /* If the queue is empty, attempt to fill it */
-    if (!sysMsgQueue->msgCount && XPending(display)) MSG_WaitXEvent( 0 );
+    if (!sysMsgQueue->msgCount && XPending(display)) EVENT_WaitXEvent( 0 );
 
     for (i = 0; i < sysMsgQueue->msgCount; i++, pos++)
     {
@@ -278,6 +276,7 @@
  */
 BOOL MSG_GetHardwareMessage( LPMSG msg )
 {
+#if 0
     int pos;
     XEvent event;
     MESSAGEQUEUE *sysMsgQueue = QUEUE_GetSysQueue();
@@ -293,92 +292,83 @@
 	XNextEvent( display, &event );
 	EVENT_ProcessEvent( &event );
     }
+#endif
+    MSG_PeekMessage( msg, 0, WM_KEYFIRST, WM_MOUSELAST, PM_REMOVE, 0 );
     return TRUE;
 }
 
 
 /***********************************************************************
- *           MSG_Synchronize
+ *           MSG_SendMessage
  *
- * Synchronize with the X server. Should not be used too often.
+ * Implementation of an inter-task SendMessage.
  */
-void MSG_Synchronize()
+LRESULT MSG_SendMessage( HQUEUE hDestQueue, HWND hwnd, UINT msg,
+                         WPARAM wParam, LPARAM lParam )
 {
-    XEvent event;
+    MESSAGEQUEUE *queue, *destQ;
 
-    XSync( display, False );
-    while (XPending( display ))
+    if (!(queue = (MESSAGEQUEUE*)GlobalLock16( GetTaskQueue(0) ))) return 0;
+    if (!(destQ = (MESSAGEQUEUE*)GlobalLock16( hDestQueue ))) return 0;
+
+    if (IsTaskLocked())
     {
-	XNextEvent( display, &event );
-	EVENT_ProcessEvent( &event );
-    }    
+        fprintf( stderr, "SendMessage: task is locked\n" );
+        return 0;
+    }
+
+    if (queue->hWnd)
+    {
+        fprintf( stderr, "Nested SendMessage() not supported\n" );
+        return 0;
+    }
+    queue->hWnd   = hwnd;
+    queue->msg    = msg;
+    queue->wParam = wParam;
+    queue->lParam = lParam;
+    queue->hPrevSendingTask = destQ->hSendingTask;
+    destQ->hSendingTask = GetTaskQueue(0);
+    QUEUE_SetWakeBit( destQ, QS_SENDMESSAGE );
+
+    /* Wait for the result */
+
+    printf( "SendMessage %04x to %04x\n", msg, hDestQueue );
+
+    if (!(queue->wakeBits & QS_SMRESULT))
+    {
+        DirectedYield( hDestQueue );
+        QUEUE_WaitBits( QS_SMRESULT );
+    }
+    printf( "SendMessage %04x to %04x: got %08x\n",
+            msg, hDestQueue, queue->SendMessageReturn );
+    queue->wakeBits &= ~QS_SMRESULT;
+    return queue->SendMessageReturn;
 }
 
 
 /***********************************************************************
- *           MSG_WaitXEvent
- *
- * Wait for an X event, but at most maxWait milliseconds (-1 for no timeout).
- * Return TRUE if an event is pending, FALSE on timeout or error
- * (for instance lost connection with the server).
+ *           ReplyMessage   (USER.115)
  */
-BOOL MSG_WaitXEvent( LONG maxWait )
+void ReplyMessage( LRESULT result )
 {
-    fd_set read_set;
-    struct timeval timeout;
-    XEvent event;
-    int fd = ConnectionNumber(display);
+    MESSAGEQUEUE *senderQ;
+    MESSAGEQUEUE *queue;
 
-    if (!XPending(display) && (maxWait != -1))
+    printf( "ReplyMessage\n " );
+    if (!(queue = (MESSAGEQUEUE*)GlobalLock16( GetTaskQueue(0) ))) return;
+    if (!(senderQ = (MESSAGEQUEUE*)GlobalLock16( queue->InSendMessageHandle)))
+        return;
+    for (;;)
     {
-        FD_ZERO( &read_set );
-        FD_SET( fd, &read_set );
-
-	timeout.tv_usec = (maxWait % 1000) * 1000;
-	timeout.tv_sec = maxWait / 1000;
-
-#ifdef CONFIG_IPC
-	sigsetjmp(env_wait_x, 1);
-	stop_wait_op= CONT;
-	    
-	if (DDE_GetRemoteMessage()) {
-	    while(DDE_GetRemoteMessage())
-		;
-	    return TRUE;
-	}
-	stop_wait_op= STOP_WAIT_X;
-	/* The code up to the next "stop_wait_op= CONT" must be reentrant  */
-	if (select( fd+1, &read_set, NULL, NULL, &timeout ) != 1 &&
-	    !XPending(display)) {
-	    stop_wait_op= CONT;
-	    return FALSE;
-	} else {
-	    stop_wait_op= CONT;
-	}
-#else  /* CONFIG_IPC */
-	if (select( fd+1, &read_set, NULL, NULL, &timeout ) != 1)
-            return FALSE;  /* Timeout or error */
-#endif  /* CONFIG_IPC */
-
+        if (queue->wakeBits & QS_SENDMESSAGE) QUEUE_ReceiveMessage( queue );
+        else if (senderQ->wakeBits & QS_SMRESULT) Yield();
+        else break;
     }
-
-    /* Process the event (and possibly others that occurred in the meantime) */
-    do
-    {
-
-#ifdef CONFIG_IPC
-        if (DDE_GetRemoteMessage())
-        {
-            while(DDE_GetRemoteMessage()) ;
-            return TRUE;
-        }
-#endif  /* CONFIG_IPC */
-
-        XNextEvent( display, &event );
-        EVENT_ProcessEvent( &event );
-    }
-    while (XPending( display ));
-    return TRUE;
+    printf( "ReplyMessage: res = %08x\n", result );
+    senderQ->SendMessageReturn = result;
+    queue->InSendMessageHandle = 0;
+    QUEUE_SetWakeBit( senderQ, QS_SMRESULT );
+    DirectedYield( queue->hSendingTask );
 }
 
 
@@ -397,58 +387,51 @@
     DDE_TestDDE(hwnd);	/* do we have dde handling in the window ?*/
     DDE_GetRemoteMessage();
 #endif  /* CONFIG_IPC */
-    
+
+    mask = QS_POSTMESSAGE | QS_SENDMESSAGE;  /* Always selected */
     if (first || last)
     {
-	mask = QS_POSTMESSAGE;  /* Always selectioned */
 	if ((first <= WM_KEYLAST) && (last >= WM_KEYFIRST)) mask |= QS_KEY;
 	if ((first <= WM_MOUSELAST) && (last >= WM_MOUSEFIRST)) mask |= QS_MOUSE;
 	if ((first <= WM_TIMER) && (last >= WM_TIMER)) mask |= QS_TIMER;
 	if ((first <= WM_SYSTIMER) && (last >= WM_SYSTIMER)) mask |= QS_TIMER;
 	if ((first <= WM_PAINT) && (last >= WM_PAINT)) mask |= QS_PAINT;
     }
-    else mask = QS_MOUSE | QS_KEY | QS_POSTMESSAGE | QS_TIMER | QS_PAINT;
+    else mask |= QS_MOUSE | QS_KEY | QS_TIMER | QS_PAINT;
+
+    if (IsTaskLocked()) flags |= PM_NOYIELD;
 
     while(1)
     {    
 	hQueue   = GetTaskQueue(0);
         msgQueue = (MESSAGEQUEUE *)GlobalLock16( hQueue );
         if (!msgQueue) return FALSE;
+        msgQueue->changeBits = 0;
 
-	  /* First handle a message put by SendMessage() */
-	if (msgQueue->status & QS_SENDMESSAGE)
-	{
-	    if (!hwnd || (msgQueue->hWnd == hwnd))
-	    {
-		if ((!first && !last) || 
-		    ((msgQueue->msg >= first) && (msgQueue->msg <= last)))
-		{
-		    msg->hwnd    = msgQueue->hWnd;
-		    msg->message = msgQueue->msg;
-		    msg->wParam  = msgQueue->wParam;
-		    msg->lParam  = msgQueue->lParam;
-		    if (flags & PM_REMOVE) msgQueue->status &= ~QS_SENDMESSAGE;
-		    break;
-		}
-	    }
-	}
+        /* First handle a message put by SendMessage() */
+
+	if (msgQueue->wakeBits & QS_SENDMESSAGE)
+            QUEUE_ReceiveMessage( msgQueue );
     
-	  /* Now find a normal message */
-	pos = QUEUE_FindMsg( msgQueue, hwnd, first, last );
-	if (pos != -1)
-	{
-	    QMSG *qmsg = &msgQueue->messages[pos];
-	    *msg = qmsg->msg;
-	    msgQueue->GetMessageTimeVal      = msg->time;
-	    msgQueue->GetMessagePosVal       = *(DWORD *)&msg->pt;
-	    msgQueue->GetMessageExtraInfoVal = qmsg->extraInfo;
+        /* Now find a normal message */
 
-	    if (flags & PM_REMOVE) QUEUE_RemoveMsg( msgQueue, pos );
-	    break;
-	}
+        if (((msgQueue->wakeBits & mask) & QS_POSTMESSAGE) &&
+            ((pos = QUEUE_FindMsg( msgQueue, hwnd, first, last )) != -1))
+        {
+            QMSG *qmsg = &msgQueue->messages[pos];
+            *msg = qmsg->msg;
+            msgQueue->GetMessageTimeVal      = msg->time;
+            msgQueue->GetMessagePosVal       = *(DWORD *)&msg->pt;
+            msgQueue->GetMessageExtraInfoVal = qmsg->extraInfo;
 
-	  /* Now find a hardware event */
-        if (MSG_PeekHardwareMsg( msg, hwnd, first, last, flags & PM_REMOVE ))
+            if (flags & PM_REMOVE) QUEUE_RemoveMsg( msgQueue, pos );
+            break;
+        }
+
+        /* Now find a hardware event */
+
+        if (((msgQueue->wakeBits & mask) & (QS_MOUSE | QS_KEY)) &&
+            MSG_PeekHardwareMsg( msg, hwnd, first, last, flags & PM_REMOVE ))
         {
             /* Got one */
 	    msgQueue->GetMessageTimeVal      = msg->time;
@@ -457,7 +440,8 @@
             break;
         }
 
-	  /* Now handle a WM_QUIT message */
+        /* Now handle a WM_QUIT message */
+
 	if (msgQueue->wPostQMsg)
 	{
 	    msg->hwnd    = hwnd;
@@ -467,8 +451,14 @@
 	    break;
 	}
 
-	  /* Now find a WM_PAINT message */
-	if ((msgQueue->status & QS_PAINT) && (mask & QS_PAINT))
+        /* Check again for SendMessage */
+
+ 	if (msgQueue->wakeBits & QS_SENDMESSAGE)
+            QUEUE_ReceiveMessage( msgQueue );
+
+        /* Now find a WM_PAINT message */
+
+	if ((msgQueue->wakeBits & mask) & QS_PAINT)
 	{
 	    msg->hwnd = WIN_FindWinToRepaint( hwnd , hQueue );
 	    msg->message = WM_PAINT;
@@ -490,23 +480,28 @@
               }
 	}
 
-	  /* Finally handle WM_TIMER messages */
-	if ((msgQueue->status & QS_TIMER) && (mask & QS_TIMER))
+        /* Check for timer messages, but yield first */
+
+        if (!(flags & PM_NOYIELD))
+        {
+            UserYield();
+            if (msgQueue->wakeBits & QS_SENDMESSAGE)
+                QUEUE_ReceiveMessage( msgQueue );
+        }
+	if ((msgQueue->wakeBits & mask) & QS_TIMER)
 	{
 	    if (TIMER_CheckTimer( &nextExp, msg, hwnd, flags & PM_REMOVE ))
 		break;  /* Got a timer msg */
 	}
 	else nextExp = -1;  /* No timeout needed */
 
-        Yield();
-
-	  /* Wait until something happens */
         if (peek)
         {
-            if (!MSG_WaitXEvent( 0 )) return FALSE;  /* No pending event */
+            if (!(flags & PM_NOYIELD)) UserYield();
+            return FALSE;
         }
-        else  /* Wait for an event, then restart the loop */
-            MSG_WaitXEvent( nextExp );
+        msgQueue->wakeMask = mask;
+        QUEUE_WaitBits( mask );
     }
 
       /* We got a message */
@@ -534,7 +529,9 @@
                                   0, 0, 0, flags, TRUE ))
 	    {
 		  /* No message present -> send ENTERIDLE and wait */
-		SendMessage16( hwndOwner, WM_ENTERIDLE, code, (LPARAM)hwnd );
+                if (IsWindow(hwndOwner))
+                    SendMessage16( hwndOwner, WM_ENTERIDLE,
+                                   code, (LPARAM)hwnd );
 		MSG_PeekMessage( (MSG *)PTR_SEG_TO_LIN(msg),
                                  0, 0, 0, flags, FALSE );
 	    }
@@ -679,6 +676,7 @@
         return TRUE;
     }
 
+
     HOOK_CallHooks( WH_CALLWNDPROC, HC_ACTION, 1,
                     (LPARAM)MAKE_SEGPTR(&msgstruct) );
     hwnd   = msgstruct.hWnd;
@@ -686,12 +684,21 @@
     wParam = msgstruct.wParam;
     lParam = msgstruct.lParam;
 
-    SPY_EnterMessage( SPY_SENDMESSAGE16, hwnd, msg, wParam, lParam );
-    if (!(wndPtr = WIN_FindWndPtr( hwnd ))) 
+    if (!(wndPtr = WIN_FindWndPtr( hwnd )))
     {
-        SPY_ExitMessage( SPY_RESULT_INVALIDHWND16, hwnd, msg, 0 );
+        fprintf( stderr, "SendMessage16: invalid hwnd %04x\n", hwnd );
         return 0;
     }
+    if (wndPtr->hmemTaskQ != GetTaskQueue(0))
+    {
+#if 0
+        fprintf( stderr, "SendMessage16: intertask message not supported\n" );
+        return 0;
+#endif
+        return MSG_SendMessage( wndPtr->hmemTaskQ, hwnd, msg, wParam, lParam );
+    }
+
+    SPY_EnterMessage( SPY_SENDMESSAGE16, hwnd, msg, wParam, lParam );
     ret = CallWindowProc16( wndPtr->lpfnWndProc, hwnd, msg, wParam, lParam );
     SPY_ExitMessage( SPY_RESULT_OK16, hwnd, msg, ret );
     return ret;
@@ -719,12 +726,18 @@
 
     /* FIXME: call hooks */
 
-    SPY_EnterMessage( SPY_SENDMESSAGE32, hwnd, msg, wParam, lParam );
-    if (!(wndPtr = WIN_FindWndPtr( hwnd ))) 
+    if (!(wndPtr = WIN_FindWndPtr( hwnd )))
     {
-        SPY_ExitMessage( SPY_RESULT_INVALIDHWND32, hwnd, msg, 0 );
+        fprintf( stderr, "SendMessage32A: invalid hwnd %08x\n", hwnd );
         return 0;
     }
+    if (wndPtr->hmemTaskQ != GetTaskQueue(0))
+    {
+        fprintf( stderr, "SendMessage32A: intertask message not supported\n" );
+        return 0;
+    }
+
+    SPY_EnterMessage( SPY_SENDMESSAGE32, hwnd, msg, wParam, lParam );
     ret = CallWindowProc32A( (WNDPROC32)wndPtr->lpfnWndProc,
                              hwnd, msg, wParam, lParam );
     SPY_ExitMessage( SPY_RESULT_OK32, hwnd, msg, ret );
@@ -753,12 +766,18 @@
 
     /* FIXME: call hooks */
 
-    SPY_EnterMessage( SPY_SENDMESSAGE32, hwnd, msg, wParam, lParam );
-    if (!(wndPtr = WIN_FindWndPtr( hwnd ))) 
+    if (!(wndPtr = WIN_FindWndPtr( hwnd )))
     {
-        SPY_ExitMessage( SPY_RESULT_INVALIDHWND32, hwnd, msg, 0 );
+        fprintf( stderr, "SendMessage32W: invalid hwnd %08x\n", hwnd );
         return 0;
     }
+    if (wndPtr->hmemTaskQ != GetTaskQueue(0))
+    {
+        fprintf( stderr, "SendMessage32W: intertask message not supported\n" );
+        return 0;
+    }
+
+    SPY_EnterMessage( SPY_SENDMESSAGE32, hwnd, msg, wParam, lParam );
     ret = CallWindowProc32W( (WNDPROC32)wndPtr->lpfnWndProc,
                              hwnd, msg, wParam, lParam );
     SPY_ExitMessage( SPY_RESULT_OK32, hwnd, msg, ret );
@@ -781,14 +800,14 @@
     
     if (!(queue = (MESSAGEQUEUE *)GlobalLock16( GetTaskQueue(0) ))) return;
     if ((queue->wPostQMsg) || 
-        (queue->status & (QS_SENDMESSAGE | QS_PAINT)) ||
+        (queue->wakeBits & (QS_SENDMESSAGE | QS_PAINT)) ||
         (queue->msgCount) || (QUEUE_GetSysQueue()->msgCount) )
         return;
-    if ((queue->status & QS_TIMER) && 
+    if ((queue->wakeBits & QS_TIMER) && 
         TIMER_CheckTimer( &nextExp, &msg, 0, FALSE))
         return;
     /* FIXME: (dde) must check DDE & X-events simultaneously */
-    MSG_WaitXEvent( nextExp );
+    EVENT_WaitXEvent( nextExp );
 }
 
 
@@ -927,14 +946,13 @@
 
 
 /***********************************************************************
- *			InSendMessage	(USER.192
- *
- * According to the book, this should return true iff the current message
- * was send from another application. In that case, the application should
- * invoke ReplyMessage before calling message relevant API.
- * Currently, Wine will always return FALSE, as there is no other app.
+ *           InSendMessage    (USER.192)
  */
 BOOL InSendMessage()
 {
-	return FALSE;
+    MESSAGEQUEUE *queue;
+
+    if (!(queue = (MESSAGEQUEUE *)GlobalLock16( GetTaskQueue(0) )))
+        return 0;
+    return (BOOL)queue->InSendMessageHandle;
 }
diff --git a/windows/queue.c b/windows/queue.c
index 5935bac..e465ebb 100644
--- a/windows/queue.c
+++ b/windows/queue.c
@@ -7,6 +7,7 @@
 #include <stdlib.h>
 #include "module.h"
 #include "queue.h"
+#include "task.h"
 #include "win.h"
 #include "stddebug.h"
 #include "debug.h"
@@ -63,7 +64,7 @@
              pq->nextFreeMessage, (unsigned)pq->lParam, pq->queueSize,
              (unsigned)pq->SendMessageReturn, pq->wWinVersion, pq->InSendMessageHandle,
              pq->wPaintCount, pq->hSendingTask, pq->wTimerCount,
-             pq->hPrevSendingTask, pq->status, pq->wakeMask, pq->hCurHook);
+             pq->hPrevSendingTask, pq->wakeBits, pq->wakeMask, pq->hCurHook);
 }
 
 
@@ -102,6 +103,7 @@
     HQUEUE hQueue;
     MESSAGEQUEUE * msgQueue;
     int queueSize;
+    TDB *pTask = (TDB *)GlobalLock16( GetCurrentTask() );
 
     dprintf_msg(stddeb,"Creating message queue...\n");
 
@@ -111,7 +113,7 @@
     msgQueue = (MESSAGEQUEUE *) GlobalLock16( hQueue );
     msgQueue->msgSize = sizeof(QMSG);
     msgQueue->queueSize = size;
-    msgQueue->wWinVersion = 0;  /* FIXME? */
+    msgQueue->wWinVersion = pTask ? pTask->version : 0;
     GlobalUnlock16( hQueue );
     return hQueue;
 }
@@ -173,6 +175,99 @@
 
 
 /***********************************************************************
+ *           QUEUE_SetWakeBit
+ *
+ * See "Windows Internals", p.449
+ */
+void QUEUE_SetWakeBit( MESSAGEQUEUE *queue, WORD bit )
+{
+    queue->changeBits |= bit;
+    queue->wakeBits   |= bit;
+    if (queue->wakeMask & bit)
+    {
+        queue->wakeMask = 0;
+        PostEvent( queue->hTask );
+    }
+}
+
+
+/***********************************************************************
+ *           QUEUE_WaitBits
+ *
+ * See "Windows Internals", p.447
+ */
+void QUEUE_WaitBits( WORD bits )
+{
+    MESSAGEQUEUE *queue;
+
+    for (;;)
+    {
+        if (!(queue = (MESSAGEQUEUE *)GlobalLock16( GetTaskQueue(0) ))) return;
+        if (queue->changeBits & bits)
+        {
+            /* One of the bits is set; we can return */
+            queue->wakeMask = 0;
+            return;
+        }
+        if (queue->wakeBits & QS_SENDMESSAGE)
+        {
+            /* Process the sent message immediately */
+            QUEUE_ReceiveMessage( queue );
+        }
+        queue->wakeMask = bits | QS_SENDMESSAGE;
+        WaitEvent( 0 );
+    }
+}
+
+
+/***********************************************************************
+ *           QUEUE_ReceiveMessage
+ *
+ * This routine is called when a sent message is waiting for the queue.
+ */
+void QUEUE_ReceiveMessage( MESSAGEQUEUE *queue )
+{
+    MESSAGEQUEUE *senderQ;
+    HWND hwnd;
+    UINT msg;
+    WPARAM wParam;
+    LPARAM lParam;
+    LRESULT result = 0;
+
+    printf( "ReceiveMessage\n" );
+    if (!(queue->wakeBits & QS_SENDMESSAGE)) return;
+    if (!(senderQ = (MESSAGEQUEUE*)GlobalLock16( queue->hSendingTask))) return;
+
+    /* Remove sending queue from the list */
+    queue->InSendMessageHandle = queue->hSendingTask;
+    queue->hSendingTask        = senderQ->hPrevSendingTask;
+    senderQ->hPrevSendingTask  = 0;
+    if (!queue->hSendingTask) queue->wakeBits &= ~QS_SENDMESSAGE;
+
+    /* Get the parameters from the sending task */
+    hwnd   = senderQ->hWnd;
+    msg    = senderQ->msg;
+    wParam = senderQ->wParam;
+    lParam = senderQ->lParam;
+    senderQ->hWnd = 0;
+    QUEUE_SetWakeBit( senderQ, QS_SMPARAMSFREE );
+
+    printf( "ReceiveMessage: calling wnd proc %04x %04x %04x %08x\n",
+            hwnd, msg, wParam, lParam );
+
+    /* Call the window procedure */
+    /* FIXME: should we use CallWindowProc here? */
+    if (IsWindow( hwnd )) result = SendMessage16( hwnd, msg, wParam, lParam );
+
+    printf( "ReceiveMessage: wnd proc %04x %04x %04x %08x ret = %08x\n",
+            hwnd, msg, wParam, lParam, result );
+
+    /* Return the result to the sender task */
+    ReplyMessage( result );
+}
+
+
+/***********************************************************************
  *           QUEUE_AddMsg
  *
  * Add a message to the queue. Return FALSE if queue is full.
@@ -199,8 +294,7 @@
     else pos = 0;
     msgQueue->nextFreeMessage = pos;
     msgQueue->msgCount++;
-    msgQueue->status |= QS_POSTMESSAGE;
-    msgQueue->tempStatus |= QS_POSTMESSAGE;
+    QUEUE_SetWakeBit( msgQueue, QS_POSTMESSAGE );
     return TRUE;
 }
 
@@ -258,8 +352,47 @@
 	else msgQueue->nextFreeMessage = msgQueue->queueSize-1;
     }
     msgQueue->msgCount--;
-    if (!msgQueue->msgCount) msgQueue->status &= ~QS_POSTMESSAGE;
-    msgQueue->tempStatus = 0;
+    if (!msgQueue->msgCount) msgQueue->wakeBits &= ~QS_POSTMESSAGE;
+}
+
+
+/***********************************************************************
+ *           QUEUE_WakeSomeone
+ *
+ * Wake a queue upon reception of a hardware event.
+ */
+static void QUEUE_WakeSomeone( UINT message )
+{
+    HWND hwnd;
+    WORD wakeBit;
+    HQUEUE hQueue;
+    MESSAGEQUEUE *queue = NULL;
+
+    if ((message >= WM_KEYFIRST) && (message <= WM_KEYLAST)) wakeBit = QS_KEY;
+    else wakeBit = (message == WM_MOUSEMOVE) ? QS_MOUSEMOVE : QS_MOUSEBUTTON;
+
+    if (!(hwnd = GetSysModalWindow()))
+    {
+        hwnd = (wakeBit == QS_KEY) ? GetFocus() : GetCapture();
+        if (!hwnd) hwnd = GetActiveWindow();
+    }
+    if (hwnd)
+    {
+        WND *wndPtr = WIN_FindWndPtr( hwnd );
+        if (wndPtr) queue = (MESSAGEQUEUE *)GlobalLock16( wndPtr->hmemTaskQ );
+    }
+    else
+    {
+        hQueue = hFirstQueue;
+        while (hQueue)
+        {
+            queue = GlobalLock16( hQueue );
+            if (queue->wakeBits & wakeBit) break;
+            hQueue = queue->next;
+        }
+    }
+    if (!queue) printf( "WakeSomeone: no one found\n" );
+    if (queue) QUEUE_SetWakeBit( queue, wakeBit );
 }
 
 
@@ -274,7 +407,7 @@
 {
     MSG *msg;
     int pos;
-  
+
     if (!sysMsgQueue) return;
     pos = sysMsgQueue->nextFreeMessage;
 
@@ -315,6 +448,7 @@
     else pos = 0;
     sysMsgQueue->nextFreeMessage = pos;
     sysMsgQueue->msgCount++;
+    QUEUE_WakeSomeone( message );
 }
 
 		    
@@ -337,8 +471,7 @@
 
     if (!(queue = (MESSAGEQUEUE *)GlobalLock16( hQueue ))) return;
     queue->wPaintCount++;
-    queue->status |= QS_PAINT;
-    queue->tempStatus |= QS_PAINT;    
+    QUEUE_SetWakeBit( queue, QS_PAINT );
 }
 
 
@@ -351,7 +484,7 @@
 
     if (!(queue = (MESSAGEQUEUE *)GlobalLock16( hQueue ))) return;
     queue->wPaintCount--;
-    if (!queue->wPaintCount) queue->status &= ~QS_PAINT;
+    if (!queue->wPaintCount) queue->wakeBits &= ~QS_PAINT;
 }
 
 
@@ -364,8 +497,7 @@
 
     if (!(queue = (MESSAGEQUEUE *)GlobalLock16( hQueue ))) return;
     queue->wTimerCount++;
-    queue->status |= QS_TIMER;
-    queue->tempStatus |= QS_TIMER;
+    QUEUE_SetWakeBit( queue, QS_TIMER );
 }
 
 
@@ -378,7 +510,7 @@
 
     if (!(queue = (MESSAGEQUEUE *)GlobalLock16( hQueue ))) return;
     queue->wTimerCount--;
-    if (!queue->wTimerCount) queue->status &= ~QS_TIMER;
+    if (!queue->wTimerCount) queue->wakeBits &= ~QS_TIMER;
 }
 
 
@@ -448,8 +580,8 @@
     DWORD ret;
 
     if (!(queue = (MESSAGEQUEUE *)GlobalLock16( GetTaskQueue(0) ))) return 0;
-    ret = MAKELONG( queue->tempStatus, queue->status );
-    queue->tempStatus = 0;
+    ret = MAKELONG( queue->changeBits, queue->wakeBits );
+    queue->changeBits = 0;
     return ret & MAKELONG( flags, flags );
 }
 
@@ -462,7 +594,7 @@
     MESSAGEQUEUE *queue;
 
     if (!(queue = (MESSAGEQUEUE *)GlobalLock16( GetTaskQueue(0) ))) return FALSE;
-    return queue->status & (QS_KEY | QS_MOUSEBUTTON);
+    return queue->wakeBits & (QS_KEY | QS_MOUSEBUTTON);
 }
 
 
diff --git a/windows/timer.c b/windows/timer.c
index 9f8cc4a..189fc36 100644
--- a/windows/timer.c
+++ b/windows/timer.c
@@ -65,69 +65,78 @@
  */
 static void TIMER_RemoveTimer( TIMER * pTimer )
 {
-    if (pTimer == pNextTimer) pNextTimer = pTimer->next;
-    else
-    {
-	TIMER * ptr = pNextTimer;
-	while (ptr && (ptr->next != pTimer)) ptr = ptr->next;
-	if (ptr) ptr->next = pTimer->next;
-    }
+    TIMER **ppTimer = &pNextTimer;
+
+    while (*ppTimer && (*ppTimer != pTimer)) ppTimer = &(*ppTimer)->next;
+    if (*ppTimer) *ppTimer = pTimer->next;
     pTimer->next = NULL;
 }
 
+
+/***********************************************************************
+ *           TIMER_ClearTimer
+ *
+ * Clear and remove a timer.
+ */
+static void TIMER_ClearTimer( TIMER * pTimer )
+{
+    TIMER_RemoveTimer( pTimer );
+    QUEUE_DecTimerCount( pTimer->hq );
+    pTimer->hwnd    = 0;
+    pTimer->msg     = 0;
+    pTimer->id      = 0;
+    pTimer->timeout = 0;
+    pTimer->proc    = 0;
+}
+
+
 /***********************************************************************
  *           TIMER_SwitchQueue
  */
 void TIMER_SwitchQueue(HQUEUE old, HQUEUE new)
 {
- TIMER*         pT = pNextTimer;
+    TIMER * pT = pNextTimer;
 
- while(pT)
-  {
-   if( pT->hq == old ) pT->hq = new;
-   pT = pT->next;
-  }
-
-}
-
-/***********************************************************************
- *           TIMER_NukeTimers
- *
- * Trash all timers that are bound to the hwnd or hq
- */
-void TIMER_NukeTimers(HWND hwnd, HQUEUE hq)
-{
- HQUEUE		hQToUpdate = ( hwnd ) ? GetTaskQueue( GetWindowTask( hwnd ) )
-				      : hq;
- TIMER*         pT = pNextTimer;
- TIMER*         pTnext;
-
- if( !pT ) return;
-
- while( (hwnd && pT->hwnd == hwnd) ||
-        (hq && pT->hq == hq) )
-      {
-	 QUEUE_DecTimerCount( hQToUpdate );
-         if( !(pT = pNextTimer = pNextTimer->next) )
-             return;
-      }
-
- /* pT points to the "good" timer */
-
- while( (pTnext = pT->next) )
+    while (pT)
     {
-      while( (hwnd && pTnext->hwnd == hwnd) ||
-             (hq && pTnext->hq == hq) )
-	   {
-	      QUEUE_DecTimerCount( hQToUpdate );
-              if( !(pT->next = pTnext->next) )
-                  return;
-	   }
-
-      pT = pT->next;
+        if (pT->hq == old) pT->hq = new;
+        pT = pT->next;
     }
 }
 
+
+/***********************************************************************
+ *           TIMER_RemoveWindowTimers
+ *
+ * Remove all timers for a given window.
+ */
+void TIMER_RemoveWindowTimers( HWND hwnd )
+{
+    int i;
+    TIMER *pTimer;
+
+    for (i = NB_TIMERS, pTimer = TimersArray; i > 0; i--, pTimer++)
+	if ((pTimer->hwnd == hwnd) && pTimer->timeout)
+            TIMER_ClearTimer( pTimer );
+}
+
+
+/***********************************************************************
+ *           TIMER_RemoveQueueTimers
+ *
+ * Remove all timers for a given queue.
+ */
+void TIMER_RemoveQueueTimers( HQUEUE hqueue )
+{
+    int i;
+    TIMER *pTimer;
+
+    for (i = NB_TIMERS, pTimer = TimersArray; i > 0; i--, pTimer++)
+	if ((pTimer->hq == hqueue) && pTimer->timeout)
+            TIMER_ClearTimer( pTimer );
+}
+
+
 /***********************************************************************
  *           TIMER_RestartTimers
  *
@@ -142,6 +151,17 @@
 
 			       
 /***********************************************************************
+ *           TIMER_GetNextExp
+ *
+ * Return next timer expiration time, or -1 if none.
+ */
+LONG TIMER_GetNextExp(void)
+{
+    return pNextTimer ? EXPIRE_TIME( pNextTimer, GetTickCount() ) : -1;
+}
+
+
+/***********************************************************************
  *           TIMER_CheckTimer
  *
  * Check whether a timer has expired, and create a message if necessary.
@@ -243,9 +263,8 @@
 {
     int i;
     TIMER * pTimer;
-    HQUEUE  hq;
     
-      /* Find the timer */
+    /* Find the timer */
     
     for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++)
 	if ((pTimer->hwnd == hwnd) && (pTimer->id == id) &&
@@ -255,17 +274,9 @@
     if (!sys && (pTimer->msg != WM_TIMER)) return FALSE;
     else if (sys && (pTimer->msg != WM_SYSTIMER)) return FALSE;    
 
-      /* Delete the timer */
+    /* Delete the timer */
 
-    hq = pTimer->hq;
-
-    pTimer->hwnd    = 0;
-    pTimer->msg     = 0;
-    pTimer->id      = 0;
-    pTimer->timeout = 0;
-    pTimer->proc    = 0;
-    TIMER_RemoveTimer( pTimer );
-    QUEUE_DecTimerCount( hq );
+    TIMER_ClearTimer( pTimer );
     return TRUE;
 }
 
diff --git a/windows/win.c b/windows/win.c
index 51e419c..c89ef23 100644
--- a/windows/win.c
+++ b/windows/win.c
@@ -15,10 +15,10 @@
 #include "dce.h"
 #include "sysmetrics.h"
 #include "cursoricon.h"
-#include "event.h"
 #include "heap.h"
 #include "hook.h"
 #include "menu.h"
+#include "message.h"
 #include "nonclient.h"
 #include "string32.h"
 #include "queue.h"
@@ -333,6 +333,7 @@
 	
     if (!wndPtr) return;
     WIN_UnlinkWindow( hwnd ); /* Remove the window from the linked list */
+    TIMER_RemoveWindowTimers( hwnd );
     wndPtr->dwMagic = 0;  /* Mark it as invalid */
     wndPtr->hwndSelf = 0;
     if ((wndPtr->hrgnUpdate) || (wndPtr->flags & WIN_INTERNAL_PAINT))
diff --git a/windows/winpos.c b/windows/winpos.c
index 841b63e..74a8942 100644
--- a/windows/winpos.c
+++ b/windows/winpos.c
@@ -10,7 +10,6 @@
 #include "module.h"
 #include "user.h"
 #include "win.h"
-#include "event.h"
 #include "hook.h"
 #include "message.h"
 #include "queue.h"
@@ -883,23 +882,17 @@
     }
 
     /* set prev active wnd to current active wnd and send notification */
-    if( (hwndPrevActive = hwndActive) )
+    if ((hwndPrevActive = hwndActive) && IsWindow(hwndPrevActive))
     {
-/* FIXME: need a Win32 translation for WINELIB32 */
-	if( !SendMessage16(hwndPrevActive, WM_NCACTIVATE, 0, MAKELONG(hWnd,wIconized)) )
+        if (!SendMessage16( hwndPrevActive, WM_NCACTIVATE, FALSE, 0 ))
         {
 	    if (GetSysModalWindow() != hWnd) return 0;
 	    /* disregard refusal if hWnd is sysmodal */
         }
 
-#ifdef WINELIB32
-	SendMessage32A( hwndActive, WM_ACTIVATE,
-		     MAKEWPARAM( WA_INACTIVE, wIconized ),
-		     (LPARAM)hWnd );
-#else
-	SendMessage16(hwndPrevActive, WM_ACTIVATE, WA_INACTIVE, 
-		    MAKELONG(hWnd,wIconized));
-#endif
+	SendMessage32A( hwndPrevActive, WM_ACTIVATE,
+                        MAKEWPARAM( WA_INACTIVE, wIconized ),
+                        (LPARAM)hWnd );
 
 	/* check if something happened during message processing */
 	if( hwndPrevActive != hwndActive ) return 0;
@@ -972,9 +965,7 @@
     wndTemp->hwndLastActive = hWnd;
 
     wIconized = HIWORD(wndTemp->dwStyle & WS_MINIMIZE);
-/* FIXME: Needs a Win32 translation for WINELIB32 */
-    SendMessage16( hWnd, WM_NCACTIVATE, 1,
-		 MAKELONG(hwndPrevActive,wIconized));
+    SendMessage16( hWnd, WM_NCACTIVATE, TRUE, 0 );
 #ifdef WINELIB32
     SendMessage32A( hWnd, WM_ACTIVATE,
 		 MAKEWPARAM( (fMouse)?WA_CLICKACTIVE:WA_ACTIVE, wIconized),
@@ -1704,7 +1695,7 @@
     
       /* Repaint the window */
 
-    if (wndPtr->window) MSG_Synchronize();  /* Wait for all expose events */
+    if (wndPtr->window) EVENT_Synchronize();  /* Wait for all expose events */
 
     EVENT_DummyMotionNotify(); /* Simulate a mouse event to set the cursor */