- Go away STDCALL, time has come for WINAPI and NTAPI
[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 hScreenDc = CreateCompatibleDC(NULL);
295 if (hScreenDc == NULL)
296 {
297 RtlFreeHeap(GetProcessHeap(), 0, SafeIconImage);
298 return(NULL);
299 }
300
301 if(fIcon)
302 hIcon = ICON_CreateIconFromData(hScreenDc, Data, SafeIconImage, cxDesired, cyDesired, wXHotspot, wYHotspot);
303 else
304 hIcon = ICON_CreateCursorFromData(hScreenDc, Data, SafeIconImage, cxDesired, cyDesired, wXHotspot, wYHotspot);
305 RtlFreeHeap(GetProcessHeap(), 0, SafeIconImage);
306 DeleteDC(hScreenDc);
307
308 return hIcon;
309 }
310
311
312 /*
313 * @implemented
314 */
315 HICON
316 WINAPI
317 CreateIconIndirect(PICONINFO IconInfo)
318 {
319 BITMAP ColorBitmap;
320 BITMAP MaskBitmap;
321
322 if(!IconInfo)
323 {
324 SetLastError(ERROR_INVALID_PARAMETER);
325 return (HICON)0;
326 }
327
328 if(!GetObjectW(IconInfo->hbmMask, sizeof(BITMAP), &MaskBitmap))
329 {
330 return (HICON)0;
331 }
332 /* FIXME - does there really *have* to be a color bitmap? monochrome cursors don't have one */
333 if(/*IconInfo->hbmColor &&*/ !GetObjectW(IconInfo->hbmColor, sizeof(BITMAP), &ColorBitmap))
334 {
335 return (HICON)0;
336 }
337
338 /* FIXME - i doubt this is right (monochrome cursors */
339 /*if(ColorBitmap.bmWidth != MaskBitmap.bmWidth ||
340 ColorBitmap.bmHeight != MaskBitmap.bmWidth)
341 {
342 SetLastError(ERROR_INVALID_PARAMETER);
343 return (HICON)0;
344 }*/
345
346 return (HICON)NtUserCreateCursorIconHandle(IconInfo, TRUE);
347 }
348
349
350 /*
351 * @implemented
352 */
353 BOOL
354 WINAPI
355 DestroyIcon(
356 HICON hIcon)
357 {
358 return (BOOL)NtUserDestroyCursor((HANDLE)hIcon, 0);
359 }
360
361
362 /*
363 * @implemented
364 */
365 BOOL
366 WINAPI
367 DrawIcon(
368 HDC hDC,
369 int X,
370 int Y,
371 HICON hIcon)
372 {
373 return DrawIconEx(hDC, X, Y, hIcon, 0, 0, 0, NULL, DI_NORMAL | DI_DEFAULTSIZE);
374 }
375
376 /*
377 * @implemented
378 */
379 BOOL
380 WINAPI
381 DrawIconEx(
382 HDC hdc,
383 int xLeft,
384 int yTop,
385 HICON hIcon,
386 int cxWidth,
387 int cyWidth,
388 UINT istepIfAniCur,
389 HBRUSH hbrFlickerFreeDraw,
390 UINT diFlags)
391 {
392 return (BOOL)NtUserDrawIconEx(hdc, xLeft, yTop, hIcon, cxWidth, cyWidth,
393 istepIfAniCur, hbrFlickerFreeDraw, diFlags,
394 0, 0);
395 }
396
397
398 /*
399 * @implemented
400 */
401 BOOL
402 WINAPI
403 GetIconInfo(
404 HICON hIcon,
405 PICONINFO IconInfo)
406 {
407 return NtUserGetIconInfo((HANDLE)hIcon, IconInfo, 0, 0, 0, 0);
408 }
409
410
411 /*
412 * @implemented
413 */
414 HICON
415 WINAPI
416 LoadIconA(
417 HINSTANCE hInstance,
418 LPCSTR lpIconName)
419 {
420 return(LoadImageA(hInstance, lpIconName, IMAGE_ICON, 0, 0, LR_SHARED | LR_DEFAULTSIZE));
421 }
422
423
424 /*
425 * @implemented
426 */
427 HICON
428 WINAPI
429 LoadIconW(
430 HINSTANCE hInstance,
431 LPCWSTR lpIconName)
432 {
433 return(LoadImageW(hInstance, lpIconName, IMAGE_ICON, 0, 0, LR_SHARED | LR_DEFAULTSIZE));
434 }
435
436
437 /*
438 * @implemented
439 */
440 int
441 WINAPI
442 LookupIconIdFromDirectory(
443 PBYTE presbits,
444 BOOL fIcon)
445 {
446 return LookupIconIdFromDirectoryEx(presbits,
447 fIcon,
448 fIcon ? GetSystemMetrics(SM_CXICON) : GetSystemMetrics(SM_CXCURSOR),
449 fIcon ? GetSystemMetrics(SM_CYICON) : GetSystemMetrics(SM_CYCURSOR),
450 LR_DEFAULTCOLOR);
451 }
452
453
454
455
456
457 /*
458 * The following macro function accounts for the irregularities of
459 * accessing cursor and icon resources in files and resource entries.
460 */
461 typedef BOOL
462 (*fnGetCIEntry)(LPVOID dir, int n, int *width, int *height, int *bits );
463
464 /**********************************************************************
465 * CURSORICON_FindBestIcon
466 *
467 * Find the icon closest to the requested size and number of colors.
468 */
469 static int
470 CURSORICON_FindBestIcon(LPVOID dir,
471 fnGetCIEntry get_entry,
472 int Width,
473 int Height,
474 int ColorBits)
475 {
476 int i, cx, cy, Bits, BestBits = 0, BestEntry = -1;
477 UINT iTotalDiff, iXDiff=0, iYDiff=0, iColorDiff;
478 UINT iTempXDiff, iTempYDiff, iTempColorDiff;
479
480 /* Find Best Fit */
481 iTotalDiff = 0xFFFFFFFF;
482 iColorDiff = 0xFFFFFFFF;
483 for (i = 0; get_entry(dir, i, &cx, &cy, &Bits); i++ )
484 {
485 iTempXDiff = abs(Width - cx);
486 iTempYDiff = abs(Height - cy);
487
488 if(iTotalDiff > (iTempXDiff + iTempYDiff))
489 {
490 iXDiff = iTempXDiff;
491 iYDiff = iTempYDiff;
492 iTotalDiff = iXDiff + iYDiff;
493 }
494 }
495
496 /* Find Best Colors for Best Fit */
497 for (i = 0; get_entry(dir, i, &cx, &cy, &Bits); i++ )
498 {
499 if(abs(Width - cx) == iXDiff && abs(Height - cy) == iYDiff)
500 {
501 iTempColorDiff = abs(ColorBits - Bits);
502 if(iColorDiff > iTempColorDiff)
503 {
504 BestEntry = i;
505 BestBits = Bits;
506 iColorDiff = iTempColorDiff;
507 }
508 }
509 }
510
511 TRACE("Best Icon: ResId: %d, bits : %d\n", BestEntry, BestBits);
512
513 return BestEntry;
514 }
515
516
517
518 /**********************************************************************
519 * CURSORICON_FindBestCursor
520 *
521 * Find the cursor closest to the requested size.
522 * FIXME: parameter 'color' ignored and entries with more than 1 bpp
523 * ignored too
524 */
525 static int
526 CURSORICON_FindBestCursor(LPVOID dir,
527 fnGetCIEntry get_entry,
528 int Width,
529 int Height,
530 int ColorBits)
531 {
532 int i, cx, cy, Bits, BestBits = 0, BestEntry = -1;
533 UINT iTotalDiff, iXDiff=0, iYDiff=0, iColorDiff;
534 UINT iTempXDiff, iTempYDiff, iTempColorDiff;
535
536 /* Find Best Fit */
537 iTotalDiff = 0xFFFFFFFF;
538 iColorDiff = 0xFFFFFFFF;
539 for (i = 0; get_entry(dir, i, &cx, &cy, &Bits); i++ )
540 {
541 iTempXDiff = abs(Width - cx);
542 iTempYDiff = abs(Height - cy);
543
544 if(iTotalDiff > (iTempXDiff + iTempYDiff))
545 {
546 iXDiff = iTempXDiff;
547 iYDiff = iTempYDiff;
548 iTotalDiff = iXDiff + iYDiff;
549 }
550 }
551
552 /* Find Best Colors for Best Fit */
553 for (i = 0; get_entry(dir, i, &cx, &cy, &Bits); i++ )
554 {
555 if(abs(Width - cx) == iXDiff && abs(Height - cy) == iYDiff)
556 {
557 iTempColorDiff = abs(ColorBits - Bits);
558 if(iColorDiff > iTempColorDiff)
559 {
560 BestEntry = i;
561 BestBits = Bits;
562 iColorDiff = iTempColorDiff;
563 }
564 }
565 }
566
567 TRACE("Best Cursor: ResId: %d, bits : %d\n", BestEntry, BestBits);
568
569 return BestEntry;
570 }
571
572
573 static BOOL
574 CURSORICON_GetResIconEntry(LPVOID dir,
575 int n,
576 int *Width,
577 int *Height,
578 int *Bits)
579 {
580 GRPCURSORICONDIR *ResDir = dir;
581 ICONRESDIR *Icon;
582
583 if (ResDir->idCount <= n)
584 return FALSE;
585
586 Icon = &ResDir->idEntries[n].ResInfo.icon;
587 *Width = Icon->bWidth;
588 *Height = Icon->bHeight;
589 *Bits = ResDir->idEntries[n].wBitCount;
590 return TRUE;
591 }
592
593 static BOOL
594 CURSORICON_GetResCursorEntry(LPVOID dir,
595 int n,
596 int *Width,
597 int *Height,
598 int *Bits)
599 {
600 GRPCURSORICONDIR *ResDir = dir;
601 CURSORRESDIR *Cursor;
602
603 if (ResDir->idCount <= n)
604 return FALSE;
605
606 Cursor = &ResDir->idEntries[n].ResInfo.cursor;
607 *Width = Cursor->wWidth;
608 *Height = Cursor->wHeight;
609 *Bits = ResDir->idEntries[n].wBitCount;
610 return TRUE;
611 }
612
613 static GRPCURSORICONDIRENTRY *
614 CURSORICON_FindBestIconRes(GRPCURSORICONDIR * dir,
615 int Width,
616 int Height,
617 int ColorBits)
618 {
619 int n;
620 n = CURSORICON_FindBestIcon(dir,
621 CURSORICON_GetResIconEntry,
622 Width,
623 Height,
624 ColorBits);
625 if (n < 0)
626 return NULL;
627
628 return &dir->idEntries[n];
629 }
630
631 static GRPCURSORICONDIRENTRY *
632 CURSORICON_FindBestCursorRes(GRPCURSORICONDIR *dir,
633 int Width,
634 int Height,
635 int ColorBits)
636 {
637 int n;
638 n = CURSORICON_FindBestCursor(dir,
639 CURSORICON_GetResCursorEntry,
640 Width,
641 Height,
642 ColorBits);
643 if (n < 0)
644 return NULL;
645
646 return &dir->idEntries[n];
647 }
648
649
650 INT WINAPI
651 LookupIconIdFromDirectoryEx(PBYTE xdir,
652 BOOL bIcon,
653 INT width,
654 INT height,
655 UINT cFlag)
656 {
657 GRPCURSORICONDIR *dir = (GRPCURSORICONDIR*)xdir;
658 UINT retVal = 0;
659 if(dir && !dir->idReserved && (IMAGE_ICON == dir->idType || IMAGE_CURSOR == dir->idType))
660 {
661 GRPCURSORICONDIRENTRY *entry = NULL;
662 int ColorBits;
663
664 if (cFlag & LR_MONOCHROME)
665 {
666 ColorBits = 1;
667 }
668 else
669 {
670 HDC hdc = CreateICW(NULL, NULL, NULL, NULL);
671 ColorBits = GetDeviceCaps(hdc, BITSPIXEL);
672 DeleteDC(hdc);
673 }
674
675 if(bIcon)
676 entry = CURSORICON_FindBestIconRes(dir, width, height, ColorBits);
677 else
678 entry = CURSORICON_FindBestCursorRes(dir, width, height, 1);
679
680 if (entry)
681 retVal = entry->nID;
682 }
683 else
684 WARN("%s() : Invalid resource directory\n", __FUNCTION__);
685
686 return retVal;
687 }