3 * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 /* $Id: icon.c,v 1.18 2004/01/23 23:38:26 ekohl Exp $
21 * PROJECT: ReactOS user32.dll
22 * FILE: lib/user32/windows/icon.c
24 * PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
26 * 09-05-2001 CSH Created
29 /* INCLUDES ******************************************************************/
37 /* FUNCTIONS *****************************************************************/
40 ICON_CreateIconFromData(HDC hDC
, PVOID ImageData
, ICONIMAGE
* IconImage
, int cxDesired
, int cyDesired
, int xHotspot
, int yHotspot
)
45 IconInfo
.fIcon
= TRUE
;
46 IconInfo
.xHotspot
= xHotspot
;
47 IconInfo
.yHotspot
= yHotspot
;
49 /* Load the XOR bitmap */
50 IconInfo
.hbmColor
= CreateDIBitmap(hDC
, &IconImage
->icHeader
, CBM_INIT
,
51 ImageData
, (BITMAPINFO
*)IconImage
, DIB_RGB_COLORS
);
53 /* make ImageData point to the start of the AND image data */
54 ImageData
= ((PBYTE
)ImageData
) + (((IconImage
->icHeader
.biWidth
*
55 IconImage
->icHeader
.biBitCount
+ 31) & ~31) >> 3) *
56 (IconImage
->icHeader
.biHeight
);
58 /* create a BITMAPINFO header for the monocrome part of the icon */
59 bwBIH
= RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof (BITMAPINFOHEADER
)+2*sizeof(RGBQUAD
));
61 bwBIH
->bmiHeader
.biBitCount
= 1;
62 bwBIH
->bmiHeader
.biWidth
= IconImage
->icHeader
.biWidth
;
63 bwBIH
->bmiHeader
.biHeight
= IconImage
->icHeader
.biHeight
;
64 bwBIH
->bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
65 bwBIH
->bmiHeader
.biPlanes
= 1;
66 bwBIH
->bmiHeader
.biSizeImage
= (((IconImage
->icHeader
.biWidth
* 1 + 31) & ~31) >> 3) *
67 (IconImage
->icHeader
.biHeight
);
68 bwBIH
->bmiHeader
.biCompression
= BI_RGB
;
69 bwBIH
->bmiHeader
.biClrImportant
= 0;
70 bwBIH
->bmiHeader
.biClrUsed
= 0;
71 bwBIH
->bmiHeader
.biXPelsPerMeter
= 0;
72 bwBIH
->bmiHeader
.biYPelsPerMeter
= 0;
74 bwBIH
->bmiColors
[0].rgbBlue
= 0;
75 bwBIH
->bmiColors
[0].rgbGreen
= 0;
76 bwBIH
->bmiColors
[0].rgbRed
= 0;
77 bwBIH
->bmiColors
[0].rgbReserved
= 0;
79 bwBIH
->bmiColors
[1].rgbBlue
= 0xff;
80 bwBIH
->bmiColors
[1].rgbGreen
= 0xff;
81 bwBIH
->bmiColors
[1].rgbRed
= 0xff;
82 bwBIH
->bmiColors
[1].rgbReserved
= 0;
84 /* load the AND bitmap */
85 IconInfo
.hbmMask
= CreateDIBitmap(hDC
, &bwBIH
->bmiHeader
, 0,
86 ImageData
, bwBIH
, DIB_RGB_COLORS
);
88 SetDIBits(hDC
, IconInfo
.hbmMask
, 0, IconImage
->icHeader
.biHeight
,
89 ImageData
, bwBIH
, DIB_RGB_COLORS
);
91 RtlFreeHeap(RtlGetProcessHeap(), 0, bwBIH
);
93 /* Create the icon based on everything we have so far */
94 return NtUserCreateCursorIconHandle(&IconInfo
, FALSE
);
98 ICON_CreateCursorFromData(HDC hDC
, PVOID ImageData
, ICONIMAGE
* IconImage
, int cxDesired
, int cyDesired
, int xHotspot
, int yHotspot
)
100 /* FIXME - color cursors */
103 PVOID XORImageData
= ImageData
;
105 IconInfo
.fIcon
= TRUE
;
106 IconInfo
.xHotspot
= xHotspot
;
107 IconInfo
.yHotspot
= yHotspot
;
109 /* create a BITMAPINFO header for the monocrome part of the icon */
110 bwBIH
= RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof (BITMAPINFOHEADER
)+2*sizeof(RGBQUAD
));
112 bwBIH
->bmiHeader
.biBitCount
= 1;
113 bwBIH
->bmiHeader
.biWidth
= IconImage
->icHeader
.biWidth
;
114 bwBIH
->bmiHeader
.biHeight
= IconImage
->icHeader
.biHeight
;
115 bwBIH
->bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
116 bwBIH
->bmiHeader
.biPlanes
= 1;
117 bwBIH
->bmiHeader
.biSizeImage
= (((IconImage
->icHeader
.biWidth
* 1 + 31) & ~31) >> 3) *
118 (IconImage
->icHeader
.biHeight
);
119 bwBIH
->bmiHeader
.biCompression
= BI_RGB
;
120 bwBIH
->bmiHeader
.biClrImportant
= 0;
121 bwBIH
->bmiHeader
.biClrUsed
= 0;
122 bwBIH
->bmiHeader
.biXPelsPerMeter
= 0;
123 bwBIH
->bmiHeader
.biYPelsPerMeter
= 0;
125 bwBIH
->bmiColors
[0].rgbBlue
= 0;
126 bwBIH
->bmiColors
[0].rgbGreen
= 0;
127 bwBIH
->bmiColors
[0].rgbRed
= 0;
128 bwBIH
->bmiColors
[0].rgbReserved
= 0;
130 bwBIH
->bmiColors
[1].rgbBlue
= 0xff;
131 bwBIH
->bmiColors
[1].rgbGreen
= 0xff;
132 bwBIH
->bmiColors
[1].rgbRed
= 0xff;
133 bwBIH
->bmiColors
[1].rgbReserved
= 0;
135 /* load the AND bitmap */
136 IconInfo
.hbmMask
= CreateDIBitmap(hDC
, &bwBIH
->bmiHeader
, 0,
137 XORImageData
, bwBIH
, DIB_RGB_COLORS
);
141 SetDIBits(hDC
, IconInfo
.hbmMask
, 0, IconImage
->icHeader
.biHeight
,
142 XORImageData
, bwBIH
, DIB_RGB_COLORS
);
146 IconInfo
.hbmColor
= (HBITMAP
)0;
148 RtlFreeHeap(RtlGetProcessHeap(), 0, bwBIH
);
150 /* Create the icon based on everything we have so far */
151 return NtUserCreateCursorIconHandle(&IconInfo
, FALSE
);
165 if(NtUserGetCursorIconInfo((HANDLE
)hIcon
, &IconInfo
))
167 return NtUserCreateCursorIconHandle(&IconInfo
, FALSE
);
189 IconInfo
.fIcon
= TRUE
;
190 IconInfo
.xHotspot
= nWidth
/ 2;
191 IconInfo
.yHotspot
= nHeight
/ 2;
192 IconInfo
.hbmMask
= CreateBitmap(nWidth
, nHeight
, 1, 1, ANDbits
);
193 if(!IconInfo
.hbmMask
)
197 IconInfo
.hbmColor
= CreateBitmap(nWidth
, nHeight
, cPlanes
, cBitsPixel
, XORbits
);
198 if(!IconInfo
.hbmColor
)
200 DeleteObject(IconInfo
.hbmMask
);
204 return NtUserCreateCursorIconHandle(&IconInfo
, FALSE
);
213 CreateIconFromResource(
219 return CreateIconFromResourceEx(presbits
, dwResSize
, fIcon
, dwVer
, 0, 0, 0);
228 CreateIconFromResourceEx(
237 ICONIMAGE
* SafeIconImage
;
247 FIXME - does win support LR_SHARED? According to msdn it does but we don't
248 have useful information to identify the icon
249 if (uFlags & LR_SHARED)
251 DbgPrint("FIXME: need LR_SHARED support in CreateIconFromResourceEx()\n");
255 DPRINT("dwVersion, cxDesired, cyDesired are all ignored in this implementation!\n");
259 wXHotspot
= (WORD
)*pbIconBits
;
261 wYHotspot
= (WORD
)*pbIconBits
;
267 wXHotspot
= cxDesired
/ 2;
268 wYHotspot
= cyDesired
/ 2;
271 /* get an safe copy of the icon data */
272 SafeIconImage
= RtlAllocateHeap(RtlGetProcessHeap(), 0, cbIconBits
);
273 memcpy(SafeIconImage
, pbIconBits
, cbIconBits
);
275 /* take into acount the origonal height was for both the AND and XOR images */
277 SafeIconImage
->icHeader
.biHeight
/= 2;
279 if (SafeIconImage
->icHeader
.biSize
== sizeof(BITMAPCOREHEADER
))
281 BITMAPCOREHEADER
* Core
= (BITMAPCOREHEADER
*)SafeIconImage
;
282 ColourCount
= (Core
->bcBitCount
<= 8) ? (1 << Core
->bcBitCount
) : 0;
283 HeaderSize
= sizeof(BITMAPCOREHEADER
) + ColourCount
* sizeof(RGBTRIPLE
);
287 ColourCount
= (SafeIconImage
->icHeader
.biBitCount
<= 8) ?
288 (1 << SafeIconImage
->icHeader
.biBitCount
) : 0;
289 HeaderSize
= sizeof(BITMAPINFOHEADER
) + ColourCount
* sizeof(RGBQUAD
);
292 /* make data point to the start of the XOR image data */
293 Data
= (PBYTE
)SafeIconImage
+ HeaderSize
;
295 /* get a handle to the screen dc, the icon we create is going to be compatable with this */
296 hScreenDc
= CreateCompatibleDC(NULL
);
297 if (hScreenDc
== NULL
)
299 RtlFreeHeap(RtlGetProcessHeap(), 0, SafeIconImage
);
304 hIcon
= ICON_CreateIconFromData(hScreenDc
, Data
, SafeIconImage
, cxDesired
, cyDesired
, wXHotspot
, wYHotspot
);
306 hIcon
= ICON_CreateCursorFromData(hScreenDc
, Data
, SafeIconImage
, cxDesired
, cyDesired
, wXHotspot
, wYHotspot
);
307 RtlFreeHeap(RtlGetProcessHeap(), 0, SafeIconImage
);
319 CreateIconIndirect(PICONINFO IconInfo
)
326 SetLastError(ERROR_INVALID_PARAMETER
);
330 if(!GetObjectW(IconInfo
->hbmMask
, sizeof(BITMAP
), &MaskBitmap
))
334 /* FIXME - does there really *have* to be a color bitmap? monochrome cursors don't have one */
335 if(IconInfo
->hbmColor
&& !GetObjectW(IconInfo
->hbmColor
, sizeof(BITMAP
), &ColorBitmap
))
340 /* FIXME - i doubt this is right (monochrome cursors */
341 /*if(ColorBitmap.bmWidth != MaskBitmap.bmWidth ||
342 ColorBitmap.bmHeight != MaskBitmap.bmWidth)
344 SetLastError(ERROR_INVALID_PARAMETER);
348 return (HICON
)NtUserCreateCursorIconHandle(IconInfo
, TRUE
);
360 return (BOOL
)NtUserDestroyCursorIcon((HANDLE
)hIcon
, 0);
375 return DrawIconEx(hDC
, X
, Y
, hIcon
, 0, 0, 0, NULL
, DI_NORMAL
| DI_DEFAULTSIZE
);
391 HBRUSH hbrFlickerFreeDraw
,
394 return (BOOL
)NtUserDrawIconEx(hdc
, xLeft
, yTop
, hIcon
, cxWidth
, cyWidth
,
395 istepIfAniCur
, hbrFlickerFreeDraw
, diFlags
,
409 /* FIXME - copy bitmaps */
410 return (BOOL
)NtUserGetCursorIconInfo((HANDLE
)hIcon
, IconInfo
);
423 return(LoadImageA(hInstance
, lpIconName
, IMAGE_ICON
, 0, 0, LR_SHARED
| LR_DEFAULTSIZE
));
436 return(LoadImageW(hInstance
, lpIconName
, IMAGE_ICON
, 0, 0, LR_SHARED
| LR_DEFAULTSIZE
));
445 LookupIconIdFromDirectory(
449 return LookupIconIdFromDirectoryEx( presbits
, fIcon
,
450 fIcon
? GetSystemMetrics(SM_CXICON
) : GetSystemMetrics(SM_CXCURSOR
),
451 fIcon
? GetSystemMetrics(SM_CYICON
) : GetSystemMetrics(SM_CYCURSOR
), LR_DEFAULTCOLOR
);
454 /* Ported from WINE20030408 */
455 GRPCURSORICONDIRENTRY
*
456 CURSORICON_FindBestCursor( GRPCURSORICONDIR
*dir
, int width
, int height
, int colors
)
459 GRPCURSORICONDIRENTRY
*entry
, *bestEntry
= NULL
;
460 UINT iTotalDiff
, iXDiff
=0, iYDiff
=0, iColorDiff
;
461 UINT iTempXDiff
, iTempYDiff
, iTempColorDiff
;
463 if (dir
->idCount
< 1)
465 DPRINT("Empty directory!\n");
468 if (dir
->idCount
== 1)
469 return &dir
->idEntries
[0]; /* No choice... */
472 iTotalDiff
= 0xFFFFFFFF;
473 iColorDiff
= 0xFFFFFFFF;
474 for (i
= 0, entry
= &dir
->idEntries
[0]; i
< dir
->idCount
; i
++,entry
++)
476 iTempXDiff
= abs(width
- entry
->ResInfo
.icon
.bWidth
);
477 iTempYDiff
= abs(height
- entry
->ResInfo
.icon
.bHeight
);
479 if(iTotalDiff
> (iTempXDiff
+ iTempYDiff
))
483 iTotalDiff
= iXDiff
+ iYDiff
;
487 /* Find Best Colors for Best Fit */
488 for (i
= 0, entry
= &dir
->idEntries
[0]; i
< dir
->idCount
; i
++,entry
++)
490 if(abs(width
- entry
->ResInfo
.icon
.bWidth
) == (int) iXDiff
&&
491 abs(height
- entry
->ResInfo
.icon
.bHeight
) == (int) iYDiff
)
493 iTempColorDiff
= abs(colors
- entry
->ResInfo
.icon
.bColorCount
);
495 if(iColorDiff
> iTempColorDiff
)
498 iColorDiff
= iTempColorDiff
;
506 /* Ported from WINE20030408 */
507 GRPCURSORICONDIRENTRY
*
508 CURSORICON_FindBestIcon( GRPCURSORICONDIR
*dir
, int width
, int height
, int colors
)
511 GRPCURSORICONDIRENTRY
*entry
, *bestEntry
= NULL
;
512 UINT iTotalDiff
, iXDiff
=0, iYDiff
=0, iColorDiff
;
513 UINT iTempXDiff
, iTempYDiff
, iTempColorDiff
;
515 if (dir
->idCount
< 1)
517 DPRINT("Empty directory!\n");
520 if (dir
->idCount
== 1)
521 return &dir
->idEntries
[0]; /* No choice... */
524 iTotalDiff
= 0xFFFFFFFF;
525 iColorDiff
= 0xFFFFFFFF;
526 for (i
= 0, entry
= &dir
->idEntries
[0]; i
< dir
->idCount
; i
++,entry
++)
528 iTempXDiff
= abs(width
- entry
->ResInfo
.icon
.bWidth
);
530 iTempYDiff
= abs(height
- entry
->ResInfo
.icon
.bHeight
);
532 if(iTotalDiff
> (iTempXDiff
+ iTempYDiff
))
536 iTotalDiff
= iXDiff
+ iYDiff
;
540 /* Find Best Colors for Best Fit */
541 for (i
= 0, entry
= &dir
->idEntries
[0]; i
< dir
->idCount
; i
++,entry
++)
543 if(abs(width
- entry
->ResInfo
.icon
.bWidth
) == (int) iXDiff
&&
544 abs(height
- entry
->ResInfo
.icon
.bHeight
) == (int) iYDiff
)
546 iTempColorDiff
= abs(colors
- entry
->ResInfo
.icon
.bColorCount
);
547 if(iColorDiff
> iTempColorDiff
)
550 iColorDiff
= iTempColorDiff
;
558 /* Ported from WINE20030408 */
563 LookupIconIdFromDirectoryEx(
570 GRPCURSORICONDIR
*dir
= (GRPCURSORICONDIR
*)presbits
;
573 if (dir
&& !dir
->idReserved
&& (dir
->idType
& 3))
575 GRPCURSORICONDIRENTRY
*entry
;
580 if (Flags
& LR_MONOCHROME
)
586 colors
= GetDeviceCaps(hdc
, BITSPIXEL
);
590 colors
= 1 << colors
;
594 entry
= CURSORICON_FindBestIcon( dir
, cxDesired
, cyDesired
, colors
);
601 DbgPrint("invalid resource directory\n");