Sync to trunk head(r38096)
[reactos.git] / reactos / dll / win32 / 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$
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 <user32.h>
32
33 #include <wine/debug.h>
34 WINE_DEFAULT_DEBUG_CHANNEL(user32);
35
36 /* FUNCTIONS *****************************************************************/
37
38
39 HICON
40 ICON_CreateIconFromData(HDC hDC, PVOID ImageData, ICONIMAGE* IconImage, int cxDesired, int cyDesired, int xHotspot, int yHotspot)
41 {
42 BYTE BitmapInfoBuffer[sizeof(BITMAPINFOHEADER) + 2 * sizeof(RGBQUAD)];
43 BITMAPINFO *bwBIH = (BITMAPINFO *)BitmapInfoBuffer;
44 ICONINFO IconInfo;
45
46 IconInfo.fIcon = TRUE;
47 IconInfo.xHotspot = xHotspot;
48 IconInfo.yHotspot = yHotspot;
49
50 /* Load the XOR bitmap */
51 IconInfo.hbmColor = CreateDIBitmap(hDC, &IconImage->icHeader, CBM_INIT,
52 ImageData, (BITMAPINFO*)IconImage,
53 DIB_RGB_COLORS);
54
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 );
59
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;
72
73 bwBIH->bmiColors[0].rgbBlue = 0;
74 bwBIH->bmiColors[0].rgbGreen = 0;
75 bwBIH->bmiColors[0].rgbRed = 0;
76 bwBIH->bmiColors[0].rgbReserved = 0;
77
78 bwBIH->bmiColors[1].rgbBlue = 0xff;
79 bwBIH->bmiColors[1].rgbGreen = 0xff;
80 bwBIH->bmiColors[1].rgbRed = 0xff;
81 bwBIH->bmiColors[1].rgbReserved = 0;
82
83 /* Load the AND bitmap. */
84 IconInfo.hbmMask = CreateDIBitmap(hDC, &bwBIH->bmiHeader, 0,
85 ImageData, bwBIH, DIB_RGB_COLORS);
86
87 SetDIBits(hDC, IconInfo.hbmMask, 0, IconImage->icHeader.biHeight,
88 ImageData, bwBIH, DIB_RGB_COLORS);
89
90 /* Create the icon based on everything we have so far */
91 return NtUserCreateCursorIconHandle(&IconInfo, FALSE);
92 }
93
94 HICON
95 ICON_CreateCursorFromData(HDC hDC, PVOID ImageData, ICONIMAGE* IconImage, int cxDesired, int cyDesired, int xHotspot, int yHotspot)
96 {
97 /* FIXME - color cursors */
98 BYTE BitmapInfoBuffer[sizeof(BITMAPINFOHEADER) + 2 * sizeof(RGBQUAD)];
99 BITMAPINFO *bwBIH = (BITMAPINFO *)BitmapInfoBuffer;
100 ICONINFO IconInfo;
101 PVOID XORImageData = ImageData;
102
103 IconInfo.fIcon = FALSE;
104 IconInfo.xHotspot = xHotspot;
105 IconInfo.yHotspot = yHotspot;
106
107 /* Create a BITMAPINFO header for the monocrome 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;
119
120 bwBIH->bmiColors[0].rgbBlue = 0;
121 bwBIH->bmiColors[0].rgbGreen = 0;
122 bwBIH->bmiColors[0].rgbRed = 0;
123 bwBIH->bmiColors[0].rgbReserved = 0;
124
125 bwBIH->bmiColors[1].rgbBlue = 0xff;
126 bwBIH->bmiColors[1].rgbGreen = 0xff;
127 bwBIH->bmiColors[1].rgbRed = 0xff;
128 bwBIH->bmiColors[1].rgbReserved = 0;
129
130 /* Load the AND bitmap */
131 IconInfo.hbmMask = CreateDIBitmap(hDC, &bwBIH->bmiHeader, 0,
132 XORImageData, bwBIH, DIB_RGB_COLORS);
133 if (IconInfo.hbmMask)
134 {
135 SetDIBits(hDC, IconInfo.hbmMask, 0, IconImage->icHeader.biHeight,
136 XORImageData, bwBIH, DIB_RGB_COLORS);
137 }
138
139 IconInfo.hbmColor = (HBITMAP)0;
140
141 /* Create the icon based on everything we have so far */
142 return NtUserCreateCursorIconHandle(&IconInfo, FALSE);
143 }
144
145
146 /*
147 * @implemented
148 */
149 HICON
150 WINAPI
151 CopyIcon(HICON hIcon)
152 {
153 HICON hRetIcon = NULL;
154 ICONINFO IconInfo;
155
156 if(GetIconInfo(hIcon, &IconInfo))
157 {
158 hRetIcon = CreateIconIndirect(&IconInfo);
159 DeleteObject(IconInfo.hbmColor);
160 DeleteObject(IconInfo.hbmMask);
161 }
162
163 return hRetIcon;
164 }
165
166
167 /*
168 * @implemented
169 */
170 HICON
171 WINAPI
172 CreateIcon(
173 HINSTANCE hInstance,
174 int nWidth,
175 int nHeight,
176 BYTE cPlanes,
177 BYTE cBitsPixel,
178 CONST BYTE *ANDbits,
179 CONST BYTE *XORbits)
180 {
181 ICONINFO IconInfo;
182
183 IconInfo.fIcon = TRUE;
184 IconInfo.xHotspot = nWidth / 2;
185 IconInfo.yHotspot = nHeight / 2;
186 IconInfo.hbmMask = CreateBitmap(nWidth, nHeight, 1, 1, ANDbits);
187 if(!IconInfo.hbmMask)
188 {
189 return (HICON)0;
190 }
191 IconInfo.hbmColor = CreateBitmap(nWidth, nHeight, cPlanes, cBitsPixel, XORbits);
192 if(!IconInfo.hbmColor)
193 {
194 DeleteObject(IconInfo.hbmMask);
195 return (HICON)0;
196 }
197
198 return NtUserCreateCursorIconHandle(&IconInfo, FALSE);
199 }
200
201
202 /*
203 * @implemented
204 */
205 HICON
206 WINAPI
207 CreateIconFromResource(
208 PBYTE presbits,
209 DWORD dwResSize,
210 BOOL fIcon,
211 DWORD dwVer)
212 {
213 return CreateIconFromResourceEx(presbits, dwResSize, fIcon, dwVer, 0, 0, LR_DEFAULTSIZE|LR_SHARED );
214 }
215
216
217 /*
218 * @implemented
219 */
220 HICON
221 WINAPI
222 CreateIconFromResourceEx(
223 PBYTE pbIconBits,
224 DWORD cbIconBits,
225 BOOL fIcon,
226 DWORD dwVersion,
227 int cxDesired,
228 int cyDesired,
229 UINT uFlags)
230 {
231 ICONIMAGE* SafeIconImage;
232 HICON hIcon;
233 ULONG HeaderSize;
234 ULONG ColourCount;
235 PVOID Data;
236 HDC hScreenDc;
237 WORD wXHotspot;
238 WORD wYHotspot;
239
240 /*
241 FIXME - does win support LR_SHARED? According to msdn it does but we don't
242 have useful information to identify the icon
243 if (uFlags & LR_SHARED)
244 {
245 DbgPrint("FIXME: need LR_SHARED support in CreateIconFromResourceEx()\n");
246 }
247 */
248
249 TRACE("dwVersion, cxDesired, cyDesired are all ignored in this implementation!\n");
250
251 if (! fIcon)
252 {
253 wXHotspot = *(WORD*)pbIconBits;
254 pbIconBits += sizeof(WORD);
255 wYHotspot = *(WORD*)pbIconBits;
256 pbIconBits += sizeof(WORD);
257 cbIconBits -= 2 * sizeof(WORD);
258 }
259 else
260 {
261 wXHotspot = cxDesired / 2;
262 wYHotspot = cyDesired / 2;
263 }
264
265 /* get an safe copy of the icon data */
266 SafeIconImage = RtlAllocateHeap(GetProcessHeap(), 0, cbIconBits);
267 if (SafeIconImage == NULL)
268 {
269 return NULL;
270 }
271 memcpy(SafeIconImage, pbIconBits, cbIconBits);
272
273 /* take into acount the original height was for both the AND and XOR images */
274 if(fIcon)
275 SafeIconImage->icHeader.biHeight /= 2;
276
277 if (SafeIconImage->icHeader.biSize == sizeof(BITMAPCOREHEADER))
278 {
279 BITMAPCOREHEADER* Core = (BITMAPCOREHEADER*)SafeIconImage;
280 ColourCount = (Core->bcBitCount <= 8) ? (1 << Core->bcBitCount) : 0;
281 HeaderSize = sizeof(BITMAPCOREHEADER) + ColourCount * sizeof(RGBTRIPLE);
282 }
283 else
284 {
285 ColourCount = (SafeIconImage->icHeader.biBitCount <= 8) ?
286 (1 << SafeIconImage->icHeader.biBitCount) : 0;
287 HeaderSize = sizeof(BITMAPINFOHEADER) + ColourCount * sizeof(RGBQUAD);
288 }
289
290 /* make data point to the start of the XOR image data */
291 Data = (PBYTE)SafeIconImage + HeaderSize;
292
293 /* get a handle to the screen dc, the icon we create is going to be compatable with this */
294 // FIXME!!! This is a victim of the Win32k Initialization BUG!!!!!
295 //hScreenDc = CreateDCW(NULL, NULL, NULL, NULL);
296 hScreenDc = CreateCompatibleDC(NULL);
297 if (hScreenDc == NULL)
298 {
299 RtlFreeHeap(GetProcessHeap(), 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(GetProcessHeap(), 0, SafeIconImage);
308 DeleteDC(hScreenDc);
309
310 return hIcon;
311 }
312
313
314 /*
315 * @implemented
316 */
317 HICON
318 WINAPI
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 WINAPI
357 DestroyIcon(
358 HICON hIcon)
359 {
360 return (BOOL)NtUserDestroyCursor((HANDLE)hIcon, 0);
361 }
362
363
364 /*
365 * @implemented
366 */
367 BOOL
368 WINAPI
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 WINAPI
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 WINAPI
405 GetIconInfo(
406 HICON hIcon,
407 PICONINFO IconInfo)
408 {
409 return NtUserGetIconInfo((HANDLE)hIcon, IconInfo, 0, 0, 0, 0);
410 }
411
412
413 /*
414 * @implemented
415 */
416 HICON
417 WINAPI
418 LoadIconA(
419 HINSTANCE hInstance,
420 LPCSTR lpIconName)
421 {
422 return(LoadImageA(hInstance, lpIconName, IMAGE_ICON, 0, 0, LR_SHARED | LR_DEFAULTSIZE));
423 }
424
425
426 /*
427 * @implemented
428 */
429 HICON
430 WINAPI
431 LoadIconW(
432 HINSTANCE hInstance,
433 LPCWSTR lpIconName)
434 {
435 return(LoadImageW(hInstance, lpIconName, IMAGE_ICON, 0, 0, LR_SHARED | LR_DEFAULTSIZE));
436 }
437
438
439 /*
440 * @implemented
441 */
442 int
443 WINAPI
444 LookupIconIdFromDirectory(
445 PBYTE presbits,
446 BOOL fIcon)
447 {
448 return LookupIconIdFromDirectoryEx(presbits,
449 fIcon,
450 fIcon ? GetSystemMetrics(SM_CXICON) : GetSystemMetrics(SM_CXCURSOR),
451 fIcon ? GetSystemMetrics(SM_CYICON) : GetSystemMetrics(SM_CYCURSOR),
452 LR_DEFAULTCOLOR);
453 }
454
455
456
457
458
459 /*
460 * The following macro function accounts for the irregularities of
461 * accessing cursor and icon resources in files and resource entries.
462 */
463 typedef BOOL
464 (*fnGetCIEntry)(LPVOID dir, int n, int *width, int *height, int *bits );
465
466 /**********************************************************************
467 * CURSORICON_FindBestIcon
468 *
469 * Find the icon closest to the requested size and number of colors.
470 */
471 static int
472 CURSORICON_FindBestIcon(LPVOID dir,
473 fnGetCIEntry get_entry,
474 int Width,
475 int Height,
476 int ColorBits)
477 {
478 int i, cx, cy, Bits, BestBits = 0, BestEntry = -1;
479 UINT iTotalDiff, iXDiff=0, iYDiff=0, iColorDiff;
480 UINT iTempXDiff, iTempYDiff, iTempColorDiff;
481
482 /* Find Best Fit */
483 iTotalDiff = 0xFFFFFFFF;
484 iColorDiff = 0xFFFFFFFF;
485 for (i = 0; get_entry(dir, i, &cx, &cy, &Bits); i++ )
486 {
487 iTempXDiff = abs(Width - cx);
488 iTempYDiff = abs(Height - cy);
489
490 if(iTotalDiff > (iTempXDiff + iTempYDiff))
491 {
492 iXDiff = iTempXDiff;
493 iYDiff = iTempYDiff;
494 iTotalDiff = iXDiff + iYDiff;
495 }
496 }
497
498 /* Find Best Colors for Best Fit */
499 for (i = 0; get_entry(dir, i, &cx, &cy, &Bits); i++ )
500 {
501 if(abs(Width - cx) == iXDiff && abs(Height - cy) == iYDiff)
502 {
503 iTempColorDiff = abs(ColorBits - Bits);
504 if(iColorDiff > iTempColorDiff)
505 {
506 BestEntry = i;
507 BestBits = Bits;
508 iColorDiff = iTempColorDiff;
509 }
510 }
511 }
512
513 TRACE("Best Icon: ResId: %d, bits : %d\n", BestEntry, BestBits);
514
515 return BestEntry;
516 }
517
518
519
520 /**********************************************************************
521 * CURSORICON_FindBestCursor
522 *
523 * Find the cursor closest to the requested size.
524 * FIXME: parameter 'color' ignored and entries with more than 1 bpp
525 * ignored too
526 */
527 static int
528 CURSORICON_FindBestCursor(LPVOID dir,
529 fnGetCIEntry get_entry,
530 int Width,
531 int Height,
532 int ColorBits)
533 {
534 int i, cx, cy, Bits, BestBits = 0, BestEntry = -1;
535 UINT iTotalDiff, iXDiff=0, iYDiff=0, iColorDiff;
536 UINT iTempXDiff, iTempYDiff, iTempColorDiff;
537
538 /* Find Best Fit */
539 iTotalDiff = 0xFFFFFFFF;
540 iColorDiff = 0xFFFFFFFF;
541 for (i = 0; get_entry(dir, i, &cx, &cy, &Bits); i++ )
542 {
543 iTempXDiff = abs(Width - cx);
544 iTempYDiff = abs(Height - cy);
545
546 if(iTotalDiff > (iTempXDiff + iTempYDiff))
547 {
548 iXDiff = iTempXDiff;
549 iYDiff = iTempYDiff;
550 iTotalDiff = iXDiff + iYDiff;
551 }
552 }
553
554 /* Find Best Colors for Best Fit */
555 for (i = 0; get_entry(dir, i, &cx, &cy, &Bits); i++ )
556 {
557 if(abs(Width - cx) == iXDiff && abs(Height - cy) == iYDiff)
558 {
559 iTempColorDiff = abs(ColorBits - Bits);
560 if(iColorDiff > iTempColorDiff)
561 {
562 BestEntry = i;
563 BestBits = Bits;
564 iColorDiff = iTempColorDiff;
565 }
566 }
567 }
568
569 TRACE("Best Cursor: ResId: %d, bits : %d\n", BestEntry, BestBits);
570
571 return BestEntry;
572 }
573
574
575 static BOOL
576 CURSORICON_GetResIconEntry(LPVOID dir,
577 int n,
578 int *Width,
579 int *Height,
580 int *Bits)
581 {
582 GRPCURSORICONDIR *ResDir = dir;
583 ICONRESDIR *Icon;
584
585 if (ResDir->idCount <= n)
586 return FALSE;
587
588 Icon = &ResDir->idEntries[n].ResInfo.icon;
589 *Width = Icon->bWidth;
590 *Height = Icon->bHeight;
591 *Bits = ResDir->idEntries[n].wBitCount;
592 return TRUE;
593 }
594
595 static BOOL
596 CURSORICON_GetResCursorEntry(LPVOID dir,
597 int n,
598 int *Width,
599 int *Height,
600 int *Bits)
601 {
602 GRPCURSORICONDIR *ResDir = dir;
603 CURSORRESDIR *Cursor;
604
605 if (ResDir->idCount <= n)
606 return FALSE;
607
608 Cursor = &ResDir->idEntries[n].ResInfo.cursor;
609 *Width = Cursor->wWidth;
610 *Height = Cursor->wHeight;
611 *Bits = ResDir->idEntries[n].wBitCount;
612 return TRUE;
613 }
614
615 static GRPCURSORICONDIRENTRY *
616 CURSORICON_FindBestIconRes(GRPCURSORICONDIR * dir,
617 int Width,
618 int Height,
619 int ColorBits)
620 {
621 int n;
622 n = CURSORICON_FindBestIcon(dir,
623 CURSORICON_GetResIconEntry,
624 Width,
625 Height,
626 ColorBits);
627 if (n < 0)
628 return NULL;
629
630 return &dir->idEntries[n];
631 }
632
633 static GRPCURSORICONDIRENTRY *
634 CURSORICON_FindBestCursorRes(GRPCURSORICONDIR *dir,
635 int Width,
636 int Height,
637 int ColorBits)
638 {
639 int n;
640 n = CURSORICON_FindBestCursor(dir,
641 CURSORICON_GetResCursorEntry,
642 Width,
643 Height,
644 ColorBits);
645 if (n < 0)
646 return NULL;
647
648 return &dir->idEntries[n];
649 }
650
651
652 INT WINAPI
653 LookupIconIdFromDirectoryEx(PBYTE xdir,
654 BOOL bIcon,
655 INT width,
656 INT height,
657 UINT cFlag)
658 {
659 GRPCURSORICONDIR *dir = (GRPCURSORICONDIR*)xdir;
660 UINT retVal = 0;
661 if(dir && !dir->idReserved && (IMAGE_ICON == dir->idType || IMAGE_CURSOR == dir->idType))
662 {
663 GRPCURSORICONDIRENTRY *entry = NULL;
664 int ColorBits;
665
666 if (cFlag & LR_MONOCHROME)
667 {
668 ColorBits = 1;
669 }
670 else
671 {
672 HDC hdc = CreateICW(NULL, NULL, NULL, NULL);
673 ColorBits = GetDeviceCaps(hdc, BITSPIXEL);
674 DeleteDC(hdc);
675 }
676
677 if(bIcon)
678 entry = CURSORICON_FindBestIconRes(dir, width, height, ColorBits);
679 else
680 entry = CURSORICON_FindBestCursorRes(dir, width, height, 1);
681
682 if (entry)
683 retVal = entry->nID;
684 }
685 else
686 WARN("%s() : Invalid resource directory\n", __FUNCTION__);
687
688 return retVal;
689 }