Cleanup: Replace WINBOOL by BOOL
[reactos.git] / reactos / lib / user32 / windows / icon.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
4 *
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.
9 *
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.
14 *
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.
18 */
19 /* $Id: icon.c,v 1.18 2004/01/23 23:38:26 ekohl Exp $
20 *
21 * PROJECT: ReactOS user32.dll
22 * FILE: lib/user32/windows/icon.c
23 * PURPOSE: Icon
24 * PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
25 * UPDATE HISTORY:
26 * 09-05-2001 CSH Created
27 */
28
29 /* INCLUDES ******************************************************************/
30
31 #include <windows.h>
32 #include <user32.h>
33 #include <string.h>
34 #include <stdlib.h>
35 #include <debug.h>
36
37 /* FUNCTIONS *****************************************************************/
38
39 HICON
40 ICON_CreateIconFromData(HDC hDC, PVOID ImageData, ICONIMAGE* IconImage, int cxDesired, int cyDesired, int xHotspot, int yHotspot)
41 {
42 BITMAPINFO* bwBIH;
43 ICONINFO IconInfo;
44
45 IconInfo.fIcon = TRUE;
46 IconInfo.xHotspot = xHotspot;
47 IconInfo.yHotspot = yHotspot;
48
49 /* Load the XOR bitmap */
50 IconInfo.hbmColor = CreateDIBitmap(hDC, &IconImage->icHeader, CBM_INIT,
51 ImageData, (BITMAPINFO*)IconImage, DIB_RGB_COLORS);
52
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 );
57
58 /* create a BITMAPINFO header for the monocrome part of the icon */
59 bwBIH = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof (BITMAPINFOHEADER)+2*sizeof(RGBQUAD));
60
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;
73
74 bwBIH->bmiColors[0].rgbBlue = 0;
75 bwBIH->bmiColors[0].rgbGreen = 0;
76 bwBIH->bmiColors[0].rgbRed = 0;
77 bwBIH->bmiColors[0].rgbReserved = 0;
78
79 bwBIH->bmiColors[1].rgbBlue = 0xff;
80 bwBIH->bmiColors[1].rgbGreen = 0xff;
81 bwBIH->bmiColors[1].rgbRed = 0xff;
82 bwBIH->bmiColors[1].rgbReserved = 0;
83
84 /* load the AND bitmap */
85 IconInfo.hbmMask = CreateDIBitmap(hDC, &bwBIH->bmiHeader, 0,
86 ImageData, bwBIH, DIB_RGB_COLORS);
87
88 SetDIBits(hDC, IconInfo.hbmMask, 0, IconImage->icHeader.biHeight,
89 ImageData, bwBIH, DIB_RGB_COLORS);
90
91 RtlFreeHeap(RtlGetProcessHeap(), 0, bwBIH);
92
93 /* Create the icon based on everything we have so far */
94 return NtUserCreateCursorIconHandle(&IconInfo, FALSE);
95 }
96
97 HICON
98 ICON_CreateCursorFromData(HDC hDC, PVOID ImageData, ICONIMAGE* IconImage, int cxDesired, int cyDesired, int xHotspot, int yHotspot)
99 {
100 /* FIXME - color cursors */
101 BITMAPINFO* bwBIH;
102 ICONINFO IconInfo;
103 PVOID XORImageData = ImageData;
104
105 IconInfo.fIcon = TRUE;
106 IconInfo.xHotspot = xHotspot;
107 IconInfo.yHotspot = yHotspot;
108
109 /* create a BITMAPINFO header for the monocrome part of the icon */
110 bwBIH = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof (BITMAPINFOHEADER)+2*sizeof(RGBQUAD));
111
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;
124
125 bwBIH->bmiColors[0].rgbBlue = 0;
126 bwBIH->bmiColors[0].rgbGreen = 0;
127 bwBIH->bmiColors[0].rgbRed = 0;
128 bwBIH->bmiColors[0].rgbReserved = 0;
129
130 bwBIH->bmiColors[1].rgbBlue = 0xff;
131 bwBIH->bmiColors[1].rgbGreen = 0xff;
132 bwBIH->bmiColors[1].rgbRed = 0xff;
133 bwBIH->bmiColors[1].rgbReserved = 0;
134
135 /* load the AND bitmap */
136 IconInfo.hbmMask = CreateDIBitmap(hDC, &bwBIH->bmiHeader, 0,
137 XORImageData, bwBIH, DIB_RGB_COLORS);
138
139 if(IconInfo.hbmMask)
140 {
141 SetDIBits(hDC, IconInfo.hbmMask, 0, IconImage->icHeader.biHeight,
142 XORImageData, bwBIH, DIB_RGB_COLORS);
143
144 }
145
146 IconInfo.hbmColor = (HBITMAP)0;
147
148 RtlFreeHeap(RtlGetProcessHeap(), 0, bwBIH);
149
150 /* Create the icon based on everything we have so far */
151 return NtUserCreateCursorIconHandle(&IconInfo, FALSE);
152 }
153
154
155 /*
156 * @implemented
157 */
158 HICON
159 STDCALL
160 CopyIcon(
161 HICON hIcon)
162 {
163 ICONINFO IconInfo;
164
165 if(NtUserGetCursorIconInfo((HANDLE)hIcon, &IconInfo))
166 {
167 return NtUserCreateCursorIconHandle(&IconInfo, FALSE);
168 }
169 return (HICON)0;
170 }
171
172
173 /*
174 * @implemented
175 */
176 HICON
177 STDCALL
178 CreateIcon(
179 HINSTANCE hInstance,
180 int nWidth,
181 int nHeight,
182 BYTE cPlanes,
183 BYTE cBitsPixel,
184 CONST BYTE *ANDbits,
185 CONST BYTE *XORbits)
186 {
187 ICONINFO IconInfo;
188
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)
194 {
195 return (HICON)0;
196 }
197 IconInfo.hbmColor = CreateBitmap(nWidth, nHeight, cPlanes, cBitsPixel, XORbits);
198 if(!IconInfo.hbmColor)
199 {
200 DeleteObject(IconInfo.hbmMask);
201 return (HICON)0;
202 }
203
204 return NtUserCreateCursorIconHandle(&IconInfo, FALSE);
205 }
206
207
208 /*
209 * @implemented
210 */
211 HICON
212 STDCALL
213 CreateIconFromResource(
214 PBYTE presbits,
215 DWORD dwResSize,
216 BOOL fIcon,
217 DWORD dwVer)
218 {
219 return CreateIconFromResourceEx(presbits, dwResSize, fIcon, dwVer, 0, 0, 0);
220 }
221
222
223 /*
224 * @implemented
225 */
226 HICON
227 STDCALL
228 CreateIconFromResourceEx(
229 PBYTE pbIconBits,
230 DWORD cbIconBits,
231 BOOL fIcon,
232 DWORD dwVersion,
233 int cxDesired,
234 int cyDesired,
235 UINT uFlags)
236 {
237 ICONIMAGE* SafeIconImage;
238 HICON hIcon;
239 ULONG HeaderSize;
240 ULONG ColourCount;
241 PVOID Data;
242 HDC hScreenDc;
243 WORD wXHotspot;
244 WORD wYHotspot;
245
246 /*
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)
250 {
251 DbgPrint("FIXME: need LR_SHARED support in CreateIconFromResourceEx()\n");
252 }
253 */
254
255 DPRINT("dwVersion, cxDesired, cyDesired are all ignored in this implementation!\n");
256
257 if (! fIcon)
258 {
259 wXHotspot = (WORD)*pbIconBits;
260 pbIconBits+=2;
261 wYHotspot = (WORD)*pbIconBits;
262 pbIconBits+=2;
263 cbIconBits-=4;
264 }
265 else
266 {
267 wXHotspot = cxDesired / 2;
268 wYHotspot = cyDesired / 2;
269 }
270
271 /* get an safe copy of the icon data */
272 SafeIconImage = RtlAllocateHeap(RtlGetProcessHeap(), 0, cbIconBits);
273 memcpy(SafeIconImage, pbIconBits, cbIconBits);
274
275 /* take into acount the origonal height was for both the AND and XOR images */
276 if(fIcon)
277 SafeIconImage->icHeader.biHeight /= 2;
278
279 if (SafeIconImage->icHeader.biSize == sizeof(BITMAPCOREHEADER))
280 {
281 BITMAPCOREHEADER* Core = (BITMAPCOREHEADER*)SafeIconImage;
282 ColourCount = (Core->bcBitCount <= 8) ? (1 << Core->bcBitCount) : 0;
283 HeaderSize = sizeof(BITMAPCOREHEADER) + ColourCount * sizeof(RGBTRIPLE);
284 }
285 else
286 {
287 ColourCount = (SafeIconImage->icHeader.biBitCount <= 8) ?
288 (1 << SafeIconImage->icHeader.biBitCount) : 0;
289 HeaderSize = sizeof(BITMAPINFOHEADER) + ColourCount * sizeof(RGBQUAD);
290 }
291
292 /* make data point to the start of the XOR image data */
293 Data = (PBYTE)SafeIconImage + HeaderSize;
294
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)
298 {
299 RtlFreeHeap(RtlGetProcessHeap(), 0, SafeIconImage);
300 return(NULL);
301 }
302
303 if(fIcon)
304 hIcon = ICON_CreateIconFromData(hScreenDc, Data, SafeIconImage, cxDesired, cyDesired, wXHotspot, wYHotspot);
305 else
306 hIcon = ICON_CreateCursorFromData(hScreenDc, Data, SafeIconImage, cxDesired, cyDesired, wXHotspot, wYHotspot);
307 RtlFreeHeap(RtlGetProcessHeap(), 0, SafeIconImage);
308 DeleteDC(hScreenDc);
309
310 return hIcon;
311 }
312
313
314 /*
315 * @implemented
316 */
317 HICON
318 STDCALL
319 CreateIconIndirect(PICONINFO IconInfo)
320 {
321 BITMAP ColorBitmap;
322 BITMAP MaskBitmap;
323
324 if(!IconInfo)
325 {
326 SetLastError(ERROR_INVALID_PARAMETER);
327 return (HICON)0;
328 }
329
330 if(!GetObjectW(IconInfo->hbmMask, sizeof(BITMAP), &MaskBitmap))
331 {
332 return (HICON)0;
333 }
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))
336 {
337 return (HICON)0;
338 }
339
340 /* FIXME - i doubt this is right (monochrome cursors */
341 /*if(ColorBitmap.bmWidth != MaskBitmap.bmWidth ||
342 ColorBitmap.bmHeight != MaskBitmap.bmWidth)
343 {
344 SetLastError(ERROR_INVALID_PARAMETER);
345 return (HICON)0;
346 }*/
347
348 return (HICON)NtUserCreateCursorIconHandle(IconInfo, TRUE);
349 }
350
351
352 /*
353 * @implemented
354 */
355 BOOL
356 STDCALL
357 DestroyIcon(
358 HICON hIcon)
359 {
360 return (BOOL)NtUserDestroyCursorIcon((HANDLE)hIcon, 0);
361 }
362
363
364 /*
365 * @implemented
366 */
367 BOOL
368 STDCALL
369 DrawIcon(
370 HDC hDC,
371 int X,
372 int Y,
373 HICON hIcon)
374 {
375 return DrawIconEx(hDC, X, Y, hIcon, 0, 0, 0, NULL, DI_NORMAL | DI_DEFAULTSIZE);
376 }
377
378 /*
379 * @implemented
380 */
381 BOOL
382 STDCALL
383 DrawIconEx(
384 HDC hdc,
385 int xLeft,
386 int yTop,
387 HICON hIcon,
388 int cxWidth,
389 int cyWidth,
390 UINT istepIfAniCur,
391 HBRUSH hbrFlickerFreeDraw,
392 UINT diFlags)
393 {
394 return (BOOL)NtUserDrawIconEx(hdc, xLeft, yTop, hIcon, cxWidth, cyWidth,
395 istepIfAniCur, hbrFlickerFreeDraw, diFlags,
396 0, 0);
397 }
398
399
400 /*
401 * @implemented
402 */
403 BOOL
404 STDCALL
405 GetIconInfo(
406 HICON hIcon,
407 PICONINFO IconInfo)
408 {
409 /* FIXME - copy bitmaps */
410 return (BOOL)NtUserGetCursorIconInfo((HANDLE)hIcon, IconInfo);
411 }
412
413
414 /*
415 * @implemented
416 */
417 HICON
418 STDCALL
419 LoadIconA(
420 HINSTANCE hInstance,
421 LPCSTR lpIconName)
422 {
423 return(LoadImageA(hInstance, lpIconName, IMAGE_ICON, 0, 0, LR_SHARED | LR_DEFAULTSIZE));
424 }
425
426
427 /*
428 * @implemented
429 */
430 HICON
431 STDCALL
432 LoadIconW(
433 HINSTANCE hInstance,
434 LPCWSTR lpIconName)
435 {
436 return(LoadImageW(hInstance, lpIconName, IMAGE_ICON, 0, 0, LR_SHARED | LR_DEFAULTSIZE));
437 }
438
439
440 /*
441 * @implemented
442 */
443 int
444 STDCALL
445 LookupIconIdFromDirectory(
446 PBYTE presbits,
447 BOOL fIcon)
448 {
449 return LookupIconIdFromDirectoryEx( presbits, fIcon,
450 fIcon ? GetSystemMetrics(SM_CXICON) : GetSystemMetrics(SM_CXCURSOR),
451 fIcon ? GetSystemMetrics(SM_CYICON) : GetSystemMetrics(SM_CYCURSOR), LR_DEFAULTCOLOR );
452 }
453
454 /* Ported from WINE20030408 */
455 GRPCURSORICONDIRENTRY*
456 CURSORICON_FindBestCursor( GRPCURSORICONDIR *dir, int width, int height, int colors)
457 {
458 int i;
459 GRPCURSORICONDIRENTRY *entry, *bestEntry = NULL;
460 UINT iTotalDiff, iXDiff=0, iYDiff=0, iColorDiff;
461 UINT iTempXDiff, iTempYDiff, iTempColorDiff;
462
463 if (dir->idCount < 1)
464 {
465 DPRINT("Empty directory!\n");
466 return NULL;
467 }
468 if (dir->idCount == 1)
469 return &dir->idEntries[0]; /* No choice... */
470
471 /* Find Best Fit */
472 iTotalDiff = 0xFFFFFFFF;
473 iColorDiff = 0xFFFFFFFF;
474 for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
475 {
476 iTempXDiff = abs(width - entry->ResInfo.icon.bWidth);
477 iTempYDiff = abs(height - entry->ResInfo.icon.bHeight);
478
479 if(iTotalDiff > (iTempXDiff + iTempYDiff))
480 {
481 iXDiff = iTempXDiff;
482 iYDiff = iTempYDiff;
483 iTotalDiff = iXDiff + iYDiff;
484 }
485 }
486
487 /* Find Best Colors for Best Fit */
488 for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
489 {
490 if(abs(width - entry->ResInfo.icon.bWidth) == (int) iXDiff &&
491 abs(height - entry->ResInfo.icon.bHeight) == (int) iYDiff)
492 {
493 iTempColorDiff = abs(colors - entry->ResInfo.icon.bColorCount);
494
495 if(iColorDiff > iTempColorDiff)
496 {
497 bestEntry = entry;
498 iColorDiff = iTempColorDiff;
499 }
500 }
501 }
502
503 return bestEntry;
504 }
505
506 /* Ported from WINE20030408 */
507 GRPCURSORICONDIRENTRY*
508 CURSORICON_FindBestIcon( GRPCURSORICONDIR *dir, int width, int height, int colors)
509 {
510 int i;
511 GRPCURSORICONDIRENTRY *entry, *bestEntry = NULL;
512 UINT iTotalDiff, iXDiff=0, iYDiff=0, iColorDiff;
513 UINT iTempXDiff, iTempYDiff, iTempColorDiff;
514
515 if (dir->idCount < 1)
516 {
517 DPRINT("Empty directory!\n");
518 return NULL;
519 }
520 if (dir->idCount == 1)
521 return &dir->idEntries[0]; /* No choice... */
522
523 /* Find Best Fit */
524 iTotalDiff = 0xFFFFFFFF;
525 iColorDiff = 0xFFFFFFFF;
526 for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
527 {
528 iTempXDiff = abs(width - entry->ResInfo.icon.bWidth);
529
530 iTempYDiff = abs(height - entry->ResInfo.icon.bHeight);
531
532 if(iTotalDiff > (iTempXDiff + iTempYDiff))
533 {
534 iXDiff = iTempXDiff;
535 iYDiff = iTempYDiff;
536 iTotalDiff = iXDiff + iYDiff;
537 }
538 }
539
540 /* Find Best Colors for Best Fit */
541 for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
542 {
543 if(abs(width - entry->ResInfo.icon.bWidth) == (int) iXDiff &&
544 abs(height - entry->ResInfo.icon.bHeight) == (int) iYDiff)
545 {
546 iTempColorDiff = abs(colors - entry->ResInfo.icon.bColorCount);
547 if(iColorDiff > iTempColorDiff)
548 {
549 bestEntry = entry;
550 iColorDiff = iTempColorDiff;
551 }
552 }
553 }
554
555 return bestEntry;
556 }
557
558 /* Ported from WINE20030408 */
559 /*
560 * @implemented
561 */
562 INT STDCALL
563 LookupIconIdFromDirectoryEx(
564 PBYTE presbits,
565 BOOL fIcon,
566 int cxDesired,
567 int cyDesired,
568 UINT Flags)
569 {
570 GRPCURSORICONDIR *dir = (GRPCURSORICONDIR*)presbits;
571 UINT retVal = 0;
572
573 if (dir && !dir->idReserved && (dir->idType & 3))
574 {
575 GRPCURSORICONDIRENTRY *entry;
576 HDC hdc;
577 int colors;
578
579 hdc = GetDC(0);
580 if (Flags & LR_MONOCHROME)
581 {
582 colors = 2;
583 }
584 else
585 {
586 colors = GetDeviceCaps(hdc, BITSPIXEL);
587 if (colors > 8)
588 colors = 256;
589 else
590 colors = 1 << colors;
591 }
592 ReleaseDC(0, hdc);
593
594 entry = CURSORICON_FindBestIcon( dir, cxDesired, cyDesired, colors );
595
596 if (entry)
597 retVal = entry->nID;
598 }
599 else
600 {
601 DbgPrint("invalid resource directory\n");
602 }
603 return retVal;
604 }