From df98de6b96b2ffbcb60fd0d42d8a698875d3d26a Mon Sep 17 00:00:00 2001
From: Andrew Riedi <andrewriedi@gmail.com>
Date: Fri, 6 Feb 2009 12:23:48 -0800
Subject: [PATCH] user32: Use the 32-bit cursor handle to draw the cursor.

Also update the 32-bit cursor cache when calling SetCursor16() for
16-bit applications.
---
 dlls/user32/cursoricon.c   |  132 ++++++++++++++++++++++++++++++++++++++++---
 dlls/user32/user16.c       |    1 +
 dlls/user32/user_private.h |    1 +
 3 files changed, 124 insertions(+), 10 deletions(-)

diff --git a/dlls/user32/cursoricon.c b/dlls/user32/cursoricon.c
index 3b531f5..cf08121 100644
--- a/dlls/user32/cursoricon.c
+++ b/dlls/user32/cursoricon.c
@@ -26,7 +26,9 @@
 /*
  * Theory:
  *
- * Cursors and icons are stored in a global heap block, with the
+ * 32-bit cursors and icons are stored in the server, cached locally.
+ *
+ * 16-bit cursors and icons are stored in a global heap block, with the
  * following layout:
  *
  * CURSORICONINFO info;
@@ -292,6 +294,121 @@ static HCURSOR16 destroy_cursor(HCURSOR cursor)
     return GlobalFree16(cursor16);
 }
 
+static CURSORICONINFO *get_cursor_object(HCURSOR hCursor)
+{
+    struct cursor_map_entry *map_entry = NULL;
+    data_size_t guess_size, cursor_size = 0;
+    CURSORICONINFO *cursor = NULL;
+
+    if (hCursor)
+    {
+        struct rb_entry *entry = wine_rb_get(&global_cursor_map, hCursor);
+        map_entry = RB_ENTRY_VALUE(entry, struct cursor_map_entry, entry);
+    }
+
+    if (!map_entry)
+        return NULL;
+
+    /* If the cache has the cursor, use it. */
+    if (map_entry->data)
+    {
+        TRACE("Cursor cache hit!\n");
+        return map_entry->data;
+    }
+
+    /* No cursor in cache, so retrive it from wineserver. */
+    TRACE("Cursor cache miss.  Retriving from wineserver.\n");
+
+    /* Guess a 32-bit (RGBA) 32x32 cursor. */
+    guess_size = sizeof(CURSORICONINFO) + (32 * 4 + 1) * 32;
+    cursor = HeapAlloc(GetProcessHeap(), 0, guess_size);
+    if (!cursor)
+    {
+        ERR("HeapAlloc() failed.\n");
+        return NULL;
+    }
+
+    /* Try out guess. */
+    SERVER_START_REQ(get_cursor_data)
+    {
+        req->handle = (user_handle_t) hCursor;
+        req->guess_size = guess_size;
+        wine_server_set_reply(req, cursor, guess_size);
+
+        wine_server_call(req);
+        cursor_size = reply->cursor_size;
+    }
+    SERVER_END_REQ;
+
+    if (guess_size > cursor_size)
+    {
+        /* Guess is too big.  Realloc to the correct size. */
+        cursor = HeapReAlloc(GetProcessHeap(), 0, cursor, cursor_size);
+    }
+    else if (guess_size < cursor_size)
+    {
+        /* Guess failed.  Allocate enough space. */
+        HeapFree(GetProcessHeap(), 0, cursor);
+        cursor = HeapAlloc(GetProcessHeap(), 0, cursor_size);
+        if (!cursor)
+        {
+            ERR("HeapAlloc() failed.\n");
+            return NULL;
+        }
+
+        /* Try again. */
+        SERVER_START_REQ(get_cursor_data)
+        {
+            req->handle = (user_handle_t) hCursor;
+            req->guess_size = cursor_size;
+            wine_server_set_reply(req, cursor, cursor_size);
+
+            wine_server_call(req);
+        }
+        SERVER_END_REQ;
+    }
+
+    /* Cache the cursor. */
+    map_entry->data = cursor;
+
+    return cursor;
+}
+
+void CURSORICON_refresh_cursor16(HCURSOR16 cursor16)
+{
+    struct cursor_map_entry *map_entry;
+    struct rb_entry *entry16;
+    CURSORICONINFO *info16;
+    SIZE_T size;
+
+    if (!cursor16)
+    {
+        TRACE("NULL cursor, returning.\n");
+        return;
+    }
+
+    entry16 = wine_rb_get(&global_cursor_map16, (void *)(ULONG) cursor16);
+    map_entry = RB_ENTRY_VALUE(entry16, struct cursor_map_entry, entry16);
+
+    if (!map_entry)
+        return;
+
+    /* Make room for new 32-bit cursor copy, if needed. */
+    size = GlobalSize16(cursor16);
+    if (!map_entry->data
+        || HeapSize(GetProcessHeap(), 0, map_entry->data) < size)
+    {
+        TRACE("Not enough room in cache, fixing.");
+        HeapFree(GetProcessHeap(), 0, map_entry->data);
+        map_entry->data = HeapAlloc(GetProcessHeap(), 0, size);
+    }
+
+    /* Copy 16-bit cursor into a 32-bit cursor. */
+    info16 = GlobalLock16(cursor16);
+    memcpy(map_entry->data, info16, size);
+    GlobalUnlock16(cursor16);
+}
+
 /***********************************************************************
  *             map_fileW
  *
@@ -1854,10 +1971,8 @@ HCURSOR WINAPI SetCursor( HCURSOR hCursor /* [in] Handle of cursor to show */ )
     thread_info->cursor = hCursor;
     /* Change the cursor shape only if it is visible */
     if (thread_info->cursor_count >= 0)
