From 6cb05646a4f717c803e51cc329b03ced3433dc9a Mon Sep 17 00:00:00 2001
From: Andrew Riedi <andrewriedi@gmail.com>
Date: Mon, 16 Feb 2009 20:52:41 -0800
Subject: [PATCH] user32 / winex11.drv: Implement themed cursors.

This patch makes user32 pass the cursor to winex11.drv.  Once there,
winex11.drv attemps to use Xcursor to load the themed cursor, but falls
back to a safe default if the themed cursor is unable to be found.
---
 dlls/user32/cursoricon.c |   44 +++++++++++++++++----
 dlls/winex11.drv/mouse.c |   96 +++++++++++++++++++++++++++++++++++++++++++++-
 include/wine/winuser16.h |    1 +
 3 files changed, 131 insertions(+), 10 deletions(-)

diff --git a/dlls/user32/cursoricon.c b/dlls/user32/cursoricon.c
index 388d7ab..b2f1b2b 100644
--- a/dlls/user32/cursoricon.c
+++ b/dlls/user32/cursoricon.c
@@ -424,6 +424,7 @@ void CURSORICON_refresh_cursor16(HCURSOR16 cursor16)
     /* Set up struct cursor. */
     map_entry->data->num_frames = 1;
     map_entry->data->delay = 0;
+    map_entry->data->oem_cursor = 0;
 
     /* Copy 16-bit cursor into a 32-bit cursor. */
     info16 = GlobalLock16(cursor16);
