Moved hardware message queue handling to the server.

diff --git a/windows/message.c b/windows/message.c
index 213e089..18baf2f 100644
--- a/windows/message.c
+++ b/windows/message.c
@@ -32,44 +32,86 @@
 
 DEFAULT_DEBUG_CHANNEL(msg);
 DECLARE_DEBUG_CHANNEL(key);
-DECLARE_DEBUG_CHANNEL(sendmsg);
 
 #define WM_NCMOUSEFIRST         WM_NCMOUSEMOVE
 #define WM_NCMOUSELAST          WM_NCMBUTTONDBLCLK
 
-    
-typedef enum { SYSQ_MSG_ABANDON, SYSQ_MSG_SKIP, 
-               SYSQ_MSG_ACCEPT, SYSQ_MSG_CONTINUE } SYSQ_STATUS;
-
-extern HQUEUE16 hCursorQueue;			 /* queue.c */
-
 static UINT doubleClickSpeed = 452;
 
+
 /***********************************************************************
- *           MSG_CheckFilter
+ *           is_keyboard_message
  */
-static BOOL MSG_CheckFilter(DWORD uMsg, DWORD first, DWORD last)
+inline static BOOL is_keyboard_message( UINT message )
 {
-   if( first || last )
-       return (uMsg >= first && uMsg <= last);
-   return TRUE;
+    return (message >= WM_KEYFIRST && message <= WM_KEYLAST);
 }
 
+
+/***********************************************************************
+ *           is_mouse_message
+ */
+inline static BOOL is_mouse_message( UINT message )
+{
+    return ((message >= WM_NCMOUSEFIRST && message <= WM_NCMOUSELAST) ||
+            (message >= WM_MOUSEFIRST && message <= WM_MOUSELAST));
+}
+
+
+/***********************************************************************
+ *           check_message_filter
+ */
+inline static BOOL check_message_filter( const MSG *msg, HWND hwnd, UINT first, UINT last )
+{
+    if (hwnd)
+    {
+        if (msg->hwnd != hwnd && !IsChild( hwnd, msg->hwnd )) return FALSE;
+    }
+    if (first || last)
+    {
+       return (msg->message >= first && msg->message <= last);
+    }
+    return TRUE;
+}
+
+
+/***********************************************************************
+ *           queue_hardware_message
+ *
+ * store a hardware message in the thread queue
+ */
+static void queue_hardware_message( MSG *msg, ULONG_PTR extra_info, enum message_kind kind )
+{
+    SERVER_START_REQ( send_message )
+    {
+        req->kind   = kind;
+        req->id     = (void *)GetWindowThreadProcessId( msg->hwnd, NULL );
+        req->type   = QMSG_HARDWARE;
+        req->win    = msg->hwnd;
+        req->msg    = msg->message;
+        req->wparam = msg->wParam;
+        req->lparam = msg->lParam;
+        req->x      = msg->pt.x;
+        req->y      = msg->pt.y;
+        req->time   = msg->time;
+        req->info   = extra_info;
+        SERVER_CALL();
+    }
+    SERVER_END_REQ;
+}
+
+
 /***********************************************************************
  *           MSG_SendParentNotify
  *
  * Send a WM_PARENTNOTIFY to all ancestors of the given window, unless
  * the window has the WS_EX_NOPARENTNOTIFY style.
  */
