added LR_SHARED flag support for LoadIcon() and LoadCursor()
[reactos.git] / reactos / lib / 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: icon.c,v 1.14 2003/11/18 19:59:51 weiden Exp $
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 <windows.h>
32 #include <user32.h>
33 #include <string.h>
34 #include <stdlib.h>
35 #include <debug.h>
36
37 /* FUNCTIONS *****************************************************************/
38
39 HICON
40 ICON_CreateIconFromData(HDC hDC, PVOID ImageData, ICONIMAGE* IconImage, int cxDesired, int cyDesired, int xHotspot, int yHotspot)
41 {
42 BITMAPINFO* bwBIH;
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, DIB_RGB_COLORS);
52
53 /* make ImageData point to the start of the AND image data */
54 ImageData = ((PBYTE)ImageData) + (((IconImage->icHeader.biWidth *
55 IconImage->icHeader.biBitCount + 31) & ~31) >> 3) *
56 (IconImage->icHeader.biHeight );
57
58 /* create a BITMAPINFO header for the monocrome part of the icon */
59 bwBIH = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof (BITMAPINFOHEADER)+2*sizeof(RGBQUAD));
60
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 = (((IconImage->icHeader.biWidth * 1 + 31) & ~31) >> 3) *
67 (IconImage->icHeader.biHeight );
68 bwBIH->bmiHeader.biCompression = BI_RGB;
69 bwBIH->bmiHeader.biClrImportant = 0;
70 bwBIH->bmiHeader.biClrUsed = 0;
71 bwBIH->bmiHeader.biXPelsPerMeter = 0;
72 bwBIH->bmiHeader.biYPelsPerMeter = 0;
73
74 bwBIH->bmiColors[0].rgbBlue = 0;
75 bwBIH->bmiColors[0].rgbGreen = 0;
76 bwBIH->bmiColors[0].rgbRed = 0;
77 bwBIH->bmiColors[0].rgbReserved = 0;
78
79 bwBIH->bmiColors[1].rgbBlue = 0xff;
80 bwBIH->bmiColors[1].rgbGreen = 0xff;
81 bwBIH->bmiColors[1].rgbRed = 0xff;
82 bwBIH->bmiColors[1].rgbReserved = 0;
83
84 /* load the AND bitmap */
85 IconInfo.hbmMask = CreateDIBitmap(hDC, &bwBIH->bmiHeader, 0,
86 ImageData, bwBIH, DIB_RGB_COLORS);
87
88 SetDIBits(hDC, IconInfo.hbmMask, 0, IconImage->icHeader.biHeight,
89 ImageData, bwBIH, DIB_RGB_COLORS);
90
91 RtlFreeHeap(RtlGetProcessHeap(), 0, bwBIH);
92
93 /* Create the icon based on everything we have so far */
94 return NtUserCreateCursorIconHandle(&IconInfo, FALSE);
95 }
96
97 HICON
98 ICON_CreateCursorFromData(HDC hDC, PVOID ImageData, ICONIMAGE* IconImage, int cxDesired, int cyDesired, int xHotspot, int yHotspot)
99 {
100 /* FIXME - color cursors */
101 BITMAPINFO* bwBIH;
102 ICONINFO IconInfo;
103 PVOID XORImageData = ImageData;
104
105 IconInfo.fIcon = TRUE;
106 IconInfo.xHotspot = xHotspot;
107 IconInfo.yHotspot = yHotspot;
108
109 /* create a BITMAPINFO header for the monocrome part of the icon */
110 bwBIH = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof (BITMAPINFOHEADER)+2*sizeof(RGBQUAD));
111
112 bwBIH->bmiHeader.biBitCount = 1;
113 bwBIH->bmiHeader.biWidth = IconImage->icHeader.biWidth;
114 bwBIH->bmiHeader.biHeight = IconImage->icHeader.biHeight;
115 bwBIH->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
116 bwBIH->bmiHeader.biPlanes = 1;
117 bwBIH->bmiHeader.biSizeImage = (((IconImage->icHeader.biWidth * 1 + 31) & ~31) >> 3) *
118 (IconImage->icHeader.biHeight );
119 bwBIH->bmiHeader.biCompression = BI_RGB;
120 bwBIH->bmiHeader.biClrImportant = 0;
121 bwBIH->bmiHeader.biClrUsed = 0;
122 bwBIH->bmiHeader.biXPelsPerMeter = 0;
123 bwBIH->bmiHeader.biYPelsPerMeter = 0;
124
125 bwBIH->bmiColors[0].rgbBlue = 0;
126 bwBIH->bmiColors[0].rgbGreen = 0;
127 bwBIH->bmiColors[0].rgbRed = 0;
128 bwBIH->bmiColors[0].rgbReserved = 0;
129
130 bwBIH->bmiColors[1].rgbBlue = 0xff;
131 bwBIH->bmiColors[1].rgbGreen = 0xff;
132 bwBIH->bmiColors[1].rgbRed = 0xff;
133 bwBIH->bmiColors[1].rgbReserved = 0;
134
135 /* load the AND bitmap */
136 IconInfo.hbmMask = CreateDIBitmap(hDC, &bwBIH->bmiHeader, 0,
137 XORImageData, bwBIH, DIB_RGB_COLORS);
138
139 if(IconInfo.hbmMask)
140 {
141 SetDIBits(hDC, IconInfo.hbmMask, 0, IconImage->icHeader.biHeight,
142 XORImageData, bwBIH, DIB_RGB_COLORS);
143
144 }
145
146 IconInfo.hbmColor = (HBITMAP)0;
147
148 RtlFreeHeap(RtlGetProcessHeap(), 0, bwBIH);
149
150 /* Create the icon based on everything we have so far */
151 return NtUserCreateCursorIconHandle(&IconInfo, FALSE);
152 }
153
154
155 /*
156 * @implemented
157 */
158 HICON
159 STDCALL
160 CopyIcon(
161 HICON hIcon)
162 {
163 ICONINFO IconInfo;
164
165 if(NtUserGetIconInfo(hIcon, &IconInfo))
166 {
167 return NtUserCreateCursorIconHandle(&IconInfo, FALSE);
168 }
169 return (HICON)0;
170 }
171
172
173 /*
174 * @implemented
175 */
176 HICON
177 STDCALL
178 CreateIcon(
179 HINSTANCE hInstance,
180 int nWidth,
181 int nHeight,
182 BYTE cPlanes,
183 BYTE cBitsPixel,
184 CONST BYTE *ANDbits,
185 CONST BYTE *XORbits)
186 {
187 ICONINFO IconInfo;
188
189 IconInfo.fIcon = TRUE;
190 IconInfo.xHotspot = nWidth / 2;
191 IconInfo.yHotspot = nHeight / 2;
192 IconInfo.hbmMask = CreateBitmap(nWidth, nHeight, 1, 1, ANDbits);
193 if(!IconInfo.hbmMask)
194 {
195 return (HICON)0;
196 }
197 IconInfo.hbmColor = CreateBitmap(nWidth, nHeight, cPlanes, cBitsPixel, XORbits);
198 if(!IconInfo.hbmColor)
199 {
200 DeleteObject(IconInfo.hbmMask);
201 return (HICON)0;
202 }
203
204 return NtUserCreateCursorIconHandle(&IconInfo, FALSE);
205 }
206
207
208 /*
209 * @implemented
210 */
211 HICON
212 STDCALL
213 CreateIconFromResource(
214 PBYTE presbits,
215 DWORD dwResSize,
216 WINBOOL fIcon,
217 DWORD dwVer)
218 {
219 return CreateIconFromResourceEx(presbits, dwResSize, fIcon, dwVer, 0, 0, 0);
220 }
221
222
223 /*
224 * @implemented
225 */
226 HICON
227 STDCALL
228 CreateIconFromResourceEx(
229 PBYTE pbIconBits,
230 DWORD cbIconBits,
231 WINBOOL fIcon,
232 DWORD dwVersion,
233 int cxDesired,
234 int cyDesired,
235 UINT uFlags)
236 {
237 ICONIMAGE* SafeIconImage;
238 HICON hIcon;
239 ULONG HeaderSize;
240 ULONG ColourCount;
241 PVOID Data;
242 HDC hScreenDc;
243 WORD wXHotspot;
244 WORD wYHotspot;
245
246 /*
247 FIXME - does win support LR_SHARED? According to msdn it does but we don't
248 have useful information to identify the icon
249 if (uFlags & LR_SHARED)
250 {
251 DbgPrint("FIXME: need LR_SHARED support in CreateIconFromResourceEx()\n");
252 }
253 */
254
255 DPRINT("dwVersion, cxDesired, cyDesired are all ignored in this implementation!\n");
256
257 if (! fIcon)
258 {
259 wXHotspot = (WORD)*pbIconBits;
260 pbIconBits+=2;
261 wYHotspot = (WORD)*pbIconBits;
262 pbIconBits+=2;
263 cbIconBits-=4;
264 }
265 else
266 {
267 wXHotspot = cxDesired / 2;
268 wYHotspot = cyDesired / 2;
269 }
270
271 /* get an safe copy of the icon data */
272 SafeIconImage = RtlAllocateHeap(RtlGetProcessHeap(), 0, cbIconBits);
273 memcpy(SafeIconImage, pbIconBits, cbIconBits);
274
275 /* take into acount the origonal height was for both the AND and XOR images */
276 if(fIcon)
277 SafeIconImage->icHeader.biHeight /= 2;
278
279 if (SafeIconImage->icHeader.biSize == sizeof(BITMAPCOREHEADER))
280 {
281 BITMAPCOREHEADER* Core = (BITMAPCOREHEADER*)SafeIconImage;
282 ColourCount = (Core->bcBitCount <= 8) ? (1 << Core->bcBitCount) : 0;
283 HeaderSize = sizeof(BITMAPCOREHEADER) + ColourCount * sizeof(RGBTRIPLE);
284 }
285 else
286 {
287 ColourCount = (SafeIconImage->icHeader.biBitCount <= 8) ?
288 (1 << SafeIconImage->icHeader.biBitCount) : 0;
289 HeaderSize = sizeof(BITMAPINFOHEADER) + ColourCount * sizeof(RGBQUAD);
290 }
291
292 /* make data point to the start of the XOR image data */
293 Data = (PBYTE)SafeIconImage + HeaderSize;
294
295 /* get a handle to the screen dc, the icon we create is going to be compatable with this */
296 hScreenDc = CreateCompatibleDC(NULL);
297 if (hScreenDc == NULL)
298 {
299 RtlFreeHeap(RtlGetProcessHeap(), 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(RtlGetProcessHeap(), 0, SafeIconImage);
308
309 return hIcon;
310 }
311
312
313 /*
314 * @implemented
315 */
316 HICON
317 STDCALL
318 CreateIconIndirect(PICONINFO IconInfo)
319 {
320 BITMAP ColorBitmap;
321 BITMAP MaskBitmap;
322
323 if(!IconInfo)
324 {
325 SetLastError(ERROR_INVALID_PARAMETER);
326 return (HICON)0;
327 }
328
329 if(!GetObjectW(IconInfo->hbmMask, sizeof(BITMAP), &MaskBitmap))
330 {
331 return (HICON)0;
332 }
333 /* FIXME - does there really *have* to be a color bitmap? monochrome cursors don't have one */
334 if(IconInfo->hbmColor && !GetObjectW(IconInfo->hbmColor, sizeof(BITMAP), &ColorBitmap))
335 {
336 return (HICON)0;
337 }
338
339 /* FIXME - i doubt this is right (monochrome cursors */
340 /*if(ColorBitmap.bmWidth != MaskBitmap.bmWidth ||
341 ColorBitmap.bmHeight != MaskBitmap.bmWidth)
342 {
343 SetLastError(ERROR_INVALID_PARAMETER);
344 return (HICON)0;
345 }*/
346
347 return NtUserCreateCursorIconHandle(IconInfo, TRUE);
348 }
349
350
351 /*
352 * @implemented
353 */
354 WINBOOL
355 STDCALL
356 DestroyIcon(
357 HICON hIcon)
358 {
359 return (WINBOOL)NtUserDestroyCursor(hIcon, 0);
360 }
361
362
363 /*
364 * @implemented
365 */
366 WINBOOL
367 STDCALL
368 DrawIcon(
369 HDC hDC,
370 int X,
371 int Y,
372 HICON hIcon)
373 {
374 return DrawIconEx(hDC, X, Y, hIcon, 0, 0, 0, NULL, DI_NORMAL | DI_DEFAULTSIZE);
375 }
376
377 /*
378 * @implemented
379 */
380 WINBOOL
381 STDCALL
382 DrawIconEx(
383 HDC hdc,
384 int xLeft,
385 int yTop,
386 HICON hIcon,
387 int cxWidth,
388 int cyWidth,
389 UINT istepIfAniCur,
390 HBRUSH hbrFlickerFreeDraw,
391 UINT diFlags)
392 {
393 return (WINBOOL)NtUserDrawIconEx(hdc, xLeft, yTop, hIcon, cxWidth, cyWidth,
394 istepIfAniCur, hbrFlickerFreeDraw, diFlags,
395 0, 0);
396 }
397
398
399 /*
400 * @implemented
401 */
402 WINBOOL
403 STDCALL
404 GetIconInfo(
405 HICON hIcon,
406 PICONINFO IconInfo)
407 {
408 /* FIXME - copy bitmaps */
409 return (WINBOOL)NtUserGetIconInfo(hIcon, IconInfo);
410 }
411
412
413 /*
414 * @implemented
415 */
416 HICON
417 STDCALL
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 STDCALL
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 STDCALL
444 LookupIconIdFromDirectory(
445 PBYTE presbits,
446 WINBOOL fIcon)
447 {
448 return LookupIconIdFromDirectoryEx( presbits, fIcon,
449 fIcon ? GetSystemMetrics(SM_CXICON) : GetSystemMetrics(SM_CXCURSOR),
450 fIcon ? GetSystemMetrics(SM_CYICON) : GetSystemMetrics(SM_CYCURSOR), LR_DEFAULTCOLOR );
451 }
452
453 /* Ported from WINE20030408 */
454 CURSORICONDIRENTRY*
455 CURSORICON_FindBestCursor( CURSORICONDIR *dir, int width, int height, int colors)
456 {
457 int i;
458 CURSORICONDIRENTRY *entry, *bestEntry = NULL;
459 UINT iTotalDiff, iXDiff=0, iYDiff=0, iColorDiff;
460 UINT iTempXDiff, iTempYDiff, iTempColorDiff;
461
462 if (dir->idCount < 1)
463 {
464 DPRINT("Empty directory!\n");
465 return NULL;
466 }
467 if (dir->idCount == 1)
468 return &dir->idEntries[0]; /* No choice... */
469
470 /* Find Best Fit */
471 iTotalDiff = 0xFFFFFFFF;
472 iColorDiff = 0xFFFFFFFF;
473 for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
474 {
475 iTempXDiff = abs(width - entry->bWidth);
476 iTempYDiff = abs(height - entry->bHeight);
477
478 if(iTotalDiff > (iTempXDiff + iTempYDiff))
479 {
480 iXDiff = iTempXDiff;
481 iYDiff = iTempYDiff;
482 iTotalDiff = iXDiff + iYDiff;
483 }
484 }
485
486 /* Find Best Colors for Best Fit */
487 for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
488 {
489 if(abs(width - entry->bWidth) == (int) iXDiff &&
490 abs(height - entry->bHeight) == (int) iYDiff)
491 {
492 iTempColorDiff = abs(colors - entry->bColorCount);
493
494 if(iColorDiff > iTempColorDiff)
495 {
496 bestEntry = entry;
497 iColorDiff = iTempColorDiff;
498 }
499 }
500 }
501
502 return bestEntry;
503 }
504
505 /* Ported from WINE20030408 */
506 CURSORICONDIRENTRY*
507 CURSORICON_FindBestIcon( CURSORICONDIR *dir, int width, int height, int colors)
508 {
509 int i;
510 CURSORICONDIRENTRY *entry, *bestEntry = NULL;
511 UINT iTotalDiff, iXDiff=0, iYDiff=0, iColorDiff;
512 UINT iTempXDiff, iTempYDiff, iTempColorDiff;
513
514 if (dir->idCount < 1)
515 {
516 DPRINT("Empty directory!\n");
517 return NULL;
518 }
519 if (dir->idCount == 1)
520 return &dir->idEntries[0]; /* No choice... */
521
522 /* Find Best Fit */
523 iTotalDiff = 0xFFFFFFFF;
524 iColorDiff = 0xFFFFFFFF;
525 for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
526 {
527 iTempXDiff = abs(width - entry->bWidth);
528
529 iTempYDiff = abs(height - entry->bHeight);
530
531 if(iTotalDiff > (iTempXDiff + iTempYDiff))
532 {
533 iXDiff = iTempXDiff;
534 iYDiff = iTempYDiff;
535 iTotalDiff = iXDiff + iYDiff;
536 }
537 }
538
539 /* Find Best Colors for Best Fit */
540 for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
541 {
542 if(abs(width - entry->bWidth) == (int) iXDiff &&
543 abs(height - entry->bHeight) == (int) iYDiff)
544 {
545 iTempColorDiff = abs(colors - entry->bColorCount);
546 if(iColorDiff > iTempColorDiff)
547 {
548 bestEntry = entry;
549 iColorDiff = iTempColorDiff;
550 }
551 }
552 }
553
554 return bestEntry;
555 }
556
557 /* Ported from WINE20030408 */
558 /*
559 * @implemented
560 */
561 int
562 STDCALL
563 LookupIconIdFromDirectoryEx(
564 PBYTE presbits,
565 WINBOOL fIcon,
566 int cxDesired,
567 int cyDesired,
568 UINT Flags)
569 {
570 GRPCURSORICONDIR *dir = (GRPCURSORICONDIR*)presbits;
571 UINT retVal = 0;
572
573 if( dir && !dir->idReserved && (dir->idType & 3) )
574 {
575 GRPCURSORICONDIRENTRY* entry;
576 HDC hdc;
577 UINT palEnts;
578 int colors;
579 hdc = GetDC(0);
580 #if 0
581 palEnts = GetSystemPaletteEntries(hdc, 0, 0, NULL);
582 if (palEnts == 0)
583 palEnts = 256;
584 #endif
585 palEnts = 16; //use this until GetSystemPaletteEntries works
586 colors = (Flags & LR_MONOCHROME) ? 2 : palEnts;
587
588 ReleaseDC(0, hdc);
589
590 entry = (GRPCURSORICONDIRENTRY*)CURSORICON_FindBestIcon( (CURSORICONDIR*)dir,
591 cxDesired,
592 cyDesired,
593 colors );
594
595 if( entry )
596 retVal = entry->nID;
597 }
598 else
599 {
600 DbgPrint("invalid resource directory\n");
601 }
602 return retVal;
603 }
604