Release 960928

Fri Sep 27 14:18:42 1996  Alexandre Julliard  <julliard@lrc.epfl.ch>

	* [controls/button.c]
	Fixed focus rectangle size and clipping.

	* [controls/scroll.c]
	Converted to Win32 and added support for scroll page.
	Completed SetScrollInfo() and implemented other Win32 functions.

	* [files/file.c]
	Removed FILE_Read() (use _lread32 instead).

	* [objects/dce.c] [include/dce.h]
	Allocate DCE on the Win32 heap, and use pointers instead of
	handles.
	Implemented Win32 version of DC functions.

	* [windows/painting.c]
	Attempt to make CS_PARENTDC style work again.

Wed Sep 25 23:40:52 1996 Alex Korobka <alex@trantor.pharm.sunysb.edu>

	* [windows/dce.c] [windows/winpos.c]
	Override SaveUnder attribute when painting took place
	in a window below. Force X to raise activated window 
	in seamless mode.

	* [misc/clipboard.c] [windows/event.c]
	Translation between DOS and Unix text formats and several
	other fixes for the sudden selection loss.

	* [windows/message.c]
	Apply "first" and "last" when checking for WM_QUIT in 
        MSG_PeekMessage().

	* [windows/win.c]
	Rearranged DestroyWindow() to fit "Windows Internals"
	description.

	* [windows/win.c] [windows/winpos.c] [windows/nonclient.c]
	Misc. fixes to CBT hook calls.

	* [controls/menu.c] [misc/user.c]
	Fixup resident popup menu window so that it doesn't get
	destroyed by USER_AppExit().

	* [loader/module.c] [loader/task.c] [windows/event.c]
	Process "unsafe" X events outside the scheduler to prevent
	deadlocks.

	* [windows/message.c] [windows/queue.c] [windows/winpos.c]
	Lots of fixes for better Win16 multitasking.

Wed Sep 25 20:36:30 1996  Marcus Meissner <msmeissn@cip.informatik.uni-erlangen.de>

	* [include/windows.h]
	Added some missing HOOK defines.

	* [misc/shell.c][if1632/shell32.spec][include/shell.h]
	SHGetFileInfoA stub added (win95 mplayer.exe /play bla.avi).

	* [win32/console.c][include/wincon.h]
	GetConsoleScreenBufferInfo, GetLargestConsoleWindowSize added.

	* [misc/registry.c]
	Some null ptr fixes.

	* [loader/pe_image.c]
	Fixed exported function lookup. (msvcrt20.dll)
	Add debugsyms for entrypoint, exported functions and sections.

	* [multimedia/mmsystem.c]
	MCIOpen: support for element opens (mplayer.exe /play bla.avi).

	* [several]
	Added several missing things/stubs/simple thunks from win32
	to win16 code.

Sat Sep 21 17:27:44 1996  O.Flebbe  <flebbe@science-computing.uni-tuebingen.de>

	* [windows/property.c]
	Fixed debugging of 16 Bit RemoveProp().

	* [debugger/memory.c]
	Added DEBUG_checkmap_bad() for linux.

Thu Sep 19 20:48:31 1996  Albrecht Kleine  <kleine@ak.sax.de>

	* [windows/event.c] [windows/hook.c]
	Use EnableHardwareInput() for JournalPlayback hook.

	* [controls/listbox.c]
	Changed handling of LB_GETITEMRECT in empty listboxes.

Thu Sep 19 13:34:35 1996  Slaven Rezic  <eserte@cs.tu-berlin.de>

	* [misc/main.c]
	Fixes to X resources handling.	