-static void MSG_SendParentNotify(WND* wndPtr, WORD event, WORD idChild, LPARAM lValue)
+static void MSG_SendParentNotify( HWND hwnd, WORD event, WORD idChild, POINT pt )
 {
-    POINT pt;
+    WND *tmpWnd = WIN_FindWndPtr(hwnd);
 
     /* pt has to be in the client coordinates of the parent window */
-    WND *tmpWnd = WIN_LockWndPtr(wndPtr);
-
-    pt.x = SLOWORD(lValue);
-    pt.y = SHIWORD(lValue);
     MapWindowPoints( 0, tmpWnd->hwndSelf, &pt, 1 );
     while (tmpWnd)
     {
@@ -82,446 +124,58 @@
 	pt.y += tmpWnd->rectClient.top;
 	WIN_UpdateWndPtr(&tmpWnd,tmpWnd->parent);
 	SendMessageA( tmpWnd->hwndSelf, WM_PARENTNOTIFY,
-		      MAKEWPARAM( event, idChild ), 
-                      MAKELONG( pt.x, pt.y ) );
+                      MAKEWPARAM( event, idChild ), MAKELPARAM( pt.x, pt.y ) );
     }
 }
 
 
 /***********************************************************************
- *           MSG_TranslateMouseMsg
- *
- * Translate a mouse hardware event into a real mouse message.
- *
- * Returns:
- *
- *  SYSQ_MSG_ABANDON  - abandon the peek message loop
- *  SYSQ_MSG_CONTINUE - leave the message in the queue and
- *                      continue with the translation loop
- *  SYSQ_MSG_ACCEPT   - proceed to process the translated message
- */
-static DWORD MSG_TranslateMouseMsg( HWND hTopWnd, DWORD first, DWORD last,
-                                    MSG *msg, BOOL remove, WND* pWndScope,
-                                    INT *pHitTest, POINT *screen_pt, BOOL *pmouseClick )
-{
-    static DWORD   dblclk_time_limit = 0;
-    static UINT16     clk_message = 0;
-    static HWND16     clk_hwnd = 0;
-    static POINT clk_pos;
-
-    WND *pWnd;
-    HWND hWnd;
-    INT16 ht, hittest;
-    UINT message = msg->message;
-    POINT pt = msg->pt;
-    HANDLE16 hQ = GetFastQueue16();
-    MESSAGEQUEUE *queue = QUEUE_Lock(hQ);
-    int mouseClick = ((message == WM_LBUTTONDOWN) ||
-                      (message == WM_RBUTTONDOWN) ||
-                      (message == WM_MBUTTONDOWN));
-    DWORD retvalue;
-
-    /* Find the window to dispatch this mouse message to */
-
-    hWnd = GetCapture();
-
-    /* If no capture HWND, find window which contains the mouse position.
-     * Also find the position of the cursor hot spot (hittest) */
-    if( !hWnd )
-    {
-	ht = hittest = WINPOS_WindowFromPoint( pWndScope, pt, &pWnd );
-	if( !pWnd ) pWnd = WIN_GetDesktop();
-        else WIN_LockWndPtr(pWnd);
-	hWnd = pWnd->hwndSelf;
-    } 
-    else 
-    {
-        ht = hittest = HTCLIENT;
-	pWnd = WIN_FindWndPtr(hWnd);
-        if (queue)
-            ht = PERQDATA_GetCaptureInfo( queue->pQData );
-    }
-
-    /* Save hittest for return */
-    *pHitTest = hittest;
-        
-	/* stop if not the right queue */
-
-    if (pWnd->hmemTaskQ && pWnd->hmemTaskQ != hQ)
-    {
-        /* Not for the current task */
-        if (queue) QUEUE_ClearWakeBit( queue, QS_MOUSE );
-        /* Wake up the other task */
-        QUEUE_Unlock( queue );
-        queue = QUEUE_Lock( pWnd->hmemTaskQ );
-        if (queue) QUEUE_SetWakeBit( queue, QS_MOUSE, 0 );
-
-        QUEUE_Unlock( queue );
-        retvalue = SYSQ_MSG_ABANDON;
-        goto END;
-    }
-
-	/* check if hWnd is within hWndScope */
-
-    if( hTopWnd && hWnd != hTopWnd )
-        if( !IsChild(hTopWnd, hWnd) )
-        {
-            QUEUE_Unlock( queue );
-            retvalue = SYSQ_MSG_CONTINUE;
-            goto END;
-        }
-
-    /* Was it a mouse click message */
-    if( mouseClick )
-    {
-	/* translate double clicks -
-	 * note that ...MOUSEMOVEs can slip in between
-	 * ...BUTTONDOWN and ...BUTTONDBLCLK messages */
-
-	if(GetClassLongA(hWnd, GCL_STYLE) & CS_DBLCLKS || ht != HTCLIENT )
-	{
-           if ((message == clk_message) && (hWnd == clk_hwnd) &&
-               (msg->time - dblclk_time_limit < doubleClickSpeed) &&
-               (abs(msg->pt.x - clk_pos.x) < GetSystemMetrics(SM_CXDOUBLECLK)/2) &&
-               (abs(msg->pt.y - clk_pos.y) < GetSystemMetrics(SM_CYDOUBLECLK)/2))
-	   {
-	      message += (WM_LBUTTONDBLCLK - WM_LBUTTONDOWN);
-	      mouseClick++;   /* == 2 */
-	   }
-	}
-    }
-    /* save mouse position */
-    *screen_pt = pt;
-
-    if (hittest != HTCLIENT)
-    {
-	message += WM_NCMOUSEMOVE - WM_MOUSEMOVE;
-	msg->wParam = hittest;
-    }
-    else
-        ScreenToClient( hWnd, &pt );
-
-	/* check message filter */
-
-    if (!MSG_CheckFilter(message, first, last))
-    {
-        QUEUE_Unlock(queue);
-        retvalue = SYSQ_MSG_CONTINUE;
-        goto END;
-    }
-
-    /* Update global hCursorQueue */
-    hCursorQueue = queue->self;
-    
-    /* Update static double click conditions */
-    if( remove && mouseClick )
-    {
-	if( mouseClick == 1 )
-	{
-	    /* set conditions */
-	    dblclk_time_limit = msg->time;
-            clk_message = msg->message;
-            clk_hwnd = hWnd;
-            clk_pos = *screen_pt;
-	} else 
-	    /* got double click - zero them out */
-	    dblclk_time_limit = clk_hwnd = 0;
-    }
-
-    QUEUE_Unlock(queue);
-
-    /* Update message params */
-    msg->hwnd    = hWnd;
-    msg->message = message;
-    msg->lParam  = MAKELONG( pt.x, pt.y );
-    retvalue = SYSQ_MSG_ACCEPT;
-
-END:
-    WIN_ReleaseWndPtr(pWnd);
-
-    /* Return mouseclick flag */
-    *pmouseClick = mouseClick;
-    
-    return retvalue;
-}
-
-
-/***********************************************************************
- *           MSG_ProcessMouseMsg
- *
- * Processes a translated mouse hardware event.
- * The passed in msg structure should contain the updated hWnd, 
- * lParam, wParam and message fields from MSG_TranslateMouseMsg.
- *
- * Returns:
- *
- *  SYSQ_MSG_SKIP     - Message should be skipped entirely (in this case
- *                      HIWORD contains hit test code). Continue translating..
- *  SYSQ_MSG_ACCEPT   - the translated message must be passed to the user
- *                      MSG_PeekHardwareMsg should return TRUE.
- */
-static DWORD MSG_ProcessMouseMsg( MSG *msg, BOOL remove, INT hittest,
-                                  POINT screen_pt, BOOL mouseClick )
-{
-    WND *pWnd;
-    HWND hWnd = msg->hwnd;
-    INT16 sendSC = (GetCapture() == 0);
-    UINT message = msg->message;
-    BOOL eatMsg = FALSE;
-    DWORD retvalue;
-
-    pWnd = WIN_FindWndPtr(hWnd);
-    
-	/* call WH_MOUSE */
-
-    if (HOOK_IsHooked( WH_MOUSE ))
-    { 
-        MOUSEHOOKSTRUCT hook;
-        hook.pt           = screen_pt;
-        hook.hwnd         = hWnd;
-        hook.wHitTestCode = hittest;
-        hook.dwExtraInfo  = 0;
-        if (HOOK_CallHooksA( WH_MOUSE, remove ? HC_ACTION : HC_NOREMOVE,
-                             message, (LPARAM)&hook ))
-        {
-            retvalue = MAKELONG((INT16)SYSQ_MSG_SKIP, hittest);
-            goto END;
-        }
-    }
-
-    if (message >= WM_NCMOUSEFIRST && message <= WM_NCMOUSELAST)
-        message += WM_MOUSEFIRST - WM_NCMOUSEFIRST;
-
-    if ((hittest == HTERROR) || (hittest == HTNOWHERE)) 
-	eatMsg = sendSC = 1;
-    else if( remove && mouseClick )
-    {
-        HWND hwndTop = WIN_GetTopParent( hWnd );
-
-	if( sendSC )
-	{
-            /* Send the WM_PARENTNOTIFY,
-	     * note that even for double/nonclient clicks
-	     * notification message is still WM_L/M/RBUTTONDOWN.
-	     */
-
-            MSG_SendParentNotify( pWnd, message, 0, MAKELPARAM(screen_pt.x, screen_pt.y) );
-
-            /* Activate the window if needed */
-
-            if (hWnd != GetActiveWindow() && hwndTop != GetDesktopWindow())
-            {
-                LONG ret = SendMessageA( hWnd, WM_MOUSEACTIVATE, hwndTop,
-                                          MAKELONG( hittest, message ) );
-
-                if ((ret == MA_ACTIVATEANDEAT) || (ret == MA_NOACTIVATEANDEAT))
-                         eatMsg = TRUE;
-
-                if (((ret == MA_ACTIVATE) || (ret == MA_ACTIVATEANDEAT))
-                        && hwndTop != GetForegroundWindow() )
-                {
-                      if (!WINPOS_SetActiveWindow( hwndTop, TRUE , TRUE ))
-			 eatMsg = TRUE;
-                }
-            }
-	}
-    } else sendSC = (remove && sendSC);
-
-     /* Send the WM_SETCURSOR message */
-
-    if (sendSC)
-    {
-        /* Windows sends the normal mouse message as the message parameter
-           in the WM_SETCURSOR message even if it's non-client mouse message */
-        SendMessageA( hWnd, WM_SETCURSOR, hWnd,
-                       MAKELONG( hittest, message ));
-    }
-    if (eatMsg)
-    {
-        retvalue = MAKELONG( (UINT16)SYSQ_MSG_SKIP, hittest);
-        goto END;
-    }
-
-    retvalue = SYSQ_MSG_ACCEPT;
-END:
-    WIN_ReleaseWndPtr(pWnd);
-
-    return retvalue;
-}
-
-
-/***********************************************************************
- *           MSG_TranslateKbdMsg
- *
- * Translate a keyboard hardware event into a real message.
- */
-static DWORD MSG_TranslateKbdMsg( HWND hTopWnd, DWORD first, DWORD last,
-				  MSG *msg, BOOL remove )
-{
-    WORD message = msg->message;
-    HWND hWnd = GetFocus();
-    WND *pWnd;
-
-      /* Should check Ctrl-Esc and PrintScreen here */
-
-    if (!hWnd)
-    {
-	  /* Send the message to the active window instead,  */
-	  /* translating messages to their WM_SYS equivalent */
-
-	hWnd = GetActiveWindow();
-
-	if( message < WM_SYSKEYDOWN )
-	    message += WM_SYSKEYDOWN - WM_KEYDOWN;
-    }
-    if ( !hWnd ) return SYSQ_MSG_ABANDON;
-    pWnd = WIN_FindWndPtr( hWnd );
-
-    if (pWnd && pWnd->hmemTaskQ && (pWnd->hmemTaskQ != GetFastQueue16()))
-    {
-        /* Not for the current task */
-        MESSAGEQUEUE *queue = QUEUE_Lock( GetFastQueue16() );
-        if (queue) QUEUE_ClearWakeBit( queue, QS_KEY );
-        QUEUE_Unlock( queue );
-        
-        /* Wake up the other task */
-        queue = QUEUE_Lock( pWnd->hmemTaskQ );
-        if (queue) QUEUE_SetWakeBit( queue, QS_KEY, 0 );
-        QUEUE_Unlock( queue );
-        WIN_ReleaseWndPtr(pWnd);
-        return SYSQ_MSG_ABANDON;
-    }
-    WIN_ReleaseWndPtr(pWnd);
-
-    if (hTopWnd && hWnd != hTopWnd)
-	if (!IsChild(hTopWnd, hWnd)) return SYSQ_MSG_CONTINUE;
-    if (!MSG_CheckFilter(message, first, last)) return SYSQ_MSG_CONTINUE;
-
-    msg->hwnd = hWnd;
-    msg->message = message;
-
-    return SYSQ_MSG_ACCEPT;
-}
-
-
-/***********************************************************************
- *           MSG_ProcessKbdMsg
- *
- *  Processes a translated keyboard message
- */
-static DWORD MSG_ProcessKbdMsg( MSG *msg, BOOL remove )
-{
-    /* Handle F1 key by sending out WM_HELP message */
-    if ((msg->message == WM_KEYUP) && 
-	(msg->wParam == VK_F1) &&
-	remove &&
-	(msg->hwnd != GetDesktopWindow()) &&
-	!MENU_IsMenuActive())
-    {   
-	HELPINFO hi;
-	WND *pWnd = WIN_FindWndPtr(msg->hwnd);
-
-	if (NULL != pWnd)
-	{
-	    hi.cbSize = sizeof(HELPINFO);
-	    hi.iContextType = HELPINFO_WINDOW;
-	    hi.iCtrlId = pWnd->wIDmenu; 
-	    hi.hItemHandle = msg->hwnd;
-	    hi.dwContextId = pWnd->helpContext;
-	    hi.MousePos = msg->pt;
-	    SendMessageA(msg->hwnd, WM_HELP, 0, (LPARAM)&hi);
-	}
-        WIN_ReleaseWndPtr(pWnd);
-    }
-
-    return (HOOK_CallHooksA( WH_KEYBOARD, remove ? HC_ACTION : HC_NOREMOVE,
-                             LOWORD (msg->wParam), msg->lParam )
-            ? SYSQ_MSG_SKIP : SYSQ_MSG_ACCEPT);
-}
-
-
-/***********************************************************************
- *           MSG_JournalRecordMsg
- *
- * Build an EVENTMSG structure and call JOURNALRECORD hook
- */
-static void MSG_JournalRecordMsg( MSG *msg )
-{
-    EVENTMSG event;
-
-    event.message = msg->message;
-    event.time = msg->time;
-    if ((msg->message >= WM_KEYFIRST) && (msg->message <= WM_KEYLAST))
-    {
-        event.paramL = (msg->wParam & 0xFF) | (HIWORD(msg->lParam) << 8);
-        event.paramH = msg->lParam & 0x7FFF;
-        if (HIWORD(msg->lParam) & 0x0100)
-            event.paramH |= 0x8000;               /* special_key - bit */
-        HOOK_CallHooksA( WH_JOURNALRECORD, HC_ACTION, 0, (LPARAM)&event );
-    }
-    else if ((msg->message >= WM_MOUSEFIRST) && (msg->message <= WM_MOUSELAST))
-    {
-        POINT pt;
-        pt.x = SLOWORD(msg->lParam);
-        pt.y = SHIWORD(msg->lParam);
-        ClientToScreen( msg->hwnd, &pt );
-        event.paramL = pt.x;
-        event.paramH = pt.y;
-        HOOK_CallHooksA( WH_JOURNALRECORD, HC_ACTION, 0, (LPARAM)&event );
-    }
-    else if ((msg->message >= WM_NCMOUSEFIRST) &&
-             (msg->message <= WM_NCMOUSELAST))
-    {
-        event.paramL = LOWORD(msg->lParam);       /* X pos */
-        event.paramH = HIWORD(msg->lParam);       /* Y pos */
-        event.message += WM_MOUSEMOVE-WM_NCMOUSEMOVE;/* give no info about NC area */
-        HOOK_CallHooksA( WH_JOURNALRECORD, HC_ACTION, 0, (LPARAM)&event );
-    }
-}
-
-/***********************************************************************
  *          MSG_JournalPlayBackMsg
  *
  * Get an EVENTMSG struct via call JOURNALPLAYBACK hook function 
  */
