[WIN32K]
[reactos.git] / reactos / subsystems / win32 / win32k / ntuser / msgqueue.c
index e34d0a3..ead730c 100644 (file)
@@ -6,16 +6,10 @@
  * PROGRAMER:        Casper S. Hornstrup (chorns@users.sourceforge.net)
                      Alexandre Julliard
                      Maarten Lankhorst
- * REVISION HISTORY:
- *       06-06-2001  CSH  Created
  */
 
-/* INCLUDES ******************************************************************/
-
 #include <win32k.h>
-
-#define NDEBUG
-#include <debug.h>
+DBG_DEFAULT_CHANNEL(UserMsgQ);
 
 /* GLOBALS *******************************************************************/
 
@@ -41,6 +35,183 @@ MsqInitializeImpl(VOID)
    return(STATUS_SUCCESS);
 }
 
+PWND FASTCALL
+IntChildrenWindowFromPoint(PWND pWndTop, INT x, INT y)
+{
+    PWND pWnd, pWndChild;
+
+    if (!(pWndTop->style & WS_VISIBLE)) return NULL;
+    if ((pWndTop->style & WS_DISABLED)) return NULL;
+    if (!IntPtInWindow(pWndTop, x, y)) return NULL;
+
+    if (x - pWndTop->rcClient.left < pWndTop->rcClient.right &&
+        y - pWndTop->rcClient.top  < pWndTop->rcClient.bottom )
+    {
+       for (pWnd = pWndTop->spwndChild;
+            pWnd != NULL;
+            pWnd = pWnd->spwndNext)
+       {
+           if (pWnd->state2 & WNDS2_INDESTROY || pWnd->state & WNDS_DESTROYED )
+           {
+               TRACE("The Window is in DESTROY!\n");
+               continue;
+           }
+
+           pWndChild = IntChildrenWindowFromPoint(pWnd, x, y);
+
+           if (pWndChild)
+           {
+              return pWndChild;
+           }
+       }
+    }
+    return pWndTop;
+}
+
+PWND FASTCALL
+IntTopLevelWindowFromPoint(INT x, INT y)
+{
+    PWND pWnd, pwndDesktop;
+
+    /* Get the desktop window */
+    pwndDesktop = UserGetDesktopWindow();
+    if (!pwndDesktop)
+        return NULL;
+
+    /* Loop all top level windows */
+    for (pWnd = pwndDesktop->spwndChild;
+         pWnd != NULL;
+         pWnd = pWnd->spwndNext)
+    {
+        if (pWnd->state2 & WNDS2_INDESTROY || pWnd->state & WNDS_DESTROYED)
+        {
+            TRACE("The Window is in DESTROY!\n");
+            continue;
+        }
+
+        if ((pWnd->style & WS_VISIBLE) && IntPtInWindow(pWnd, x, y))
+            return pWnd;
+    }
+    
+    /* Window has not been found */
+    return NULL;
+}
+
+PCURICON_OBJECT
+FASTCALL
+UserSetCursor(
+    PCURICON_OBJECT NewCursor,
+    BOOL ForceChange)
+{
+    PCURICON_OBJECT OldCursor;
+    HDC hdcScreen;
+    PTHREADINFO pti;
+    PUSER_MESSAGE_QUEUE MessageQueue;
+    PWND pWnd;
+
+    pti = PsGetCurrentThreadWin32Thread();
+    MessageQueue = pti->MessageQueue;
+
+    /* Get the screen DC */
+    if(!(hdcScreen = IntGetScreenDC()))
+    {
+        return (HCURSOR)0;
+    }
+
+    OldCursor = MessageQueue->CursorObject;
+
+    /* Check if cursors are different */
+    if (OldCursor == NewCursor)
+        return OldCursor;
+
+    /* Update cursor for this message queue */
+    MessageQueue->CursorObject = NewCursor;
+
+    /* If cursor is not visible we have nothing to do */
+    if (MessageQueue->ShowingCursor < 0)
+        return OldCursor;
+
+    /* Update cursor if this message queue controls it */
+    pWnd = IntTopLevelWindowFromPoint(gpsi->ptCursor.x, gpsi->ptCursor.y);
+    if (pWnd && pWnd->head.pti->MessageQueue == MessageQueue)
+    {
+        if (NewCursor)
+        {
+            /* Call GDI to set the new screen cursor */
+            GreSetPointerShape(hdcScreen,
+                               NewCursor->IconInfo.hbmMask,
+                               NewCursor->IconInfo.hbmColor,
+                               NewCursor->IconInfo.xHotspot,
+                               NewCursor->IconInfo.yHotspot,
+                               gpsi->ptCursor.x,
+                               gpsi->ptCursor.y);
+        }
+        else /* Note: OldCursor != NewCursor so we have to hide cursor */
+        {
+            /* Remove the cursor */
+            GreMovePointer(hdcScreen, -1, -1);
+            TRACE("Removing pointer!\n");
+        }
+        IntGetSysCursorInfo()->CurrentCursorObject = NewCursor;
+    }
+
+    /* Return the old cursor */
+    return OldCursor;
+}
+
+/* Called from NtUserCallOneParam with Routine ONEPARAM_ROUTINE_SHOWCURSOR
+ * User32 macro NtUserShowCursor */
+int UserShowCursor(BOOL bShow)
+{
+    HDC hdcScreen;
+    PTHREADINFO pti;
+    PUSER_MESSAGE_QUEUE MessageQueue;
+    PWND pWnd;
+
+    if (!(hdcScreen = IntGetScreenDC()))
+    {
+        return -1; /* No mouse */
+    }
+
+    pti = PsGetCurrentThreadWin32Thread();
+    MessageQueue = pti->MessageQueue;
+    
+    /* Update counter */
+    MessageQueue->ShowingCursor += bShow ? 1 : -1;
+    
+    /* Check for trivial cases */
+    if ((bShow && MessageQueue->ShowingCursor != 0) ||
+        (!bShow && MessageQueue->ShowingCursor != -1))
+    {
+        /* Note: w don't update global info here because it is used only
+          internally to check if cursor is visible */
+        return MessageQueue->ShowingCursor;
+    }
+    
+    /* Check if cursor is above window owned by this MessageQueue */
+    pWnd = IntTopLevelWindowFromPoint(gpsi->ptCursor.x, gpsi->ptCursor.y);
+    if (pWnd && pWnd->head.pti->MessageQueue == MessageQueue)
+    {
+        if (bShow)
+        {
+            /* Show the pointer */
+            GreMovePointer(hdcScreen, gpsi->ptCursor.x, gpsi->ptCursor.y);
+            TRACE("Showing pointer!\n");
+        }
+        else
+        {
+            /* Remove the pointer */
+            GreMovePointer(hdcScreen, -1, -1);
+            TRACE("Removing pointer!\n");
+        }
+        
+        /* Update global info */
+        IntGetSysCursorInfo()->ShowingCursor = MessageQueue->ShowingCursor;
+    }
+
+    return MessageQueue->ShowingCursor;
+}
+
 DWORD FASTCALL UserGetKeyState(DWORD key)
 {
    DWORD ret = 0;
@@ -50,20 +221,25 @@ DWORD FASTCALL UserGetKeyState(DWORD key)
    pti = PsGetCurrentThreadWin32Thread();
    MessageQueue = pti->MessageQueue;
 
-   if( key < 0x100 )
+   if (key < 0x100)
    {
        ret = (DWORD)MessageQueue->KeyState[key];
        if (MessageQueue->KeyState[key] & KS_DOWN_BIT)
-          ret |= 0xFF00; // If down, windows returns 0xFF80. 
+           ret |= 0xFF80; // If down, windows returns 0xFF80.
+       if (MessageQueue->KeyState[key] & KS_LOCK_BIT)
+           ret |= 0x1;
+   }
+   else
+   {
+      EngSetLastError(ERROR_INVALID_PARAMETER);
    }
-
    return ret;
 }
 
 /* change the input key state for a given key */
 static void set_input_key_state( PUSER_MESSAGE_QUEUE MessageQueue, UCHAR key, BOOL down )
 {
-    DPRINT("set_input_key_state key:%d, down:%d\n", key, down);
+    TRACE("set_input_key_state key:%d, down:%d\n", key, down);
 
     if (down)
     {
@@ -85,7 +261,7 @@ static void update_input_key_state( PUSER_MESSAGE_QUEUE MessageQueue, MSG* msg )
     UCHAR key;
     BOOL down = 0;
 
-    DPRINT("update_input_key_state message:%d\n", msg->message);
+    TRACE("update_input_key_state message:%d\n", msg->message);
 
     switch (msg->message)
     {
@@ -167,7 +343,7 @@ IntMsqSetWakeMask(DWORD WakeMask)
       if ( (Win32Thread->pcti->fsChangeBits & LOWORD(WakeMask)) ||
            ( (dwFlags & MWMO_INPUTAVAILABLE) && (Win32Thread->pcti->fsWakeBits & LOWORD(WakeMask)) ) )
       {
-         DPRINT1("Chg 0x%x Wake 0x%x Mask 0x%x\n",Win32Thread->pcti->fsChangeBits, Win32Thread->pcti->fsWakeBits, WakeMask);
+         ERR("Chg 0x%x Wake 0x%x Mask 0x%x\n",Win32Thread->pcti->fsChangeBits, Win32Thread->pcti->fsWakeBits, WakeMask);
          KeSetEvent(MessageQueue->NewMessages, IO_NO_INCREMENT, FALSE); // Wake it up!
          return MessageEventHandle;
       }
@@ -302,13 +478,15 @@ co_MsqInsertMouseMessage(MSG* Msg, DWORD flags, ULONG_PTR dwExtraInfo, BOOL Hook
    MSLLHOOKSTRUCT MouseHookData;
    PDESKTOP pDesk;
    PWND pwnd, pwndDesktop;
+   HDC hdcScreen;
+   PSYSTEM_CURSORINFO CurInfo;
 
    KeQueryTickCount(&LargeTickCount);
    Msg->time = MsqCalculateMessageTime(&LargeTickCount);
 
    MouseHookData.pt.x = LOWORD(Msg->lParam);
    MouseHookData.pt.y = HIWORD(Msg->lParam);
-   switch(Msg->message)
+   switch (Msg->message)
    {
       case WM_MOUSEWHEEL:
          MouseHookData.mouseData = MAKELONG(0, GET_WHEEL_DELTA_WPARAM(Msg->wParam));
@@ -339,85 +517,128 @@ co_MsqInsertMouseMessage(MSG* Msg, DWORD flags, ULONG_PTR dwExtraInfo, BOOL Hook
 
    /* Get the desktop window */
    pwndDesktop = UserGetDesktopWindow();
-   if(!pwndDesktop)
-       return;
-
-   /* Set hit somewhere on the desktop */
+   if (!pwndDesktop) return;
    pDesk = pwndDesktop->head.rpdesk;
-   pDesk->htEx = HTNOWHERE;
-   pDesk->spwndTrack = pwndDesktop;
 
    /* Check if the mouse is captured */
    Msg->hwnd = IntGetCaptureWindow();
-   if(Msg->hwnd != NULL)
+   if (Msg->hwnd != NULL)
    {
        pwnd = UserGetWindowObject(Msg->hwnd);
-       if ((pwnd->style & WS_VISIBLE) &&
-            IntPtInWindow(pwnd, Msg->pt.x, Msg->pt.y))
-       {
-          pDesk->htEx = HTCLIENT;
-          pDesk->spwndTrack = pwnd;
-       }
    }
    else
    {
-       /* Loop all top level windows to find which one should receive input */
-       for( pwnd = pwndDesktop->spwndChild;
-            pwnd != NULL;
-            pwnd = pwnd->spwndNext )
-       {
-           if ( pwnd->state2 & WNDS2_INDESTROY || pwnd->state & WNDS_DESTROYED )
-           {
-              DPRINT("The Window is in DESTROY!\n");
-              continue;
-           }
+       pwnd = IntTopLevelWindowFromPoint(Msg->pt.x, Msg->pt.y);
+       if (pwnd) Msg->hwnd = pwnd->head.h;
+   }
 
-           if((pwnd->style & WS_VISIBLE) &&
-              IntPtInWindow(pwnd, Msg->pt.x, Msg->pt.y))
-           {
-               Msg->hwnd = pwnd->head.h;
-               pDesk->htEx = HTCLIENT;
-               pDesk->spwndTrack = pwnd;
-               break;
-           }
-       }
+   if (pwnd)
+   {
+      /* If we a re tracking the mouse and it moves to another top level window */
+      if(pDesk->spwndTrack && 
+         UserGetAncestor(pDesk->spwndTrack, GA_ROOT) != pwnd)
+      {
+          /* Generate a WM_MOUSELEAVE message */
+          if ( pDesk->dwDTFlags & DF_TME_LEAVE )
+          {
+              MSG msgMouseLeave;
+
+              TRACE("co_MsqInsertMouseMessage: generating WM_MOUSELEAVE\n");
+
+              msgMouseLeave.hwnd = UserHMGetHandle(pDesk->spwndTrack);
+              msgMouseLeave.message = WM_MOUSELEAVE;
+              msgMouseLeave.pt = Msg->pt;
+              msgMouseLeave.time = Msg->time;
+              msgMouseLeave.lParam = msgMouseLeave.wParam = 0;
+
+              MsqPostMessage(pwnd->head.pti->MessageQueue, Msg, TRUE, QS_MOUSE);
+          }
+
+          /* Stop tracking */
+          if ( pDesk->dwDTFlags & DF_TME_HOVER )
+          {
+              IntKillTimer(pDesk->spwndTrack, ID_EVENT_SYSTIMER_MOUSEHOVER, TRUE);
+          }
+
+          pDesk->spwndTrack = NULL;
+          pDesk->htEx = 0;
+      }
    }
 
+   hdcScreen = IntGetScreenDC();
+   CurInfo = IntGetSysCursorInfo();
+
    /* Check if we found a window */
-   if(Msg->hwnd != NULL && pwnd != NULL)
+   if (Msg->hwnd != NULL && pwnd != NULL)
    {
-       if(Msg->message == WM_MOUSEMOVE)
+       if (Msg->message == WM_MOUSEMOVE)
        {
-           /* Mouse move is a special case*/
-           MsqPostMouseMove(pwnd->head.pti->MessageQueue, Msg);
+           PUSER_MESSAGE_QUEUE MessageQueue = pwnd->head.pti->MessageQueue;
+
+           /* Check if cursor should be visible */
+           if(hdcScreen &&
+              MessageQueue->CursorObject &&
+              MessageQueue->ShowingCursor >= 0)
+           {
+               /* Check if shape has changed */
+               if(CurInfo->CurrentCursorObject != MessageQueue->CursorObject)
+               {
+                   /* Call GDI to set the new screen cursor */
+                   GreSetPointerShape(hdcScreen,
+                                      MessageQueue->CursorObject->IconInfo.hbmMask,
+                                      MessageQueue->CursorObject->IconInfo.hbmColor,
+                                      MessageQueue->CursorObject->IconInfo.xHotspot,
+                                      MessageQueue->CursorObject->IconInfo.yHotspot,
+                                      gpsi->ptCursor.x,
+                                      gpsi->ptCursor.y);
+               } else
+                   GreMovePointer(hdcScreen, Msg->pt.x, Msg->pt.y);
+           }
+           /* Check if w have to hide cursor */
+           else if (CurInfo->ShowingCursor >= 0)
+               GreMovePointer(hdcScreen, -1, -1);
+
+           /* Update global cursor info */
+           CurInfo->ShowingCursor = MessageQueue->ShowingCursor;
+           CurInfo->CurrentCursorObject = MessageQueue->CursorObject;
+
+           /* Mouse move is a special case */
+           MsqPostMouseMove(MessageQueue, Msg);
        }
        else
        {
-           DPRINT("Posting mouse message to hwnd=0x%x!\n", UserHMGetHandle(pwnd));
+           TRACE("Posting mouse message to hwnd=0x%x!\n", UserHMGetHandle(pwnd));
            MsqPostMessage(pwnd->head.pti->MessageQueue, Msg, TRUE, QS_MOUSEBUTTON);
        }
    }
+   else if (hdcScreen)
+   {
+       /* always show cursor on background; FIXME: set default pointer */
+       GreMovePointer(hdcScreen, Msg->pt.x, Msg->pt.y);
+       CurInfo->ShowingCursor = 0;
+   }
 
    /* Do GetMouseMovePointsEx FIFO. */
    MouseHistoryOfMoves[gcur_count].x = Msg->pt.x;
    MouseHistoryOfMoves[gcur_count].y = Msg->pt.y;
    MouseHistoryOfMoves[gcur_count].time = Msg->time;
    MouseHistoryOfMoves[gcur_count].dwExtraInfo = dwExtraInfo;
-   if (gcur_count++ == 64) gcur_count = 0; // 0 - 63 is 64, FIFO forwards.
+   if (++gcur_count == ARRAYSIZE(MouseHistoryOfMoves))
+      gcur_count = 0; // 0 - 63 is 64, FIFO forwards.
 }
 
 //
 // Note: Only called from input.c.
 //
 VOID FASTCALL
-co_MsqPostKeyboardMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
+co_MsqPostKeyboardMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL bInjected)
 {
    PUSER_MESSAGE_QUEUE FocusMessageQueue;
    MSG Msg;
    LARGE_INTEGER LargeTickCount;
    KBDLLHOOKSTRUCT KbdHookData;
 
-   DPRINT("MsqPostKeyboardMessage(uMsg 0x%x, wParam 0x%x, lParam 0x%x)\n",
+   TRACE("MsqPostKeyboardMessage(uMsg 0x%x, wParam 0x%x, lParam 0x%x)\n",
           uMsg, wParam, lParam);
 
    // Condition may arise when calling MsqPostMessage and waiting for an event.
@@ -442,28 +663,34 @@ co_MsqPostKeyboardMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
 
    KbdHookData.vkCode = Msg.wParam;
    KbdHookData.scanCode = (Msg.lParam >> 16) & 0xff;
-   KbdHookData.flags = (0 == (Msg.lParam & 0x01000000) ? 0 : LLKHF_EXTENDED) |
-                       (0 == (Msg.lParam & 0x20000000) ? 0 : LLKHF_ALTDOWN) |
-                       (0 == (Msg.lParam & 0x80000000) ? 0 : LLKHF_UP);
+   KbdHookData.flags = 0;
+   if (Msg.lParam & 0x01000000)
+      KbdHookData.flags |= LLKHF_EXTENDED;
+   if (Msg.lParam & 0x20000000)
+      KbdHookData.flags |= LLKHF_ALTDOWN;
+   if (Msg.lParam & 0x80000000)
+      KbdHookData.flags |= LLKHF_UP;
+   if (bInjected)
+      KbdHookData.flags |= LLKHF_INJECTED;
    KbdHookData.time = Msg.time;
    KbdHookData.dwExtraInfo = 0;
    if (co_HOOK_CallHooks(WH_KEYBOARD_LL, HC_ACTION, Msg.message, (LPARAM) &KbdHookData))
    {
-      DPRINT1("Kbd msg %d wParam %d lParam 0x%08x dropped by WH_KEYBOARD_LL hook\n",
+      ERR("Kbd msg %d wParam %d lParam 0x%08x dropped by WH_KEYBOARD_LL hook\n",
              Msg.message, Msg.wParam, Msg.lParam);
       return;
    }
 
    if (FocusMessageQueue == NULL)
    {
-         DPRINT("No focus message queue\n");
+         TRACE("No focus message queue\n");
          return;
    }
 
    if (FocusMessageQueue->FocusWindow != (HWND)0)
    {
          Msg.hwnd = FocusMessageQueue->FocusWindow;
-         DPRINT("Msg.hwnd = %x\n", Msg.hwnd);
+         TRACE("Msg.hwnd = %x\n", Msg.hwnd);
 
          FocusMessageQueue->Desktop->pDeskInfo->LastInputWasKbd = TRUE;
 
@@ -472,7 +699,7 @@ co_MsqPostKeyboardMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
    }
    else
    {
-         DPRINT("Invalid focus window handle\n");
+         TRACE("Invalid focus window handle\n");
    }
 
    return;
@@ -598,6 +825,12 @@ co_MsqDispatchOneSentMessage(PUSER_MESSAGE_QUEUE MessageQueue)
                                     Message->Msg.wParam,
                                     Message->Msg.lParam);
    }
+   else if(Message->HookMessage == MSQ_INJECTMODULE)
+   {
+       Result = IntLoadHookModule(Message->Msg.message,
+                                  (HHOOK)Message->Msg.lParam,
+                                  Message->Msg.wParam);
+   }
    else if ((Message->CompletionCallback)
        && (Message->CallBackSenderQueue == MessageQueue))
    {   /* Call the callback routine */
@@ -616,7 +849,7 @@ co_MsqDispatchOneSentMessage(PUSER_MESSAGE_QUEUE MessageQueue)
          /* The message has not been processed yet, reinsert it. */
          RemoveEntryList(&Message->ListEntry);
          InsertTailList(&Message->CallBackSenderQueue->SentMessagesListHead, &Message->ListEntry);
-         DPRINT("Callback Message not processed yet. Requeuing the message\n");
+         TRACE("Callback Message not processed yet. Requeuing the message\n");
          return (FALSE);
       }
    }
@@ -744,7 +977,7 @@ MsqRemoveWindowMessagesFromQueue(PVOID pWindow)
                                       ListEntry);
       if(SentMessage->Msg.hwnd == Window->head.h)
       {
-         DPRINT("Notify the sender and remove a message from the queue that had not been dispatched\n");
+         TRACE("Notify the sender and remove a message from the queue that had not been dispatched\n");
 
          RemoveEntryList(&SentMessage->ListEntry);
          ClearMsgBitsMask(MessageQueue, SentMessage->QS_Flags);
@@ -793,6 +1026,58 @@ MsqRemoveWindowMessagesFromQueue(PVOID pWindow)
    }
 }
 
+BOOL FASTCALL
+co_MsqSendMessageAsync(PTHREADINFO ptiReceiver,
+                       HWND hwnd,
+                       UINT Msg,
+                       WPARAM wParam,
+                       LPARAM lParam,
+                       SENDASYNCPROC CompletionCallback,
+                       ULONG_PTR CompletionCallbackContext,
+                       BOOL HasPackedLParam,
+                       INT HookMessage)
+{
+
+    PTHREADINFO ptiSender;
+    PUSER_SENT_MESSAGE Message;
+
+    if(!(Message = ExAllocatePoolWithTag(NonPagedPool, sizeof(USER_SENT_MESSAGE), TAG_USRMSG)))
+    {
+        ERR("MsqSendMessage(): Not enough memory to allocate a message");
+        return FALSE;
+    }
+
+    ptiSender = PsGetCurrentThreadWin32Thread();
+
+    IntReferenceMessageQueue(ptiReceiver->MessageQueue);
+    /* Take reference on this MessageQueue if its a callback. It will be released
+       when message is processed or removed from target hwnd MessageQueue */
+    if (CompletionCallback)
+       IntReferenceMessageQueue(ptiSender->MessageQueue);
+
+    Message->Msg.hwnd = hwnd;
+    Message->Msg.message = Msg;
+    Message->Msg.wParam = wParam;
+    Message->Msg.lParam = lParam;
+    Message->CompletionEvent = NULL;
+    Message->Result = 0;
+    Message->lResult = 0;
+    Message->SenderQueue = NULL;
+    Message->CallBackSenderQueue = ptiSender->MessageQueue;
+    Message->DispatchingListEntry.Flink = NULL;
+    Message->CompletionCallback = CompletionCallback;
+    Message->CompletionCallbackContext = CompletionCallbackContext;
+    Message->HookMessage = HookMessage;
+    Message->HasPackedLParam = HasPackedLParam;
+    Message->QS_Flags = QS_SENDMESSAGE;
+
+    InsertTailList(&ptiReceiver->MessageQueue->SentMessagesListHead, &Message->ListEntry);
+    MsqWakeQueue(ptiReceiver->MessageQueue, QS_SENDMESSAGE, TRUE);
+    IntDereferenceMessageQueue(ptiReceiver->MessageQueue);
+
+    return TRUE;
+}
+
 NTSTATUS FASTCALL
 co_MsqSendMessage(PUSER_MESSAGE_QUEUE MessageQueue,
                   HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam,
@@ -810,7 +1095,7 @@ co_MsqSendMessage(PUSER_MESSAGE_QUEUE MessageQueue,
 
    if(!(Message = ExAllocatePoolWithTag(PagedPool, sizeof(USER_SENT_MESSAGE), TAG_USRMSG)))
    {
-      DPRINT1("MsqSendMessage(): Not enough memory to allocate a message");
+      ERR("MsqSendMessage(): Not enough memory to allocate a message");
       return STATUS_INSUFFICIENT_RESOURCES;
    }
 
@@ -912,7 +1197,7 @@ co_MsqSendMessage(PUSER_MESSAGE_QUEUE MessageQueue,
             Entry = Entry->Flink;
          }
 
-         DPRINT("MsqSendMessage (blocked) timed out 1\n");
+         TRACE("MsqSendMessage (blocked) timed out 1\n");
       }
       while (co_MsqDispatchOneSentMessage(ThreadQueue))
          ;
@@ -972,7 +1257,7 @@ co_MsqSendMessage(PUSER_MESSAGE_QUEUE MessageQueue,
                Entry = Entry->Flink;
             }
 
-            DPRINT("MsqSendMessage timed out 2\n");
+            TRACE("MsqSendMessage timed out 2\n");
             break;
          }
          while (co_MsqDispatchOneSentMessage(ThreadQueue))
@@ -1068,6 +1353,7 @@ BOOL co_IntProcessMouseMessage(MSG* msg, BOOL* RemoveMessages, UINT first, UINT
     PUSER_MESSAGE_QUEUE MessageQueue;
     PTHREADINFO pti;
     PSYSTEM_CURSORINFO CurInfo;
+    PDESKTOP pDesk;
     DECLARE_RETURN(BOOL);
 
     pti = PsGetCurrentThreadWin32Thread();
@@ -1076,6 +1362,7 @@ BOOL co_IntProcessMouseMessage(MSG* msg, BOOL* RemoveMessages, UINT first, UINT
     CurInfo = IntGetSysCursorInfo();
     pwndMsg = UserGetWindowObject(msg->hwnd);
     clk_msg = MessageQueue->msgDblClk;
+    pDesk = pwndDesktop->head.rpdesk;
 
     /* find the window to dispatch this mouse message to */
     if (MessageQueue->CaptureWindow)
@@ -1088,7 +1375,7 @@ BOOL co_IntProcessMouseMessage(MSG* msg, BOOL* RemoveMessages, UINT first, UINT
         pwndMsg = co_WinPosWindowFromPoint(pwndMsg, &msg->pt, &hittest);
     }
 
-    DPRINT("Got mouse message for 0x%x, hittest: 0x%x\n", msg->hwnd, hittest );
+    TRACE("Got mouse message for 0x%x, hittest: 0x%x\n", msg->hwnd, hittest );
 
     if (pwndMsg == NULL || pwndMsg->head.pti != pti)
     {
@@ -1097,6 +1384,45 @@ BOOL co_IntProcessMouseMessage(MSG* msg, BOOL* RemoveMessages, UINT first, UINT
         RETURN(FALSE);
     }
 
+    /* If we a re tracking the mouse and it moves to another window */
+    if(pDesk->spwndTrack && 
+       pDesk->spwndTrack != pwndMsg &&
+       msg->message != WM_MOUSELEAVE)
+    {
+        /* Generate a WM_MOUSELEAVE message */
+        if ( pDesk->dwDTFlags & DF_TME_LEAVE )
+        {
+            MSG msgMouseLeave;
+
+            TRACE("co_IntProcessMouseMessage: generating WM_MOUSELEAVE\n");
+
+            msgMouseLeave.hwnd = UserHMGetHandle(pDesk->spwndTrack);
+            msgMouseLeave.message = WM_MOUSELEAVE;
+            msgMouseLeave.pt = msg->pt;
+            msgMouseLeave.time = msg->time;
+            msgMouseLeave.lParam = msgMouseLeave.wParam = 0;
+
+            MsqPostMessage(pwndMsg->head.pti->MessageQueue, 
+                           &msgMouseLeave, 
+                           TRUE, 
+                           QS_MOUSE);
+        }
+
+        /* Stop tracking */
+        if ( pDesk->dwDTFlags & DF_TME_HOVER )
+        {
+            IntKillTimer(pDesk->spwndTrack, ID_EVENT_SYSTIMER_MOUSEHOVER, TRUE);
+        }
+
+        pDesk->spwndTrack = NULL;
+        pDesk->htEx = 0;
+    }
+
+    if(pDesk->spwndTrack)
+    {
+        pDesk->htEx = hittest;
+    }
+
     msg->hwnd = UserHMGetHandle(pwndMsg);
 
 #if 0
@@ -1161,7 +1487,7 @@ BOOL co_IntProcessMouseMessage(MSG* msg, BOOL* RemoveMessages, UINT first, UINT
 
         if (!((first ==  0 && last == 0) || (message >= first || message <= last)))
         {
-            DPRINT("Message out of range!!!\n");
+            TRACE("Message out of range!!!\n");
             RETURN(FALSE);
         }
 
@@ -1172,7 +1498,7 @@ BOOL co_IntProcessMouseMessage(MSG* msg, BOOL* RemoveMessages, UINT first, UINT
     {
         if (!((first ==  0 && last == 0) || (message >= first || message <= last)))
         {
-            DPRINT("Message out of range!!!\n");
+            TRACE("Message out of range!!!\n");
             RETURN(FALSE);
         }
     }
@@ -1230,7 +1556,7 @@ BOOL co_IntProcessMouseMessage(MSG* msg, BOOL* RemoveMessages, UINT first, UINT
         hook.dwExtraInfo  = 0/*extra_info*/;
         co_HOOK_CallHooks( WH_CBT, HCBT_CLICKSKIPPED, message, (LPARAM)&hook );
 
-        DPRINT1("WH_MOUSE dorpped mouse message!\n");
+        ERR("WH_MOUSE dorpped mouse message!\n");
 
         /* Remove and skip message */
         *RemoveMessages = TRUE;
@@ -1299,7 +1625,7 @@ BOOL co_IntProcessMouseMessage(MSG* msg, BOOL* RemoveMessages, UINT first, UINT
                     if(!co_IntMouseActivateWindow(pwndMsg)) eatMsg = TRUE;
                     break;
                 default:
-                    DPRINT1( "unknown WM_MOUSEACTIVATE code %d\n", ret );
+                    ERR( "unknown WM_MOUSEACTIVATE code %d\n", ret );
                     break;
                 }
             }
@@ -1340,10 +1666,6 @@ BOOL co_IntProcessKeyboardMessage(MSG* Msg, BOOL* RemoveMessages)
             case VK_LMENU: case VK_RMENU:
                 Msg->wParam = VK_MENU;
                 break;
-            case VK_F10:
-                if (Msg->message == WM_KEYUP) Msg->message = WM_SYSKEYUP;
-                if (Msg->message == WM_KEYDOWN) Msg->message = WM_SYSKEYDOWN;
-                break;
         }
     }
 
@@ -1365,7 +1687,7 @@ BOOL co_IntProcessKeyboardMessage(MSG* Msg, BOOL* RemoveMessages)
                            HCBT_KEYSKIPPED,
                            LOWORD(Msg->wParam),
                            Msg->lParam );
-        DPRINT1("KeyboardMessage WH_CBT Call Hook return!\n");
+        ERR("KeyboardMessage WH_CBT Call Hook return!\n");
         return FALSE;
     }
     return TRUE;
@@ -1461,9 +1783,17 @@ co_MsqPeekHardwareMessage(IN PUSER_MESSAGE_QUEUE MessageQueue,
         if (IsListEmpty(CurrentEntry)) break;
         if (!CurrentMessage) break;
         CurrentEntry = CurrentMessage->ListEntry.Flink;
-
-        if ( (( MsgFilterLow == 0 && MsgFilterHigh == 0 ) && (CurrentMessage->QS_Flags & QSflags)) ||
-             ( MsgFilterLow <= CurrentMessage->Msg.message && MsgFilterHigh >= CurrentMessage->Msg.message ) )
+/*
+ MSDN:
+ 1: any window that belongs to the current thread, and any messages on the current thread's message queue whose hwnd value is NULL.
+ 2: retrieves only messages on the current thread's message queue whose hwnd value is NULL.
+ 3: handle to the window whose messages are to be retrieved.
+ */
+      if ( ( !Window || // 1
+            ( Window == HWND_BOTTOM && CurrentMessage->Msg.hwnd == NULL ) || // 2
+            ( Window != HWND_BOTTOM && Window->head.h == CurrentMessage->Msg.hwnd ) ) && // 3
+            ( ( ( MsgFilterLow == 0 && MsgFilterHigh == 0 ) && CurrentMessage->QS_Flags & QSflags ) ||
+              ( MsgFilterLow <= CurrentMessage->Msg.message && MsgFilterHigh >= CurrentMessage->Msg.message ) ) )
         {
            msg = CurrentMessage->Msg;
 
@@ -1574,8 +1904,8 @@ VOID
 CALLBACK
 HungAppSysTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
 {
-   //DoTheScreenSaver();
-   DPRINT("HungAppSysTimerProc\n");
+   DoTheScreenSaver();
+   TRACE("HungAppSysTimerProc\n");
    // Process list of windows that are hung and waiting.
 }
 
@@ -1592,13 +1922,15 @@ MsqInitializeMessageQueue(struct _ETHREAD *Thread, PUSER_MESSAGE_QUEUE MessageQu
    InitializeListHead(&MessageQueue->HardwareMessagesListHead);
    InitializeListHead(&MessageQueue->DispatchingMessagesHead);
    InitializeListHead(&MessageQueue->LocalDispatchingMessagesHead);
-   KeInitializeMutex(&MessageQueue->HardwareLock, 0);
    MessageQueue->QuitPosted = FALSE;
    MessageQueue->QuitExitCode = 0;
    KeQueryTickCount(&LargeTickCount);
    MessageQueue->LastMsgRead = LargeTickCount.u.LowPart;
    MessageQueue->FocusWindow = NULL;
    MessageQueue->NewMessagesHandle = NULL;
+   MessageQueue->ShowingCursor = 0;
+   MessageQueue->CursorObject = NULL;
+   RtlCopyMemory(MessageQueue->KeyState, gafAsyncKeyState, sizeof(gafAsyncKeyState));
 
    Status = ZwCreateEvent(&MessageQueue->NewMessagesHandle, EVENT_ALL_ACCESS,
                           NULL, SynchronizationEvent, FALSE);
@@ -1653,7 +1985,7 @@ MsqCleanupMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue)
          IntDereferenceMessageQueue(CurrentSentMessage->CallBackSenderQueue);
       }
 
-      DPRINT("Notify the sender and remove a message from the queue that had not been dispatched\n");
+      TRACE("Notify the sender and remove a message from the queue that had not been dispatched\n");
       /* Only if the message has a sender was the message in the DispatchingList */
       if ((CurrentSentMessage->SenderQueue)
          && (CurrentSentMessage->DispatchingListEntry.Flink != NULL))
@@ -1705,7 +2037,7 @@ MsqCleanupMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue)
          RemoveEntryList(&CurrentSentMessage->DispatchingListEntry);
       }
 
-      DPRINT("Notify the sender, the thread has been terminated while dispatching a message!\n");
+      TRACE("Notify the sender, the thread has been terminated while dispatching a message!\n");
 
       /* wake the sender's thread */
       if (CurrentSentMessage->CompletionEvent != NULL)
@@ -1745,8 +2077,11 @@ MsqCleanupMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue)
    }
 
    // Clear it all out.