Wed Sep 18 00:31:15 1996  Huw D. M. Davies <h.davies1@physics.oxford.ac.uk>

	* [objects/metafile.c] [include/gdi.h] [objects/dc.c]
	Individual handle table created for each metafile. Fixed
 	GlobalReAlloc() bug in MF_AddHandleDC() (was MF_AddHandleInternal).

	* [windows/graphics.c] [objects/dc.c]
	Rectangle() changed to work better with wide pens and PS_NULL.
	Use JoinMiter.

	* [windows/winpos.c]
	Make the whole (non X) window invalid on resize if CS_[VH]REDRAW
 	is set.

	* [windows/nonclient.c]
	AdjustWindowRectEx() should perform calculations even if the
 	window is minimized.

	* [windows/mdi.c]
	Better handling of system button painting. Maximized windows can
 	contain scroll bars. Icons now maximize properly.

	* [windows/defwnd.c] [windows/nonclient.c] [controls/menu.c]
	Improved greying of items in system menu. WM_INITMEMUPOPUP no
 	longer caught in DefWndProc, DEFWND_InitSysMenuPopup moved to
 	menu.c.

Mon Sep 16 21:30:00 1996  Uwe Bonnes <bon@elektron.ikp.physik.th-darmstadt.de>

	* [several files]
	Fix missing includes and wrong printing arguments.

	* [controls/listbox.c]
	Don't sort drives in ListBoxDirectory().
	
Sat Sep 14 09:05:47 1996  Petri Tuomola <ptuomola@xs4all.nl>

	* [windows/dialog.c]
	Fixed handling of Shift-TAB in dialogs.

Thu Sep 12 18:31:00 1996  Thomas Sandford <t.d.g.sandford@prds-grn.demon.co.uk>

	* [if1632/gdi32.spec]
	Added SelectClipRgn - call win16 version.

	* [if1632/user32.spec]
	Added GetAsyncKeyState, GetMenuItemID and GetMenuStringA.

	* [include/wincon.h]
	Added COORD and SMALL_RECT typedefs, moved CONSOLE_SCREEN_BUFFER_INFO
	out of #if 0 protected portion of file.

	* [loader/pe_image.c]
	PE_InitTEB() - Tidy up, bug fix to stack pointer value (Borland
	programs now work better)

	* [win32/console.c]
	Added stub functions for GetConsoleScreenBufferInfo and 
	GetLargestConsoleWindowSize

	* [win32/findfile.c]
	FindFirstFile32A() - removed erroneous strcpy

	* [windows/keyboard.c]
	GetAsyncKeyState() - bug fix - now returns value as per Microsoft
	specification. NB - I still have doubts about some other functions
	in this file.
diff --git a/windows/message.c b/windows/message.c
index 5dd9fae..2f9cae1 100644
--- a/windows/message.c
+++ b/windows/message.c
@@ -34,15 +34,21 @@
 
 #define ASCII_CHAR_HACK 0x0800 
 
+typedef enum { SYSQ_MSG_ABANDON, SYSQ_MSG_SKIP, SYSQ_MSG_ACCEPT } SYSQ_STATUS;
+
 extern WPARAM	lastEventChar;				 /* event.c */
 extern BOOL MouseButtonsStates[3];
 extern BOOL AsyncMouseButtonsStates[3];
 extern BYTE KeyStateTable[256];
 extern BYTE AsyncKeyStateTable[256];
 
+extern MESSAGEQUEUE *pCursorQueue;			 /* queue.c */
+extern MESSAGEQUEUE *pActiveQueue;
+
 DWORD MSG_WineStartTicks; /* Ticks at Wine startup */
 
 static WORD doubleClickSpeed = 452;
+static INT32 debugSMRL = 0;       /* intertask SendMessage() recursion level */
 
 /***********************************************************************
  *           MSG_TranslateMouseMsg
@@ -59,7 +65,7 @@
  *   the coordinates to client coordinates.
  * - Send the WM_SETCURSOR message.
  */