-static int MSG_JournalPlayBackMsg(void)
+static void MSG_JournalPlayBackMsg(void)
 {
     EVENTMSG tmpMsg;
-    LPARAM lParam;
-    WPARAM wParam;
+    MSG msg;
     LRESULT wtime;
     int keyDown,i;
 
-    if (!HOOK_IsHooked( WH_JOURNALPLAYBACK )) return 0;
+    if (!HOOK_IsHooked( WH_JOURNALPLAYBACK )) return;
 
     wtime=HOOK_CallHooksA( WH_JOURNALPLAYBACK, HC_GETNEXT, 0, (LPARAM)&tmpMsg );
     /*  TRACE(msg,"Playback wait time =%ld\n",wtime); */
     if (wtime<=0)
     {
         wtime=0;
+        msg.message = tmpMsg.message;
+        msg.hwnd    = tmpMsg.hwnd;
+        msg.time    = tmpMsg.time;
         if ((tmpMsg.message >= WM_KEYFIRST) && (tmpMsg.message <= WM_KEYLAST))
         {
-            wParam=tmpMsg.paramL & 0xFF;
-            lParam=MAKELONG(tmpMsg.paramH&0x7ffff,tmpMsg.paramL>>8);
+            msg.wParam  = tmpMsg.paramL & 0xFF;
+            msg.lParam  = MAKELONG(tmpMsg.paramH&0x7ffff,tmpMsg.paramL>>8);
             if (tmpMsg.message == WM_KEYDOWN || tmpMsg.message == WM_SYSKEYDOWN)
             {
                 for (keyDown=i=0; i<256 && !keyDown; i++)
                     if (InputKeyStateTable[i] & 0x80)
                         keyDown++;
                 if (!keyDown)
-                    lParam |= 0x40000000;
-                AsyncKeyStateTable[wParam]=InputKeyStateTable[wParam] |= 0x80;
+                    msg.lParam |= 0x40000000;
+                AsyncKeyStateTable[msg.wParam]=InputKeyStateTable[msg.wParam] |= 0x80;
             }
             else                                       /* WM_KEYUP, WM_SYSKEYUP */
             {
-                lParam |= 0xC0000000;
-                AsyncKeyStateTable[wParam]=InputKeyStateTable[wParam] &= ~0x80;
+                msg.lParam |= 0xC0000000;
+                AsyncKeyStateTable[msg.wParam]=InputKeyStateTable[msg.wParam] &= ~0x80;
             }
             if (InputKeyStateTable[VK_MENU] & 0x80)
-                lParam |= 0x20000000;
+                msg.lParam |= 0x20000000;
             if (tmpMsg.paramH & 0x8000)              /*special_key bit*/
-                lParam |= 0x01000000;
-            hardware_event( tmpMsg.message, wParam, lParam, 0, 0, tmpMsg.time, 0 );
+                msg.lParam |= 0x01000000;
+
+            msg.pt.x = msg.pt.y = 0;
+            queue_hardware_message( &msg, 0, RAW_HW_MESSAGE );
         }
         else if ((tmpMsg.message>= WM_MOUSEFIRST) && (tmpMsg.message <= WM_MOUSELAST))
         {
@@ -544,180 +198,333 @@
             AsyncKeyStateTable[VK_MBUTTON]= InputKeyStateTable[VK_MBUTTON] = MouseButtonsStates[1] ? 0x80 : 0;
             AsyncKeyStateTable[VK_RBUTTON]= InputKeyStateTable[VK_RBUTTON] = MouseButtonsStates[2] ? 0x80 : 0;
             SetCursorPos(tmpMsg.paramL,tmpMsg.paramH);
-            lParam=MAKELONG(tmpMsg.paramL,tmpMsg.paramH);
-            wParam=0;
-            if (MouseButtonsStates[0]) wParam |= MK_LBUTTON;
-            if (MouseButtonsStates[1]) wParam |= MK_MBUTTON;
-            if (MouseButtonsStates[2]) wParam |= MK_RBUTTON;
-            hardware_event( tmpMsg.message, wParam, lParam,
-                            tmpMsg.paramL, tmpMsg.paramH, tmpMsg.time, 0 );
+            msg.lParam=MAKELONG(tmpMsg.paramL,tmpMsg.paramH);
+            msg.wParam=0;
+            if (MouseButtonsStates[0]) msg.wParam |= MK_LBUTTON;
+            if (MouseButtonsStates[1]) msg.wParam |= MK_MBUTTON;
+            if (MouseButtonsStates[2]) msg.wParam |= MK_RBUTTON;
+
+            msg.pt.x = tmpMsg.paramL;
+            msg.pt.y = tmpMsg.paramH;
+            queue_hardware_message( &msg, 0, RAW_HW_MESSAGE );
         }
         HOOK_CallHooksA( WH_JOURNALPLAYBACK, HC_SKIP, 0, (LPARAM)&tmpMsg);
-        return 0;
     }
     else
     {
         if( tmpMsg.message == WM_QUEUESYNC )
             if (HOOK_IsHooked( WH_CBT ))
                 HOOK_CallHooksA( WH_CBT, HCBT_QS, 0, 0L);
-
-        return QS_MOUSE | QS_KEY; /* ? */
     }
 }
 