-   pti->pcti->fsWakeBits = 0;
-   pti->pcti->fsChangeBits = 0;
+   if(pti->pcti)
+   {
+       pti->pcti->fsWakeBits = 0;
+       pti->pcti->fsChangeBits = 0;
+   }
 
    MessageQueue->nCntsQBits[QSRosKey] = 0;
    MessageQueue->nCntsQBits[QSRosMouseMove] = 0;
@@ -1754,6 +2089,28 @@ MsqCleanupMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue)
    MessageQueue->nCntsQBits[QSRosPostMessage] = 0;
    MessageQueue->nCntsQBits[QSRosSendMessage] = 0;
    MessageQueue->nCntsQBits[QSRosHotKey] = 0;
+   
+   if (MessageQueue->CursorObject)
+   {
+       PCURICON_OBJECT pCursor = MessageQueue->CursorObject;
+
+       /* Change to another cursor if we going to dereference current one
+          Note: we can't use UserSetCursor because it uses current thread
+                message queue instead of queue given for cleanup */
+       if (IntGetSysCursorInfo()->CurrentCursorObject == pCursor)
+       {
+           HDC hdcScreen;
+
+           /* Get the screen DC */
+           hdcScreen = IntGetScreenDC();
+           if (hdcScreen)
+               GreMovePointer(hdcScreen, -1, -1);
+           IntGetSysCursorInfo()->CurrentCursorObject = NULL;
+       }
+
+       UserDereferenceObject(pCursor);
+   }
+      
 }
 
 PUSER_MESSAGE_QUEUE FASTCALL
@@ -1980,5 +2337,4 @@ NtUserSetKeyboardState(LPBYTE lpKeyState)
    return ret;
 }
 
-
 /* EOF */