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.
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 ******************************************************************/
33 #include <wine/debug.h>
34 WINE_DEFAULT_DEBUG_CHANNEL(user32
);
36 /* FUNCTIONS *****************************************************************/
40 ICON_CreateIconFromData(HDC hDC
, PVOID ImageData
, ICONIMAGE
* IconImage
, int cxDesired
, int cyDesired
, int xHotspot
, int yHotspot
)
42 BYTE BitmapInfoBuffer
[sizeof(BITMAPINFOHEADER
) + 2 * sizeof(RGBQUAD
)];
43 BITMAPINFO
*bwBIH
= (BITMAPINFO
*)BitmapInfoBuffer
;
46 IconInfo
.fIcon
= TRUE
;
47 IconInfo
.xHotspot
= xHotspot
;
48 IconInfo
.yHotspot
= yHotspot
;
50 /* Load the XOR bitmap */
51 IconInfo
.hbmColor
= CreateDIBitmap(hDC
, &IconImage
->icHeader
, CBM_INIT
,
52 ImageData
, (BITMAPINFO
*)IconImage
,
55 /* Make ImageData point to the start of the AND image data. */
56 ImageData
= ((PBYTE
)ImageData
) + (((IconImage
->icHeader
.biWidth
*
57 IconImage
->icHeader
.biBitCount
+ 31) & ~31) >> 3) *
58 (IconImage
->icHeader
.biHeight
);
60 /* Create a BITMAPINFO header for the monocrome part of the icon. */
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
= 0;
67 bwBIH
->bmiHeader
.biCompression
= BI_RGB
;
68 bwBIH
->bmiHeader
.biClrImportant
= 0;
69 bwBIH
->bmiHeader
.biClrUsed
= 0;
70 bwBIH
->bmiHeader
.biXPelsPerMeter
= 0;
71 bwBIH
->bmiHeader
.biYPelsPerMeter
= 0;
73 bwBIH
->bmiColors
[0].rgbBlue
= 0;
74 bwBIH
->bmiColors
[0].rgbGreen
= 0;
75 bwBIH
->bmiColors
[0].rgbRed
= 0;
76 bwBIH
->bmiColors
[0].rgbReserved
= 0;
78 bwBIH
->bmiColors
[1].rgbBlue
= 0xff;
79 bwBIH
->bmiColors
[1].rgbGreen
= 0xff;
80 bwBIH
->bmiColors
[1].rgbRed
= 0xff;
81 bwBIH
->bmiColors
[1].rgbReserved
= 0;
83 /* Load the AND bitmap. */
84 IconInfo
.hbmMask
= CreateDIBitmap(hDC
, &bwBIH
->bmiHeader
, 0,
85 ImageData
, bwBIH
, DIB_RGB_COLORS
);
87 SetDIBits(hDC
, IconInfo
.hbmMask
, 0, IconImage
->icHeader
.biHeight
,
88 ImageData
, bwBIH
, DIB_RGB_COLORS
);
90 /* Create the icon based on everything we have so far */
91 return NtUserCreateCursorIconHandle(&IconInfo
, FALSE
);
95 ICON_CreateCursorFromData(HDC hDC
, PVOID ImageData
, ICONIMAGE
* IconImage
, int cxDesired
, int cyDesired
, int xHotspot
, int yHotspot
)
97 BYTE BitmapInfoBuffer
[sizeof(BITMAPINFOHEADER
) + 2 * sizeof(RGBQUAD
)];
98 BITMAPINFO
*bwBIH
= (BITMAPINFO
*)BitmapInfoBuffer
;
99 BITMAPINFO
*orgBIH
= (BITMAPINFO
*)IconImage
;
101 PVOID XORImageData
= ImageData
;
103 IconInfo
.fIcon
= FALSE
;
104 IconInfo
.xHotspot
= xHotspot
;
105 IconInfo
.yHotspot
= yHotspot
;
107 /* Create a BITMAPINFO header for the monochrome part of the icon */
108 bwBIH
->bmiHeader
.biBitCount
= 1;
109 bwBIH
->bmiHeader
.biWidth
= IconImage
->icHeader
.biWidth
;
110 bwBIH
->bmiHeader
.biHeight
= IconImage
->icHeader
.biHeight
;
111 bwBIH
->bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
112 bwBIH
->bmiHeader
.biPlanes
= 1;
113 bwBIH
->bmiHeader
.biSizeImage
= 0;
114 bwBIH
->bmiHeader
.biCompression
= BI_RGB
;
115 bwBIH
->bmiHeader
.biClrImportant
= 0;
116 bwBIH
->bmiHeader
.biClrUsed
= 0;
117 bwBIH
->bmiHeader
.biXPelsPerMeter
= 0;
118 bwBIH
->bmiHeader
.biYPelsPerMeter
= 0;
120 bwBIH
->bmiColors
[0].rgbBlue
= 0;
121 bwBIH
->bmiColors
[0].rgbGreen
= 0;
122 bwBIH
->bmiColors
[0].rgbRed
= 0;
123 bwBIH
->bmiColors
[0].rgbReserved
= 0;
125 bwBIH
->bmiColors
[1].rgbBlue
= 0xff;
126 bwBIH
->bmiColors
[1].rgbGreen
= 0xff;
127 bwBIH
->bmiColors
[1].rgbRed
= 0xff;
128 bwBIH
->bmiColors
[1].rgbReserved
= 0;
130 /* Load the AND bitmap */
131 IconInfo
.hbmMask
= CreateDIBitmap(hDC
, &bwBIH
->bmiHeader
, 0,
132 XORImageData
, bwBIH
, DIB_RGB_COLORS
);
133 if (IconInfo
.hbmMask
)
135 SetDIBits(hDC
, IconInfo
.hbmMask
, 0, IconImage
->icHeader
.biHeight
,
136 XORImageData
, orgBIH
, DIB_RGB_COLORS
);
139 if (IconImage
->icHeader
.biBitCount
== 1)
141 IconInfo
.hbmColor
= (HBITMAP
)0;
145 /* Create the color part of the icon */
146 IconInfo
.hbmColor
= CreateDIBitmap(hDC
, &IconImage
->icHeader
, 0,
147 XORImageData
, orgBIH
, DIB_RGB_COLORS
);
148 if (IconInfo
.hbmColor
)
150 SetDIBits(hDC
, IconInfo
.hbmColor
, 0, IconImage
->icHeader
.biHeight
,
151 XORImageData
, orgBIH
, DIB_RGB_COLORS
);
155 /* Create the icon based on everything we have so far */
156 return NtUserCreateCursorIconHandle(&IconInfo
, FALSE
);
165 CopyIcon(HICON hIcon
)
167 HICON hRetIcon
= NULL
;
170 if(GetIconInfo(hIcon
, &IconInfo
))
172 hRetIcon
= CreateIconIndirect(&IconInfo
);
173 DeleteObject(IconInfo
.hbmColor
);
174 DeleteObject(IconInfo
.hbmMask
);
197 IconInfo
.fIcon
= TRUE
;
203 IconInfo
.hbmMask
= CreateBitmap(nWidth
, nHeight
, 1, 1, ANDbits
);
204 if(!IconInfo
.hbmMask
)
211 IconInfo
.hbmColor
= (HBITMAP
)0;
215 IconInfo
.hbmColor
= CreateBitmap(nWidth
, nHeight
, cPlanes
, cBitsPixel
, XORbits
);
216 if(!IconInfo
.hbmColor
)
218 DeleteObject(IconInfo
.hbmMask
);
223 return NtUserCreateCursorIconHandle(&IconInfo
, FALSE
);
232 CreateIconFromResource(
238 return CreateIconFromResourceEx(presbits
, dwResSize
, fIcon
, dwVer
, 0, 0, LR_DEFAULTSIZE
|LR_SHARED
);
247 CreateIconFromResourceEx(
256 ICONIMAGE
* SafeIconImage
;
266 FIXME - does win support LR_SHARED? According to msdn it does but we don't
267 have useful information to identify the icon
268 if (uFlags & LR_SHARED)
270 DbgPrint("FIXME: need LR_SHARED support in CreateIconFromResourceEx()\n");
274 TRACE("dwVersion, cxDesired, cyDesired are all ignored in this implementation!\n");
278 wXHotspot
= *(WORD
*)pbIconBits
;
279 pbIconBits
+= sizeof(WORD
);
280 wYHotspot
= *(WORD
*)pbIconBits
;
281 pbIconBits
+= sizeof(WORD
);
282 cbIconBits
-= 2 * sizeof(WORD
);
286 wXHotspot
= cxDesired
/ 2;
287 wYHotspot
= cyDesired
/ 2;
290 /* get an safe copy of the icon data */
291 SafeIconImage
= RtlAllocateHeap(GetProcessHeap(), 0, cbIconBits
);
292 if (SafeIconImage
== NULL
)
296 memcpy(SafeIconImage
, pbIconBits
, cbIconBits
);
298 /* take into acount the original height was for both the AND and XOR images */
300 SafeIconImage
->icHeader
.biHeight
/= 2;
302 if (SafeIconImage
->icHeader
.biSize
== sizeof(BITMAPCOREHEADER
))
304 BITMAPCOREHEADER
* Core
= (BITMAPCOREHEADER
*)SafeIconImage
;
305 ColourCount
= (Core
->bcBitCount
<= 8) ? (1 << Core
->bcBitCount
) : 0;
306 HeaderSize
= sizeof(BITMAPCOREHEADER
) + ColourCount
* sizeof(RGBTRIPLE
);
310 ColourCount
= (SafeIconImage
->icHeader
.biBitCount
<= 8) ?
311 (1 << SafeIconImage
->icHeader
.biBitCount
) : 0;
312 HeaderSize
= sizeof(BITMAPINFOHEADER
) + ColourCount
* sizeof(RGBQUAD
);
315 /* make data point to the start of the XOR image data */
316 Data
= (PBYTE
)SafeIconImage
+ HeaderSize
;
318 /* get a handle to the screen dc, the icon we create is going to be compatable with this */
319 // FIXME!!! This is a victim of the Win32k Initialization BUG!!!!!
320 //hScreenDc = CreateDCW(NULL, NULL, NULL, NULL);
321 hScreenDc
= CreateCompatibleDC(NULL
);
322 if (hScreenDc
== NULL
)
324 RtlFreeHeap(GetProcessHeap(), 0, SafeIconImage
);
329 hIcon
= ICON_CreateIconFromData(hScreenDc
, Data
, SafeIconImage
, cxDesired
, cyDesired
, wXHotspot
, wYHotspot
);
331 hIcon
= ICON_CreateCursorFromData(hScreenDc
, Data
, SafeIconImage
, cxDesired
, cyDesired
, wXHotspot
, wYHotspot
);
332 RtlFreeHeap(GetProcessHeap(), 0, SafeIconImage
);
344 CreateIconIndirect(PICONINFO IconInfo
)
352 SetLastError(ERROR_INVALID_PARAMETER
);
356 if(!GetObjectW(IconInfo
->hbmMask
, sizeof(BITMAP
), &MaskBitmap
))
361 /* Try to get color bitmap */
362 if (GetObjectW(IconInfo
->hbmColor
, sizeof(BITMAP
), &ColorBitmap
))
364 /* Compare size of color and mask bitmap*/
365 if (ColorBitmap
.bmWidth
!= MaskBitmap
.bmWidth
||
366 ColorBitmap
.bmHeight
!= MaskBitmap
.bmHeight
)
368 ERR("Color and mask size are different!");
369 SetLastError(ERROR_INVALID_PARAMETER
);
372 /* Check if color and mask are switched and switch them back */
373 if (MaskBitmap
.bmBitsPixel
!= 1 && ColorBitmap
.bmBitsPixel
== 1)
375 hbmTemp
= IconInfo
->hbmMask
;
376 IconInfo
->hbmMask
= IconInfo
->hbmColor
;
377 IconInfo
->hbmColor
= hbmTemp
;
380 return (HICON
)NtUserCreateCursorIconHandle(IconInfo
, TRUE
);
392 return (BOOL
)NtUserDestroyCursor((HANDLE
)hIcon
, 0);
407 return DrawIconEx(hDC
, X
, Y
, hIcon
, 0, 0, 0, NULL
, DI_NORMAL
| DI_DEFAULTSIZE
);
423 HBRUSH hbrFlickerFreeDraw
,
426 return (BOOL
)NtUserDrawIconEx(hdc
, xLeft
, yTop
, hIcon
, cxWidth
, cyWidth
,
427 istepIfAniCur
, hbrFlickerFreeDraw
, diFlags
,
441 return NtUserGetIconInfo((HANDLE
)hIcon
, IconInfo
, 0, 0, 0, 0);
454 return(LoadImageA(hInstance
, lpIconName
, IMAGE_ICON
, 0, 0, LR_SHARED
| LR_DEFAULTSIZE
));
467 return(LoadImageW(hInstance
, lpIconName
, IMAGE_ICON
, 0, 0, LR_SHARED
| LR_DEFAULTSIZE
));
476 LookupIconIdFromDirectory(
480 return LookupIconIdFromDirectoryEx(presbits
,
482 fIcon
? GetSystemMetrics(SM_CXICON
) : GetSystemMetrics(SM_CXCURSOR
),
483 fIcon
? GetSystemMetrics(SM_CYICON
) : GetSystemMetrics(SM_CYCURSOR
),
492 * The following macro function accounts for the irregularities of
493 * accessing cursor and icon resources in files and resource entries.
496 (*fnGetCIEntry
)(LPVOID dir
, int n
, int *width
, int *height
, int *bits
);
498 /**********************************************************************
499 * CURSORICON_FindBestIcon
501 * Find the icon closest to the requested size and number of colors.
504 CURSORICON_FindBestIcon(LPVOID dir
,
505 fnGetCIEntry get_entry
,
510 int i
, cx
, cy
, Bits
, BestBits
= 0, BestEntry
= -1;
511 UINT iTotalDiff
, iXDiff
=0, iYDiff
=0, iColorDiff
;
512 UINT iTempXDiff
, iTempYDiff
, iTempColorDiff
;
515 iTotalDiff
= 0xFFFFFFFF;
516 iColorDiff
= 0xFFFFFFFF;
517 for (i
= 0; get_entry(dir
, i
, &cx
, &cy
, &Bits
); i
++ )
519 iTempXDiff
= abs(Width
- cx
);
520 iTempYDiff
= abs(Height
- cy
);
522 if(iTotalDiff
> (iTempXDiff
+ iTempYDiff
))
526 iTotalDiff
= iXDiff
+ iYDiff
;
530 /* Find Best Colors for Best Fit */
531 for (i
= 0; get_entry(dir
, i
, &cx
, &cy
, &Bits
); i
++ )
533 if(abs(Width
- cx
) == iXDiff
&& abs(Height
- cy
) == iYDiff
)
535 iTempColorDiff
= abs(ColorBits
- Bits
);
536 if(iColorDiff
> iTempColorDiff
)
540 iColorDiff
= iTempColorDiff
;
545 TRACE("Best Icon: ResId: %d, bits : %d\n", BestEntry
, BestBits
);
552 /**********************************************************************
553 * CURSORICON_FindBestCursor
555 * Find the cursor closest to the requested size.
556 * FIXME: parameter 'color' ignored and entries with more than 1 bpp
560 CURSORICON_FindBestCursor(LPVOID dir
,
561 fnGetCIEntry get_entry
,
566 int i
, cx
, cy
, Bits
, BestBits
= 0, BestEntry
= -1;
567 UINT iTotalDiff
, iXDiff
=0, iYDiff
=0, iColorDiff
;
568 UINT iTempXDiff
, iTempYDiff
, iTempColorDiff
;
571 iTotalDiff
= 0xFFFFFFFF;
572 iColorDiff
= 0xFFFFFFFF;
573 for (i
= 0; get_entry(dir
, i
, &cx
, &cy
, &Bits
); i
++ )
575 iTempXDiff
= abs(Width
- cx
);
576 iTempYDiff
= abs(Height
- cy
);
578 if(iTotalDiff
> (iTempXDiff
+ iTempYDiff
))
582 iTotalDiff
= iXDiff
+ iYDiff
;
586 /* Find Best Colors for Best Fit */
587 for (i
= 0; get_entry(dir
, i
, &cx
, &cy
, &Bits
); i
++ )
589 if(abs(Width
- cx
) == iXDiff
&& abs(Height
- cy
) == iYDiff
)
591 iTempColorDiff
= abs(ColorBits
- Bits
);
592 if(iColorDiff
> iTempColorDiff
)
596 iColorDiff
= iTempColorDiff
;
601 TRACE("Best Cursor: ResId: %d, bits : %d\n", BestEntry
, BestBits
);
608 CURSORICON_GetResIconEntry(LPVOID dir
,
614 GRPCURSORICONDIR
*ResDir
= dir
;
617 if (ResDir
->idCount
<= n
)
620 Icon
= &ResDir
->idEntries
[n
].ResInfo
.icon
;
621 *Width
= Icon
->bWidth
;
622 *Height
= Icon
->bHeight
;
623 *Bits
= ResDir
->idEntries
[n
].wBitCount
;
628 CURSORICON_GetResCursorEntry(LPVOID dir
,
634 GRPCURSORICONDIR
*ResDir
= dir
;
635 CURSORRESDIR
*Cursor
;
637 if (ResDir
->idCount
<= n
)
640 Cursor
= &ResDir
->idEntries
[n
].ResInfo
.cursor
;
641 *Width
= Cursor
->wWidth
;
642 *Height
= Cursor
->wHeight
;
643 *Bits
= ResDir
->idEntries
[n
].wBitCount
;
647 static GRPCURSORICONDIRENTRY
*
648 CURSORICON_FindBestIconRes(GRPCURSORICONDIR
* dir
,
654 n
= CURSORICON_FindBestIcon(dir
,
655 CURSORICON_GetResIconEntry
,
662 return &dir
->idEntries
[n
];
665 static GRPCURSORICONDIRENTRY
*
666 CURSORICON_FindBestCursorRes(GRPCURSORICONDIR
*dir
,
672 n
= CURSORICON_FindBestCursor(dir
,
673 CURSORICON_GetResCursorEntry
,
680 return &dir
->idEntries
[n
];
685 LookupIconIdFromDirectoryEx(PBYTE xdir
,
691 GRPCURSORICONDIR
*dir
= (GRPCURSORICONDIR
*)xdir
;
696 if(dir
&& !dir
->idReserved
&& (IMAGE_ICON
== dir
->idType
|| IMAGE_CURSOR
== dir
->idType
))
698 GRPCURSORICONDIRENTRY
*entry
= NULL
;
701 if (cFlag
& LR_MONOCHROME
)
705 else if (cFlag
& LR_VGACOLOR
)
711 ColorBits
= g_psi
->BitsPixel
;
715 entry
= CURSORICON_FindBestIconRes(dir
, width
, height
, ColorBits
);
717 entry
= CURSORICON_FindBestCursorRes(dir
, width
, height
, 1);
723 WARN("%s() : Invalid resource directory\n", __FUNCTION__
);