[3/10] user: Use 32-bit cursor handles

H. Verbeet hverbeet at gmail.com
Sat Aug 5 16:39:10 CDT 2006


This patch makes user store the contents of a cursor / icon in the
server. A 16-bit handle is only created when required. Unfortunately
that still quite a few places due to 32->16 calls.
-------------- next part --------------
diff --git a/dlls/user/cursoricon.c b/dlls/user/cursoricon.c
index c644bc4..d58dedc 100644
--- a/dlls/user/cursoricon.c
+++ b/dlls/user/cursoricon.c
@@ -5,6 +5,7 @@
  *           1996 Martin Von Loewis
  *           1997 Alex Korobka
  *           1998 Turchanov Sergey
+ *           2006 Henri Verbeet
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -26,7 +27,9 @@
  *
  * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnwui/html/msdn_icons.asp
  *
- * Cursors and icons are stored in a global heap block, with the
+ * 32-bit cursors and icons are stored in the server.
+ *
+ * 16-bit cursors and icons are stored in a global heap block, with the
  * following layout:
  *
  * CURSORICONINFO info;
@@ -50,6 +53,8 @@ #include <stdarg.h>
 #include <string.h>
 #include <stdlib.h>
 
+#include "ntstatus.h"
+#define WIN32_NO_STATUS
 #include "windef.h"
 #include "winbase.h"
 #include "wingdi.h"
@@ -206,7 +211,8 @@ static cursor_map_entry_t *remove_cursor
     return entry;
 }
 
-static HCURSOR create_cursor( unsigned int num_frames, unsigned int delay, HCURSOR16 cursor16 )
+/* Ask the server for a cursor */
+static HCURSOR create_cursor( unsigned int num_frames, unsigned int delay )
 {
     HCURSOR cursor = 0;
 
@@ -218,19 +224,10 @@ static HCURSOR create_cursor( unsigned i
     }
     SERVER_END_REQ;
 
-    if (cursor)
-    {
-        cursor_map_entry_t *entry = HeapAlloc( GetProcessHeap(), 0, sizeof(cursor_map_entry_t) );
-        entry->cursor16 = cursor16;
-        entry->cursor32 = cursor;
-
-        add_cursor16to32_entry( entry );
-        add_cursor32to16_entry( entry );
-    }
-
     return cursor;
 }
 
