This patch removes the cursor location from the window station object and always uses it in the GDIDEVICE. Patch by tinus. Fixes bug #484
Modified: trunk/reactos/include/win32k/dc.h
Modified: trunk/reactos/subsys/win32k/eng/mouse.c
Modified: trunk/reactos/subsys/win32k/include/cursoricon.h
Modified: trunk/reactos/subsys/win32k/ntuser/cursoricon.c
Modified: trunk/reactos/subsys/win32k/ntuser/input.c
Modified: trunk/reactos/subsys/win32k/ntuser/message.c
Modified: trunk/reactos/subsys/win32k/ntuser/misc.c
Modified: trunk/reactos/subsys/win32k/ntuser/winsta.c

Modified: trunk/reactos/include/win32k/dc.h
--- trunk/reactos/include/win32k/dc.h	2005-01-27 00:33:11 UTC (rev 13332)
+++ trunk/reactos/include/win32k/dc.h	2005-01-27 00:49:24 UTC (rev 13333)
@@ -124,9 +124,6 @@
   RECTL Exclude; /* required publicly for SPS_ACCEPT_EXCLUDE */
   PGD_MOVEPOINTER MovePointer;
   ULONG Status;
-  UINT SafetyRemoveLevel; /* at what level was the cursor removed?
-			     0 for not removed */
-  UINT SafetyRemoveCount;
 } GDIPOINTER, *PGDIPOINTER;
 
 typedef struct
@@ -141,6 +138,11 @@
   PFILE_OBJECT VideoFileObject;
 
   GDIPOINTER Pointer;
+
+  /* Stuff to keep track of software cursors; win32k gdi part */
+  UINT SafetyRemoveLevel; /* at what level was the cursor removed?
+			     0 for not removed */
+  UINT SafetyRemoveCount;
 } GDIDEVICE;
 
 /*  Internal functions  */

Modified: trunk/reactos/subsys/win32k/eng/mouse.c
--- trunk/reactos/subsys/win32k/eng/mouse.c	2005-01-27 00:33:11 UTC (rev 13332)
+++ trunk/reactos/subsys/win32k/eng/mouse.c	2005-01-27 00:49:24 UTC (rev 13333)
@@ -68,9 +68,9 @@
       tmp = HazardY2; HazardY2 = HazardY1; HazardY1 = tmp;
     }
 
-  pgp->SafetyRemoveCount++;
+  ppdev->SafetyRemoveCount++;
 
-  if (pgp->SafetyRemoveLevel)
+  if (ppdev->SafetyRemoveLevel)
     {
       /* already hidden */
       return FALSE;
@@ -81,7 +81,7 @@
       && pgp->Exclude.bottom >= HazardY1
       && pgp->Exclude.top <= HazardY2)
     {
-      pgp->SafetyRemoveLevel = pgp->SafetyRemoveCount;
+      ppdev->SafetyRemoveLevel = ppdev->SafetyRemoveCount;
       if (pgp->MovePointer)
         pgp->MovePointer(SurfObj, -1, -1, NULL);
       else
@@ -100,6 +100,8 @@
   GDIDEVICE *ppdev;
   GDIPOINTER *pgp;
 
+  ASSERT(WinSta);
+
   ASSERT(SurfObj != NULL);
 
   ppdev = GDIDEV(SurfObj);
@@ -117,22 +119,16 @@
     return FALSE;
   }
 
-  if (--pgp->SafetyRemoveCount >= pgp->SafetyRemoveLevel)
+  if (--ppdev->SafetyRemoveCount >= ppdev->SafetyRemoveLevel)
    {
       return FALSE;
    }
-   /* FIXME - this is wrong!!!!!! we must NOT access pgp->Pos from here, it's
-	      a private field for ENG/driver. This will paint the cursor to the
-	      wrong screen coordinates when a driver overrides DrvMovePointer()!
-	      We should store the coordinates before calling Drv/EngMovePointer()
-	      and Drv/EngSetPointerShape() separately in the GDIDEVICE structure
-	      or somewhere where ntuser can access it! */
   if (pgp->MovePointer)
     pgp->MovePointer(SurfObj, pgp->Pos.x, pgp->Pos.y, &pgp->Exclude);
   else
     EngMovePointer(SurfObj, pgp->Pos.x, pgp->Pos.y, &pgp->Exclude);
 
