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