user32: Add get/release routines for accessing cursor frames.

This commit is contained in:
Erich Hoover 2011-03-11 19:21:26 -07:00 committed by Alexandre Julliard
parent 22cc547156
commit 0bb1aadb8f
1 changed files with 126 additions and 52 deletions

View File

@ -83,6 +83,8 @@ static struct list icon_cache = LIST_INIT( icon_cache );
struct cursoricon_frame struct cursoricon_frame
{ {
UINT width; /* frame-specific width */
UINT height; /* frame-specific height */
UINT delay; /* frame-specific delay between this frame and the next (in jiffies) */ UINT delay; /* frame-specific delay between this frame and the next (in jiffies) */
HBITMAP color; /* color bitmap */ HBITMAP color; /* color bitmap */
HBITMAP alpha; /* pre-multiplied alpha bitmap for 32-bpp icons */ HBITMAP alpha; /* pre-multiplied alpha bitmap for 32-bpp icons */
@ -98,8 +100,6 @@ struct cursoricon_object
LPWSTR resname; /* resource name for icons loaded from resources */ LPWSTR resname; /* resource name for icons loaded from resources */
HRSRC rsrc; /* resource for shared icons */ HRSRC rsrc; /* resource for shared icons */
BOOL is_icon; /* whether icon or cursor */ BOOL is_icon; /* whether icon or cursor */
UINT width;
UINT height;
POINT hotspot; POINT hotspot;
UINT num_frames; /* number of frames in the icon/cursor */ UINT num_frames; /* number of frames in the icon/cursor */
UINT num_steps; /* number of sequence steps in the icon/cursor */ UINT num_steps; /* number of sequence steps in the icon/cursor */
@ -135,6 +135,16 @@ static void release_icon_ptr( HICON handle, struct cursoricon_object *ptr )
release_user_handle_ptr( ptr ); release_user_handle_ptr( ptr );
} }
static struct cursoricon_frame *get_icon_frame( struct cursoricon_object *obj, int istep )
{
return &obj->frames[istep];
}
static void release_icon_frame( struct cursoricon_object *obj, int istep, struct cursoricon_frame *frame )
{
/* placeholder */
}
static BOOL free_icon_handle( HICON handle ) static BOOL free_icon_handle( HICON handle )
{ {
struct cursoricon_object *obj = free_user_handle( handle, USER_ICON ); struct cursoricon_object *obj = free_user_handle( handle, USER_ICON );
@ -149,9 +159,12 @@ static BOOL free_icon_handle( HICON handle )
for (i=0; i<obj->num_frames; i++) for (i=0; i<obj->num_frames; i++)
{ {
if (obj->frames[i].alpha) DeleteObject( obj->frames[i].alpha ); struct cursoricon_frame *frame = get_icon_frame( obj, i );
if (obj->frames[i].color) DeleteObject( obj->frames[i].color );
DeleteObject( obj->frames[i].mask ); if (frame->alpha) DeleteObject( frame->alpha );
if (frame->color) DeleteObject( frame->color );
DeleteObject( frame->mask );
release_icon_frame( obj, 0, frame );
} }
if (!IS_INTRESOURCE( obj->resname )) HeapFree( GetProcessHeap(), 0, obj->resname ); if (!IS_INTRESOURCE( obj->resname )) HeapFree( GetProcessHeap(), 0, obj->resname );
HeapFree( GetProcessHeap(), 0, obj ); HeapFree( GetProcessHeap(), 0, obj );
@ -396,10 +409,13 @@ static int DIB_GetBitmapInfo( const BITMAPINFOHEADER *header, LONG *width,
BOOL get_icon_size( HICON handle, SIZE *size ) BOOL get_icon_size( HICON handle, SIZE *size )
{ {
struct cursoricon_object *info; struct cursoricon_object *info;
struct cursoricon_frame *frame;
if (!(info = get_icon_ptr( handle ))) return FALSE; if (!(info = get_icon_ptr( handle ))) return FALSE;
size->cx = info->width; frame = get_icon_frame( info, 0 );
size->cy = info->height; size->cx = frame->width;
size->cy = frame->height;
release_icon_frame( info, 0, frame);
release_icon_ptr( handle, info ); release_icon_ptr( handle, info );
return TRUE; return TRUE;
} }
@ -845,16 +861,19 @@ static HICON CURSORICON_CreateIconFromBMI( BITMAPINFO *bmi, HMODULE module, LPCW
if (hObj) if (hObj)
{ {
struct cursoricon_object *info = get_icon_ptr( hObj ); struct cursoricon_object *info = get_icon_ptr( hObj );
struct cursoricon_frame *frame;
info->is_icon = bIcon; info->is_icon = bIcon;
info->module = module; info->module = module;
info->hotspot = hotspot; info->hotspot = hotspot;
info->width = width; frame = get_icon_frame( info, 0 );
info->height = height; frame->delay = ~0;
info->frames[0].delay = ~0; frame->width = width;
info->frames[0].color = color; frame->height = height;
info->frames[0].mask = mask; frame->color = color;
info->frames[0].alpha = alpha; frame->mask = mask;
frame->alpha = alpha;
release_icon_frame( info, 0, frame );
if (!IS_INTRESOURCE(resname)) if (!IS_INTRESOURCE(resname))
{ {
info->resname = HeapAlloc( GetProcessHeap(), 0, (strlenW(resname) + 1) * sizeof(WCHAR) ); info->resname = HeapAlloc( GetProcessHeap(), 0, (strlenW(resname) + 1) * sizeof(WCHAR) );
@ -1065,8 +1084,9 @@ static HCURSOR CURSORICON_CreateIconFromANI( const LPBYTE bits, DWORD bits_size,
for (i=0; i<header.num_frames; i++) for (i=0; i<header.num_frames; i++)
{ {
const DWORD chunk_size = *(const DWORD *)(icon_chunk + sizeof(DWORD)); const DWORD chunk_size = *(const DWORD *)(icon_chunk + sizeof(DWORD));
struct cursoricon_frame *frame = &info->frames[i];
const CURSORICONFILEDIRENTRY *entry; const CURSORICONFILEDIRENTRY *entry;
struct cursoricon_frame *frame;
INT frameWidth, frameHeight;
const BITMAPINFO *bmi; const BITMAPINFO *bmi;
entry = CURSORICON_FindBestIconFile((const CURSORICONFILEDIR *) icon_data, entry = CURSORICON_FindBestIconFile((const CURSORICONFILEDIR *) icon_data,
@ -1077,16 +1097,20 @@ static HCURSOR CURSORICON_CreateIconFromANI( const LPBYTE bits, DWORD bits_size,
info->hotspot.y = entry->yHotspot; info->hotspot.y = entry->yHotspot;
if (!header.width || !header.height) if (!header.width || !header.height)
{ {
header.width = entry->bWidth; frameWidth = entry->bWidth;
header.height = entry->bHeight; frameHeight = entry->bHeight;
} }
if (frame_rates)
frame->delay = frame_rates[i];
else else
frame->delay = ~0; {
frameWidth = header.width;
frameHeight = header.height;
}
frame = get_icon_frame( info, i );
frame->width = frameWidth;
frame->height = frameHeight;
/* Grab a frame from the animation */ /* Grab a frame from the animation */
if (!create_icon_bitmaps( bmi, header.width, header.height, if (!create_icon_bitmaps( bmi, frameWidth, frameHeight,
&frame->color, &frame->mask, &frame->alpha )) &frame->color, &frame->mask, &frame->alpha ))
{ {
FIXME_(cursor)("failed to convert animated cursor frame.\n"); FIXME_(cursor)("failed to convert animated cursor frame.\n");
@ -1102,6 +1126,13 @@ static HCURSOR CURSORICON_CreateIconFromANI( const LPBYTE bits, DWORD bits_size,
break; break;
} }
/* Setup the animated frame */
if (frame_rates)
frame->delay = frame_rates[i];
else
frame->delay = ~0;
release_icon_frame( info, i, frame );
/* Advance to the next chunk */ /* Advance to the next chunk */
icon_chunk += chunk_size + (2 * sizeof(DWORD)); icon_chunk += chunk_size + (2 * sizeof(DWORD));
icon_data = icon_chunk + (2 * sizeof(DWORD)); icon_data = icon_chunk + (2 * sizeof(DWORD));
@ -1121,8 +1152,6 @@ static HCURSOR CURSORICON_CreateIconFromANI( const LPBYTE bits, DWORD bits_size,
info->num_steps = 1; info->num_steps = 1;
info->delay = 0; info->delay = 0;
} }
info->width = header.width;
info->height = header.height;
release_icon_ptr( cursor, info ); release_icon_ptr( cursor, info );
return cursor; return cursor;
@ -1423,15 +1452,32 @@ HICON WINAPI CopyIcon( HICON hIcon )
} }
if ((hNew = alloc_icon_handle(1))) if ((hNew = alloc_icon_handle(1)))
{ {
struct cursoricon_frame *frameOld, *frameNew;
ptrNew = get_icon_ptr( hNew ); ptrNew = get_icon_ptr( hNew );
ptrNew->is_icon = ptrOld->is_icon; ptrNew->is_icon = ptrOld->is_icon;
ptrNew->width = ptrOld->width;
ptrNew->height = ptrOld->height;
ptrNew->hotspot = ptrOld->hotspot; ptrNew->hotspot = ptrOld->hotspot;
ptrNew->frames[0].delay = ptrOld->frames[0].delay; if (!(frameOld = get_icon_frame( ptrOld, 0 )))
ptrNew->frames[0].mask = copy_bitmap( ptrOld->frames[0].mask ); {
ptrNew->frames[0].color = copy_bitmap( ptrOld->frames[0].color ); release_icon_ptr( hIcon, ptrOld );
ptrNew->frames[0].alpha = copy_bitmap( ptrOld->frames[0].alpha ); SetLastError( ERROR_INVALID_CURSOR_HANDLE );
return 0;
}
if (!(frameNew = get_icon_frame( ptrNew, 0 )))
{
release_icon_frame( ptrOld, 0, frameOld );
release_icon_ptr( hIcon, ptrOld );
SetLastError( ERROR_INVALID_CURSOR_HANDLE );
return 0;
}
frameNew->delay = 0;
frameNew->width = frameOld->width;
frameNew->height = frameOld->height;
frameNew->mask = copy_bitmap( frameOld->mask );
frameNew->color = copy_bitmap( frameOld->color );
frameNew->alpha = copy_bitmap( frameOld->alpha );
release_icon_frame( ptrOld, 0, frameOld );
release_icon_frame( ptrNew, 0, frameNew );
release_icon_ptr( hNew, ptrNew ); release_icon_ptr( hNew, ptrNew );
} }
release_icon_ptr( hIcon, ptrOld ); release_icon_ptr( hIcon, ptrOld );
@ -1758,15 +1804,19 @@ HCURSOR WINAPI GetCursorFrameInfo(HCURSOR hCursor, DWORD unk1, DWORD istep, DWOR
} }
else else
{ {
struct cursoricon_frame *frame;
frame = get_icon_frame( ptr, istep );
if (ptr->num_steps == 1) if (ptr->num_steps == 1)
*num_steps = ~0; *num_steps = ~0;
else else
*num_steps = ptr->num_steps; *num_steps = ptr->num_steps;
/* If this specific frame does not have a delay then use the global delay */ /* If this specific frame does not have a delay then use the global delay */
if (ptr->frames[istep].delay == ~0) if (frame->delay == ~0)
*rate_jiffies = ptr->delay; *rate_jiffies = ptr->delay;
else else
*rate_jiffies = ptr->frames[istep].delay; *rate_jiffies = frame->delay;
release_icon_frame( ptr, istep, frame );
} }
} }
@ -1822,6 +1872,7 @@ BOOL WINAPI GetIconInfoExA( HICON icon, ICONINFOEXA *info )
*/ */
BOOL WINAPI GetIconInfoExW( HICON icon, ICONINFOEXW *info ) BOOL WINAPI GetIconInfoExW( HICON icon, ICONINFOEXW *info )
{ {
struct cursoricon_frame *frame;
struct cursoricon_object *ptr; struct cursoricon_object *ptr;
HMODULE module; HMODULE module;
BOOL ret = TRUE; BOOL ret = TRUE;
@ -1837,13 +1888,21 @@ BOOL WINAPI GetIconInfoExW( HICON icon, ICONINFOEXW *info )
return FALSE; return FALSE;
} }
TRACE("%p => %dx%d\n", icon, ptr->width, ptr->height); frame = get_icon_frame( ptr, 0 );
if (!frame)
{
release_icon_ptr( icon, ptr );
SetLastError( ERROR_INVALID_CURSOR_HANDLE );
return FALSE;
}
TRACE("%p => %dx%d\n", icon, frame->width, frame->height);
info->fIcon = ptr->is_icon; info->fIcon = ptr->is_icon;
info->xHotspot = ptr->hotspot.x; info->xHotspot = ptr->hotspot.x;
info->yHotspot = ptr->hotspot.y; info->yHotspot = ptr->hotspot.y;
info->hbmColor = copy_bitmap( ptr->frames[0].color ); info->hbmColor = copy_bitmap( frame->color );
info->hbmMask = copy_bitmap( ptr->frames[0].mask ); info->hbmMask = copy_bitmap( frame->mask );
info->wResID = 0; info->wResID = 0;
info->szModName[0] = 0; info->szModName[0] = 0;
info->szResName[0] = 0; info->szResName[0] = 0;
@ -1852,13 +1911,14 @@ BOOL WINAPI GetIconInfoExW( HICON icon, ICONINFOEXW *info )
if (IS_INTRESOURCE( ptr->resname )) info->wResID = LOWORD( ptr->resname ); if (IS_INTRESOURCE( ptr->resname )) info->wResID = LOWORD( ptr->resname );
else lstrcpynW( info->szResName, ptr->resname, MAX_PATH ); else lstrcpynW( info->szResName, ptr->resname, MAX_PATH );
} }
if (!info->hbmMask || (!info->hbmColor && ptr->frames[0].color)) if (!info->hbmMask || (!info->hbmColor && frame->color))
{ {
DeleteObject( info->hbmMask ); DeleteObject( info->hbmMask );
DeleteObject( info->hbmColor ); DeleteObject( info->hbmColor );
ret = FALSE; ret = FALSE;
} }
module = ptr->module; module = ptr->module;
release_icon_frame( ptr, 0, frame );
release_icon_ptr( icon, ptr ); release_icon_ptr( icon, ptr );
if (ret && module) GetModuleFileNameW( module, info->szModName, MAX_PATH ); if (ret && module) GetModuleFileNameW( module, info->szModName, MAX_PATH );
return ret; return ret;
@ -1967,14 +2027,17 @@ HICON WINAPI CreateIconIndirect(PICONINFO iconinfo)
if (hObj) if (hObj)
{ {
struct cursoricon_object *info = get_icon_ptr( hObj ); struct cursoricon_object *info = get_icon_ptr( hObj );
struct cursoricon_frame *frame;
info->is_icon = iconinfo->fIcon; info->is_icon = iconinfo->fIcon;
info->width = width; frame = get_icon_frame( info, 0 );
info->height = height; frame->delay = ~0;
info->frames[0].delay = ~0; frame->width = width;
info->frames[0].color = color; frame->height = height;
info->frames[0].mask = mask; frame->color = color;
info->frames[0].alpha = create_alpha_bitmap( iconinfo->hbmColor, mask, NULL, NULL ); frame->mask = mask;
frame->alpha = create_alpha_bitmap( iconinfo->hbmColor, mask, NULL, NULL );
release_icon_frame( info, 0, frame );
if (info->is_icon) if (info->is_icon)
{ {
info->hotspot.x = width / 2; info->hotspot.x = width / 2;
@ -2017,6 +2080,7 @@ BOOL WINAPI DrawIconEx( HDC hdc, INT x0, INT y0, HICON hIcon,
INT cxWidth, INT cyWidth, UINT istep, INT cxWidth, INT cyWidth, UINT istep,
HBRUSH hbr, UINT flags ) HBRUSH hbr, UINT flags )
{ {
struct cursoricon_frame *frame;
struct cursoricon_object *ptr; struct cursoricon_object *ptr;
HDC hdc_dest, hMemDC; HDC hdc_dest, hMemDC;
BOOL result = FALSE, DoOffscreen; BOOL result = FALSE, DoOffscreen;
@ -2034,8 +2098,15 @@ BOOL WINAPI DrawIconEx( HDC hdc, INT x0, INT y0, HICON hIcon,
release_icon_ptr( hIcon, ptr ); release_icon_ptr( hIcon, ptr );
return FALSE; return FALSE;
} }
if (!(frame = get_icon_frame( ptr, istep )))
{
FIXME_(icon)("Error retrieving icon frame %d\n", istep);
release_icon_ptr( hIcon, ptr );
return FALSE;
}
if (!(hMemDC = CreateCompatibleDC( hdc ))) if (!(hMemDC = CreateCompatibleDC( hdc )))
{ {
release_icon_frame( ptr, istep, frame );
release_icon_ptr( hIcon, ptr ); release_icon_ptr( hIcon, ptr );
return FALSE; return FALSE;
} }
@ -2049,14 +2120,14 @@ BOOL WINAPI DrawIconEx( HDC hdc, INT x0, INT y0, HICON hIcon,
if (flags & DI_DEFAULTSIZE) if (flags & DI_DEFAULTSIZE)
cxWidth = GetSystemMetrics (SM_CXICON); cxWidth = GetSystemMetrics (SM_CXICON);
else else
cxWidth = ptr->width; cxWidth = frame->width;
} }
if (cyWidth == 0) if (cyWidth == 0)
{ {
if (flags & DI_DEFAULTSIZE) if (flags & DI_DEFAULTSIZE)
cyWidth = GetSystemMetrics (SM_CYICON); cyWidth = GetSystemMetrics (SM_CYICON);
else else
cyWidth = ptr->height; cyWidth = frame->height;
} }
DoOffscreen = (GetObjectType( hbr ) == OBJ_BRUSH); DoOffscreen = (GetObjectType( hbr ) == OBJ_BRUSH);
@ -2091,7 +2162,7 @@ BOOL WINAPI DrawIconEx( HDC hdc, INT x0, INT y0, HICON hIcon,
oldFg = SetTextColor( hdc, RGB(0,0,0) ); oldFg = SetTextColor( hdc, RGB(0,0,0) );
oldBg = SetBkColor( hdc, RGB(255,255,255) ); oldBg = SetBkColor( hdc, RGB(255,255,255) );
if (ptr->frames[istep].alpha && (flags & DI_IMAGE)) if (frame->alpha && (flags & DI_IMAGE))
{ {
BOOL is_mono = FALSE; BOOL is_mono = FALSE;
@ -2104,34 +2175,36 @@ BOOL WINAPI DrawIconEx( HDC hdc, INT x0, INT y0, HICON hIcon,
if (!is_mono) if (!is_mono)
{ {
BLENDFUNCTION pixelblend = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA }; BLENDFUNCTION pixelblend = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
SelectObject( hMemDC, ptr->frames[istep].alpha ); SelectObject( hMemDC, frame->alpha );
if (GdiAlphaBlend( hdc_dest, x, y, cxWidth, cyWidth, hMemDC, if (GdiAlphaBlend( hdc_dest, x, y, cxWidth, cyWidth, hMemDC,
0, 0, ptr->width, ptr->height, pixelblend )) goto done; 0, 0, frame->width, frame->height,
pixelblend )) goto done;
} }
} }
if (flags & DI_MASK) if (flags & DI_MASK)
{ {
SelectObject( hMemDC, ptr->frames[istep].mask ); SelectObject( hMemDC, frame->mask );
StretchBlt( hdc_dest, x, y, cxWidth, cyWidth, StretchBlt( hdc_dest, x, y, cxWidth, cyWidth,
hMemDC, 0, 0, ptr->width, ptr->height, SRCAND ); hMemDC, 0, 0, frame->width, frame->height, SRCAND );
} }
if (flags & DI_IMAGE) if (flags & DI_IMAGE)
{ {
if (ptr->frames[istep].color) if (frame->color)
{ {
DWORD rop = (flags & DI_MASK) ? SRCINVERT : SRCCOPY; DWORD rop = (flags & DI_MASK) ? SRCINVERT : SRCCOPY;
SelectObject( hMemDC, ptr->frames[istep].color ); SelectObject( hMemDC, frame->color );
StretchBlt( hdc_dest, x, y, cxWidth, cyWidth, StretchBlt( hdc_dest, x, y, cxWidth, cyWidth,
hMemDC, 0, 0, ptr->width, ptr->height, rop ); hMemDC, 0, 0, frame->width, frame->height, rop );
} }
else else
{ {
DWORD rop = (flags & DI_MASK) ? SRCINVERT : SRCCOPY; DWORD rop = (flags & DI_MASK) ? SRCINVERT : SRCCOPY;
SelectObject( hMemDC, ptr->frames[istep].mask ); SelectObject( hMemDC, frame->mask );
StretchBlt( hdc_dest, x, y, cxWidth, cyWidth, StretchBlt( hdc_dest, x, y, cxWidth, cyWidth,
hMemDC, 0, ptr->height, ptr->width, ptr->height, rop ); hMemDC, 0, frame->height, frame->width,
frame->height, rop );
} }
} }
@ -2146,6 +2219,7 @@ done:
if (hB_off) DeleteObject(hB_off); if (hB_off) DeleteObject(hB_off);
failed: failed:
DeleteDC( hMemDC ); DeleteDC( hMemDC );
release_icon_frame( ptr, istep, frame );
release_icon_ptr( hIcon, ptr ); release_icon_ptr( hIcon, ptr );
return result; return result;
} }