+
 /***********************************************************************
- *           MSG_PeekHardwareMsg
+ *          process_raw_keyboard_message
  *
- * Peek for a hardware message matching the hwnd and message filters.
+ * returns TRUE if the contents of 'msg' should be passed to the application
  */
-static BOOL MSG_PeekHardwareMsg( MSG *msg, HWND hwnd, DWORD first, DWORD last,
-                                   BOOL remove )
+static BOOL process_raw_keyboard_message( MSG *msg, ULONG_PTR extra_info )
 {
-    DWORD status = SYSQ_MSG_ACCEPT;
-    MESSAGEQUEUE *sysMsgQueue = QUEUE_GetSysQueue();
-    enum { MOUSE_MSG = 0, KEYBOARD_MSG, HARDWARE_MSG } msgType;
-    QMSG *nextqmsg, *qmsg = 0;
-    BOOL bRet = FALSE;
-
-    EnterCriticalSection(&sysMsgQueue->cSection);
-
-    /* Loop through the Q and translate the message we wish to process
-     * while we own the lock. Based on the translation status (abandon/cont/accept)
-     * we then process the message accordingly
-     */
-
-    for ( qmsg = sysMsgQueue->firstMsg; qmsg; qmsg = nextqmsg )
+    if (!(msg->hwnd = GetFocus()))
     {
-        INT hittest;
-        POINT screen_pt;
-        BOOL mouseClick;
-
-        *msg = qmsg->msg;
-
-        nextqmsg = qmsg->nextMsg;
-
-          /* Translate message */
-
-        if ((msg->message >= WM_MOUSEFIRST) && (msg->message <= WM_MOUSELAST))
-        {
-            HWND hWndScope = (HWND)qmsg->extraInfo;
-            WND *tmpWnd = IsWindow(hWndScope) ? WIN_FindWndPtr(hWndScope) : WIN_GetDesktop();
-
-            status = MSG_TranslateMouseMsg(hwnd, first, last, msg, remove, tmpWnd,
-                                           &hittest, &screen_pt, &mouseClick );
-	    msgType = MOUSE_MSG;
-            
-            WIN_ReleaseWndPtr(tmpWnd);
-
-        }
-        else if ((msg->message >= WM_KEYFIRST) && (msg->message <= WM_KEYLAST))
-        {
-            status = MSG_TranslateKbdMsg(hwnd, first, last, msg, remove);
-	    msgType = KEYBOARD_MSG;
-        }
-        else /* Non-standard hardware event */
-        {
-            HARDWAREHOOKSTRUCT16 *hook;
-	    msgType = HARDWARE_MSG;
-            if ((hook = SEGPTR_NEW(HARDWAREHOOKSTRUCT16)))
-            {
-                BOOL ret;
-                hook->hWnd     = msg->hwnd;
-                hook->wMessage = msg->message & 0xffff;
-                hook->wParam   = LOWORD (msg->wParam);
-                hook->lParam   = msg->lParam;
-                ret = HOOK_CallHooks16( WH_HARDWARE,
-                                        remove ? HC_ACTION : HC_NOREMOVE,
-                                        0, (LPARAM)SEGPTR_GET(hook) );
-                SEGPTR_FREE(hook);
-                if (ret) 
-		{
-                    QUEUE_RemoveMsg( sysMsgQueue, qmsg );
-		    continue;
-		}
-		status = SYSQ_MSG_ACCEPT; 
-            }
-        }
-
-        
-	switch (LOWORD(status))
-	{
-	   case SYSQ_MSG_ACCEPT:
-           {
-               /* Remove the message from the system msg Q while it is still locked,
-                * before accepting it */
-               if (remove)
-               {
-                   if (HOOK_IsHooked( WH_JOURNALRECORD )) MSG_JournalRecordMsg( msg );
-                   QUEUE_RemoveMsg( sysMsgQueue, qmsg );
-               }
-               /* Now actually process the message, after we unlock the system msg Q.
-                * We should not hold on to the crst since SendMessage calls during processing 
-                * will potentially cause callbacks to PeekMessage from the application.
-                * If we're holding the crst and QUEUE_WaitBits is called with a
-                * QS_SENDMESSAGE mask we will deadlock in hardware_event() when a
-                * message is being posted to the Q.
-                */
-               LeaveCriticalSection(&sysMsgQueue->cSection);
-               if( msgType == KEYBOARD_MSG )
-                   status = MSG_ProcessKbdMsg( msg, remove );
-               else if ( msgType == MOUSE_MSG )
-                   status = MSG_ProcessMouseMsg( msg, remove, hittest, screen_pt, mouseClick );
-
-               /* Reclaim the sys msg Q crst */
-               EnterCriticalSection(&sysMsgQueue->cSection);
-               
-               /* Pass the translated message to the user if it was accepted */
-               if (status == SYSQ_MSG_ACCEPT)
-		break;
-
-               /* If not accepted, fall through into the SYSQ_MSG_SKIP case */
-           }
-                
-	   case SYSQ_MSG_SKIP:
-                if (HOOK_IsHooked( WH_CBT ))
-                {
-                   if( msgType == KEYBOARD_MSG )
-                       HOOK_CallHooksA( WH_CBT, HCBT_KEYSKIPPED,
-                                         LOWORD (msg->wParam), msg->lParam );
-		   else if ( msgType == MOUSE_MSG )
-		   {
-                       MOUSEHOOKSTRUCT hook;
-                       hook.pt           = msg->pt;
-                       hook.hwnd         = msg->hwnd;
-                       hook.wHitTestCode = HIWORD(status);
-                       hook.dwExtraInfo  = 0;
-                       HOOK_CallHooksA( WH_CBT, HCBT_CLICKSKIPPED, msg->message, (LPARAM)&hook );
-                   }
-                }
-
-                /* If the message was removed earlier set up nextqmsg so that we start 
-                 * at the top of the queue again.  We need to do this since our next pointer
-                 * could be invalid due to us unlocking the system message Q to process the message.
-                 * If not removed just refresh nextqmsg to point to the next msg.
-                 */
-		if (remove)
-                    nextqmsg = sysMsgQueue->firstMsg;
-                else
-                    nextqmsg = qmsg->nextMsg;
-
-		continue;
-                
-	   case SYSQ_MSG_CONTINUE:
-		continue;
-
-	   case SYSQ_MSG_ABANDON: 
-               bRet = FALSE;
-               goto END;
-	}
-
-        bRet = TRUE;
-        goto END;
+        /* Send the message to the active window instead,  */
+        /* translating messages to their WM_SYS equivalent */
+        msg->hwnd = GetActiveWindow();
+        if (msg->message < WM_SYSKEYDOWN) msg->message += WM_SYSKEYDOWN - WM_KEYDOWN;
     }
 
-END:
-    LeaveCriticalSection(&sysMsgQueue->cSection);
-    return bRet;
+    if (HOOK_IsHooked( WH_JOURNALRECORD ))
+    {
+        EVENTMSG event;
+
+        event.message = msg->message;
+        event.hwnd    = msg->hwnd;
+        event.time    = msg->time;
+        event.paramL  = (msg->wParam & 0xFF) | (HIWORD(msg->lParam) << 8);
+        event.paramH  = msg->lParam & 0x7FFF;
+        if (HIWORD(msg->lParam) & 0x0100) event.paramH |= 0x8000; /* special_key - bit */
+        HOOK_CallHooksA( WH_JOURNALRECORD, HC_ACTION, 0, (LPARAM)&event );
+    }
+
+    return (msg->hwnd != 0);
+}
+
+
+/***********************************************************************
+ *          process_cooked_keyboard_message
+ *
+ * returns TRUE if the contents of 'msg' should be passed to the application
+ */
+static BOOL process_cooked_keyboard_message( MSG *msg, BOOL remove )
+{
+    if (remove)
+    {
+        /* Handle F1 key by sending out WM_HELP message */
+        if ((msg->message == WM_KEYUP) &&
+            (msg->wParam == VK_F1) &&
+            (msg->hwnd != GetDesktopWindow()) &&
+            !MENU_IsMenuActive())
+        {
+            HELPINFO hi;
+            hi.cbSize = sizeof(HELPINFO);
+            hi.iContextType = HELPINFO_WINDOW;
+            hi.iCtrlId = GetWindowLongA( msg->hwnd, GWL_ID );
+            hi.hItemHandle = msg->hwnd;
+            hi.dwContextId = GetWindowContextHelpId( msg->hwnd );
+            hi.MousePos = msg->pt;
+            SendMessageA(msg->hwnd, WM_HELP, 0, (LPARAM)&hi);
+        }
+    }
+
+    if (HOOK_CallHooksA( WH_KEYBOARD, remove ? HC_ACTION : HC_NOREMOVE,
+                         LOWORD(msg->wParam), msg->lParam ))
+    {
+        /* skip this message */
+        HOOK_CallHooksA( WH_CBT, HCBT_KEYSKIPPED, LOWORD(msg->wParam), msg->lParam );
+        return FALSE;
+    }
+    return TRUE;
+}
+
+
+/***********************************************************************
+ *          process_raw_mouse_message
+ *
+ * returns TRUE if the contents of 'msg' should be passed to the application
+ */
+static BOOL process_raw_mouse_message( MSG *msg, ULONG_PTR extra_info )
+{
+    static MSG clk_msg;
+
+    POINT pt;
+    INT ht, hittest;
+
+    /* find the window to dispatch this mouse message to */
+
+    if (!(msg->hwnd = GetCapture()))
+    {
+        /* If no capture HWND, find window which contains the mouse position.
+         * Also find the position of the cursor hot spot (hittest) */
+        HWND hWndScope = (HWND)extra_info;
+        WND *pWndScope = IsWindow(hWndScope) ? WIN_FindWndPtr(hWndScope) : WIN_GetDesktop();
+        WND *pWnd;
+
+        ht = hittest = WINPOS_WindowFromPoint( pWndScope, msg->pt, &pWnd );
+        msg->hwnd = pWnd ? pWnd->hwndSelf : GetDesktopWindow();
+        WIN_ReleaseWndPtr( pWndScope );
+    }
+    else
+    {
+        MESSAGEQUEUE *queue = QUEUE_Lock( GetFastQueue16() );
+
+        ht = hittest = HTCLIENT;
+        if (queue)
+        {
+            ht = PERQDATA_GetCaptureInfo( queue->pQData );
+            QUEUE_Unlock(queue);
+        }
+    }
+
+    if (HOOK_IsHooked( WH_JOURNALRECORD ))
+    {
+        EVENTMSG event;
+        event.message = msg->message;
+        event.time    = msg->time;
+        event.hwnd    = msg->hwnd;
+        event.paramL  = msg->pt.x;
+        event.paramH  = msg->pt.y;
+        HOOK_CallHooksA( WH_JOURNALRECORD, HC_ACTION, 0, (LPARAM)&event );
+    }
+
+    /* translate double clicks */
+
+    if ((msg->message == WM_LBUTTONDOWN) ||
+        (msg->message == WM_RBUTTONDOWN) ||
+        (msg->message == WM_MBUTTONDOWN))
+    {
+        BOOL update = TRUE;
+        /* translate double clicks -
+	 * note that ...MOUSEMOVEs can slip in between
+	 * ...BUTTONDOWN and ...BUTTONDBLCLK messages */
+
+        if (GetClassLongA( msg->hwnd, GCL_STYLE ) & CS_DBLCLKS || ht != HTCLIENT )
+        {
+           if ((msg->message == clk_msg.message) &&
+               (msg->hwnd == clk_msg.hwnd) &&
+               (msg->time - clk_msg.time < doubleClickSpeed) &&
+               (abs(msg->pt.x - clk_msg.pt.x) < GetSystemMetrics(SM_CXDOUBLECLK)/2) &&
+               (abs(msg->pt.y - clk_msg.pt.y) < GetSystemMetrics(SM_CYDOUBLECLK)/2))
+           {
+               msg->message += (WM_LBUTTONDBLCLK - WM_LBUTTONDOWN);
+               clk_msg.message = 0;
+               update = FALSE;
+           }
+        }
+        /* update static double click conditions */
+        if (update) clk_msg = *msg;
+    }
+
+    pt = msg->pt;
+    if (hittest != HTCLIENT)
+    {
+        msg->message += WM_NCMOUSEMOVE - WM_MOUSEMOVE;
+        msg->wParam = hittest;
+    }
+    else ScreenToClient( msg->hwnd, &pt );
+    msg->lParam = MAKELONG( pt.x, pt.y );
+    return TRUE;
+}
+
+
+/***********************************************************************
+ *          process_cooked_mouse_message
+ *
+ * returns TRUE if the contents of 'msg' should be passed to the application
+ */
+static BOOL process_cooked_mouse_message( MSG *msg, BOOL remove )
+{
+    INT hittest = HTCLIENT;
+    UINT raw_message = msg->message;
+    BOOL eatMsg;
+
+    if (msg->message >= WM_NCMOUSEFIRST && msg->message <= WM_NCMOUSELAST)
+    {
+        raw_message += WM_MOUSEFIRST - WM_NCMOUSEFIRST;
+        hittest = msg->wParam;
+    }
+    if (raw_message == WM_LBUTTONDBLCLK ||
+        raw_message == WM_RBUTTONDBLCLK ||
+        raw_message == WM_MBUTTONDBLCLK)
+    {
+        raw_message += WM_LBUTTONDOWN - WM_LBUTTONDBLCLK;
+    }
+
+    if (HOOK_IsHooked( WH_MOUSE ))
+    {
+        MOUSEHOOKSTRUCT hook;
+        hook.pt           = msg->pt;
+        hook.hwnd         = msg->hwnd;
+        hook.wHitTestCode = hittest;
+        hook.dwExtraInfo  = 0;
+        if (HOOK_CallHooksA( WH_MOUSE, remove ? HC_ACTION : HC_NOREMOVE,
+                             msg->message, (LPARAM)&hook ))
+        {
+            hook.pt           = msg->pt;
+            hook.hwnd         = msg->hwnd;
+            hook.wHitTestCode = hittest;
+            hook.dwExtraInfo  = 0;
+            HOOK_CallHooksA( WH_CBT, HCBT_CLICKSKIPPED, msg->message, (LPARAM)&hook );
+            return FALSE;
+        }
+    }
+
+    if ((hittest == HTERROR) || (hittest == HTNOWHERE))
+    {
+        SendMessageA( msg->hwnd, WM_SETCURSOR, msg->hwnd, MAKELONG( hittest, raw_message ));
+        return FALSE;
+    }
+
+    if (!remove || GetCapture()) return TRUE;
+
+    eatMsg = FALSE;
+
+    if ((raw_message == WM_LBUTTONDOWN) ||
+        (raw_message == WM_RBUTTONDOWN) ||
+        (raw_message == WM_MBUTTONDOWN))
+    {
+        HWND hwndTop = WIN_GetTopParent( msg->hwnd );
+
+        /* Send the WM_PARENTNOTIFY,
+         * note that even for double/nonclient clicks
+         * notification message is still WM_L/M/RBUTTONDOWN.
+         */
+        MSG_SendParentNotify( msg->hwnd, raw_message, 0, msg->pt );
+
+        /* Activate the window if needed */
+
+        if (msg->hwnd != GetActiveWindow() && hwndTop != GetDesktopWindow())
+        {
+            LONG ret = SendMessageA( msg->hwnd, WM_MOUSEACTIVATE, hwndTop,
+                                     MAKELONG( hittest, raw_message ) );
+
+            switch(ret)
+            {
+            case MA_NOACTIVATEANDEAT:
+                eatMsg = TRUE;
+                /* fall through */
+            case MA_NOACTIVATE:
+                break;
+            case MA_ACTIVATEANDEAT:
+                eatMsg = TRUE;
+                /* fall through */
+            case MA_ACTIVATE:
+                if (hwndTop != GetForegroundWindow() )
+                {
+                    if (!WINPOS_SetActiveWindow( hwndTop, TRUE , TRUE ))
+                        eatMsg = TRUE;
+                }
+                break;
+            default:
+                WARN( "unknown WM_MOUSEACTIVATE code %ld\n", ret );
+                break;
+            }
+        }
+    }
+
+    /* send the WM_SETCURSOR message */
+
+    /* Windows sends the normal mouse message as the message parameter
+       in the WM_SETCURSOR message even if it's non-client mouse message */
+    SendMessageA( msg->hwnd, WM_SETCURSOR, msg->hwnd, MAKELONG( hittest, raw_message ));
+
+    return !eatMsg;
+}
+
+
+/***********************************************************************
+ *          process_hardware_message
+ *
+ * returns TRUE if the contents of 'msg' should be passed to the application
+ */
+static BOOL process_hardware_message( QMSG *qmsg, HWND hwnd_filter,
+                                      UINT first, UINT last, BOOL remove )
+{
+    if (qmsg->kind == RAW_HW_MESSAGE)
+    {
+        /* if it is raw, try to cook it first */
+        if (is_keyboard_message( qmsg->msg.message ))
+        {
+            if (!process_raw_keyboard_message( &qmsg->msg, qmsg->extraInfo )) return FALSE;
+        }
+        else if (is_mouse_message( qmsg->msg.message ))
+        {
+            if (!process_raw_mouse_message( &qmsg->msg, qmsg->extraInfo )) return FALSE;
+        }
+        else goto invalid;
+
+        /* check destination thread and filters */
+        if (!check_message_filter( &qmsg->msg, hwnd_filter, first, last ) ||
+            GetWindowThreadProcessId( qmsg->msg.hwnd, NULL ) != GetCurrentThreadId())
+        {
+            /* queue it for later, or for another thread */
+            queue_hardware_message( &qmsg->msg, qmsg->extraInfo, COOKED_HW_MESSAGE );
+            return FALSE;
+        }
+
+        /* save the message in the cooked queue if we didn't want to remove it */
+        if (!remove) queue_hardware_message( &qmsg->msg, qmsg->extraInfo, COOKED_HW_MESSAGE );
+    }
+
+    if (is_keyboard_message( qmsg->msg.message ))
+        return process_cooked_keyboard_message( &qmsg->msg, remove );
+
+    if (is_mouse_message( qmsg->msg.message ))
+        return process_cooked_mouse_message( &qmsg->msg, remove );
+
+ invalid:
+    ERR( "unknown message type %x\n", qmsg->msg.message );
+    return FALSE;
 }
 
 