-    {
-        USER_Driver->pSetCursor( (CURSORICONINFO*)GlobalLock16(get_cursor_handle16(hCursor)) );
-        GlobalUnlock16(get_cursor_handle16(hCursor));
-    }
+        USER_Driver->pSetCursor(get_cursor_object(hCursor));
+
     return hOldCursor;
 }
 
@@ -1873,15 +1988,12 @@ INT WINAPI ShowCursor( BOOL bShow )
     if (bShow)
     {
         if (++thread_info->cursor_count == 0) /* Show it */
-        {
-            USER_Driver->pSetCursor((CURSORICONINFO*)GlobalLock16(get_cursor_handle16(thread_info->cursor)));
-            GlobalUnlock16(get_cursor_handle16(thread_info->cursor));
-        }
+            USER_Driver->pSetCursor(get_cursor_object(thread_info->cursor));
     }
     else
     {
         if (--thread_info->cursor_count == -1) /* Hide it */
-            USER_Driver->pSetCursor( NULL );
+            USER_Driver->pSetCursor(0);
     }
     return thread_info->cursor_count;
 }
diff --git a/dlls/user32/user16.c b/dlls/user32/user16.c
index 0890603..d5a224e 100644
--- a/dlls/user32/user16.c
+++ b/dlls/user32/user16.c
@@ -176,6 +176,7 @@ BOOL16 WINAPI GetCursorPos16( POINT16 *pt )
  */
 HCURSOR16 WINAPI SetCursor16(HCURSOR16 hCursor)
 {
+    CURSORICON_refresh_cursor16(hCursor);
     return get_cursor_handle16(SetCursor(get_cursor_handle(hCursor)));
 }
 
diff --git a/dlls/user32/user_private.h b/dlls/user32/user_private.h
index 23abd82..3e6a2a2 100644
--- a/dlls/user32/user_private.h
+++ b/dlls/user32/user_private.h
@@ -352,6 +352,7 @@ typedef struct
 #include "poppack.h"
 
 extern void CURSORICON_init(void) DECLSPEC_HIDDEN;
+extern void CURSORICON_refresh_cursor16(HCURSOR16 cursor16) DECLSPEC_HIDDEN;
 extern void CURSORICON_FreeModuleIcons( HMODULE16 hModule ) DECLSPEC_HIDDEN;
 
 #endif /* __WINE_USER_PRIVATE_H */
-- 
1.5.6.3

