Replace RtlNtStatusToDosError(STATUS_NO_MEMORY) with ERROR_OUTOFMEMORY.
[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$
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 #define NDEBUG
33 #include <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, 0);
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+=2;
251 wYHotspot = (WORD)*pbIconBits;
252 pbIconBits+=2;
253 cbIconBits-=4;
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 memcpy(SafeIconImage, pbIconBits, cbIconBits);
264
265 /* take into acount the origonal height was for both the AND and XOR images */
266 if(fIcon)
267 SafeIconImage->icHeader.biHeight /= 2;
268
269 if (SafeIconImage->icHeader.biSize == sizeof(BITMAPCOREHEADER))
270 {
271 BITMAPCOREHEADER* Core = (BITMAPCOREHEADER*)SafeIconImage;
272 ColourCount = (Core->bcBitCount <= 8) ? (1 << Core->bcBitCount) : 0;
273 HeaderSize = sizeof(BITMAPCOREHEADER) + ColourCount * sizeof(RGBTRIPLE);
274 }
275 else
276 {
277 ColourCount = (SafeIconImage->icHeader.biBitCount <= 8) ?
278 (1 << SafeIconImage->icHeader.biBitCount) : 0;
279 HeaderSize = sizeof(BITMAPINFOHEADER) + ColourCount * sizeof(RGBQUAD);
280 }
281
282 /* make data point to the start of the XOR image data */
283 Data = (PBYTE)SafeIconImage + HeaderSize;
284
285 /* get a handle to the screen dc, the icon we create is going to be compatable with this */
286 hScreenDc = CreateCompatibleDC(NULL);
287 if (hScreenDc == NULL)
288 {
289 RtlFreeHeap(GetProcessHeap(), 0, SafeIconImage);
290 return(NULL);
291 }
292
293 if(fIcon)
294 hIcon = ICON_CreateIconFromData(hScreenDc, Data, SafeIconImage, cxDesired, cyDesired, wXHotspot, wYHotspot);
295 else
296 hIcon = ICON_CreateCursorFromData(hScreenDc, Data, SafeIconImage, cxDesired, cyDesired, wXHotspot, wYHotspot);
297 RtlFreeHeap(GetProcessHeap(), 0, SafeIconImage);
298 DeleteDC(hScreenDc);
299
300 return hIcon;
301 }
302
303
304 /*
305 * @implemented
306 */
307 HICON
308 STDCALL
309 CreateIconIndirect(PICONINFO IconInfo)
310 {
311 BITMAP ColorBitmap;
312 BITMAP MaskBitmap;
313
314 if(!IconInfo)
315 {
316 SetLastError(ERROR_INVALID_PARAMETER);
317 return (HICON)0;
318 }
319
320 if(!GetObjectW(IconInfo->hbmMask, sizeof(BITMAP), &MaskBitmap))
321 {
322 return (HICON)0;
323 }
324 /* FIXME - does there really *have* to be a color bitmap? monochrome cursors don't have one */
325 if(IconInfo->hbmColor && !GetObjectW(IconInfo->hbmColor, sizeof(BITMAP), &ColorBitmap))
326 {
327 return (HICON)0;
328 }
329
330 /* FIXME - i doubt this is right (monochrome cursors */
331 /*if(ColorBitmap.bmWidth != MaskBitmap.bmWidth ||
332 ColorBitmap.bmHeight != MaskBitmap.bmWidth)
333 {
334 SetLastError(ERROR_INVALID_PARAMETER);
335 return (HICON)0;
336 }*/
337
338 return (HICON)NtUserCreateCursorIconHandle(IconInfo, TRUE);
339 }
340
341
342 /*
343 * @implemented
344 */
345 BOOL
346 STDCALL
347 DestroyIcon(
348 HICON hIcon)
349 {
350 return (BOOL)NtUserDestroyCursorIcon((HANDLE)hIcon, 0);
351 }
352
353
354 /*
355 * @implemented
356 */
357 BOOL
358 STDCALL
359 DrawIcon(
360 HDC hDC,
361 int X,
362 int Y,
363 HICON hIcon)
364 {
365 return DrawIconEx(hDC, X, Y, hIcon, 0, 0, 0, NULL, DI_NORMAL | DI_DEFAULTSIZE);
366 }
367
368 /*
369 * @implemented
370 */
371 BOOL
372 STDCALL
373 DrawIconEx(
374 HDC hdc,
375 int xLeft,
376 int yTop,
377 HICON hIcon,
378 int cxWidth,
379 int cyWidth,
380 UINT istepIfAniCur,
381 HBRUSH hbrFlickerFreeDraw,
382 UINT diFlags)
383 {
384 return (BOOL)NtUserDrawIconEx(hdc, xLeft, yTop, hIcon, cxWidth, cyWidth,
385 istepIfAniCur, hbrFlickerFreeDraw, diFlags,
386 0, 0);
387 }
388
389
390 /*
391 * @implemented
392 */
393 BOOL
394 STDCALL
395 GetIconInfo(
396 HICON hIcon,
397 PICONINFO IconInfo)
398 {
399 /* FIXME - copy bitmaps */
400 return (BOOL)NtUserGetCursorIconInfo((HANDLE)hIcon, IconInfo);
401 }
402
403
404 /*
405 * @implemented
406 */
407 HICON
408 STDCALL
409 LoadIconA(
410 HINSTANCE hInstance,
411 LPCSTR lpIconName)
412 {
413 return(LoadImageA(hInstance, lpIconName, IMAGE_ICON, 0, 0, LR_SHARED | LR_DEFAULTSIZE));
414 }
415
416
417 /*
418 * @implemented
419 */
420 HICON
421 STDCALL
422 LoadIconW(
423 HINSTANCE hInstance,
424 LPCWSTR lpIconName)
425 {
426 return(LoadImageW(hInstance, lpIconName, IMAGE_ICON, 0, 0, LR_SHARED | LR_DEFAULTSIZE));
427 }
428
429
430 /*
431 * @implemented
432 */
433 int
434 STDCALL
435 LookupIconIdFromDirectory(
436 PBYTE presbits,
437 BOOL fIcon)
438 {
439 return LookupIconIdFromDirectoryEx( presbits, fIcon,
440 fIcon ? GetSystemMetrics(SM_CXICON) : GetSystemMetrics(SM_CXCURSOR),
441 fIcon ? GetSystemMetrics(SM_CYICON) : GetSystemMetrics(SM_CYCURSOR), LR_DEFAULTCOLOR );
442 }
443
444 /* Ported from WINE20030408 */
445 GRPCURSORICONDIRENTRY*
446 CURSORICON_FindBestCursor( GRPCURSORICONDIR *dir, int width, int height, int colors)
447 {
448 int i;
449 GRPCURSORICONDIRENTRY *entry, *bestEntry = NULL;
450 UINT iTotalDiff, iXDiff=0, iYDiff=0, iColorDiff;
451 UINT iTempXDiff, iTempYDiff, iTempColorDiff;
452
453 if (dir->idCount < 1)
454 {
455 DPRINT("Empty directory!\n");
456 return NULL;
457 }
458 if (dir->idCount == 1)
459 return &dir->idEntries[0]; /* No choice... */
460
461 /* Find Best Fit */
462 iTotalDiff = 0xFFFFFFFF;
463 iColorDiff = 0xFFFFFFFF;
464 for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
465 {
466 iTempXDiff = abs(width - entry->ResInfo.icon.bWidth);
467 iTempYDiff = abs(height - entry->ResInfo.icon.bHeight);
468
469 if(iTotalDiff > (iTempXDiff + iTempYDiff))
470 {
471 iXDiff = iTempXDiff;
472 iYDiff = iTempYDiff;
473 iTotalDiff = iXDiff + iYDiff;
474 }
475 }
476
477 /* Find Best Colors for Best Fit */
478 for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
479 {
480 if(abs(width - entry->ResInfo.icon.bWidth) == (int) iXDiff &&
481 abs(height - entry->ResInfo.icon.bHeight) == (int) iYDiff)
482 {
483 iTempColorDiff = abs(colors - entry->ResInfo.icon.bColorCount);
484
485 if(iColorDiff > iTempColorDiff)
486 {
487 bestEntry = entry;
488 iColorDiff = iTempColorDiff;
489 }
490 }
491 }
492
493 return bestEntry;
494 }
495
496 /* Ported from WINE20030408 */
497 GRPCURSORICONDIRENTRY*
498 CURSORICON_FindBestIcon( GRPCURSORICONDIR *dir, int width, int height, int colorbits)
499 {
500 int i;
501 GRPCURSORICONDIRENTRY *entry, *bestEntry = NULL;
502 UINT iTotalDiff, iXDiff=0, iYDiff=0, iColorDiff;
503 UINT iTempXDiff, iTempYDiff, iTempColorDiff;
504
505 if (dir->idCount < 1)
506 {
507 DPRINT("Empty directory!\n");
508 return NULL;
509 }
510 if (dir->idCount == 1)
511 return &dir->idEntries[0]; /* No choice... */
512
513 /* Find Best Fit */
514 iTotalDiff = 0xFFFFFFFF;
515 iColorDiff = 0xFFFFFFFF;
516 for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
517 {
518 iTempXDiff = abs(width - entry->ResInfo.icon.bWidth);
519
520 iTempYDiff = abs(height - entry->ResInfo.icon.bHeight);
521
522 if(iTotalDiff > (iTempXDiff + iTempYDiff))
523 {
524 iXDiff = iTempXDiff;
525 iYDiff = iTempYDiff;
526 iTotalDiff = iXDiff + iYDiff;
527 }
528 }
529
530 /* Find Best Colors for Best Fit */
531 for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
532 {
533 if(abs(width - entry->ResInfo.icon.bWidth) == (int) iXDiff &&
534 abs(height - entry->ResInfo.icon.bHeight) == (int) iYDiff)
535 {
536 iTempColorDiff = abs(colorbits - entry->wBitCount);
537 if(iColorDiff > iTempColorDiff)
538 {
539 bestEntry = entry;
540 iColorDiff = iTempColorDiff;
541 }
542 }
543 }
544
545 return bestEntry;
546 }
547
548 /* Ported from WINE20030408 */
549 /*
550 * @implemented
551 */
552 INT STDCALL
553 LookupIconIdFromDirectoryEx(
554 PBYTE presbits,
555 BOOL fIcon,
556 int cxDesired,
557 int cyDesired,
558 UINT Flags)
559 {
560 GRPCURSORICONDIR *dir = (GRPCURSORICONDIR*)presbits;
561 UINT retVal = 0;
562
563 if (dir && !dir->idReserved && (IMAGE_ICON == dir->idType || IMAGE_CURSOR == dir->idType))
564 {
565 GRPCURSORICONDIRENTRY *entry;
566 HDC hdc;
567 int ColorBits;
568
569 hdc = CreateICW(NULL, NULL, NULL, NULL);
570 if (Flags & LR_MONOCHROME)
571 {
572 ColorBits = 1;
573 }
574 else
575 {
576 ColorBits = GetDeviceCaps(hdc, BITSPIXEL);
577 if (ColorBits > 8)
578 ColorBits = 8;
579 }
580 DeleteDC(hdc);
581
582 entry = CURSORICON_FindBestIcon( dir, cxDesired, cyDesired, ColorBits );
583
584 if (entry)
585 retVal = entry->nID;
586 }
587 else
588 {
589 DbgPrint("invalid resource directory\n");
590 }
591 return retVal;
592 }