@@ -766,35 +573,33 @@
  *    0 if error or timeout
  *    1 if successful
  */
-static LRESULT MSG_SendMessageInterThread( HQUEUE16 hDestQueue,
-                                           HWND hwnd, UINT msg,
+static LRESULT MSG_SendMessageInterThread( DWORD dest_tid, HWND hwnd, UINT msg,
                                            WPARAM wParam, LPARAM lParam,
                                            DWORD timeout, WORD type,
                                            LRESULT *pRes)
 {
-    MESSAGEQUEUE *destQ;
     BOOL ret;
     int iWndsLocks;
     LRESULT result = 0;
 
     TRACE( "hwnd %x msg %x (%s) wp %x lp %lx\n", hwnd, msg, SPY_GetMsgName(msg), wParam, lParam );
 
-    if (!(destQ = QUEUE_Lock( hDestQueue ))) return 0;
-
     SERVER_START_REQ( send_message )
     {
-        req->posted = FALSE;
-        req->id     = destQ->teb->tid;
+        req->kind   = SEND_MESSAGE;
+        req->id     = (void *)dest_tid;
         req->type   = type;
         req->win    = hwnd;
         req->msg    = msg;
         req->wparam = wParam;
         req->lparam = lParam;
+        req->x      = 0;
+        req->y      = 0;
+        req->time   = GetCurrentTime();
         req->info   = 0;
         ret = !SERVER_CALL_ERR();
     }
     SERVER_END_REQ;
-    QUEUE_Unlock( destQ );
     if (!ret) return 0;
 
     iWndsLocks = WIN_SuspendWndsLock();
@@ -960,11 +765,11 @@
 static BOOL MSG_PeekMessage( int type, LPMSG msg_out, HWND hwnd, 
                              DWORD first, DWORD last, WORD flags, BOOL peek )
 {
-    int changeBits, mask;
+    int mask;
     MESSAGEQUEUE *msgQueue;
-    HQUEUE16 hQueue;
+    HQUEUE16 hQueue = GetFastQueue16();
     int iWndsLocks;
-    MSG msg;
+    QMSG qmsg;
 
     mask = QS_POSTMESSAGE | QS_SENDMESSAGE;  /* Always selected */
     if (first || last)
@@ -982,166 +787,110 @@
 
     iWndsLocks = WIN_SuspendWndsLock();
 
+    /* check for graphics events */
+    if (USER_Driver.pMsgWaitForMultipleObjectsEx)
+        USER_Driver.pMsgWaitForMultipleObjectsEx( 0, NULL, 0, 0, 0 );
+
     while(1)
     {
+        /* FIXME: should remove this */
         WORD wakeBits = HIWORD(GetQueueStatus( mask ));
 
-	hQueue   = GetFastQueue16();
-        msgQueue = QUEUE_Lock( hQueue );
-        if (!msgQueue)
-        {
-            WIN_RestoreWndsLock(iWndsLocks);
-            return FALSE;
-        }
-
-#if 0
-        /* First handle a message put by SendMessage() */
-
-        while ( QUEUE_ReceiveMessage( msgQueue ) )
-            ;
-
-        /* Now handle a WM_QUIT message */
-
-        EnterCriticalSection( &msgQueue->cSection );
-        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;
-            if (flags & PM_REMOVE) msgQueue->wPostQMsg = 0;
-            LeaveCriticalSection( &msgQueue->cSection );
-            break;
-        }
-        LeaveCriticalSection( &msgQueue->cSection );
-#endif
-
-        /* Now find a normal message */
-
   retry:
-        if (wakeBits & (QS_SENDMESSAGE|QS_POSTMESSAGE|QS_TIMER|QS_PAINT))
+        if (QUEUE_FindMsg( hwnd, first, last, flags & PM_REMOVE, &qmsg ))
         {
-            QMSG qmsg;
-            if (QUEUE_FindMsg( hwnd, first, last, flags & PM_REMOVE, FALSE, &qmsg ))
+            if (qmsg.kind == RAW_HW_MESSAGE || qmsg.kind == COOKED_HW_MESSAGE)
+            {
+                if (!process_hardware_message( &qmsg, hwnd, first, last, flags & PM_REMOVE ))
+                    goto retry;
+            }
+            else
             {
                 /* Try to convert message to requested type */
-                MSG tmpMsg = qmsg.msg;
-                if ( !MSG_ConvertMsg( &tmpMsg, qmsg.type, type ) )
+                if ( !MSG_ConvertMsg( &qmsg.msg, qmsg.type, type ) )
                 {
                     ERR( "Message %s of wrong type contains pointer parameters. Skipped!\n",
-                         SPY_GetMsgName(tmpMsg.message));
+                         SPY_GetMsgName(qmsg.msg.message));
                     /* remove it (FIXME) */
-                    if (!(flags & PM_REMOVE)) QUEUE_FindMsg( hwnd, first, last, TRUE, FALSE, &qmsg );
+                    if (!(flags & PM_REMOVE)) QUEUE_FindMsg( hwnd, first, last, TRUE, &qmsg );
                     goto retry;
                 }
+            }
 
-                msg = tmpMsg;
-                msgQueue->GetMessageTimeVal      = msg.time;
-                msgQueue->GetMessagePosVal       = MAKELONG( (INT16)msg.pt.x, (INT16)msg.pt.y );
-                msgQueue->GetMessageExtraInfoVal = qmsg.extraInfo;
-
-                /* need to fill the window handle for WM_PAINT message */
-                if (msg.message == WM_PAINT)
+            /* need to fill the window handle for WM_PAINT message */
+            if (qmsg.msg.message == WM_PAINT)
+            {
+                if ((qmsg.msg.hwnd = WIN_FindWinToRepaint( hwnd, hQueue )))
                 {
-                    WND* wndPtr;
-                    msg.hwnd = WIN_FindWinToRepaint( hwnd , hQueue );
-                    if ((wndPtr = WIN_FindWndPtr(msg.hwnd)))
+                    if (IsIconic( qmsg.msg.hwnd ) && GetClassLongA( qmsg.msg.hwnd, GCL_HICON ))
                     {
-                        if( wndPtr->dwStyle & WS_MINIMIZE &&
-                            (HICON) GetClassLongA(wndPtr->hwndSelf, GCL_HICON) )
-                        {
-                            msg.message = WM_PAINTICON;
-                            msg.wParam = 1;
-                        }
-
-                        if( !hwnd || msg.hwnd == hwnd || IsChild16(hwnd,msg.hwnd) )
-                        {
-                            if( wndPtr->flags & WIN_INTERNAL_PAINT && !wndPtr->hrgnUpdate)
-                            {
-                                wndPtr->flags &= ~WIN_INTERNAL_PAINT;
-                                QUEUE_DecPaintCount( hQueue );
-                            }
-                            WIN_ReleaseWndPtr(wndPtr);
-                            break;
-                        }
-                        WIN_ReleaseWndPtr(wndPtr);
+                        qmsg.msg.message = WM_PAINTICON;
+                        qmsg.msg.wParam = 1;
+                    }
+                    if( !hwnd || qmsg.msg.hwnd == hwnd || IsChild(hwnd,qmsg.msg.hwnd) )
+                    {
+                        /* clear internal paint flag */
+                        RedrawWindow( qmsg.msg.hwnd, NULL, 0,
+                                      RDW_NOINTERNALPAINT | RDW_NOCHILDREN );
+                        break;
                     }
                 }
-                else break;
             }
+            else break;
         }
 
-        changeBits = MSG_JournalPlayBackMsg();
-#if 0  /* FIXME */
-        EnterCriticalSection( &msgQueue->cSection );
-        msgQueue->changeBits |= changeBits;
-        LeaveCriticalSection( &msgQueue->cSection );
-#endif
-
-        /* Now find a hardware event */
-
-        if (MSG_PeekHardwareMsg( &msg, hwnd, first, last, flags & PM_REMOVE ))
-        {
-            /* Got one */
-	    msgQueue->GetMessageTimeVal      = msg.time;
-            msgQueue->GetMessagePosVal       = MAKELONG( (INT16)msg.pt.x, (INT16)msg.pt.y );
-	    msgQueue->GetMessageExtraInfoVal = 0;  /* Always 0 for now */
-            break;
-        }
+        /* FIXME: should be done before checking for hw events */
+        MSG_JournalPlayBackMsg();
 
         if (peek)
         {
 #if 0  /* FIXME */
             if (!(flags & PM_NOYIELD)) UserYield16();
 #endif
-            /* check for graphics events */
-            if (USER_Driver.pMsgWaitForMultipleObjectsEx)
-                USER_Driver.pMsgWaitForMultipleObjectsEx( 0, NULL, 0, 0, 0 );
-
-            QUEUE_Unlock( msgQueue );
             WIN_RestoreWndsLock(iWndsLocks);
             return FALSE;
         }
 
         QUEUE_WaitBits( mask, INFINITE );
-        QUEUE_Unlock( msgQueue );
     }
 
     WIN_RestoreWndsLock(iWndsLocks);
-    
-    /* instead of unlocking queue for every break condition, all break
-       condition will fall here */
-    QUEUE_Unlock( msgQueue );
-    
+
+    if ((msgQueue = QUEUE_Lock( hQueue )))
+    {
+        msgQueue->GetMessageTimeVal      = qmsg.msg.time;
+        msgQueue->GetMessagePosVal       = MAKELONG( qmsg.msg.pt.x, qmsg.msg.pt.y );
+        msgQueue->GetMessageExtraInfoVal = qmsg.extraInfo;
+        QUEUE_Unlock( msgQueue );
+    }
+
       /* We got a message */
     if (flags & PM_REMOVE)
     {
-	WORD message = msg.message;
+	WORD message = qmsg.msg.message;
 
 	if (message == WM_KEYDOWN || message == WM_SYSKEYDOWN)
 	{
-	    BYTE *p = &QueueKeyStateTable[msg.wParam & 0xff];
+	    BYTE *p = &QueueKeyStateTable[qmsg.msg.wParam & 0xff];
 
 	    if (!(*p & 0x80))
 		*p ^= 0x01;
 	    *p |= 0x80;
 	}
 	else if (message == WM_KEYUP || message == WM_SYSKEYUP)
-	    QueueKeyStateTable[msg.wParam & 0xff] &= ~0x80;
+	    QueueKeyStateTable[qmsg.msg.wParam & 0xff] &= ~0x80;
     }
 
     /* copy back our internal safe copy of message data to msg_out.
      * msg_out is a variable from the *program*, so it can't be used
      * internally as it can get "corrupted" by our use of SendMessage()
      * (back to the program) inside the message handling itself. */
-    *msg_out = msg;
+    *msg_out = qmsg.msg;
     if (peek)
         return TRUE;
 
     else
-        return (msg.message != WM_QUIT);
+        return (qmsg.msg.message != WM_QUIT);
 }
 
 /***********************************************************************
@@ -1408,13 +1157,16 @@
 
     SERVER_START_REQ( send_message )
     {
-        req->posted = TRUE;
+        req->kind   = POST_MESSAGE;
         req->id     = (void *)tid;
         req->type   = type;
         req->win    = hwnd;
         req->msg    = message;
         req->wparam = wParam;
         req->lparam = lParam;
+        req->x      = 0;
+        req->y      = 0;
+        req->time   = GetCurrentTime();
         req->info   = 0;
         res = SERVER_CALL();
     }
@@ -1643,6 +1395,8 @@
     WND * wndPtr = 0;
     WND **list, **ppWnd;
     LRESULT ret = 1;
+    DWORD dest_tid;
+    WNDPROC winproc;
 
     if (pRes) *pRes = 0;
 
@@ -1716,17 +1470,23 @@
     }
     if (QUEUE_IsExitingQueue(wndPtr->hmemTaskQ))
     {
-        ret = 0;  /* Don't send anything if the task is dying */
-        goto END;
+        WIN_ReleaseWndPtr( wndPtr );
+        return 0;  /* Don't send anything if the task is dying */
     }