-  pgp->SafetyRemoveLevel = 0;
+  ppdev->SafetyRemoveLevel = 0;
 
   return(TRUE);
 }
@@ -368,6 +364,8 @@
    pgp->HotSpot.x = xHot;
    pgp->HotSpot.y = yHot;
 
+   /* Actually this should be set by 'the other side', but it would be
+    * done right after this. It helps IntShowMousePointer. */
    if (x != -1)
    {
      pgp->Pos.x = x;
@@ -472,14 +470,13 @@
      
      if (prcl != NULL)
      {
-       prcl->left = pgp->Pos.x - pgp->HotSpot.x;
-       prcl->top = pgp->Pos.y - pgp->HotSpot.x;
+       prcl->left = x - pgp->HotSpot.x;
+       prcl->top = y - pgp->HotSpot.x;
        prcl->right = prcl->left + pgp->Size.cx;
        prcl->bottom = prcl->top + pgp->Size.cy;
      }
-   }
-   
-   /* FIXME - touch prcl when x == -1? */
+   } else if (prcl != NULL)
+     prcl->left = prcl->top = prcl->right = prcl->bottom = -1;
 
    return SPS_ACCEPT_EXCLUDE;
 }
@@ -509,19 +506,21 @@
    IntHideMousePointer(ppdev, pso);
    if (x != -1)
    {
+     /* Actually this should be set by 'the other side', but it would be
+      * done right after this. It helps IntShowMousePointer. */
      pgp->Pos.x = x;
      pgp->Pos.y = y;
      IntShowMousePointer(ppdev, pso);
      if (prcl != NULL)
      {
-       prcl->left = pgp->Pos.x - pgp->HotSpot.x;
-       prcl->top = pgp->Pos.y - pgp->HotSpot.x;
+       prcl->left = x - pgp->HotSpot.x;
+       prcl->top = y - pgp->HotSpot.x;
        prcl->right = prcl->left + pgp->Size.cx;
        prcl->bottom = prcl->top + pgp->Size.cy;
      }
-   }
+   } else if (prcl != NULL)
+     prcl->left = prcl->top = prcl->right = prcl->bottom = -1;
    
-   /* FIXME - touch prcl when x == -1? */
 }
 
 /* EOF */

Modified: trunk/reactos/subsys/win32k/include/cursoricon.h
--- trunk/reactos/subsys/win32k/include/cursoricon.h	2005-01-27 00:33:11 UTC (rev 13332)
+++ trunk/reactos/subsys/win32k/include/cursoricon.h	2005-01-27 00:49:24 UTC (rev 13333)
@@ -37,7 +37,6 @@
   BOOL Enabled;
   BOOL SwapButtons;
   UINT ButtonsDown;
-  LONG x, y;
   FAST_MUTEX CursorMutex;
   CURSORCLIP_INFO CursorClipInfo;
   PCURICON_OBJECT CurrentCursorObject;
@@ -57,6 +56,8 @@
 PCURICON_OBJECT FASTCALL IntCreateCurIconHandle(PWINSTATION_OBJECT WinStaObject);
 VOID FASTCALL IntCleanupCurIcons(struct _EPROCESS *Process, PW32PROCESS Win32Process);
 
+BOOL FASTCALL IntGetCursorLocation(PWINSTATION_OBJECT WinStaObject, POINT *loc);
+
 #define IntGetSysCursorInfo(WinStaObj) \
   (PSYSTEM_CURSORINFO)((WinStaObj)->SystemCursor)
 

Modified: trunk/reactos/subsys/win32k/ntuser/cursoricon.c
--- trunk/reactos/subsys/win32k/ntuser/cursoricon.c	2005-01-27 00:33:11 UTC (rev 13332)
+++ trunk/reactos/subsys/win32k/ntuser/cursoricon.c	2005-01-27 00:49:24 UTC (rev 13333)
@@ -42,6 +42,40 @@
 static LIST_ENTRY CurIconList;
 static FAST_MUTEX CurIconListLock;
 
