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