-static BOOL MSG_TranslateMouseMsg( MSG16 *msg, BOOL remove )
+static SYSQ_STATUS MSG_TranslateMouseMsg( MSG16 *msg, BOOL remove )
 {
     WND *pWnd;
     BOOL eatMsg = FALSE;
@@ -70,6 +76,7 @@
     static WORD  lastClickMsg = 0;
     static POINT16 lastClickPos = { 0, 0 };
     POINT16 pt = msg->pt;
+    MESSAGEQUEUE *queue = (MESSAGEQUEUE *)GlobalLock16(GetTaskQueue(0));
 
     BOOL mouseClick = ((msg->message == WM_LBUTTONDOWN) ||
 		       (msg->message == WM_RBUTTONDOWN) ||
@@ -77,7 +84,7 @@
 
       /* Find the window */
 
-    if ((msg->hwnd = GetCapture()) != 0)
+    if ((msg->hwnd = GetCapture16()) != 0)
     {
         BOOL32 ret;
 
@@ -87,7 +94,7 @@
 
         if (!HOOK_GetHook( WH_MOUSE, GetTaskQueue(0)) ||
             !(hook = SEGPTR_NEW(MOUSEHOOKSTRUCT16)))
-            return TRUE;
+            return SYSQ_MSG_ACCEPT;
         hook->pt           = msg->pt;
         hook->hwnd         = msg->hwnd;
         hook->wHitTestCode = HTCLIENT;
@@ -95,21 +102,22 @@
         ret = !HOOK_CallHooks( WH_MOUSE, remove ? HC_ACTION : HC_NOREMOVE,
                                msg->message, (LPARAM)SEGPTR_GET(hook));
         SEGPTR_FREE(hook);
-        return ret;
+        return ret ? SYSQ_MSG_ACCEPT : SYSQ_MSG_SKIP ;
     }
    
     hittest = WINPOS_WindowFromPoint( msg->pt, &pWnd );
     if (pWnd->hmemTaskQ != GetTaskQueue(0))
     {
         /* Not for the current task */
-        MESSAGEQUEUE *queue = (MESSAGEQUEUE *)GlobalLock16( GetTaskQueue(0) );
         if (queue) QUEUE_ClearWakeBit( queue, QS_MOUSE );
         /* Wake up the other task */
         queue = (MESSAGEQUEUE *)GlobalLock16( pWnd->hmemTaskQ );
         if (queue) QUEUE_SetWakeBit( queue, QS_MOUSE );
-        return FALSE;
+        return SYSQ_MSG_ABANDON;
     }
-    msg->hwnd = pWnd->hwndSelf;
+    pCursorQueue = queue;
+    msg->hwnd    = pWnd->hwndSelf;
+
     if ((hittest != HTERROR) && mouseClick)
     {
         HWND hwndTop = WIN_GetTopParent( msg->hwnd );
@@ -121,7 +129,8 @@
 
         /* Activate the window if needed */
 
-        if (msg->hwnd != GetActiveWindow() && msg->hwnd != GetDesktopWindow())
+        if (msg->hwnd != GetActiveWindow() &&
+            msg->hwnd != GetDesktopWindow16())
         {
             LONG ret = SendMessage16( msg->hwnd, WM_MOUSEACTIVATE, hwndTop,
                                     MAKELONG( hittest, msg->message ) );
@@ -139,7 +148,7 @@
 
     SendMessage16( msg->hwnd, WM_SETCURSOR, (WPARAM)msg->hwnd,
                    MAKELONG( hittest, msg->message ));
-    if (eatMsg) return FALSE;
+    if (eatMsg) return SYSQ_MSG_SKIP;
 
       /* Check for double-click */
 
@@ -189,7 +198,7 @@
 
     if (!HOOK_GetHook( WH_MOUSE, GetTaskQueue(0)) ||
         !(hook = SEGPTR_NEW(MOUSEHOOKSTRUCT16)))
-        return TRUE;
+        return SYSQ_MSG_ACCEPT;
 
     hook->pt           = msg->pt;
     hook->hwnd         = msg->hwnd;
@@ -198,7 +207,7 @@
     ret = !HOOK_CallHooks( WH_MOUSE, remove ? HC_ACTION : HC_NOREMOVE,
                            msg->message, (LPARAM)SEGPTR_GET(hook) );
     SEGPTR_FREE(hook);
-    return ret;
+    return ret ? SYSQ_MSG_ACCEPT : SYSQ_MSG_SKIP;
 }
 
 
@@ -209,7 +218,7 @@
  * Return value indicates whether the translated message must be passed
  * to the user.
  */
-static BOOL MSG_TranslateKeyboardMsg( MSG16 *msg, BOOL remove )
+static SYSQ_STATUS MSG_TranslateKeyboardMsg( MSG16 *msg, BOOL remove )
 {
     WND *pWnd;
 
@@ -235,12 +244,14 @@
         /* Wake up the other task */
         queue = (MESSAGEQUEUE *)GlobalLock16( pWnd->hmemTaskQ );
         if (queue) QUEUE_SetWakeBit( queue, QS_KEY );
-        return FALSE;
+        return SYSQ_MSG_ABANDON;
     }
-    return !HOOK_CallHooks( WH_KEYBOARD, remove ? HC_ACTION : HC_NOREMOVE,
-                            msg->wParam, msg->lParam );
+    return (HOOK_CallHooks( WH_KEYBOARD, remove ? HC_ACTION : HC_NOREMOVE,
+                            msg->wParam, msg->lParam ))
+            ? SYSQ_MSG_SKIP : SYSQ_MSG_ACCEPT;
 }
 
+
 /***********************************************************************
  *           MSG_JournalRecordMsg
  *
@@ -392,26 +403,30 @@
 static BOOL MSG_PeekHardwareMsg( MSG16 *msg, HWND hwnd, WORD first, WORD last,
                                  BOOL remove )
 {
+    SYSQ_STATUS status;
     MESSAGEQUEUE *sysMsgQueue = QUEUE_GetSysQueue();
     int i, pos = sysMsgQueue->nextMessage;
 
     /* If the queue is empty, attempt to fill it */
-    if (!sysMsgQueue->msgCount && XPending(display)) EVENT_WaitXEvent( FALSE );
+    if (!sysMsgQueue->msgCount && XPending(display))
+        EVENT_WaitXEvent( FALSE, FALSE );
 
     for (i = 0; i < sysMsgQueue->msgCount; i++, pos++)
     {
         if (pos >= sysMsgQueue->queueSize) pos = 0;
 	*msg = sysMsgQueue->messages[pos].msg;
 
-          /* Translate message */
+          /* Translate message; return FALSE immediately on SYSQ_MSG_ABANDON */
 
         if ((msg->message >= WM_MOUSEFIRST) && (msg->message <= WM_MOUSELAST))
         {
-            if (!MSG_TranslateMouseMsg( msg, remove )) continue;
+            if ((status = MSG_TranslateMouseMsg(msg,remove)) == SYSQ_MSG_ABANDON)
+                return FALSE;
         }
         else if ((msg->message >= WM_KEYFIRST) && (msg->message <= WM_KEYLAST))
         {
-            if (!MSG_TranslateKeyboardMsg( msg, remove )) continue;
+            if ((status = MSG_TranslateKeyboardMsg(msg,remove)) == SYSQ_MSG_ABANDON)
+                return FALSE;
         }
         else  /* Non-standard hardware event */
         {
@@ -427,21 +442,28 @@
                                       remove ? HC_ACTION : HC_NOREMOVE,
                                       0, (LPARAM)SEGPTR_GET(hook) );
                 SEGPTR_FREE(hook);
-                if (ret) continue;
+                status = ret ? SYSQ_MSG_SKIP : SYSQ_MSG_ACCEPT;
             }
         }
 
+        if (status == SYSQ_MSG_SKIP)
+        {
+            if (remove) QUEUE_RemoveMsg( sysMsgQueue, pos );
+            /* FIXME: call CBT_CLICKSKIPPED from here */
+            continue;
+        }
+
           /* Check message against filters */
 
         if (hwnd && (msg->hwnd != hwnd)) continue;
         if ((first || last) && 
             ((msg->message < first) || (msg->message > last))) continue;
-        if ((msg->hwnd != GetDesktopWindow()) && 
-            (GetWindowTask16(msg->hwnd) != GetCurrentTask()))
-            continue;  /* Not for this task */
-        if (remove && HOOK_GetHook( WH_JOURNALRECORD, GetTaskQueue(0) ))
-            MSG_JournalRecordMsg( msg );
-        if (remove) QUEUE_RemoveMsg( sysMsgQueue, pos );
+        if (remove)
+        {
+            if (HOOK_GetHook( WH_JOURNALRECORD, GetTaskQueue(0) ))
+                MSG_JournalRecordMsg( msg );
+            QUEUE_RemoveMsg( sysMsgQueue, pos );
+        }
         return TRUE;
     }
     return FALSE;