+/* Look up the location of the cursor in the GDIDEVICE structure
+ * when all we know is the window station object
+ * Actually doesn't use the window station, but should... */
+BOOL FASTCALL
+IntGetCursorLocation(PWINSTATION_OBJECT WinStaObject, POINT *loc)
+{
+  HDC hDC;
+  PDC dc;
+  HBITMAP hBitmap;
+  BITMAPOBJ *BitmapObj;
+  SURFOBJ *SurfObj;
+
+#if 1
+  /* FIXME - get the screen dc from the window station or desktop */
+  if (!(hDC = IntGetScreenDC())) 
+    return FALSE;
+#endif
+
+  if (!(dc = DC_LockDc(hDC)))
+    return FALSE;
+    
+  hBitmap = dc->w.hBitmap;
+  DC_UnlockDc(hDC);                                                                                 
+  if (!(BitmapObj = BITMAPOBJ_LockBitmap(hBitmap)))
+    return FALSE;
+
+  SurfObj = &BitmapObj->SurfObj;
+  loc->x = GDIDEV(SurfObj)->Pointer.Pos.x;
+  loc->y = GDIDEV(SurfObj)->Pointer.Pos.y;
+
+  BITMAPOBJ_UnlockBitmap(hBitmap);
+  return TRUE;
+}
+
 PCURICON_OBJECT FASTCALL
 IntGetCurIconObject(PWINSTATION_OBJECT WinStaObject, HANDLE Handle)
 {
@@ -116,10 +150,9 @@
       {
          /* Remove the cursor if it was displayed */
          if (GDIDEV(SurfObj)->Pointer.MovePointer)
-           GDIDEV(SurfObj)->Pointer.MovePointer(SurfObj, -1, -1, NULL);
+           GDIDEV(SurfObj)->Pointer.MovePointer(SurfObj, -1, -1, &GDIDEV(SurfObj)->Pointer.Exclude);
          else
-           EngMovePointer(SurfObj, -1, -1, NULL);
-         GDIDEV(SurfObj)->Pointer.Exclude.right = -1;
+           EngMovePointer(SurfObj, -1, -1, &GDIDEV(SurfObj)->Pointer.Exclude);
       }
 
       GDIDEV(SurfObj)->Pointer.Status = SPS_ACCEPT_NOEXCLUDE;
@@ -218,8 +251,8 @@
                                                         SurfObj, soMask, soColor, XlateObj,
                                                         NewCursor->IconInfo.xHotspot,
                                                         NewCursor->IconInfo.yHotspot,
-                                                        CurInfo->x, 
-                                                        CurInfo->y, 
+                                                        GDIDEV(SurfObj)->Pointer.Pos.x,
+                                                        GDIDEV(SurfObj)->Pointer.Pos.y,
                                                         &(GDIDEV(SurfObj)->Pointer.Exclude),
                                                         SPS_CHANGE);
       DPRINT("SetCursor: DrvSetPointerShape() returned %x\n",
@@ -236,8 +269,8 @@
                          SurfObj, soMask, soColor, XlateObj,
                          NewCursor->IconInfo.xHotspot,
                          NewCursor->IconInfo.yHotspot,
-                         CurInfo->x, 
-                         CurInfo->y, 
+                         GDIDEV(SurfObj)->Pointer.Pos.x, 
+                         GDIDEV(SurfObj)->Pointer.Pos.y, 
                          &(GDIDEV(SurfObj)->Pointer.Exclude),
                          SPS_CHANGE);
       GDIDEV(SurfObj)->Pointer.MovePointer = EngMovePointer;
@@ -760,6 +793,16 @@
   PWINSTATION_OBJECT WinStaObject;
   NTSTATUS Status;
   PCURICON_OBJECT CursorObject;
+
+#if 1
+  HDC hDC;
+
+  /* FIXME - get the screen dc from the window station or desktop */
+  if (!(hDC = IntGetScreenDC()))
+  {
+    return FALSE;
+  }
+#endif
   
   Status = MmCopyFromCaller(&SafeCi.cbSize, pci, sizeof(DWORD));
   if(!NT_SUCCESS(Status))
