5840b89a01a893087122713f65cd06d372e2073b
[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 CreateCursorIconFromData(HDC hDC, PVOID ImageData, ICONIMAGE* IconImage, int cxDesired, int cyDesired, int xHotspot, int yHotspot, BOOL fIcon)
41 {
42 BYTE BitmapInfoBuffer[sizeof(BITMAPINFOHEADER) + 2 * sizeof(RGBQUAD)];
43 BITMAPINFO *bwBIH = (BITMAPINFO *)BitmapInfoBuffer;
44 ICONINFO IconInfo;
45
46 IconInfo.fIcon = fIcon;
47 IconInfo.xHotspot = xHotspot;
48 IconInfo.yHotspot = yHotspot;
49
50 if (IconImage->icHeader.biBitCount == 1)
51 {
52 IconInfo.hbmColor = (HBITMAP)0;
53 IconImage->icHeader.biHeight *= 2;
54 IconInfo.hbmMask = CreateDIBitmap(hDC, &IconImage->icHeader, CBM_INIT,
55 ImageData, (BITMAPINFO*)IconImage,
56 DIB_RGB_COLORS);
57 }
58 else
59 {
60 /* Create the XOR bitmap */
61 IconInfo.hbmColor = CreateDIBitmap(hDC, &IconImage->icHeader, CBM_INIT,
62 ImageData, (BITMAPINFO*)IconImage,
63 DIB_RGB_COLORS);
64
65 /* Make ImageData point to the start of the AND image data. */
66 ImageData = ((PBYTE)ImageData) + (((IconImage->icHeader.biWidth *
67 IconImage->icHeader.biBitCount + 31) & ~31) >> 3) *
68 (IconImage->icHeader.biHeight );
69
70 /* Create a BITMAPINFO header for the monochrome part of the icon. */
71 bwBIH->bmiHeader.biBitCount = 1;
72 bwBIH->bmiHeader.biWidth = IconImage->icHeader.biWidth;
73 bwBIH->bmiHeader.biHeight = IconImage->icHeader.biHeight;
74 bwBIH->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
75 bwBIH->bmiHeader.biPlanes = 1;
76 bwBIH->bmiHeader.biSizeImage = 0;
77 bwBIH->bmiHeader.biCompression = BI_RGB;
78 bwBIH->bmiHeader.biClrImportant = 0;
79 bwBIH->bmiHeader.biClrUsed = 0;
80 bwBIH->bmiHeader.biXPelsPerMeter = 0;
81 bwBIH->bmiHeader.biYPelsPerMeter = 0;
82
83 bwBIH->bmiColors[0].rgbBlue = 0;
84 bwBIH->bmiColors[0].rgbGreen = 0;
85 bwBIH->bmiColors[0].rgbRed = 0;
86 bwBIH->bmiColors[0].rgbReserved = 0;
87
88 bwBIH->bmiColors[1].rgbBlue = 0xff;
89 bwBIH->bmiColors[1].rgbGreen = 0xff;
90 bwBIH->bmiColors[1].rgbRed = 0xff;
91 bwBIH->bmiColors[1].rgbReserved = 0;
92
93 /* Create the AND bitmap. */
94 IconInfo.hbmMask = CreateDIBitmap(hDC, &bwBIH->bmiHeader, 0,
95 ImageData, bwBIH, DIB_RGB_COLORS);
96
97 SetDIBits(hDC, IconInfo.hbmMask, 0, IconImage->icHeader.biHeight,
98 ImageData, bwBIH, DIB_RGB_COLORS);
99 }
100
101
102 /* Create the icon based on everything we have so far */
103 return NtUserCreateCursorIconHandle(&IconInfo, FALSE);
104 }
105
106 /*
107 * @implemented
108 */
109 HICON
110 WINAPI
111 CopyIcon(HICON hIcon)
112 {
113 HICON hRetIcon = NULL;
114 ICONINFO IconInfo;
115
116 if(GetIconInfo(hIcon, &IconInfo))
117 {
118 hRetIcon = CreateIconIndirect(&IconInfo);
119 DeleteObject(IconInfo.hbmColor);
120 DeleteObject(IconInfo.hbmMask);
121 }
122
123 return hRetIcon;
124 }
125
126
127 /*
128 * @implemented
129 */
130 HICON
131 WINAPI
132 CreateIcon(
133 HINSTANCE hInstance,
134 int nWidth,
135 int nHeight,
136 BYTE cPlanes,
137 BYTE cBitsPixel,
138 CONST BYTE *ANDbits,
139 CONST BYTE *XORbits)
140 {
141 ICONINFO IconInfo;
142
143 IconInfo.fIcon = TRUE;
144
145 if (cBitsPixel == 1)
146 {
147 nHeight <<= 1;
148 }
149 IconInfo.hbmMask = CreateBitmap(nWidth, nHeight, 1, 1, ANDbits);
150 if(!IconInfo.hbmMask)
151 {
152 return (HICON)0;
153 }
154
155 if (cBitsPixel == 1)
156 {
157 IconInfo.hbmColor = (HBITMAP)0;
158 }
159 else
160 {
161 IconInfo.hbmColor = CreateBitmap(nWidth, nHeight, cPlanes, cBitsPixel, XORbits);
162 if(!IconInfo.hbmColor)
163 {
164 DeleteObject(IconInfo.hbmMask);
165 return (HICON)0;
166 }
167 }
168
169 return NtUserCreateCursorIconHandle(&IconInfo, FALSE);
170 }
171
172
173 /*
174 * @implemented
175 */
176 HICON
177 WINAPI
178 CreateIconFromResource(
179 PBYTE presbits,
180 DWORD dwResSize,
181 BOOL fIcon,
182 DWORD dwVer)
183 {
184 return CreateIconFromResourceEx(presbits, dwResSize, fIcon, dwVer, 0, 0, LR_DEFAULTSIZE|LR_SHARED );
185 }
186
187
188 /*
189 * @implemented
190 */
191 HICON
192 WINAPI
193 CreateIconFromResourceEx(
194 PBYTE pbIconBits,
195 DWORD cbIconBits,
196 BOOL fIcon,
197 DWORD dwVersion,
198 int cxDesired,
199 int cyDesired,
200 UINT uFlags)
201 {
202 ICONIMAGE* SafeIconImage;
203 HICON hIcon;
204 ULONG HeaderSize;
205 ULONG ColourCount;
206 PVOID Data;
207 HDC hScreenDc;
208 WORD wXHotspot;
209 WORD wYHotspot;
210
211 /*
212 FIXME - does win support LR_SHARED? According to msdn it does but we don't
213 have useful information to identify the icon
214 if (uFlags & LR_SHARED)
215 {
216 DbgPrint("FIXME: need LR_SHARED support in CreateIconFromResourceEx()\n");
217 }
218 */
219
220 TRACE("dwVersion, cxDesired, cyDesired are all ignored in this implementation!\n");
221
222 if (! fIcon)
223 {
224 wXHotspot = *(WORD*)pbIconBits;
225 pbIconBits += sizeof(WORD);
226 wYHotspot = *(WORD*)pbIconBits;
227 pbIconBits += sizeof(WORD);
228 cbIconBits -= 2 * sizeof(WORD);
229 }
230 else
231 {
232 wXHotspot = cxDesired / 2;
233 wYHotspot = cyDesired / 2;
234 }
235
236 /* get an safe copy of the icon data */
237 SafeIconImage = RtlAllocateHeap(GetProcessHeap(), 0, cbIconBits);
238 if (SafeIconImage == NULL)
239 {
240 return NULL;
241 }
242 memcpy(SafeIconImage, pbIconBits, cbIconBits);
243
244 /* Take into acount the original height was for both the AND and XOR images */
245 SafeIconImage->icHeader.biHeight /= 2;
246
247 if (SafeIconImage->icHeader.biSize == sizeof(BITMAPCOREHEADER))
248 {
249 BITMAPCOREHEADER* Core = (BITMAPCOREHEADER*)SafeIconImage;
250 ColourCount = (Core->bcBitCount <= 8) ? (1 << Core->bcBitCount) : 0;
251 HeaderSize = sizeof(BITMAPCOREHEADER) + ColourCount * sizeof(RGBTRIPLE);
252 }
253 else
254 {
255 ColourCount = (SafeIconImage->icHeader.biBitCount <= 8) ?
256 (1 << SafeIconImage->icHeader.biBitCount) : 0;
257 HeaderSize = sizeof(BITMAPINFOHEADER) + ColourCount * sizeof(RGBQUAD);
258 }
259
260 /* make data point to the start of the XOR image data */
261 Data = (PBYTE)SafeIconImage + HeaderSize;
262
263 /* get a handle to the screen dc, the icon we create is going to be compatable with this */
264 // FIXME!!! This is a victim of the Win32k Initialization BUG!!!!!
265 //hScreenDc = CreateDCW(NULL, NULL, NULL, NULL);
266 hScreenDc = CreateCompatibleDC(NULL);
267 if (hScreenDc == NULL)
268 {
269 RtlFreeHeap(GetProcessHeap(), 0, SafeIconImage);
270 return(NULL);
271 }
272
273 hIcon = CreateCursorIconFromData(hScreenDc, Data, SafeIconImage, cxDesired, cyDesired, wXHotspot, wYHotspot, fIcon);
274 RtlFreeHeap(GetProcessHeap(), 0, SafeIconImage);
275 DeleteDC(hScreenDc);
276
277 return hIcon;
278 }
279
280
281 /*
282 * @implemented
283 */
284 HICON
285 WINAPI
286 CreateIconIndirect(PICONINFO IconInfo)
287 {
288 BITMAP ColorBitmap;
289 BITMAP MaskBitmap;
290 HBITMAP hbmTemp;
291
292 if(!IconInfo)
293 {
294 SetLastError(ERROR_INVALID_PARAMETER);
295 return (HICON)0;
296 }
297
298 if(!GetObjectW(IconInfo->hbmMask, sizeof(BITMAP), &MaskBitmap))
299 {
300 return (HICON)0;
301 }
302
303 /* Try to get color bitmap */
304 if (GetObjectW(IconInfo->hbmColor, sizeof(BITMAP), &ColorBitmap))
305 {
306 /* Compare size of color and mask bitmap*/
307 if (ColorBitmap.bmWidth != MaskBitmap.bmWidth ||
308 ColorBitmap.bmHeight != MaskBitmap.bmHeight)
309 {
310 ERR("Color and mask size are different!");
311 SetLastError(ERROR_INVALID_PARAMETER);
312 return (HICON)0;
313 }
314 /* Check if color and mask are switched and switch them back */
315 if (MaskBitmap.bmBitsPixel != 1 && ColorBitmap.bmBitsPixel == 1)
316 {
317 hbmTemp = IconInfo->hbmMask;
318 IconInfo->hbmMask = IconInfo->hbmColor;
319 IconInfo->hbmColor = hbmTemp;
320 }
321 }
322 return (HICON)NtUserCreateCursorIconHandle(IconInfo, TRUE);
323 }
324
325
326 /*
327 * @implemented
328 */
329 BOOL
330 WINAPI
331 DestroyIcon(
332 HICON hIcon)
333 {
334 return (BOOL)NtUserDestroyCursor((HANDLE)hIcon, 0);
335 }
336
337
338 /*
339 * @implemented
340 */
341 BOOL
342 WINAPI
343 DrawIcon(
344 HDC hDC,
345 int X,
346 int Y,
347 HICON hIcon)
348 {
349 return DrawIconEx(hDC, X, Y, hIcon, 0, 0, 0, NULL, DI_NORMAL | DI_DEFAULTSIZE);
350 }
351
352 /*
353 * @implemented
354 */
355 BOOL
356 WINAPI
357 DrawIconEx(
358 HDC hdc,
359 int xLeft,
360 int yTop,
361 HICON hIcon,
362 int cxWidth,
363 int cyWidth,
364 UINT istepIfAniCur,
365 HBRUSH hbrFlickerFreeDraw,
366 UINT diFlags)
367 {
368 return (BOOL)NtUserDrawIconEx(hdc, xLeft, yTop, hIcon, cxWidth, cyWidth,
369 istepIfAniCur, hbrFlickerFreeDraw, diFlags,
370 0, 0);
371 }
372
373
374 /*
375 * @implemented
376 */
377 BOOL
378 WINAPI
379 GetIconInfo(
380 HICON hIcon,
381 PICONINFO IconInfo)
382 {
383 return NtUserGetIconInfo((HANDLE)hIcon, IconInfo, 0, 0, 0, 0);
384 }
385
386
387 /*
388 * @implemented
389 */
390 HICON
391 WINAPI
392 LoadIconA(
393 HINSTANCE hInstance,
394 LPCSTR lpIconName)
395 {
396 return(LoadImageA(hInstance, lpIconName, IMAGE_ICON, 0, 0, LR_SHARED | LR_DEFAULTSIZE));
397 }
398
399
400 /*
401 * @implemented
402 */
403 HICON
404 WINAPI
405 LoadIconW(
406 HINSTANCE hInstance,
407 LPCWSTR lpIconName)
408 {
409 return(LoadImageW(hInstance, lpIconName, IMAGE_ICON, 0, 0, LR_SHARED | LR_DEFAULTSIZE));
410 }
411
412
413 /*
414 * @implemented
415 */
416 int
417 WINAPI
418 LookupIconIdFromDirectory(
419 PBYTE presbits,
420 BOOL fIcon)
421 {
422 return LookupIconIdFromDirectoryEx(presbits,
423 fIcon,
424 fIcon ? GetSystemMetrics(SM_CXICON) : GetSystemMetrics(SM_CXCURSOR),
425 fIcon ? GetSystemMetrics(SM_CYICON) : GetSystemMetrics(SM_CYCURSOR),
426 LR_DEFAULTCOLOR);
427 }
428
429
430
431
432
433 /*
434 * The following macro function accounts for the irregularities of
435 * accessing cursor and icon resources in files and resource entries.
436 */
437 typedef BOOL
438 (*fnGetCIEntry)(LPVOID dir, int n, int *width, int *height, int *bits );
439
440 /**********************************************************************
441 * CURSORICON_FindBestIcon
442 *
443 * Find the icon closest to the requested size and number of colors.
444 */
445 static int
446 CURSORICON_FindBestIcon(LPVOID dir,
447 fnGetCIEntry get_entry,
448 int Width,
449 int Height,
450 int ColorBits)
451 {
452 int i, cx, cy, Bits, BestBits = 0, BestEntry = -1;
453 UINT iTotalDiff, iXDiff=0, iYDiff=0, iColorDiff;
454 UINT iTempXDiff, iTempYDiff, iTempColorDiff;
455
456 /* Find Best Fit */
457 iTotalDiff = 0xFFFFFFFF;
458 iColorDiff = 0xFFFFFFFF;
459 for (i = 0; get_entry(dir, i, &cx, &cy, &Bits); i++ )
460 {
461 iTempXDiff = abs(Width - cx);
462 iTempYDiff = abs(Height - cy);
463
464 if(iTotalDiff > (iTempXDiff + iTempYDiff))
465 {
466 iXDiff = iTempXDiff;
467 iYDiff = iTempYDiff;
468 iTotalDiff = iXDiff + iYDiff;
469 }
470 }
471
472 /* Find Best Colors for Best Fit */
473 for (i = 0; get_entry(dir, i, &cx, &cy, &Bits); i++ )
474 {
475 if(abs(Width - cx) == iXDiff && abs(Height - cy) == iYDiff)
476 {
477 iTempColorDiff = abs(ColorBits - Bits);
478 if(iColorDiff > iTempColorDiff)
479 {
480 BestEntry = i;
481 BestBits = Bits;
482 iColorDiff = iTempColorDiff;
483 }
484 }
485 }
486
487 TRACE("Best Icon: ResId: %d, bits : %d\n", BestEntry, BestBits);
488
489 return BestEntry;
490 }
491
492
493
494 /**********************************************************************
495 * CURSORICON_FindBestCursor
496 *
497 * Find the cursor closest to the requested size.
498 * FIXME: parameter 'color' ignored and entries with more than 1 bpp
499 * ignored too
500 */
501 static int
502 CURSORICON_FindBestCursor(LPVOID dir,
503 fnGetCIEntry get_entry,
504 int Width,
505 int Height,
506 int ColorBits)
507 {
508 int i, cx, cy, Bits, BestBits = 0, BestEntry = -1;
509 UINT iTotalDiff, iXDiff=0, iYDiff=0, iColorDiff;
510 UINT iTempXDiff, iTempYDiff, iTempColorDiff;
511
512 /* Find Best Fit */
513 iTotalDiff = 0xFFFFFFFF;
514 iColorDiff = 0xFFFFFFFF;
515 for (i = 0; get_entry(dir, i, &cx, &cy, &Bits); i++ )
516 {
517 iTempXDiff = abs(Width - cx);
518 iTempYDiff = abs(Height - cy);
519
520 if(iTotalDiff > (iTempXDiff + iTempYDiff))
521 {
522 iXDiff = iTempXDiff;
523 iYDiff = iTempYDiff;
524 iTotalDiff = iXDiff + iYDiff;
525 }
526 }
527
528 /* Find Best Colors for Best Fit */
529 for (i = 0; get_entry(dir, i, &cx, &cy, &Bits); i++ )
530 {
531 if(abs(Width - cx) == iXDiff && abs(Height - cy) == iYDiff)
532 {
533 iTempColorDiff = abs(ColorBits - Bits);
534 if(iColorDiff > iTempColorDiff)
535 {
536 BestEntry = i;
537 BestBits = Bits;
538 iColorDiff = iTempColorDiff;
539 }
540 }
541 }
542
543 TRACE("Best Cursor: ResId: %d, bits : %d\n", BestEntry, BestBits);
544
545 return BestEntry;
546 }
547
548
549 static BOOL
550 CURSORICON_GetResIconEntry(LPVOID dir,
551 int n,
552 int *Width,
553 int *Height,
554 int *Bits)
555 {
556 GRPCURSORICONDIR *ResDir = dir;
557 ICONRESDIR *Icon;
558
559 if (ResDir->idCount <= n)
560 return FALSE;
561
562 Icon = &ResDir->idEntries[n].ResInfo.icon;
563 *Width = Icon->bWidth;
564 *Height = Icon->bHeight;
565 *Bits = ResDir->idEntries[n].wBitCount;
566 return TRUE;
567 }
568
569 static BOOL
570 CURSORICON_GetResCursorEntry(LPVOID dir,
571 int n,
572 int *Width,
573 int *Height,
574 int *Bits)
575 {
576 GRPCURSORICONDIR *ResDir = dir;
577 CURSORRESDIR *Cursor;
578
579 if (ResDir->idCount <= n)
580 return FALSE;
581
582 Cursor = &ResDir->idEntries[n].ResInfo.cursor;
583 *Width = Cursor->wWidth;
584 *Height = Cursor->wHeight;
585 *Bits = ResDir->idEntries[n].wBitCount;
586 return TRUE;
587 }
588
589 static GRPCURSORICONDIRENTRY *
590 CURSORICON_FindBestIconRes(GRPCURSORICONDIR * dir,
591 int Width,
592 int Height,
593 int ColorBits)
594 {
595 int n;
596 n = CURSORICON_FindBestIcon(dir,
597 CURSORICON_GetResIconEntry,
598 Width,
599 Height,
600 ColorBits);
601 if (n < 0)
602 return NULL;
603
604 return &dir->idEntries[n];
605 }
606
607 static GRPCURSORICONDIRENTRY *
608 CURSORICON_FindBestCursorRes(GRPCURSORICONDIR *dir,
609 int Width,
610 int Height,
611 int ColorBits)
612 {
613 int n;
614 n = CURSORICON_FindBestCursor(dir,
615 CURSORICON_GetResCursorEntry,
616 Width,
617 Height,
618 ColorBits);
619 if (n < 0)
620 return NULL;
621
622 return &dir->idEntries[n];
623 }
624
625
626 INT WINAPI
627 LookupIconIdFromDirectoryEx(PBYTE xdir,
628 BOOL bIcon,
629 INT width,
630 INT height,
631 UINT cFlag)
632 {
633 GRPCURSORICONDIR *dir = (GRPCURSORICONDIR*)xdir;
634 UINT retVal = 0;
635
636 GetConnected();
637
638 if(dir && !dir->idReserved && (IMAGE_ICON == dir->idType || IMAGE_CURSOR == dir->idType))
639 {
640 GRPCURSORICONDIRENTRY *entry = NULL;
641 int ColorBits;
642
643 if (cFlag & LR_MONOCHROME)
644 {
645 ColorBits = 1;
646 }
647 else if (cFlag & LR_VGACOLOR)
648 {
649 ColorBits = 4;
650 }
651 else
652 {
653 ColorBits = gpsi->BitsPixel;
654 }
655
656 if(bIcon)
657 entry = CURSORICON_FindBestIconRes(dir, width, height, ColorBits);
658 else
659 entry = CURSORICON_FindBestCursorRes(dir, width, height, 1);
660
661 if (entry)
662 retVal = entry->nID;
663 }
664 else
665 WARN("%s() : Invalid resource directory\n", __FUNCTION__);
666
667 return retVal;
668 }