+/* Tell the server to kill a cursor */
 static HCURSOR16 destroy_cursor( HCURSOR cursor )
 {
     cursor_map_entry_t *entry;
@@ -256,7 +253,73 @@ static HCURSOR16 destroy_cursor( HCURSOR
     return GlobalFree16( cursor16 );
 }
 
-HCURSOR16 get_cursor_handle16( HCURSOR cursor32 )
+/* Upload a cursor frame to the server */
+static void set_cursor_frame( HCURSOR cursor, unsigned int frame_idx, cursor_frame_t *frame )
+{
+    SERVER_START_REQ(set_cursor_frame)
+    {
+        req->handle = cursor;
+        req->frame_idx = frame_idx;
+        req->xhot = frame->xhot;
+        req->yhot = frame->yhot;
+        req->width = frame->width;
+        req->height = frame->height;
+        req->and_width_bytes = frame->and_width_bytes;
+        req->xor_width_bytes = frame->xor_width_bytes;
+        req->planes = frame->planes;
+        req->bpp = frame->bpp;
+        wine_server_add_data( req, frame->bits, (frame->and_width_bytes + frame->xor_width_bytes) * frame->height );
+        wine_server_call( req );
+    }
+    SERVER_END_REQ;
+}
+
+/* Download a cursor frame from the server */
+static BOOL get_cursor_frame( HCURSOR cursor, unsigned int frame_idx, cursor_frame_t *frame )
+{
+    NTSTATUS res;
+    /* Enough for a 32-bits 32x32 cursor / icon. */
+    unsigned int buffer_size = 4224;
+    unsigned int count = 0;
+
+    do
+    {
+        frame->bits = HeapAlloc(GetProcessHeap(), 0, buffer_size);
+        SERVER_START_REQ(get_cursor_frame)
+        {
+            req->handle = cursor;
+            req->frame_idx = frame_idx;
+            wine_server_set_reply( req, frame->bits, buffer_size);
+            if (!(res = wine_server_call_err( req )))
+            {
+                frame->xhot = reply->xhot;
+                frame->yhot = reply->yhot;
+                frame->width = reply->width;
+                frame->height = reply->height;
+                frame->and_width_bytes = reply->and_width_bytes;
+                frame->xor_width_bytes = reply->xor_width_bytes;
+                frame->planes = reply->planes;
+                frame->bpp = reply->bpp;
+            } else {
+                HeapFree( GetProcessHeap(), 0, frame->bits );
+                buffer_size = (reply->and_width_bytes + reply->xor_width_bytes) * reply->height;
+            }
+        }
+        SERVER_END_REQ;
+    } while (res == STATUS_BUFFER_OVERFLOW && !count++);
+
+    if (!frame->height)
+    {
+        HeapFree( GetProcessHeap(), 0, frame->bits );
+
+        return FALSE;
+    }
+
+    return TRUE;
+}
+
+/* Lookup the cursor's 16-bit handle. Create one if it doesn't already exist. */
+HCURSOR16 get_cursor_handle16( HCURSOR cursor32, BOOL create )
 {
     cursor_map_entry_t *entry;
     int idx = hash_cursor_handle( (DWORD)cursor32 );
@@ -269,6 +332,43 @@ HCURSOR16 get_cursor_handle16( HCURSOR c
             if (entry->cursor32 == cursor32) return entry->cursor16;
     }
 
+    /* 16-bit cursor handle not found, create one */
+    if (create)
+    {
+        size_t bits_size;
+        HCURSOR16 cursor16;
+        cursor_frame_t frame;
+
+        if (!get_cursor_frame( cursor32, 0, &frame )) return 0;
+
+        entry = HeapAlloc( GetProcessHeap(), 0, sizeof(cursor_map_entry_t) );
+        bits_size = (frame.and_width_bytes + frame.xor_width_bytes) * frame.height;
+        cursor16 = GlobalAlloc16( GMEM_MOVEABLE, sizeof(CURSORICONINFO) + bits_size );
+        if (cursor16)
+        {
+            CURSORICONINFO *info;
+
+            info = (CURSORICONINFO *)GlobalLock16( cursor16 );
+            info->ptHotSpot.x = frame.xhot;
+            info->ptHotSpot.y = frame.yhot;
+            info->nWidth = frame.width;
+            info->nHeight = frame.height;
+            info->nWidthBytes = frame.xor_width_bytes;
+            info->bPlanes = frame.planes;
+            info->bBitsPerPixel = frame.bpp;
+            CopyMemory( info + 1, frame.bits, bits_size );
+            GlobalUnlock16( cursor16 );
+        }
+        HeapFree( GetProcessHeap(), 0, frame.bits );
+
+        entry->cursor16 = cursor16;
+        entry->cursor32 = cursor32;
+        add_cursor16to32_entry( entry );
+        add_cursor32to16_entry( entry );
+
+        return cursor16;
+    }
+
     return 0;
 }
 
@@ -832,7 +932,8 @@ HICON WINAPI CreateIconFromResourceEx( L
                                        INT width, INT height,
                                        UINT cFlag )
 {
-    HGLOBAL16 hObj;
+    HCURSOR cursor;
+    cursor_frame_t frame = {0};
     static HDC hdcMem;
     int sizeAnd, sizeXor;
     HBITMAP hAndBits = 0, hXorBits = 0; /* error condition for later */
@@ -998,38 +1099,31 @@ HICON WINAPI CreateIconFromResourceEx( L
         return 0;
     }
 
-    /* Now create the CURSORICONINFO structure */
+    /* Setup a cursor frame, send it to the server */
     GetObjectA( hXorBits, sizeof(bmpXor), &bmpXor );
     GetObjectA( hAndBits, sizeof(bmpAnd), &bmpAnd );
     sizeXor = bmpXor.bmHeight * bmpXor.bmWidthBytes;
     sizeAnd = bmpAnd.bmHeight * bmpAnd.bmWidthBytes;
 
-    hObj = GlobalAlloc16( GMEM_MOVEABLE,
-                     sizeof(CURSORICONINFO) + sizeXor + sizeAnd );
-    if (hObj)
-    {
-        CURSORICONINFO *info;
-
-        info = (CURSORICONINFO *)GlobalLock16( hObj );
-        info->ptHotSpot.x   = hotspot.x;
-        info->ptHotSpot.y   = hotspot.y;
-        info->nWidth        = bmpXor.bmWidth;
-        info->nHeight       = bmpXor.bmHeight;
-        info->nWidthBytes   = bmpXor.bmWidthBytes;
-        info->bPlanes       = bmpXor.bmPlanes;
-        info->bBitsPerPixel = bmpXor.bmBitsPixel;
-
-        /* Transfer the bitmap bits to the CURSORICONINFO structure */
-
-        GetBitmapBits( hAndBits, sizeAnd, (char *)(info + 1) );
-        GetBitmapBits( hXorBits, sizeXor, (char *)(info + 1) + sizeAnd );
-        GlobalUnlock16( hObj );
-    }
+    cursor = create_cursor( 1, 0 );
+    frame.xhot              = hotspot.x;
+    frame.yhot              = hotspot.y;
+    frame.width             = bmpXor.bmWidth;
+    frame.height            = bmpXor.bmHeight;
+    frame.and_width_bytes   = bmpAnd.bmWidthBytes;
+    frame.xor_width_bytes   = bmpXor.bmWidthBytes;
+    frame.planes            = bmpXor.bmPlanes;
+    frame.bpp               = bmpXor.bmBitsPixel;
+    frame.bits              = HeapAlloc( GetProcessHeap(), 0, sizeAnd + sizeXor );
+    GetBitmapBits( hAndBits, sizeAnd, frame.bits );
+    GetBitmapBits( hXorBits, sizeXor, frame.bits + sizeAnd );
+    set_cursor_frame( cursor, 0, &frame );
+    HeapFree( GetProcessHeap(), 0, frame.bits );
 
     DeleteObject( hAndBits );
     DeleteObject( hXorBits );
 
-    return create_cursor( 1, 0, hObj );
+    return cursor;
 }
 
 
@@ -1167,22 +1261,20 @@ static HICON CURSORICON_Load(HINSTANCE h
  */
 static HICON CURSORICON_Copy( HINSTANCE16 hInst16, HICON hIcon )
 {
-    char *ptrOld, *ptrNew;
-    int size;
-    HICON16 hOld = HICON_16(hIcon);
-    HICON16 hNew;
+    /* Should animated cursors be copyable like this as well? */
+    HCURSOR new_cursor;
+    cursor_frame_t frame;
 
-    if (!(ptrOld = (char *)GlobalLock16( hOld ))) return 0;
-    if (hInst16 && !(hInst16 = GetExePtr( hInst16 ))) return 0;
-    size = GlobalSize16( hOld );
-    hNew = GlobalAlloc16( GMEM_MOVEABLE, size );
-    FarSetOwner16( hNew, hInst16 );
-    ptrNew = (char *)GlobalLock16( hNew );
-    memcpy( ptrNew, ptrOld, size );
-    GlobalUnlock16( hOld );
-    GlobalUnlock16( hNew );
+    if (!hIcon || !get_cursor_frame( hIcon, 0, &frame ))
+    {
+        return 0;
+    }
+
+    new_cursor = create_cursor( 1, 0 );
+    set_cursor_frame( new_cursor, 0, &frame );
+    HeapFree( GetProcessHeap(), 0, frame.bits );
 
-    return create_cursor( 1, 0, hNew );
+    return new_cursor;
 }
 
 /*************************************************************************
@@ -1485,25 +1577,31 @@ HGLOBAL16 WINAPI CreateCursorIconIndirec
                                            LPCVOID lpANDbits,
                                            LPCVOID lpXORbits )
 {
-    HGLOBAL16 handle;
-    char *ptr;
+    HCURSOR cursor;
+    cursor_frame_t frame;
     int sizeAnd, sizeXor;
 
-    hInstance = GetExePtr( hInstance );  /* Make it a module handle */
     if (!lpXORbits || !lpANDbits || info->bPlanes != 1) return 0;
     info->nWidthBytes = get_bitmap_width_bytes(info->nWidth,info->bBitsPerPixel);
     sizeXor = info->nHeight * info->nWidthBytes;
     sizeAnd = info->nHeight * get_bitmap_width_bytes( info->nWidth, 1 );
-    if (!(handle = GlobalAlloc16( GMEM_MOVEABLE,
-                                  sizeof(CURSORICONINFO) + sizeXor + sizeAnd)))
-        return 0;
-    FarSetOwner16( handle, hInstance );
-    ptr = (char *)GlobalLock16( handle );
-    memcpy( ptr, info, sizeof(*info) );
-    memcpy( ptr + sizeof(CURSORICONINFO), lpANDbits, sizeAnd );
-    memcpy( ptr + sizeof(CURSORICONINFO) + sizeAnd, lpXORbits, sizeXor );
-    GlobalUnlock16( handle );
-    return HICON_16(create_cursor( 1, 0, handle ));
+
+    cursor = create_cursor( 1, 0 );
+    frame.xhot              = info->ptHotSpot.x;
+    frame.yhot              = info->ptHotSpot.y;
+    frame.width             = info->nWidth;
+    frame.height            = info->nHeight;
+    frame.and_width_bytes   = get_bitmap_width_bytes( info->nWidth, 1 );
+    frame.xor_width_bytes   = info->nWidthBytes;
+    frame.planes            = info->bPlanes;
+    frame.bpp               = info->bBitsPerPixel;
+    frame.bits              = HeapAlloc( GetProcessHeap(), 0, sizeAnd + sizeXor );
+    CopyMemory( frame.bits, lpANDbits, sizeAnd );
+    CopyMemory( frame.bits + sizeAnd, lpXORbits, sizeXor );
+    set_cursor_frame( cursor, 0, &frame );
+    HeapFree( GetProcessHeap(), 0, frame.bits );
+
+    return HICON_16(cursor);
 }
 
 
@@ -1966,8 +2064,9 @@ BOOL WINAPI GetIconInfo(HICON hIcon, PIC
  */
 HICON WINAPI CreateIconIndirect(PICONINFO iconinfo)
 {
+    HCURSOR cursor;
+    cursor_frame_t frame;
     BITMAP bmpXor,bmpAnd;
-    HICON16 hObj;
     int	sizeXor,sizeAnd;
 
     if (iconinfo->hbmColor) GetObjectA( iconinfo->hbmColor, sizeof(bmpXor), &bmpXor );
@@ -1976,51 +2075,46 @@ HICON WINAPI CreateIconIndirect(PICONINF
     sizeXor = iconinfo->hbmColor ? (bmpXor.bmHeight * bmpXor.bmWidthBytes) : 0;
     sizeAnd = bmpAnd.bmHeight * bmpAnd.bmWidthBytes;
 
-    hObj = GlobalAlloc16( GMEM_MOVEABLE,
-                          sizeof(CURSORICONINFO) + sizeXor + sizeAnd );
-    if (hObj)
-    {
-        CURSORICONINFO *info;
-
-        info = (CURSORICONINFO *)GlobalLock16( hObj );
-
-        /* If we are creating an icon, the hotspot is unused */
-        if (iconinfo->fIcon)
-        {
-            info->ptHotSpot.x   = ICON_HOTSPOT;
-            info->ptHotSpot.y   = ICON_HOTSPOT;
-        }
-        else
-        {
-            info->ptHotSpot.x   = iconinfo->xHotspot;
-            info->ptHotSpot.y   = iconinfo->yHotspot;
-        }
-
-        if (iconinfo->hbmColor)
-        {
-            info->nWidth        = bmpXor.bmWidth;
-            info->nHeight       = bmpXor.bmHeight;
-            info->nWidthBytes   = bmpXor.bmWidthBytes;
-            info->bPlanes       = bmpXor.bmPlanes;
-            info->bBitsPerPixel = bmpXor.bmBitsPixel;
-        }
-        else
-        {
-            info->nWidth        = bmpAnd.bmWidth;
-            info->nHeight       = bmpAnd.bmHeight / 2;
-            info->nWidthBytes   = bmpAnd.bmWidthBytes;
-            info->bPlanes       = bmpAnd.bmPlanes;
-            info->bBitsPerPixel = bmpAnd.bmBitsPixel;
-        }
+    cursor = create_cursor( 1, 0 );
 
-        /* Transfer the bitmap bits to the CURSORICONINFO structure */
+    /* If we are creating an icon, the hotspot is unused */
+    if (iconinfo->fIcon)
+    {
+        frame.xhot              = ICON_HOTSPOT;
+        frame.yhot              = ICON_HOTSPOT;
+    }
+    else
+    {
+        frame.xhot              = iconinfo->xHotspot;
+        frame.yhot              = iconinfo->yHotspot;
+    }
 
-        GetBitmapBits( iconinfo->hbmMask, sizeAnd, (char*)(info + 1) );
-        if (iconinfo->hbmColor) GetBitmapBits( iconinfo->hbmColor, sizeXor, (char*)(info + 1) + sizeAnd );
-        GlobalUnlock16( hObj );
+    if (iconinfo->hbmColor)
+    {
+        frame.width             = bmpXor.bmWidth;
+        frame.height            = bmpXor.bmHeight;
+        frame.and_width_bytes   = bmpAnd.bmWidthBytes;
+        frame.xor_width_bytes   = bmpXor.bmWidthBytes;
+        frame.planes            = bmpXor.bmPlanes;
+        frame.bpp               = bmpXor.bmBitsPixel;
+    }
+    else
+    {
+        frame.width             = bmpAnd.bmWidth;
+        frame.height            = bmpAnd.bmHeight / 2;
+        frame.and_width_bytes   = bmpAnd.bmWidthBytes;
+        frame.xor_width_bytes   = 0;
+        frame.planes            = bmpAnd.bmPlanes;
+        frame.bpp               = bmpAnd.bmBitsPixel;
     }
 
-    return create_cursor( 1, 0, hObj );
+    frame.bits = HeapAlloc( GetProcessHeap(), 0, sizeAnd + sizeXor );
+    GetBitmapBits( iconinfo->hbmMask, sizeAnd, frame.bits );
+    if (iconinfo->hbmColor) GetBitmapBits( iconinfo->hbmColor, sizeXor, frame.bits + sizeAnd );
+    set_cursor_frame( cursor, 0, &frame );
+    HeapFree( GetProcessHeap(), 0, frame.bits );
+
+    return cursor;
 }
 
 /******************************************************************************
diff --git a/dlls/user/user_private.h b/dlls/user/user_private.h
index 9bd1d38..f41e37a 100644
--- a/dlls/user/user_private.h
+++ b/dlls/user/user_private.h
@@ -232,11 +232,11 @@ extern void SPY_ExitMessage( INT iFlag, 
 extern int SPY_Init(void);
 
 /* HANDLE16 <-> HANDLE conversions */
-HCURSOR16 get_cursor_handle16( HCURSOR cursor32 );
+HCURSOR16 get_cursor_handle16( HCURSOR cursor32, BOOL create );
 HCURSOR get_cursor_handle32( HCURSOR16 cursor16 );
 
-#define HCURSOR_16(h32)    get_cursor_handle16(h32)
-#define HICON_16(h32)      get_cursor_handle16(h32)
+#define HCURSOR_16(h32)    get_cursor_handle16(h32, TRUE)
+#define HICON_16(h32)      get_cursor_handle16(h32, TRUE)
 #define HINSTANCE_16(h32)  (LOWORD(h32))
 
 #define HCURSOR_32(h16)    get_cursor_handle32(h16)
diff --git a/include/wine/winuser16.h b/include/wine/winuser16.h
index 8ed9965..e795e7c 100644
--- a/include/wine/winuser16.h
+++ b/include/wine/winuser16.h
@@ -148,6 +148,25 @@ typedef struct
 
 /* Cursors / Icons */
 
+typedef struct {
+    unsigned short xhot;
+    unsigned short yhot;
+    unsigned short width;
+    unsigned short height;
+    unsigned short and_width_bytes;
+    unsigned short xor_width_bytes;
+    unsigned char planes;
+    unsigned char bpp;
+    /* XOR & AND bitmap bits */
+    unsigned char *bits;
+} cursor_frame_t;
+
+typedef struct cursor_t {
+    unsigned int num_frames;
+    unsigned short delay;
+    cursor_frame_t *frames;
+} cursor_t;
+
 typedef struct tagCURSORICONINFO
 {
     POINT16 ptHotSpot;


More information about the wine-patches mailing list