diff --git a/dlls/user32/cursoricon.c b/dlls/user32/cursoricon.c index 0b3e7cc623e..141bec80e59 100644 --- a/dlls/user32/cursoricon.c +++ b/dlls/user32/cursoricon.c @@ -101,6 +101,7 @@ struct cursoricon_object UINT height; POINT hotspot; UINT num_frames; /* number of frames in the icon/cursor */ + UINT num_steps; /* number of sequence steps in the icon/cursor */ UINT delay; /* delay between frames (in jiffies) */ struct cursoricon_frame frames[1]; /* icon frame information */ }; @@ -112,6 +113,7 @@ static HICON alloc_icon_handle( UINT num_frames ) if (!obj) return 0; obj->delay = 0; + obj->num_steps = num_frames; /* changed later for some animated cursors */ obj->num_frames = num_frames; return alloc_user_handle( &obj->obj, USER_ICON ); } @@ -1027,6 +1029,13 @@ static HCURSOR CURSORICON_CreateIconFromANI( const LPBYTE bits, DWORD bits_size, info = get_icon_ptr( cursor ); info->is_icon = FALSE; + if (header.num_steps > header.num_frames) + { + FIXME("More steps than frames and sequence-based cursors not yet supported.\n"); + info->num_steps = header.num_frames; + } + else + info->num_steps = header.num_steps; /* The .ANI stores the display rate in jiffies (1/60s) */ info->delay = header.display_rate; @@ -1085,6 +1094,7 @@ static HCURSOR CURSORICON_CreateIconFromANI( const LPBYTE bits, DWORD bits_size, if (info->frames[i].alpha) DeleteObject( info->frames[i].alpha ); } info->num_frames = 1; + info->num_steps = 1; info->delay = 0; } info->width = header.width; @@ -1700,28 +1710,33 @@ HICON WINAPI LoadIconA(HINSTANCE hInstance, LPCSTR name) /********************************************************************** * GetCursorFrameInfo (USER32.@) */ -HCURSOR WINAPI GetCursorFrameInfo(HCURSOR hCursor, DWORD unk1, DWORD rate_index_num, DWORD *rate_jiffies, DWORD *is_static) +HCURSOR WINAPI GetCursorFrameInfo(HCURSOR hCursor, DWORD unk1, DWORD istep, DWORD *rate_jiffies, DWORD *num_steps) { struct cursoricon_object *ptr; HCURSOR ret = 0; - if (rate_jiffies == NULL || is_static == NULL) return 0; + if (rate_jiffies == NULL || num_steps == NULL) return 0; if (!(ptr = get_icon_ptr( hCursor ))) return 0; - FIXME("semi-stub! %p => %d %d %p %p\n", hCursor, unk1, rate_index_num, rate_jiffies, is_static); + FIXME("semi-stub! %p => %d %d %p %p\n", hCursor, unk1, istep, rate_jiffies, num_steps); - if (ptr->num_frames == 1 || rate_index_num == 0) + /* Important Note: Sequences are not currently supported, so this implementation + * will not properly handle all cases. */ + if (istep < ptr->num_steps || ptr->num_frames == 1) { ret = hCursor; if (ptr->num_frames == 1) { *rate_jiffies = 0; - *is_static = 1; + *num_steps = 1; } else { - *is_static = ~0; + if (ptr->num_steps == 1) + *num_steps = ~0; + else + *num_steps = ptr->num_steps; *rate_jiffies = ptr->delay; } } @@ -1983,7 +1998,7 @@ BOOL WINAPI DrawIconEx( HDC hdc, INT x0, INT y0, HICON hIcon, hdc,x0,y0,hIcon,cxWidth,cyWidth,istep,hbr,flags ); if (!(ptr = get_icon_ptr( hIcon ))) return FALSE; - if (istep >= ptr->num_frames) + if (istep >= ptr->num_steps) { TRACE_(icon)("Stepped past end of animated frames=%d\n", istep); release_icon_ptr( hIcon, ptr ); diff --git a/dlls/user32/tests/cursoricon.c b/dlls/user32/tests/cursoricon.c index 7bc065d3337..0374d5ec832 100644 --- a/dlls/user32/tests/cursoricon.c +++ b/dlls/user32/tests/cursoricon.c @@ -148,7 +148,7 @@ riff_cursor1_t empty_anicursor = { }, { ANI_LIST_ID, - sizeof(riff_icon32x32x32_t)*1 + sizeof(DWORD), + sizeof(riff_icon32x32x32_t)*(1 /*frames*/) + sizeof(DWORD), ANI_fram_ID, }, { @@ -202,7 +202,7 @@ riff_cursor3_t empty_anicursor3 = { { sizeof(ani_header), 3, /* frames */ - 1, /* steps */ + 3, /* steps */ 32, /* width */ 32, /* height */ 32, /* depth */ @@ -1442,17 +1442,42 @@ static void test_CreateIconFromResource(void) static HCURSOR WINAPI (*pGetCursorFrameInfo)(HCURSOR hCursor, VOID *unk1, VOID *unk2, VOID *unk3, VOID *unk4); static void test_GetCursorFrameInfo(void) { + HBITMAP bmp = NULL, bmpOld = NULL; DWORD unk1, unk2, unk3, unk4; BITMAPINFOHEADER *icon_header; + BITMAPINFO bitmapInfo; + HDC hdc = NULL; + void *bits = 0; INT16 *hotspot; HANDLE h1, h2; BOOL ret; + int i; if (!pGetCursorFrameInfo) { win_skip( "GetCursorFrameInfo not supported, skipping tests.\n" ); return; } + + hdc = CreateCompatibleDC(0); + ok(hdc != 0, "CreateCompatibleDC(0) failed to return a valid DC\n"); + if (!hdc) + return; + + memset(&bitmapInfo, 0, sizeof(bitmapInfo)); + bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bitmapInfo.bmiHeader.biWidth = 3; + bitmapInfo.bmiHeader.biHeight = 3; + bitmapInfo.bmiHeader.biBitCount = 32; + bitmapInfo.bmiHeader.biPlanes = 1; + bitmapInfo.bmiHeader.biCompression = BI_RGB; + bitmapInfo.bmiHeader.biSizeImage = sizeof(UINT32); + bmp = CreateDIBSection(hdc, &bitmapInfo, DIB_RGB_COLORS, &bits, NULL, 0); + ok (bmp && bits, "CreateDIBSection failed to return a valid bitmap and buffer\n"); + if (!bmp || !bits) + goto cleanup; + bmpOld = SelectObject(hdc, bmp); + #define ICON_RES_WIDTH 32 #define ICON_RES_HEIGHT 32 #define ICON_RES_AND_SIZE (ICON_WIDTH*ICON_HEIGHT/8) @@ -1485,8 +1510,8 @@ static void test_GetCursorFrameInfo(void) unk1 = unk2 = unk3 = unk4 = 0xdead; h2 = pGetCursorFrameInfo(h1, &unk1, &unk2, &unk3, &unk4); ok(h1 == h2, "GetCursorFrameInfo() failed: (%p != %p).\n", h1, h2); - ok(unk1 == 0xdead, "GetCursorFrameInfo() unexpected param 2 value (%d != 0xdead).\n", unk1); - ok(unk2 == 0xdead, "GetCursorFrameInfo() unexpected param 3 value (%d != 0xdead).\n", unk2); + ok(unk1 == 0xdead, "GetCursorFrameInfo() unexpected param 2 value (0x%x != 0xdead).\n", unk1); + ok(unk2 == 0xdead, "GetCursorFrameInfo() unexpected param 3 value (0x%x != 0xdead).\n", unk2); ok(unk3 == 0, "GetCursorFrameInfo() unexpected param 4 value (0x%x != 0x0).\n", unk3); ok(unk4 == 1, "GetCursorFrameInfo() unexpected param 5 value (%d != 1).\n", unk4); @@ -1498,57 +1523,120 @@ static void test_GetCursorFrameInfo(void) empty_anicursor.frames[0].data.icon_info.idType = 2; /* type: cursor */ empty_anicursor.frames[0].data.icon_info.idEntries[0].xHotspot = 3; empty_anicursor.frames[0].data.icon_info.idEntries[0].yHotspot = 3; - h1 = CreateIconFromResource((PBYTE) &empty_anicursor, sizeof(empty_anicursor3), FALSE, 0x00030000); + h1 = CreateIconFromResource((PBYTE) &empty_anicursor, sizeof(empty_anicursor), FALSE, 0x00030000); ok(h1 != NULL, "Create cursor failed.\n"); /* Check GetCursorFrameInfo behavior on a single-frame animated cursor */ unk1 = unk2 = unk3 = unk4 = 0xdead; h2 = pGetCursorFrameInfo(h1, &unk1, (VOID*)0, &unk3, &unk4); ok(h1 == h2, "GetCursorFrameInfo() failed: (%p != %p).\n", h1, h2); - ok(unk1 == 0xdead, "GetCursorFrameInfo() unexpected param 2 value (%d != 0xdead).\n", unk1); - ok(unk2 == 0xdead, "GetCursorFrameInfo() unexpected param 3 value (%d != 0xdead).\n", unk2); + ok(unk1 == 0xdead, "GetCursorFrameInfo() unexpected param 2 value (0x%x != 0xdead).\n", unk1); + ok(unk2 == 0xdead, "GetCursorFrameInfo() unexpected param 3 value (0x%x != 0xdead).\n", unk2); ok(unk3 == 0x0, "GetCursorFrameInfo() unexpected param 4 value (0x%x != 0x0).\n", unk3); - ok(unk4 == 1, "GetCursorFrameInfo() unexpected param 5 value (%d != 1).\n", unk4); + ok(unk4 == empty_anicursor.header.header.num_steps, + "GetCursorFrameInfo() unexpected param 5 value (%d != 1).\n", unk4); /* Clean up single-frame animated cursor. */ ret = DestroyCursor(h1); ok(ret, "DestroyCursor() failed.\n"); /* Creating a multi-frame animated cursor. */ - empty_anicursor3.frames[0].data.icon_info.idType = 2; /* type: cursor */ - empty_anicursor3.frames[0].data.icon_info.idEntries[0].xHotspot = 3; - empty_anicursor3.frames[0].data.icon_info.idEntries[0].yHotspot = 3; - empty_anicursor3.frames[1].data.icon_info.idType = 2; /* type: cursor */ - empty_anicursor3.frames[1].data.icon_info.idEntries[0].xHotspot = 3; - empty_anicursor3.frames[1].data.icon_info.idEntries[0].yHotspot = 3; - empty_anicursor3.frames[2].data.icon_info.idType = 2; /* type: cursor */ - empty_anicursor3.frames[2].data.icon_info.idEntries[0].xHotspot = 3; - empty_anicursor3.frames[2].data.icon_info.idEntries[0].yHotspot = 3; + for (i=0; i