@@ -1146,7 +1147,8 @@ static CURSORICONINFO *CURSORICON_CreateFrameFromBMI(BITMAPINFO *bmi,
 }
 
 static HICON CURSORICON_CreateIconFromBMI(BITMAPINFO *bmi, POINT16 hotspot,
-    BOOL bIcon, DWORD dwVersion, INT width, INT height, UINT cFlag)
+    BOOL bIcon, DWORD dwVersion, INT width, INT height, UINT cFlag,
+    UINT oem_cursor)
 {
     HICON cursor = 0;
     struct cursor *cursor_data;
@@ -1167,6 +1169,7 @@ static HICON CURSORICON_CreateIconFromBMI(BITMAPINFO *bmi, POINT16 hotspot,
     {
         cursor_data->num_frames = 1;
         cursor_data->delay = 0;
+        cursor_data->oem_cursor = oem_cursor;
 
         memcpy(cursor_data + 1, frame, frame_size);
 
@@ -1451,6 +1454,7 @@ static HCURSOR CURSORICON_CreateIconFromANI( const LPBYTE bits, DWORD bits_size,
 
         cursor_data->num_frames = header.num_steps;
         cursor_data->delay = header.display_rate;
+        cursor_data->oem_cursor = 0;
 
         /* Loop through frames and copy. */
         next = (BYTE *) (cursor_data + 1);
@@ -1519,8 +1523,8 @@ HICON WINAPI CreateIconFromResourceEx( LPBYTE bits, UINT cbSize,
         bmi = (BITMAPINFO *)(pt + 1);
     }
 
-    return CURSORICON_CreateIconFromBMI( bmi, hotspot, bIcon, dwVersion,
-					 width, height, cFlag );
+    return CURSORICON_CreateIconFromBMI(bmi, hotspot, bIcon, dwVersion,
+        width, height, cFlag, 0);
 }
 
 
@@ -1591,9 +1595,9 @@ static HICON CURSORICON_LoadFromFile( LPCWSTR filename,
         hotspot.x = ICON_HOTSPOT;
         hotspot.y = ICON_HOTSPOT;
     }
-    hIcon = CURSORICON_CreateIconFromBMI( (BITMAPINFO *)&bits[entry->dwDIBOffset],
-					  hotspot, !fCursor, 0x00030000,
-					  width, height, loadflags );
+    hIcon = CURSORICON_CreateIconFromBMI(
+        (BITMAPINFO *)&bits[entry->dwDIBOffset], hotspot, !fCursor, 0x00030000,
+        width, height, loadflags, 0);
 end:
     TRACE("loaded %s -> %p\n", debugstr_w( filename ), hIcon );
     UnmapViewOfFile( bits );
@@ -1617,6 +1621,9 @@ static HICON CURSORICON_Load(HINSTANCE hInstance, LPCWSTR name,
     LPBYTE bits;
     WORD wResId;
     DWORD dwBytesInRes;
+    UINT oem_cursor = 0;
+    POINT16 hotspot;
+    BITMAPINFO *bmi;
 
     TRACE("%p, %s, %dx%d, colors %d, fCursor %d, flags 0x%04x\n",
           hInstance, debugstr_w(name), width, height, colors, fCursor, loadflags);
@@ -1624,7 +1631,11 @@ static HICON CURSORICON_Load(HINSTANCE hInstance, LPCWSTR name,
     if ( loadflags & LR_LOADFROMFILE )    /* Load from file */
         return CURSORICON_LoadFromFile( name, width, height, colors, fCursor, loadflags );
 
-    if (!hInstance) hInstance = user32_module;  /* Load OEM cursor/icon */
+    if (!hInstance)
+    {
+        hInstance = user32_module;  /* Load OEM cursor/icon. */
+        oem_cursor = (UINT) name;
+    }
 
     /* Normalize hInstance (must be uniquely represented for icon cache) */
 
@@ -1663,8 +1674,21 @@ static HICON CURSORICON_Load(HINSTANCE hInstance, LPCWSTR name,
 
     if (!(handle = LoadResource( hInstance, hRsrc ))) return 0;
     bits = LockResource( handle );
-    hIcon = CreateIconFromResourceEx( bits, dwBytesInRes,
-                                      !fCursor, 0x00030000, width, height, loadflags);
+
+    hotspot.x = ICON_HOTSPOT;
+    hotspot.y = ICON_HOTSPOT;
+
+    if (!fCursor)
+        bmi = (BITMAPINFO *)bits;
+    else /* get the hotspot */
+    {
+        POINT16 *pt = (POINT16 *)bits;
+        hotspot = *pt;
+        bmi = (BITMAPINFO *)(pt + 1);
+    }
+
+    hIcon = CURSORICON_CreateIconFromBMI(bmi, hotspot, !fCursor, 0x00030000,
+        width, height, loadflags, oem_cursor);
     FreeResource( handle );
 
     /* If shared icon, add to icon cache */
@@ -1969,6 +1993,7 @@ HGLOBAL16 WINAPI CreateCursorIconIndirect16(HINSTANCE16 hInstance,
 
     cursor_data->num_frames = 1;
     cursor_data->delay = 0;
+    cursor_data->oem_cursor = 0;
 
     ptr = (CURSORICONINFO *) (cursor_data + 1);
     memcpy(ptr, info, sizeof(*info));
@@ -2501,6 +2526,7 @@ HICON WINAPI CreateIconIndirect(PICONINFO iconinfo)
 
         cursor_data->num_frames = 1;
         cursor_data->delay = 0;
+        cursor_data->oem_cursor = 0;
 
         /* If we are creating an icon, the hotspot is unused */
         if (iconinfo->fIcon)
diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c
index 10f1d31..0ef442e 100644
--- a/dlls/winex11.drv/mouse.c
+++ b/dlls/winex11.drv/mouse.c
@@ -36,11 +36,13 @@ MAKE_FUNCPTR(XcursorImageLoadCursor);
 MAKE_FUNCPTR(XcursorImagesCreate);
 MAKE_FUNCPTR(XcursorImagesDestroy);
 MAKE_FUNCPTR(XcursorImagesLoadCursor);
+MAKE_FUNCPTR(XcursorLibraryLoadCursor);
 # undef MAKE_FUNCPTR
 #endif /* SONAME_LIBXCURSOR */
 
 #define NONAMELESSUNION
 #define NONAMELESSSTRUCT
+#define OEMRESOURCE
 #include "windef.h"
 #include "winbase.h"
 #include "wine/winuser16.h"
@@ -119,6 +121,7 @@ void X11DRV_Xcursor_Init(void)
     LOAD_FUNCPTR(XcursorImagesCreate);
     LOAD_FUNCPTR(XcursorImagesDestroy);
     LOAD_FUNCPTR(XcursorImagesLoadCursor);
+    LOAD_FUNCPTR(XcursorLibraryLoadCursor);
 #undef LOAD_FUNCPTR
 #endif /* SONAME_LIBXCURSOR */
 }
@@ -590,7 +593,7 @@ static XcursorImage *create_cursor_image(CURSORICONINFO *ptr, SIZE_T *offset)
 static Cursor create_xcursor_cursor(Display *display,
     struct cursor *cursor_data)
 {
-    Cursor cursor;
+    Cursor cursor = 0;
     XcursorImage *image;
     XcursorImages *images;
     CURSORICONINFO *ptr;
@@ -609,6 +612,97 @@ static Cursor create_xcursor_cursor(Display *display,
         return cursor;
     }
 
+    /* Try to load a system cursor in place of the OEM ones. */
+    TRACE("oem_cursor: %u\n", cursor_data->oem_cursor);
+    switch (cursor_data->oem_cursor)
+    {
+        case OCR_NORMAL:
+            cursor = pXcursorLibraryLoadCursor(display, "wine_normal");
+            if (!cursor)
+                cursor = pXcursorLibraryLoadCursor(display, "arrow");
+            break;
+        case OCR_IBEAM:
+            cursor = pXcursorLibraryLoadCursor(display, "wine_ibeam");
+            if (!cursor)
+                cursor = pXcursorLibraryLoadCursor(display, "xterm");
+            break;
+        case OCR_WAIT:
+            cursor = pXcursorLibraryLoadCursor(display, "wine_wait");
+            if (!cursor)
+                cursor = pXcursorLibraryLoadCursor(display, "watch");
+            break;
+        case OCR_CROSS:
+            cursor = pXcursorLibraryLoadCursor(display, "wine_cross");
+            if (!cursor)
+                cursor = pXcursorLibraryLoadCursor(display, "crosshair");
+            break;
+        case OCR_UP:
+            cursor = pXcursorLibraryLoadCursor(display, "wine_up");
+            if (!cursor)
+                cursor = pXcursorLibraryLoadCursor(display, "sb_up_arrow");
+            break;
+        case OCR_ICOCUR:
+        /* Fallthrough. */
+        case OCR_ICON:
+            cursor = pXcursorLibraryLoadCursor(display, "wine_icon");
+            if (!cursor)
+                cursor = pXcursorLibraryLoadCursor(display, "icon");
+            break;
+        case OCR_SIZENWSE:
+            /* FIXME: Is there a mapping for this cursor? */
+            cursor = pXcursorLibraryLoadCursor(display, "wine_sizenwse");
+            break;
+        case OCR_SIZENESW:
+            /* FIXME: Is there a mapping for this cursor? */
+            cursor = pXcursorLibraryLoadCursor(display, "wine_sizenesw");
+            break;
+        case OCR_SIZEWE:
+            cursor = pXcursorLibraryLoadCursor(display, "wine_sizewe");
+            if (!cursor)
+                cursor = pXcursorLibraryLoadCursor(display, "sb_h_double_arrow");
+            break;
+        case OCR_SIZENS:
+            cursor = pXcursorLibraryLoadCursor(display, "wine_sizens");
+            if (!cursor)
+                cursor = pXcursorLibraryLoadCursor(display, "sb_v_double_arrow");
+            break;
+        case OCR_SIZE:
+        /* Fallthrough. */
+        case OCR_SIZEALL:
+            cursor = pXcursorLibraryLoadCursor(display, "wine_sizeall");
+            if (!cursor)
+                cursor = pXcursorLibraryLoadCursor(display, "sizing");
+            break;
+        case OCR_NO:
+            cursor = pXcursorLibraryLoadCursor(display, "wine_no");
+            if (!cursor)
+                cursor = pXcursorLibraryLoadCursor(display, "circle");
+            break;
+        case OCR_HAND:
+            cursor = pXcursorLibraryLoadCursor(display, "wine_hand");
+            if (!cursor)
+                cursor = pXcursorLibraryLoadCursor(display, "hand1");
+            break;
+        case OCR_APPSTARTING:
+            cursor = pXcursorLibraryLoadCursor(display, "wine_appstarting");
+            if (!cursor)
+                cursor = pXcursorLibraryLoadCursor(display, "wait");
+            break;
+        case OCR_HELP:
+            cursor = pXcursorLibraryLoadCursor(display, "wine_help");
+            if (!cursor)
+                cursor = pXcursorLibraryLoadCursor(display, "question_arrow");
+            break;
+        case OCR_DRAGOBJECT:
+            cursor = pXcursorLibraryLoadCursor(display, "wine_dragobject");
+            if (!cursor)
+                cursor = pXcursorLibraryLoadCursor(display, "hand1");
+            break;
+    }
+    /* If cursor wasn't found, load the default cursor like normal. */
+    if (cursor)
+        return cursor;
+
     ptr = (CURSORICONINFO *) (cursor_data + 1);
 
     images = pXcursorImagesCreate(cursor_data->num_frames);
diff --git a/include/wine/winuser16.h b/include/wine/winuser16.h
index ca78f56..bf690e1 100644
--- a/include/wine/winuser16.h
+++ b/include/wine/winuser16.h
@@ -162,6 +162,7 @@ struct cursor
 {
     UINT num_frames;
     UINT delay;
+    UINT oem_cursor;
 };
 
 typedef struct {
-- 
1.5.6.3