+    winproc = (WNDPROC)wndPtr->winproc;
+    WIN_ReleaseWndPtr( wndPtr );
+
     if (type != QMSG_WIN16)
         SPY_EnterMessage( SPY_SENDMESSAGE, hwnd, msg, wParam, lParam );
     else
         SPY_EnterMessage( SPY_SENDMESSAGE16, hwnd, msg, wParam, lParam );
 
-    if (wndPtr->hmemTaskQ && wndPtr->hmemTaskQ != GetFastQueue16())
-        ret = MSG_SendMessageInterThread( wndPtr->hmemTaskQ, hwnd, msg,
+    dest_tid = GetWindowThreadProcessId( hwnd, NULL );
+    if (dest_tid && dest_tid != GetCurrentThreadId())
+    {
+        ret = MSG_SendMessageInterThread( dest_tid, hwnd, msg,
                                           wParam, lParam, timeout, type, pRes );
+    }
     else
     {
         LRESULT res = 0;
@@ -1735,13 +1495,13 @@
         switch(type)
         {
         case QMSG_WIN16:
-            res = CallWindowProc16( (WNDPROC16)wndPtr->winproc, hwnd, msg, wParam, lParam );
+            res = CallWindowProc16( (WNDPROC16)winproc, hwnd, msg, wParam, lParam );
             break;
         case QMSG_WIN32A:
-            res = CallWindowProcA( (WNDPROC)wndPtr->winproc, hwnd, msg, wParam, lParam );
+            res = CallWindowProcA( winproc, hwnd, msg, wParam, lParam );
             break;
         case QMSG_WIN32W:
-            res = CallWindowProcW( (WNDPROC)wndPtr->winproc, hwnd, msg, wParam, lParam );
+            res = CallWindowProcW( winproc, hwnd, msg, wParam, lParam );
             break;
         }
         if (pRes) *pRes = res;
@@ -1751,8 +1511,7 @@
         SPY_ExitMessage( SPY_RESULT_OK, hwnd, msg, pRes?*pRes:0, wParam, lParam );
     else
         SPY_ExitMessage( SPY_RESULT_OK16, hwnd, msg, pRes?*pRes:0, wParam, lParam );
-END:
-    WIN_ReleaseWndPtr(wndPtr);
+
     return ret;
 }
 
@@ -2471,7 +2230,7 @@
 	DWORD dwFlags,LPDWORD recipients,UINT uMessage,WPARAM wParam,
 	LPARAM lParam
 ) {
-	FIXME_(sendmsg)("(%08lx,%08lx,%08x,%08x,%08lx): stub!\n",
+	FIXME("(%08lx,%08lx,%08x,%08x,%08lx): stub!\n",
 	      dwFlags,*recipients,uMessage,wParam,lParam
 	);
 	return 0;