@@ -785,9 +828,9 @@
   
   SafeCi.flags = ((CurInfo->ShowingCursor && CursorObject) ? CURSOR_SHOWING : 0);
   SafeCi.hCursor = (CursorObject ? (HCURSOR)CursorObject->Self : (HCURSOR)0);
-  SafeCi.ptScreenPos.x = CurInfo->x;
-  SafeCi.ptScreenPos.y = CurInfo->y;
-  
+
+  IntGetCursorLocation(WinStaObject, &SafeCi.ptScreenPos);
+
   Status = MmCopyToCaller(pci, &SafeCi, sizeof(CURSORINFO));
   if(!NT_SUCCESS(Status))
   {
@@ -815,6 +858,7 @@
   PSYSTEM_CURSORINFO CurInfo;
   RECT Rect;
   PWINDOW_OBJECT DesktopWindow = NULL;
+  POINT MousePos;
 
   WinStaObject = IntGetWinStaObj();
   if (WinStaObject == NULL)
@@ -830,6 +874,8 @@
   }
   
   CurInfo = IntGetSysCursorInfo(WinStaObject);
+  IntGetCursorLocation(WinStaObject, &MousePos);
+
   if(WinStaObject->ActiveDesktop)
     DesktopWindow = IntGetWindowObject(WinStaObject->ActiveDesktop->DesktopWindow);
   
@@ -845,8 +891,8 @@
     CurInfo->CursorClipInfo.Bottom = min(Rect.bottom - 1, DesktopWindow->WindowRect.bottom - 1);
     IntReleaseWindowObject(DesktopWindow);
     
-    mi.dx = CurInfo->x;
-    mi.dy = CurInfo->y;
+    mi.dx = MousePos.x;
+    mi.dy = MousePos.y;
     mi.mouseData = 0;
     mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE;
     mi.time = 0;

Modified: trunk/reactos/subsys/win32k/ntuser/input.c
--- trunk/reactos/subsys/win32k/ntuser/input.c	2005-01-27 00:33:11 UTC (rev 13332)
+++ trunk/reactos/subsys/win32k/ntuser/input.c	2005-01-27 00:49:24 UTC (rev 13333)
@@ -540,7 +540,7 @@
   const UINT SwapBtnMsg[2][2] = {{WM_LBUTTONDOWN, WM_RBUTTONDOWN},
                                  {WM_LBUTTONUP, WM_RBUTTONUP}};
   const WPARAM SwapBtn[2] = {MK_LBUTTON, MK_RBUTTON};
-  POINT MousePos;
+  POINT MousePos, OrgPos;
   PSYSTEM_CURSORINFO CurInfo;
   PWINSTATION_OBJECT WinSta;
   BOOL DoMove, SwapButtons;
@@ -586,8 +586,10 @@
   DoMove = FALSE;
 
   ExAcquireFastMutex(&CurInfo->CursorMutex);
-  MousePos.x = CurInfo->x;
-  MousePos.y = CurInfo->y;
+  IntGetCursorLocation(WinSta, &MousePos);
+  OrgPos.x = MousePos.x;
+  OrgPos.y = MousePos.y;
+
   if(mi->dwFlags & MOUSEEVENTF_MOVE)
   {
     if(mi->dwFlags & MOUSEEVENTF_ABSOLUTE)
@@ -631,12 +633,7 @@
         MousePos.y = (LONG)CurInfo->CursorClipInfo.Top;
     }
     
-    DoMove = (MousePos.x != CurInfo->x || MousePos.y != CurInfo->y);
-    if(DoMove)
-    {
-      CurInfo->x = MousePos.x;
-      CurInfo->y = MousePos.y;
-    }
+    DoMove = (MousePos.x != OrgPos.x || MousePos.y != OrgPos.y);
   }
 
   ExReleaseFastMutex(&CurInfo->CursorMutex);