@@ -474,43 +496,71 @@
 static LRESULT MSG_SendMessage( HQUEUE16 hDestQueue, HWND hwnd, UINT msg,
                                 WPARAM wParam, LPARAM lParam )
 {
+    INT32	  prevSMRL = debugSMRL;
+    QSMCTRL 	  qCtrl = { 0, 1};
     MESSAGEQUEUE *queue, *destQ;
 
     if (!(queue = (MESSAGEQUEUE*)GlobalLock16( GetTaskQueue(0) ))) return 0;
     if (!(destQ = (MESSAGEQUEUE*)GlobalLock16( hDestQueue ))) return 0;
 
-    if (IsTaskLocked())
+    if (IsTaskLocked() || !IsWindow(hwnd)) return 0;
+
+    debugSMRL+=4;
+    dprintf_sendmsg(stddeb,"%*sSM: %s [%04x] (%04x -> %04x)\n", 
+		    prevSMRL, "", SPY_GetMsgName(msg), msg, queue->self, hDestQueue );
+
+    if( !(queue->wakeBits & QS_SMPARAMSFREE) )
     {
-        fprintf( stderr, "SendMessage: task is locked\n" );
-        return 0;
+      dprintf_sendmsg(stddeb,"\tIntertask SendMessage: sleeping since unreplied SendMessage pending\n");
+      queue->changeBits &= ~QS_SMPARAMSFREE;
+      QUEUE_WaitBits( QS_SMPARAMSFREE );
     }
 
-    if (queue->hWnd)
-    {
-        fprintf( stderr, "Nested SendMessage(), msg %04x skipped\n", msg );
-        return 0;
-    }
+    /* resume sending */ 
+
     queue->hWnd   = hwnd;
     queue->msg    = msg;
     queue->wParam = wParam;
     queue->lParam = lParam;
     queue->hPrevSendingTask = destQ->hSendingTask;
     destQ->hSendingTask = GetTaskQueue(0);
+
+    queue->wakeBits &= ~QS_SMPARAMSFREE;
+
+    dprintf_sendmsg(stddeb,"%*ssm: smResultInit = %08x\n", prevSMRL, "", (unsigned)&qCtrl);
+
+    queue->smResultInit = &qCtrl;
+
     QUEUE_SetWakeBit( destQ, QS_SENDMESSAGE );
 
-    /* Wait for the result */
+    /* perform task switch and wait for the result */
 
-    printf( "SendMessage %04x to %04x\n", msg, hDestQueue );
-
-    if (!(queue->wakeBits & QS_SMRESULT))
+    while( qCtrl.bPending )
     {
+      if (!(queue->wakeBits & QS_SMRESULT))
+      {
+        queue->changeBits &= ~QS_SMRESULT;
         DirectedYield( destQ->hTask );
         QUEUE_WaitBits( QS_SMRESULT );
+	dprintf_sendmsg(stddeb,"\tsm: have result!\n");
+      }
+      /* got something */
+
+      dprintf_sendmsg(stddeb,"%*ssm: smResult = %08x\n", prevSMRL, "", (unsigned)queue->smResult );
+
+      queue->smResult->lResult = queue->SendMessageReturn;
+      queue->smResult->bPending = FALSE;
+      queue->wakeBits &= ~QS_SMRESULT;
+
+      if( queue->smResult != &qCtrl )
+	  dprintf_msg(stddeb,"%*ssm: weird scenes inside the goldmine!\n", prevSMRL, "");
     }
-    printf( "SendMessage %04x to %04x: got %08lx\n",
-            msg, hDestQueue, queue->SendMessageReturn );
-    queue->wakeBits &= ~QS_SMRESULT;
-    return queue->SendMessageReturn;
+    queue->smResultInit = NULL;
+    
+    dprintf_sendmsg(stddeb,"%*sSM: [%04x] returning %08lx\n", prevSMRL, "", msg, qCtrl.lResult);
+    debugSMRL-=4;
+
+    return qCtrl.lResult;
 }
 
 