@@ -657,12 +654,13 @@
         if (GDIDEV(SurfObj)->Pointer.MovePointer)
         {
           GDIDEV(SurfObj)->Pointer.MovePointer(SurfObj, MousePos.x, MousePos.y, &(GDIDEV(SurfObj)->Pointer.Exclude));
-        }
-        /* FIXME - That's a bad thing! We should't access private gdi pointer fields
-                   from here. However it is required so MouseSafetyOnDrawEnd() can
-                   properly paint the mouse cursor to the screen again. See the
-                   comment in MouseSafetyOnDrawEnd() to fix this problem! */
-        GDIDEV(SurfObj)->Pointer.Pos = MousePos;
+        } else {
+	  EngMovePointer(SurfObj, MousePos.x, MousePos.y, &(GDIDEV(SurfObj)->Pointer.Exclude));
+	}
+        /* Only now, update the info in the GDIDEVICE, so EngMovePointer can
+	 * use the old values to move the pointer image */
+	GDIDEV(SurfObj)->Pointer.Pos.x = MousePos.x;
+	GDIDEV(SurfObj)->Pointer.Pos.y = MousePos.y;
 
         BITMAPOBJ_UnlockBitmap(hBitmap);
       }

Modified: trunk/reactos/subsys/win32k/ntuser/message.c
--- trunk/reactos/subsys/win32k/ntuser/message.c	2005-01-27 00:33:11 UTC (rev 13332)
+++ trunk/reactos/subsys/win32k/ntuser/message.c	2005-01-27 00:49:24 UTC (rev 13333)
@@ -1123,7 +1123,6 @@
     }
   else
     {
-      PSYSTEM_CURSORINFO CurInfo;
       Window = IntGetWindowObject(Wnd);
       if (NULL == Window)
         {
@@ -1149,9 +1148,8 @@
           SetLastWin32Error(ERROR_INVALID_PARAMETER);
           return FALSE;
         }
-      CurInfo = IntGetSysCursorInfo(PsGetWin32Thread()->Desktop->WindowStation);
-      KernelModeMsg.pt.x = CurInfo->x;
-      KernelModeMsg.pt.y = CurInfo->y;
+      IntGetCursorLocation(PsGetWin32Thread()->Desktop->WindowStation,
+                           &KernelModeMsg.pt);
       KeQueryTickCount(&LargeTickCount);
       KernelModeMsg.time = LargeTickCount.u.LowPart;
       MsqPostMessage(Window->MessageQueue, &KernelModeMsg,

Modified: trunk/reactos/subsys/win32k/ntuser/misc.c
--- trunk/reactos/subsys/win32k/ntuser/misc.c	2005-01-27 00:33:11 UTC (rev 13332)
+++ trunk/reactos/subsys/win32k/ntuser/misc.c	2005-01-27 00:49:24 UTC (rev 13333)
@@ -263,7 +263,6 @@
     
     case ONEPARAM_ROUTINE_GETCURSORPOSITION:
     {
-      PSYSTEM_CURSORINFO CurInfo;
       PWINSTATION_OBJECT WinStaObject;
       NTSTATUS Status;
       POINT Pos;
@@ -277,10 +276,8 @@
       if (!NT_SUCCESS(Status))
         return (DWORD)FALSE;
       
-      CurInfo = IntGetSysCursorInfo(WinStaObject);
       /* FIXME - check if process has WINSTA_READATTRIBUTES */
-      Pos.x = CurInfo->x;
-      Pos.y = CurInfo->y;
+      IntGetCursorLocation(WinStaObject, &Pos);
       
       Status = MmCopyToCaller((PPOINT)Param, &Pos, sizeof(POINT));
       if(!NT_SUCCESS(Status))

Modified: trunk/reactos/subsys/win32k/ntuser/winsta.c
--- trunk/reactos/subsys/win32k/ntuser/winsta.c	2005-01-27 00:33:11 UTC (rev 13332)
+++ trunk/reactos/subsys/win32k/ntuser/winsta.c	2005-01-27 00:49:24 UTC (rev 13333)
@@ -389,8 +389,6 @@
    ExInitializeFastMutex(&CurInfo->CursorMutex);
    CurInfo->Enabled = FALSE;
    CurInfo->ButtonsDown = 0;
-   CurInfo->x = (LONG)0;
-   CurInfo->y = (LONG)0;
    CurInfo->CursorClipInfo.IsClipped = FALSE;
    CurInfo->LastBtnDown = 0;
    CurInfo->CurrentCursorObject = NULL;