@@ -522,19 +572,33 @@
     MESSAGEQUEUE *senderQ;
     MESSAGEQUEUE *queue;
 
-    printf( "ReplyMessage\n " );
     if (!(queue = (MESSAGEQUEUE*)GlobalLock16( GetTaskQueue(0) ))) return;
-    if (!(senderQ = (MESSAGEQUEUE*)GlobalLock16( queue->InSendMessageHandle)))
-        return;
-    for (;;)
+
+    dprintf_msg(stddeb,"ReplyMessage, queue %04x\n", queue->self);
+
+    while( (senderQ = (MESSAGEQUEUE*)GlobalLock16( queue->InSendMessageHandle)))
     {
-        if (queue->wakeBits & QS_SENDMESSAGE) QUEUE_ReceiveMessage( queue );
-        else if (senderQ->wakeBits & QS_SMRESULT) Yield();
-        else break;
-    }
-    printf( "ReplyMessage: res = %08lx\n", result );
+      dprintf_msg(stddeb,"\trpm: replying to %04x (%04x -> %04x)\n",
+                          queue->msg, queue->self, senderQ->self);
+
+      if( queue->wakeBits & QS_SENDMESSAGE )
+      {
+	QUEUE_ReceiveMessage( queue );
+	continue; /* ReceiveMessage() already called us */
+      }
+
+      if(!(senderQ->wakeBits & QS_SMRESULT) ) break;
+      OldYield();
+    } 
+    if( !senderQ ) { dprintf_msg(stddeb,"\trpm: done\n"); return; }
+
     senderQ->SendMessageReturn = result;
+    dprintf_msg(stddeb,"\trpm: smResult = %08x, result = %08lx\n", 
+			(unsigned)queue->smResultCurrent, result );
+
+    senderQ->smResult = queue->smResultCurrent;
     queue->InSendMessageHandle = 0;
+
     QUEUE_SetWakeBit( senderQ, QS_SMRESULT );
     DirectedYield( queue->hSendingTask );
 }
@@ -582,6 +646,23 @@
 
 	if (msgQueue->wakeBits & QS_SENDMESSAGE)
             QUEUE_ReceiveMessage( msgQueue );
+
+        /* Now handle a WM_QUIT message 
+	 *
+	 * FIXME: PostQuitMessage() should post WM_QUIT and 
+	 *	  set QS_POSTMESSAGE wakebit instead of this.
+	 */
+
+        if (msgQueue->wPostQMsg &&
+	   (!first || WM_QUIT >= first) && 
+	   (!last || WM_QUIT <= last) )
+        {
+            msg->hwnd    = hwnd;
+            msg->message = WM_QUIT;
+            msg->wParam  = msgQueue->wExitCode;
+            msg->lParam  = 0;
+            break;
+        }
     
         /* Now find a normal message */
 
@@ -612,17 +693,6 @@
             break;
         }
 
-        /* Now handle a WM_QUIT message */
-
-	if (msgQueue->wPostQMsg)
-	{
-	    msg->hwnd    = hwnd;
-	    msg->message = WM_QUIT;
-	    msg->wParam  = msgQueue->wExitCode;
-	    msg->lParam  = 0;
-	    break;
-	}
-
         /* Check again for SendMessage */
 
  	if (msgQueue->wakeBits & QS_SENDMESSAGE)