2 * Cursor and icon support
4 * Copyright 1995 Alexandre Julliard
5 * 1996 Martin Von Loewis
7 * 1998 Turchanov Sergey
13 * http://www.microsoft.com/win32dev/ui/icons.htm
15 * Cursors and icons are stored in a global heap block, with the
18 * CURSORICONINFO info;
22 * The bits structures are in the format of a device-dependent bitmap.
24 * This layout is very sub-optimal, as the bitmap bits are stored in
25 * the X client instead of in the server like other bitmaps; however,
26 * some programs (notably Paint Brush) expect to be able to manipulate
27 * the bits directly :-(
29 * FIXME: what are we going to do with animation and color (bpp > 1) cursors ?!
35 #include "wine/winbase16.h"
36 #include "wine/winuser16.h"
40 #include "cursoricon.h"
43 #include "sysmetrics.h"
54 DECLARE_DEBUG_CHANNEL(cursor)
55 DECLARE_DEBUG_CHANNEL(icon)
57 static HCURSOR hActiveCursor = 0; /* Active cursor */
58 static INT CURSOR_ShowCount = 0; /* Cursor display count */
59 static RECT CURSOR_ClipRect; /* Cursor clipping rect */
62 /**********************************************************************
63 * ICONCACHE for cursors/icons loaded with LR_SHARED.
65 * FIXME: This should not be allocated on the system heap, but on a
66 * subsystem-global heap (i.e. one for all Win16 processes,
67 * and one each for every Win32 process).
69 typedef struct tagICONCACHE
71 struct tagICONCACHE *next;
81 static ICONCACHE *IconAnchor = NULL;
82 static CRITICAL_SECTION IconCrst;
84 /**********************************************************************
87 void CURSORICON_Init( void )
89 InitializeCriticalSection( &IconCrst );
90 MakeCriticalSectionGlobal( &IconCrst );
93 /**********************************************************************
94 * CURSORICON_FindSharedIcon
96 static HANDLE CURSORICON_FindSharedIcon( HMODULE hModule, HRSRC hRsrc )
101 EnterCriticalSection( &IconCrst );
103 for ( ptr = IconAnchor; ptr; ptr = ptr->next )
104 if ( ptr->hModule == hModule && ptr->hRsrc == hRsrc )
107 handle = ptr->handle;
111 LeaveCriticalSection( &IconCrst );
116 /**********************************************************************
117 * CURSORICON_AddSharedIcon
119 static void CURSORICON_AddSharedIcon( HMODULE hModule, HRSRC hRsrc, HANDLE handle )
121 ICONCACHE *ptr = HeapAlloc( SystemHeap, 0, sizeof(ICONCACHE) );
124 ptr->hModule = hModule;
126 ptr->handle = handle;
129 EnterCriticalSection( &IconCrst );
130 ptr->next = IconAnchor;
132 LeaveCriticalSection( &IconCrst );
135 /**********************************************************************
136 * CURSORICON_DelSharedIcon
138 static INT CURSORICON_DelSharedIcon( HANDLE handle )
143 EnterCriticalSection( &IconCrst );
145 for ( ptr = IconAnchor; ptr; ptr = ptr->next )
146 if ( ptr->handle == handle )
148 if ( ptr->count > 0 ) ptr->count--;
153 LeaveCriticalSection( &IconCrst );
158 /**********************************************************************
159 * CURSORICON_FreeModuleIcons
161 void CURSORICON_FreeModuleIcons( HMODULE hModule )
163 ICONCACHE **ptr = &IconAnchor;
165 if ( HIWORD( hModule ) )
166 hModule = MapHModuleLS( hModule );
168 hModule = GetExePtr( hModule );
170 EnterCriticalSection( &IconCrst );
174 if ( (*ptr)->hModule == hModule )
176 ICONCACHE *freePtr = *ptr;
177 *ptr = freePtr->next;
179 GlobalFree16( freePtr->handle );
180 HeapFree( SystemHeap, 0, freePtr );
186 LeaveCriticalSection( &IconCrst );
189 /**********************************************************************
190 * CURSORICON_FindBestIcon
192 * Find the icon closest to the requested size and number of colors.
194 static CURSORICONDIRENTRY *CURSORICON_FindBestIcon( CURSORICONDIR *dir, int width,
195 int height, int colors )
197 int i, maxcolors, maxwidth, maxheight;
198 CURSORICONDIRENTRY *entry, *bestEntry = NULL;
200 if (dir->idCount < 1)
202 WARN(icon, "Empty directory!\n" );
205 if (dir->idCount == 1) return &dir->idEntries[0]; /* No choice... */
207 /* First find the exact size with less colors */
210 for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
211 if ((entry->ResInfo.icon.bWidth == width) && (entry->ResInfo.icon.bHeight == height) &&
212 (entry->ResInfo.icon.bColorCount <= colors) && (entry->ResInfo.icon.bColorCount > maxcolors))
215 maxcolors = entry->ResInfo.icon.bColorCount;
217 if (bestEntry) return bestEntry;
219 /* First find the exact size with more colors */
222 for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
223 if ((entry->ResInfo.icon.bWidth == width) && (entry->ResInfo.icon.bHeight == height) &&
224 (entry->ResInfo.icon.bColorCount > colors) && (entry->ResInfo.icon.bColorCount <= maxcolors))
227 maxcolors = entry->ResInfo.icon.bColorCount;
229 if (bestEntry) return bestEntry;
231 /* Now find a smaller one with less colors */
233 maxcolors = maxwidth = maxheight = 0;
234 for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
235 if ((entry->ResInfo.icon.bWidth <= width) && (entry->ResInfo.icon.bHeight <= height) &&
236 (entry->ResInfo.icon.bWidth >= maxwidth) && (entry->ResInfo.icon.bHeight >= maxheight) &&
237 (entry->ResInfo.icon.bColorCount <= colors) && (entry->ResInfo.icon.bColorCount > maxcolors))
240 maxwidth = entry->ResInfo.icon.bWidth;
241 maxheight = entry->ResInfo.icon.bHeight;
242 maxcolors = entry->ResInfo.icon.bColorCount;
244 if (bestEntry) return bestEntry;
246 /* Now find a smaller one with more colors */
249 maxwidth = maxheight = 0;
250 for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
251 if ((entry->ResInfo.icon.bWidth <= width) && (entry->ResInfo.icon.bHeight <= height) &&
252 (entry->ResInfo.icon.bWidth >= maxwidth) && (entry->ResInfo.icon.bHeight >= maxheight) &&
253 (entry->ResInfo.icon.bColorCount > colors) && (entry->ResInfo.icon.bColorCount <= maxcolors))
256 maxwidth = entry->ResInfo.icon.bWidth;
257 maxheight = entry->ResInfo.icon.bHeight;
258 maxcolors = entry->ResInfo.icon.bColorCount;
260 if (bestEntry) return bestEntry;
262 /* Now find a larger one with less colors */
265 maxwidth = maxheight = 255;
266 for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
267 if ((entry->ResInfo.icon.bWidth <= maxwidth) && (entry->ResInfo.icon.bHeight <= maxheight) &&
268 (entry->ResInfo.icon.bColorCount <= colors) && (entry->ResInfo.icon.bColorCount > maxcolors))
271 maxwidth = entry->ResInfo.icon.bWidth;
272 maxheight = entry->ResInfo.icon.bHeight;
273 maxcolors = entry->ResInfo.icon.bColorCount;
275 if (bestEntry) return bestEntry;
277 /* Now find a larger one with more colors */
279 maxcolors = maxwidth = maxheight = 255;
280 for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
281 if ((entry->ResInfo.icon.bWidth <= maxwidth) && (entry->ResInfo.icon.bHeight <= maxheight) &&
282 (entry->ResInfo.icon.bColorCount > colors) && (entry->ResInfo.icon.bColorCount <= maxcolors))
285 maxwidth = entry->ResInfo.icon.bWidth;
286 maxheight = entry->ResInfo.icon.bHeight;
287 maxcolors = entry->ResInfo.icon.bColorCount;
294 /**********************************************************************
295 * CURSORICON_FindBestCursor
297 * Find the cursor closest to the requested size.
298 * FIXME: parameter 'color' ignored and entries with more than 1 bpp
301 static CURSORICONDIRENTRY *CURSORICON_FindBestCursor( CURSORICONDIR *dir,
302 int width, int height, int color)
304 int i, maxwidth, maxheight;
305 CURSORICONDIRENTRY *entry, *bestEntry = NULL;
307 if (dir->idCount < 1)
309 WARN(cursor, "Empty directory!\n" );
312 if (dir->idCount == 1) return &dir->idEntries[0]; /* No choice... */
314 /* First find the largest one smaller than or equal to the requested size*/
316 maxwidth = maxheight = 0;
317 for(i = 0,entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
318 if ((entry->ResInfo.cursor.wWidth <= width) && (entry->ResInfo.cursor.wHeight <= height) &&
319 (entry->ResInfo.cursor.wWidth > maxwidth) && (entry->ResInfo.cursor.wHeight > maxheight) &&
320 (entry->wBitCount == 1))
323 maxwidth = entry->ResInfo.cursor.wWidth;
324 maxheight = entry->ResInfo.cursor.wHeight;
326 if (bestEntry) return bestEntry;
328 /* Now find the smallest one larger than the requested size */
330 maxwidth = maxheight = 255;
331 for(i = 0,entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
332 if ((entry->ResInfo.cursor.wWidth < maxwidth) && (entry->ResInfo.cursor.wHeight < maxheight) &&
333 (entry->wBitCount == 1))
336 maxwidth = entry->ResInfo.cursor.wWidth;
337 maxheight = entry->ResInfo.cursor.wHeight;
343 /*********************************************************************
344 * The main purpose of this function is to create fake resource directory
345 * and fake resource entries. There are several reasons for this:
346 * - CURSORICONDIR and CURSORICONFILEDIR differ in sizes and their
348 * There are some "bad" cursor files which do not have
349 * bColorCount initialized but instead one must read this info
350 * directly from corresponding DIB sections
351 * Note: wResId is index to array of pointer returned in ptrs (origin is 1)
353 BOOL CURSORICON_SimulateLoadingFromResourceW( LPWSTR filename, BOOL fCursor,
354 CURSORICONDIR **res, LPBYTE **ptr)
357 CURSORICONFILEDIR *bits;
358 int entries, size, i;
362 if (!(bits = (CURSORICONFILEDIR *)VIRTUAL_MapFileW( filename ))) return FALSE;
364 /* FIXME: test for inimated icons
365 * hack to load the first icon from the *.ani file
367 if ( *(LPDWORD)bits==0x46464952 ) /* "RIFF" */
368 { LPBYTE pos = (LPBYTE) bits;
369 FIXME (cursor,"Animated icons not correctly implemented! %p \n", bits);
372 { if (*(LPDWORD)pos==0x6e6f6369) /* "icon" */
373 { FIXME (cursor,"icon entry found! %p\n", bits);
375 if ( !*(LPWORD) pos==0x2fe) /* iconsize */
379 FIXME (cursor,"icon size ok %p \n", bits);
383 if (pos>=(LPBYTE)bits+766) goto fail;
386 if (!(entries = bits->idCount)) goto fail;
387 (int)_free = size = sizeof(CURSORICONDIR) + sizeof(CURSORICONDIRENTRY) *
389 for (i=0; i < entries; i++)
390 size += bits->idEntries[i].dwDIBSize + (fCursor ? sizeof(POINT16): 0);
392 if (!(*ptr = HeapAlloc( GetProcessHeap(), 0,
393 entries * sizeof (CURSORICONDIRENTRY*)))) goto fail;
394 if (!(*res = HeapAlloc( GetProcessHeap(), 0, size))) goto fail;
396 _free = (LPBYTE)(*res) + (int)_free;
397 memcpy((*res), bits, 6);
398 for (i=0; i<entries; i++)
400 ((LPBYTE*)(*ptr))[i] = _free;
402 (*res)->idEntries[i].ResInfo.cursor.wWidth=bits->idEntries[i].bWidth;
403 (*res)->idEntries[i].ResInfo.cursor.wHeight=bits->idEntries[i].bHeight;
404 ((LPPOINT16)_free)->x=bits->idEntries[i].xHotspot;
405 ((LPPOINT16)_free)->y=bits->idEntries[i].yHotspot;
406 _free+=sizeof(POINT16);
408 (*res)->idEntries[i].ResInfo.icon.bWidth=bits->idEntries[i].bWidth;
409 (*res)->idEntries[i].ResInfo.icon.bHeight=bits->idEntries[i].bHeight;
410 (*res)->idEntries[i].ResInfo.icon.bColorCount = bits->idEntries[i].bColorCount;
412 (*res)->idEntries[i].wPlanes=1;
413 (*res)->idEntries[i].wBitCount = ((LPBITMAPINFOHEADER)((LPBYTE)bits +
414 bits->idEntries[i].dwDIBOffset))->biBitCount;
415 (*res)->idEntries[i].dwBytesInRes = bits->idEntries[i].dwDIBSize;
416 (*res)->idEntries[i].wResId=i+1;
418 memcpy(_free,(LPBYTE)bits +bits->idEntries[i].dwDIBOffset,
419 (*res)->idEntries[i].dwBytesInRes);
420 _free += (*res)->idEntries[i].dwBytesInRes;
422 UnmapViewOfFile( bits );
425 if (*res) HeapFree( GetProcessHeap(), 0, *res );
426 if (*ptr) HeapFree( GetProcessHeap(), 0, *ptr );
427 UnmapViewOfFile( bits );
432 /**********************************************************************
433 * CURSORICON_CreateFromResource
435 * Create a cursor or icon from in-memory resource template.
437 * FIXME: Convert to mono when cFlag is LR_MONOCHROME. Do something
438 * with cbSize parameter as well.
440 static HGLOBAL16 CURSORICON_CreateFromResource( HINSTANCE16 hInstance, HGLOBAL16 hObj, LPBYTE bits,
441 UINT cbSize, BOOL bIcon, DWORD dwVersion,
442 INT width, INT height, UINT loadflags )
444 int sizeAnd, sizeXor;
445 HBITMAP hAndBits = 0, hXorBits = 0; /* error condition for later */
446 BITMAPOBJ *bmpXor, *bmpAnd;
447 POINT16 hotspot = { 0 ,0 };
453 TRACE(cursor,"%08x (%u bytes), ver %08x, %ix%i %s %s\n",
454 (unsigned)bits, cbSize, (unsigned)dwVersion, width, height,
455 bIcon ? "icon" : "cursor", (loadflags & LR_MONOCHROME) ? "mono" : "" );
456 if (dwVersion == 0x00020000)
458 FIXME(cursor,"\t2.xx resources are not supported\n");
463 bmi = (BITMAPINFO *)bits;
464 else /* get the hotspot */
466 POINT16 *pt = (POINT16 *)bits;
468 bmi = (BITMAPINFO *)(pt + 1);
470 size = DIB_BitmapInfoSize( bmi, DIB_RGB_COLORS );
472 if (!width) width = bmi->bmiHeader.biWidth;
473 if (!height) height = bmi->bmiHeader.biHeight/2;
474 DoStretch = (bmi->bmiHeader.biHeight/2 != height) ||
475 (bmi->bmiHeader.biWidth != width);
477 /* Check bitmap header */
479 if ( (bmi->bmiHeader.biSize != sizeof(BITMAPCOREHEADER)) &&
480 (bmi->bmiHeader.biSize != sizeof(BITMAPINFOHEADER) ||
481 bmi->bmiHeader.biCompression != BI_RGB) )
483 WARN(cursor,"\tinvalid resource bitmap header.\n");
487 if( (hdc = GetDC( 0 )) )
491 /* Make sure we have room for the monochrome bitmap later on.
492 * Note that BITMAPINFOINFO and BITMAPCOREHEADER are the same
493 * up to and including the biBitCount. In-memory icon resource
494 * format is as follows:
496 * BITMAPINFOHEADER icHeader // DIB header
497 * RGBQUAD icColors[] // Color table
498 * BYTE icXOR[] // DIB bits for XOR mask
499 * BYTE icAND[] // DIB bits for AND mask
502 if ((pInfo = (BITMAPINFO *)HeapAlloc( GetProcessHeap(), 0,
503 MAX(size, sizeof(BITMAPINFOHEADER) + 2*sizeof(RGBQUAD)))))
505 memcpy( pInfo, bmi, size );
506 pInfo->bmiHeader.biHeight /= 2;
508 /* Create the XOR bitmap */
511 if ((hXorBits = CreateCompatibleBitmap(hdc, width, height))) {
513 HDC hMem = CreateCompatibleDC(hdc);
517 hOld = SelectObject(hMem, hXorBits);
518 res = StretchDIBits(hMem, 0, 0, width, height, 0, 0,
519 bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight/2,
520 (char*)bmi + size, pInfo, DIB_RGB_COLORS, SRCCOPY);
521 SelectObject(hMem, hOld);
524 if (!res) { DeleteObject(hXorBits); hXorBits = 0; }
526 } else hXorBits = CreateDIBitmap( hdc, &pInfo->bmiHeader,
527 CBM_INIT, (char*)bmi + size, pInfo, DIB_RGB_COLORS );
530 char* bits = (char *)bmi + size +
531 DIB_GetDIBImageBytes(bmi->bmiHeader.biWidth,
532 bmi->bmiHeader.biHeight,
533 bmi->bmiHeader.biBitCount) / 2;
535 pInfo->bmiHeader.biBitCount = 1;
536 if (pInfo->bmiHeader.biSize == sizeof(BITMAPINFOHEADER))
538 RGBQUAD *rgb = pInfo->bmiColors;
540 pInfo->bmiHeader.biClrUsed = pInfo->bmiHeader.biClrImportant = 2;
541 rgb[0].rgbBlue = rgb[0].rgbGreen = rgb[0].rgbRed = 0x00;
542 rgb[1].rgbBlue = rgb[1].rgbGreen = rgb[1].rgbRed = 0xff;
543 rgb[0].rgbReserved = rgb[1].rgbReserved = 0;
547 RGBTRIPLE *rgb = (RGBTRIPLE *)(((BITMAPCOREHEADER *)pInfo) + 1);
549 rgb[0].rgbtBlue = rgb[0].rgbtGreen = rgb[0].rgbtRed = 0x00;
550 rgb[1].rgbtBlue = rgb[1].rgbtGreen = rgb[1].rgbtRed = 0xff;
553 /* Create the AND bitmap */
556 if ((hAndBits = CreateBitmap(width, height, 1, 1, NULL))) {
558 HDC hMem = CreateCompatibleDC(hdc);
562 hOld = SelectObject(hMem, hAndBits);
563 res = StretchDIBits(hMem, 0, 0, width, height, 0, 0,
564 pInfo->bmiHeader.biWidth, pInfo->bmiHeader.biHeight,
565 bits, pInfo, DIB_RGB_COLORS, SRCCOPY);
566 SelectObject(hMem, hOld);
569 if (!res) { DeleteObject(hAndBits); hAndBits = 0; }
571 } else hAndBits = CreateDIBitmap( hdc, &pInfo->bmiHeader,
572 CBM_INIT, bits, pInfo, DIB_RGB_COLORS );
574 if( !hAndBits ) DeleteObject( hXorBits );
576 HeapFree( GetProcessHeap(), 0, pInfo );
581 if( !hXorBits || !hAndBits )
583 WARN(cursor,"\tunable to create an icon bitmap.\n");
587 /* Now create the CURSORICONINFO structure */
588 bmpXor = (BITMAPOBJ *) GDI_GetObjPtr( hXorBits, BITMAP_MAGIC );
589 bmpAnd = (BITMAPOBJ *) GDI_GetObjPtr( hAndBits, BITMAP_MAGIC );
590 sizeXor = bmpXor->bitmap.bmHeight * bmpXor->bitmap.bmWidthBytes;
591 sizeAnd = bmpAnd->bitmap.bmHeight * bmpAnd->bitmap.bmWidthBytes;
593 if (hObj) hObj = GlobalReAlloc16( hObj,
594 sizeof(CURSORICONINFO) + sizeXor + sizeAnd, GMEM_MOVEABLE );
595 if (!hObj) hObj = GlobalAlloc16( GMEM_MOVEABLE,
596 sizeof(CURSORICONINFO) + sizeXor + sizeAnd );
599 CURSORICONINFO *info;
601 /* Make it owned by the module */
602 if (hInstance) FarSetOwner16( hObj, GetExePtr(hInstance) );
604 info = (CURSORICONINFO *)GlobalLock16( hObj );
605 info->ptHotSpot.x = hotspot.x;
606 info->ptHotSpot.y = hotspot.y;
607 info->nWidth = bmpXor->bitmap.bmWidth;
608 info->nHeight = bmpXor->bitmap.bmHeight;
609 info->nWidthBytes = bmpXor->bitmap.bmWidthBytes;
610 info->bPlanes = bmpXor->bitmap.bmPlanes;
611 info->bBitsPerPixel = bmpXor->bitmap.bmBitsPixel;
613 /* Transfer the bitmap bits to the CURSORICONINFO structure */
615 GetBitmapBits( hAndBits, sizeAnd, (char *)(info + 1) );
616 GetBitmapBits( hXorBits, sizeXor, (char *)(info + 1) + sizeAnd );
617 GlobalUnlock16( hObj );
620 DeleteObject( hXorBits );
621 DeleteObject( hAndBits );
626 /**********************************************************************
627 * CreateIconFromResourceEx16 (USER.450)
629 * FIXME: not sure about exact parameter types
631 HICON16 WINAPI CreateIconFromResourceEx16( LPBYTE bits, UINT16 cbSize, BOOL16 bIcon,
632 DWORD dwVersion, INT16 width, INT16 height, UINT16 cFlag )
634 return CreateIconFromResourceEx(bits, cbSize, bIcon, dwVersion,
635 width, height, cFlag);
639 /**********************************************************************
640 * CreateIconFromResource (USER32.76)
642 HICON WINAPI CreateIconFromResource( LPBYTE bits, UINT cbSize,
643 BOOL bIcon, DWORD dwVersion)
645 return CreateIconFromResourceEx( bits, cbSize, bIcon, dwVersion, 0,0,0);
649 /**********************************************************************
650 * CreateIconFromResourceEx32 (USER32.77)
652 HICON WINAPI CreateIconFromResourceEx( LPBYTE bits, UINT cbSize,
653 BOOL bIcon, DWORD dwVersion,
654 INT width, INT height,
657 TDB* pTask = (TDB*)GlobalLock16( GetCurrentTask() );
659 return CURSORICON_CreateFromResource( pTask->hInstance, 0, bits, cbSize, bIcon, dwVersion,
660 width, height, cFlag );
664 /**********************************************************************
667 * Load a cursor or icon from resource or file.
669 HGLOBAL CURSORICON_Load( HINSTANCE hInstance, LPCWSTR name,
670 INT width, INT height, INT colors,
671 BOOL fCursor, UINT loadflags )
673 HANDLE handle = 0, h = 0;
676 CURSORICONDIRENTRY *dirEntry;
679 if ( loadflags & LR_LOADFROMFILE ) /* Load from file */
682 if (!CURSORICON_SimulateLoadingFromResourceW((LPWSTR)name, fCursor, &dir, &ptr))
685 dirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestCursor(dir, width, height, 1);
687 dirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestIcon(dir, width, height, colors);
688 bits = ptr[dirEntry->wResId-1];
689 h = CURSORICON_CreateFromResource( 0, 0, bits, dirEntry->dwBytesInRes,
690 !fCursor, 0x00030000, width, height, loadflags);
691 HeapFree( GetProcessHeap(), 0, dir );
692 HeapFree( GetProcessHeap(), 0, ptr );
695 else if ( !hInstance ) /* Load OEM cursor/icon */
703 LPSTR ansi = HEAP_strdupWtoA(GetProcessHeap(),0,name);
704 if( ansi[0]=='#') /*Check for '#xxx' name */
706 resid = atoi(ansi+1);
707 HeapFree( GetProcessHeap(), 0, ansi );
711 HeapFree( GetProcessHeap(), 0, ansi );
715 else resid = LOWORD(name);
716 hdc = CreateDCA( "DISPLAY", NULL, NULL, NULL );
717 dc = DC_GetDCPtr( hdc );
718 if (dc->funcs->pLoadOEMResource)
719 h = dc->funcs->pLoadOEMResource( resid, fCursor ?
720 OEM_CURSOR : OEM_ICON );
721 GDI_HEAP_UNLOCK( hdc );
725 else /* Load from resource */
730 /* Normalize hInstance (must be uniquely represented for icon cache) */
732 if ( HIWORD( hInstance ) )
733 hInstance = MapHModuleLS( hInstance );
735 hInstance = GetExePtr( hInstance );
737 /* Get directory resource ID */
739 if (!(hRsrc = FindResourceW( hInstance, name,
740 fCursor ? RT_GROUP_CURSORW : RT_GROUP_ICONW )))
743 /* If shared icon, check whether it was already loaded */
745 if ( (loadflags & LR_SHARED)
746 && (h = CURSORICON_FindSharedIcon( hInstance, hRsrc ) ) != 0 )
749 /* Find the best entry in the directory */
751 if (!(handle = LoadResource( hInstance, hRsrc ))) return 0;
752 if (!(dir = (CURSORICONDIR*)LockResource( handle ))) return 0;
754 dirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestCursor( dir,
757 dirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestIcon( dir,
758 width, height, colors );
759 if (!dirEntry) return 0;
760 wResId = dirEntry->wResId;
761 dwBytesInRes = dirEntry->dwBytesInRes;
762 FreeResource( handle );
764 /* Load the resource */
766 if (!(hRsrc = FindResourceW(hInstance,MAKEINTRESOURCEW(wResId),
767 fCursor ? RT_CURSORW : RT_ICONW ))) return 0;
768 if (!(handle = LoadResource( hInstance, hRsrc ))) return 0;
769 bits = (LPBYTE)LockResource( handle );
770 h = CURSORICON_CreateFromResource( 0, 0, bits, dwBytesInRes,
771 !fCursor, 0x00030000, width, height, loadflags);
772 FreeResource( handle );
774 /* If shared icon, add to icon cache */
776 if ( h && (loadflags & LR_SHARED) )
777 CURSORICON_AddSharedIcon( hInstance, hRsrc, h );
783 /***********************************************************************
786 * Make a copy of a cursor or icon.
788 static HGLOBAL16 CURSORICON_Copy( HINSTANCE16 hInstance, HGLOBAL16 handle )
790 char *ptrOld, *ptrNew;
794 if (!(ptrOld = (char *)GlobalLock16( handle ))) return 0;
795 if (!(hInstance = GetExePtr( hInstance ))) return 0;
796 size = GlobalSize16( handle );
797 hNew = GlobalAlloc16( GMEM_MOVEABLE, size );
798 FarSetOwner16( hNew, hInstance );
799 ptrNew = (char *)GlobalLock16( hNew );
800 memcpy( ptrNew, ptrOld, size );
801 GlobalUnlock16( handle );
802 GlobalUnlock16( hNew );
806 /***********************************************************************
807 * CURSORICON_IconToCursor
809 * Converts bitmap to mono and truncates if icon is too large (should
810 * probably do StretchBlt() instead).
812 HCURSOR16 CURSORICON_IconToCursor(HICON16 hIcon, BOOL bSemiTransparent)
815 CURSORICONINFO *pIcon = NULL;
816 HTASK16 hTask = GetCurrentTask();
817 TDB* pTask = (TDB *)GlobalLock16(hTask);
820 if (!(pIcon = (CURSORICONINFO*)GlobalLock16( hIcon ))) return FALSE;
821 if (pIcon->bPlanes * pIcon->bBitsPerPixel == 1)
822 hRet = CURSORICON_Copy( pTask->hInstance, hIcon );
827 int maxx, maxy, ix, iy, bpp = pIcon->bBitsPerPixel;
828 BYTE* psPtr, *pxbPtr = pXorBits;
829 unsigned xor_width, and_width, val_base = 0xffffffff >> (32 - bpp);
834 TRACE(icon, "[%04x] %ix%i %ibpp (bogus %ibps)\n",
835 hIcon, pIcon->nWidth, pIcon->nHeight, pIcon->bBitsPerPixel, pIcon->nWidthBytes );
837 xor_width = BITMAP_GetWidthBytes( pIcon->nWidth, bpp );
838 and_width = BITMAP_GetWidthBytes( pIcon->nWidth, 1 );
839 psPtr = (BYTE *)(pIcon + 1) + pIcon->nHeight * and_width;
841 memset(pXorBits, 0, 128);
842 cI.bBitsPerPixel = 1; cI.bPlanes = 1;
843 cI.ptHotSpot.x = cI.ptHotSpot.y = 15;
844 cI.nWidth = 32; cI.nHeight = 32;
845 cI.nWidthBytes = 4; /* 32x1bpp */
847 maxx = (pIcon->nWidth > 32) ? 32 : pIcon->nWidth;
848 maxy = (pIcon->nHeight > 32) ? 32 : pIcon->nHeight;
850 for( iy = 0; iy < maxy; iy++ )
852 unsigned shift = iy % 2;
854 memcpy( pAndBits + iy * 4, (BYTE *)(pIcon + 1) + iy * and_width,
855 (and_width > 4) ? 4 : and_width );
856 for( ix = 0; ix < maxx; ix++ )
858 if( bSemiTransparent && ((ix+shift)%2) )
860 /* set AND bit, XOR bit stays 0 */
862 pbc = pAndBits + iy * 4 + ix/8;
863 *pbc |= 0x80 >> (ix%8);
867 /* keep AND bit, set XOR bit */
869 unsigned *psc = (unsigned*)(psPtr + (ix * bpp)/8);
870 unsigned val = ((*psc) >> (ix * bpp)%8) & val_base;
871 if(!PALETTE_Driver->pIsDark(val))
874 *pbc |= 0x80 >> (ix%8);
882 hRet = CreateCursorIconIndirect16( pTask->hInstance , &cI, pAndBits, pXorBits);
884 if( !hRet ) /* fall back on default drag cursor */
885 hRet = CURSORICON_Copy( pTask->hInstance ,
886 CURSORICON_Load(0,MAKEINTRESOURCEW(OCR_DRAGOBJECT),
887 SYSMETRICS_CXCURSOR, SYSMETRICS_CYCURSOR, 1, TRUE, 0) );
894 /***********************************************************************
895 * LoadCursor16 (USER.173)
897 HCURSOR16 WINAPI LoadCursor16( HINSTANCE16 hInstance, SEGPTR name )
899 LPCSTR nameStr = HIWORD(name)? PTR_SEG_TO_LIN(name) : (LPCSTR)name;
900 return LoadCursorA( hInstance, nameStr );
904 /***********************************************************************
905 * LoadIcon16 (USER.174)
907 HICON16 WINAPI LoadIcon16( HINSTANCE16 hInstance, SEGPTR name )
909 LPCSTR nameStr = HIWORD(name)? PTR_SEG_TO_LIN(name) : (LPCSTR)name;
910 return LoadIconA( hInstance, nameStr );
914 /***********************************************************************
915 * CreateCursor16 (USER.406)
917 HCURSOR16 WINAPI CreateCursor16( HINSTANCE16 hInstance,
918 INT16 xHotSpot, INT16 yHotSpot,
919 INT16 nWidth, INT16 nHeight,
920 LPCVOID lpANDbits, LPCVOID lpXORbits )
922 CURSORICONINFO info = { { xHotSpot, yHotSpot }, nWidth, nHeight, 0, 1, 1 };
924 TRACE(cursor, "%dx%d spot=%d,%d xor=%p and=%p\n",
925 nWidth, nHeight, xHotSpot, yHotSpot, lpXORbits, lpANDbits);
926 return CreateCursorIconIndirect16( hInstance, &info, lpANDbits, lpXORbits );
930 /***********************************************************************
931 * CreateCursor32 (USER32.67)
933 HCURSOR WINAPI CreateCursor( HINSTANCE hInstance,
934 INT xHotSpot, INT yHotSpot,
935 INT nWidth, INT nHeight,
936 LPCVOID lpANDbits, LPCVOID lpXORbits )
938 CURSORICONINFO info = { { xHotSpot, yHotSpot }, nWidth, nHeight, 0, 1, 1 };
940 TRACE(cursor, "%dx%d spot=%d,%d xor=%p and=%p\n",
941 nWidth, nHeight, xHotSpot, yHotSpot, lpXORbits, lpANDbits);
942 return CreateCursorIconIndirect16( 0, &info, lpANDbits, lpXORbits );
946 /***********************************************************************
947 * CreateIcon16 (USER.407)
949 HICON16 WINAPI CreateIcon16( HINSTANCE16 hInstance, INT16 nWidth,
950 INT16 nHeight, BYTE bPlanes, BYTE bBitsPixel,
951 LPCVOID lpANDbits, LPCVOID lpXORbits )
953 CURSORICONINFO info = { { 0, 0 }, nWidth, nHeight, 0, bPlanes, bBitsPixel};
955 TRACE(icon, "%dx%dx%d, xor=%p, and=%p\n",
956 nWidth, nHeight, bPlanes * bBitsPixel, lpXORbits, lpANDbits);
957 return CreateCursorIconIndirect16( hInstance, &info, lpANDbits, lpXORbits );
961 /***********************************************************************
962 * CreateIcon32 (USER32.75)
964 HICON WINAPI CreateIcon( HINSTANCE hInstance, INT nWidth,
965 INT nHeight, BYTE bPlanes, BYTE bBitsPixel,
966 LPCVOID lpANDbits, LPCVOID lpXORbits )
968 CURSORICONINFO info = { { 0, 0 }, nWidth, nHeight, 0, bPlanes, bBitsPixel};
970 TRACE(icon, "%dx%dx%d, xor=%p, and=%p\n",
971 nWidth, nHeight, bPlanes * bBitsPixel, lpXORbits, lpANDbits);
972 return CreateCursorIconIndirect16( 0, &info, lpANDbits, lpXORbits );
976 /***********************************************************************
977 * CreateCursorIconIndirect (USER.408)
979 HGLOBAL16 WINAPI CreateCursorIconIndirect16( HINSTANCE16 hInstance,
980 CURSORICONINFO *info,
986 int sizeAnd, sizeXor;
988 hInstance = GetExePtr( hInstance ); /* Make it a module handle */
989 if (!lpXORbits || !lpANDbits || info->bPlanes != 1) return 0;
990 info->nWidthBytes = BITMAP_GetWidthBytes(info->nWidth,info->bBitsPerPixel);
991 sizeXor = info->nHeight * info->nWidthBytes;
992 sizeAnd = info->nHeight * BITMAP_GetWidthBytes( info->nWidth, 1 );
993 if (!(handle = GlobalAlloc16( GMEM_MOVEABLE,
994 sizeof(CURSORICONINFO) + sizeXor + sizeAnd)))
996 if (hInstance) FarSetOwner16( handle, hInstance );
997 ptr = (char *)GlobalLock16( handle );
998 memcpy( ptr, info, sizeof(*info) );
999 memcpy( ptr + sizeof(CURSORICONINFO), lpANDbits, sizeAnd );
1000 memcpy( ptr + sizeof(CURSORICONINFO) + sizeAnd, lpXORbits, sizeXor );
1001 GlobalUnlock16( handle );
1006 /***********************************************************************
1007 * CopyIcon16 (USER.368)
1009 HICON16 WINAPI CopyIcon16( HINSTANCE16 hInstance, HICON16 hIcon )
1011 TRACE(icon, "%04x %04x\n", hInstance, hIcon );
1012 return CURSORICON_Copy( hInstance, hIcon );
1016 /***********************************************************************
1017 * CopyIcon32 (USER32.60)
1019 HICON WINAPI CopyIcon( HICON hIcon )
1021 HTASK16 hTask = GetCurrentTask ();
1022 TDB* pTask = (TDB *) GlobalLock16 (hTask);
1023 TRACE(icon, "%04x\n", hIcon );
1024 return CURSORICON_Copy( pTask->hInstance, hIcon );
1028 /***********************************************************************
1029 * CopyCursor16 (USER.369)
1031 HCURSOR16 WINAPI CopyCursor16( HINSTANCE16 hInstance, HCURSOR16 hCursor )
1033 TRACE(cursor, "%04x %04x\n", hInstance, hCursor );
1034 return CURSORICON_Copy( hInstance, hCursor );
1037 /**********************************************************************
1038 * CURSORICON_Destroy (USER.610)
1040 * This routine is actually exported from Win95 USER under the name
1041 * DestroyIcon32 ... The behaviour implemented here should mimic
1042 * the Win95 one exactly, especially the return values, which
1043 * depend on the setting of various flags.
1045 WORD WINAPI CURSORICON_Destroy( HGLOBAL16 handle, UINT16 flags )
1049 TRACE( icon, "(%04x, %04x)\n", handle, flags );
1051 /* Check whether destroying active cursor */
1053 if ( hActiveCursor == handle )
1055 ERR( cursor, "Destroying active cursor!\n" );
1059 /* Try shared cursor/icon first */
1061 if ( !(flags & CID_NONSHARED) )
1063 INT count = CURSORICON_DelSharedIcon( handle );
1066 return (flags & CID_WIN32)? TRUE : (count == 0);
1068 /* FIXME: OEM cursors/icons should be recognized */
1071 /* Now assume non-shared cursor/icon */
1073 retv = GlobalFree16( handle );
1074 return (flags & CID_RESOURCE)? retv : TRUE;
1077 /***********************************************************************
1078 * DestroyIcon16 (USER.457)
1080 BOOL16 WINAPI DestroyIcon16( HICON16 hIcon )
1082 return CURSORICON_Destroy( hIcon, 0 );
1085 /***********************************************************************
1086 * DestroyIcon (USER32.133)
1088 BOOL WINAPI DestroyIcon( HICON hIcon )
1090 return CURSORICON_Destroy( hIcon, CID_WIN32 );
1093 /***********************************************************************
1094 * DestroyCursor16 (USER.458)
1096 BOOL16 WINAPI DestroyCursor16( HCURSOR16 hCursor )
1098 return CURSORICON_Destroy( hCursor, 0 );
1101 /***********************************************************************
1102 * DestroyCursor (USER32.132)
1104 BOOL WINAPI DestroyCursor( HCURSOR hCursor )
1106 return CURSORICON_Destroy( hCursor, CID_WIN32 );
1110 /***********************************************************************
1111 * DrawIcon16 (USER.84)
1113 BOOL16 WINAPI DrawIcon16( HDC16 hdc, INT16 x, INT16 y, HICON16 hIcon )
1115 return DrawIcon( hdc, x, y, hIcon );
1119 /***********************************************************************
1120 * DrawIcon32 (USER32.159)
1122 BOOL WINAPI DrawIcon( HDC hdc, INT x, INT y, HICON hIcon )
1124 CURSORICONINFO *ptr;
1126 HBITMAP hXorBits, hAndBits;
1127 COLORREF oldFg, oldBg;
1129 if (!(ptr = (CURSORICONINFO *)GlobalLock16( hIcon ))) return FALSE;
1130 if (!(hMemDC = CreateCompatibleDC( hdc ))) return FALSE;
1131 hAndBits = CreateBitmap( ptr->nWidth, ptr->nHeight, 1, 1,
1133 hXorBits = CreateBitmap( ptr->nWidth, ptr->nHeight, ptr->bPlanes,
1134 ptr->bBitsPerPixel, (char *)(ptr + 1)
1135 + ptr->nHeight * BITMAP_GetWidthBytes(ptr->nWidth,1) );
1136 oldFg = SetTextColor( hdc, RGB(0,0,0) );
1137 oldBg = SetBkColor( hdc, RGB(255,255,255) );
1139 if (hXorBits && hAndBits)
1141 HBITMAP hBitTemp = SelectObject( hMemDC, hAndBits );
1142 BitBlt( hdc, x, y, ptr->nWidth, ptr->nHeight, hMemDC, 0, 0, SRCAND );
1143 SelectObject( hMemDC, hXorBits );
1144 BitBlt(hdc, x, y, ptr->nWidth, ptr->nHeight, hMemDC, 0, 0,SRCINVERT);
1145 SelectObject( hMemDC, hBitTemp );
1148 if (hXorBits) DeleteObject( hXorBits );
1149 if (hAndBits) DeleteObject( hAndBits );
1150 GlobalUnlock16( hIcon );
1151 SetTextColor( hdc, oldFg );
1152 SetBkColor( hdc, oldBg );
1157 /***********************************************************************
1158 * DumpIcon (USER.459)
1160 DWORD WINAPI DumpIcon16( SEGPTR pInfo, WORD *lpLen,
1161 SEGPTR *lpXorBits, SEGPTR *lpAndBits )
1163 CURSORICONINFO *info = PTR_SEG_TO_LIN( pInfo );
1164 int sizeAnd, sizeXor;
1166 if (!info) return 0;
1167 sizeXor = info->nHeight * info->nWidthBytes;
1168 sizeAnd = info->nHeight * BITMAP_GetWidthBytes( info->nWidth, 1 );
1169 if (lpAndBits) *lpAndBits = pInfo + sizeof(CURSORICONINFO);
1170 if (lpXorBits) *lpXorBits = pInfo + sizeof(CURSORICONINFO) + sizeAnd;
1171 if (lpLen) *lpLen = sizeof(CURSORICONINFO) + sizeAnd + sizeXor;
1172 return MAKELONG( sizeXor, sizeXor );
1176 /***********************************************************************
1177 * SetCursor16 (USER.69)
1179 HCURSOR16 WINAPI SetCursor16( HCURSOR16 hCursor )
1181 return (HCURSOR16)SetCursor( hCursor );
1185 /***********************************************************************
1186 * SetCursor32 (USER32.472)
1188 * A handle to the previous cursor shape.
1190 HCURSOR WINAPI SetCursor(
1191 HCURSOR hCursor /* Handle of cursor to show */
1195 if (hCursor == hActiveCursor) return hActiveCursor; /* No change */
1196 TRACE(cursor, "%04x\n", hCursor );
1197 hOldCursor = hActiveCursor;
1198 hActiveCursor = hCursor;
1199 /* Change the cursor shape only if it is visible */
1200 if (CURSOR_ShowCount >= 0)
1202 DISPLAY_SetCursor( (CURSORICONINFO*)GlobalLock16( hActiveCursor ) );
1203 GlobalUnlock16( hActiveCursor );
1209 /***********************************************************************
1210 * SetCursorPos16 (USER.70)
1212 void WINAPI SetCursorPos16( INT16 x, INT16 y )
1214 SetCursorPos( x, y );
1218 /***********************************************************************
1219 * SetCursorPos32 (USER32.474)
1221 BOOL WINAPI SetCursorPos( INT x, INT y )
1223 DISPLAY_MoveCursor( x, y );
1228 /***********************************************************************
1229 * ShowCursor16 (USER.71)
1231 INT16 WINAPI ShowCursor16( BOOL16 bShow )
1233 return ShowCursor( bShow );
1237 /***********************************************************************
1238 * ShowCursor32 (USER32.530)
1240 INT WINAPI ShowCursor( BOOL bShow )
1242 TRACE(cursor, "%d, count=%d\n",
1243 bShow, CURSOR_ShowCount );
1247 if (++CURSOR_ShowCount == 0) /* Show it */
1249 DISPLAY_SetCursor((CURSORICONINFO*)GlobalLock16( hActiveCursor ));
1250 GlobalUnlock16( hActiveCursor );
1255 if (--CURSOR_ShowCount == -1) /* Hide it */
1256 DISPLAY_SetCursor( NULL );
1258 return CURSOR_ShowCount;
1262 /***********************************************************************
1263 * GetCursor16 (USER.247)
1265 HCURSOR16 WINAPI GetCursor16(void)
1267 return hActiveCursor;
1271 /***********************************************************************
1272 * GetCursor32 (USER32.227)
1274 HCURSOR WINAPI GetCursor(void)
1276 return hActiveCursor;
1280 /***********************************************************************
1281 * ClipCursor16 (USER.16)
1283 BOOL16 WINAPI ClipCursor16( const RECT16 *rect )
1285 if (!rect) SetRectEmpty( &CURSOR_ClipRect );
1286 else CONV_RECT16TO32( rect, &CURSOR_ClipRect );
1291 /***********************************************************************
1292 * ClipCursor32 (USER32.53)
1294 BOOL WINAPI ClipCursor( const RECT *rect )
1296 if (!rect) SetRectEmpty( &CURSOR_ClipRect );
1297 else CopyRect( &CURSOR_ClipRect, rect );
1302 /***********************************************************************
1303 * GetCursorPos16 (USER.17)
1305 BOOL16 WINAPI GetCursorPos16( POINT16 *pt )
1307 DWORD posX, posY, state;
1310 if (!EVENT_QueryPointer( &posX, &posY, &state ))
1316 if (state & MK_LBUTTON)
1317 AsyncMouseButtonsStates[0] = MouseButtonsStates[0] = TRUE;
1319 MouseButtonsStates[0] = FALSE;
1320 if (state & MK_MBUTTON)
1321 AsyncMouseButtonsStates[1] = MouseButtonsStates[1] = TRUE;
1323 MouseButtonsStates[1] = FALSE;
1324 if (state & MK_RBUTTON)
1325 AsyncMouseButtonsStates[2] = MouseButtonsStates[2] = TRUE;
1327 MouseButtonsStates[2] = FALSE;
1329 TRACE(cursor, "ret=%d,%d\n", pt->x, pt->y );
1334 /***********************************************************************
1335 * GetCursorPos32 (USER32.229)
1337 BOOL WINAPI GetCursorPos( POINT *pt )
1342 ret = GetCursorPos16( &pt16 );
1343 if (pt) CONV_POINT16TO32( &pt16, pt );
1344 return ((pt) ? ret : 0);
1348 /***********************************************************************
1349 * GetClipCursor16 (USER.309)
1351 void WINAPI GetClipCursor16( RECT16 *rect )
1353 if (rect) CONV_RECT32TO16( &CURSOR_ClipRect, rect );
1357 /***********************************************************************
1358 * GetClipCursor32 (USER32.221)
1360 BOOL WINAPI GetClipCursor( RECT *rect )
1364 CopyRect( rect, &CURSOR_ClipRect );
1370 /**********************************************************************
1371 * LookupIconIdFromDirectoryEx16 (USER.364)
1373 * FIXME: exact parameter sizes
1375 INT16 WINAPI LookupIconIdFromDirectoryEx16( LPBYTE xdir, BOOL16 bIcon,
1376 INT16 width, INT16 height, UINT16 cFlag )
1378 CURSORICONDIR *dir = (CURSORICONDIR*)xdir;
1380 if( dir && !dir->idReserved && (dir->idType & 3) )
1382 CURSORICONDIRENTRY* entry;
1387 palEnts = GetSystemPaletteEntries(hdc, 0, 0, NULL);
1390 colors = (cFlag & LR_MONOCHROME) ? 2 : palEnts;
1395 entry = CURSORICON_FindBestIcon( dir, width, height, colors );
1397 entry = CURSORICON_FindBestCursor( dir, width, height, 1);
1399 if( entry ) retVal = entry->wResId;
1401 else WARN(cursor, "invalid resource directory\n");
1405 /**********************************************************************
1406 * LookupIconIdFromDirectoryEx32 (USER32.380)
1408 INT WINAPI LookupIconIdFromDirectoryEx( LPBYTE dir, BOOL bIcon,
1409 INT width, INT height, UINT cFlag )
1411 return LookupIconIdFromDirectoryEx16( dir, bIcon, width, height, cFlag );
1414 /**********************************************************************
1415 * LookupIconIdFromDirectory (USER.???)
1417 INT16 WINAPI LookupIconIdFromDirectory16( LPBYTE dir, BOOL16 bIcon )
1419 return LookupIconIdFromDirectoryEx16( dir, bIcon,
1420 bIcon ? SYSMETRICS_CXICON : SYSMETRICS_CXCURSOR,
1421 bIcon ? SYSMETRICS_CYICON : SYSMETRICS_CYCURSOR, bIcon ? 0 : LR_MONOCHROME );
1424 /**********************************************************************
1425 * LookupIconIdFromDirectory (USER32.379)
1427 INT WINAPI LookupIconIdFromDirectory( LPBYTE dir, BOOL bIcon )
1429 return LookupIconIdFromDirectoryEx( dir, bIcon,
1430 bIcon ? SYSMETRICS_CXICON : SYSMETRICS_CXCURSOR,
1431 bIcon ? SYSMETRICS_CYICON : SYSMETRICS_CYCURSOR, bIcon ? 0 : LR_MONOCHROME );
1434 /**********************************************************************
1435 * GetIconID (USER.455)
1437 WORD WINAPI GetIconID16( HGLOBAL16 hResource, DWORD resType )
1439 LPBYTE lpDir = (LPBYTE)GlobalLock16(hResource);
1441 TRACE(cursor, "hRes=%04x, entries=%i\n",
1442 hResource, lpDir ? ((CURSORICONDIR*)lpDir)->idCount : 0);
1447 return (WORD)LookupIconIdFromDirectoryEx16( lpDir, FALSE,
1448 SYSMETRICS_CXCURSOR, SYSMETRICS_CYCURSOR, LR_MONOCHROME );
1450 return (WORD)LookupIconIdFromDirectoryEx16( lpDir, TRUE,
1451 SYSMETRICS_CXICON, SYSMETRICS_CYICON, 0 );
1453 WARN(cursor, "invalid res type %ld\n", resType );
1458 /**********************************************************************
1459 * LoadCursorIconHandler (USER.336)
1461 * Supposed to load resources of Windows 2.x applications.
1463 HGLOBAL16 WINAPI LoadCursorIconHandler16( HGLOBAL16 hResource, HMODULE16 hModule, HRSRC16 hRsrc )
1465 FIXME(cursor,"(%04x,%04x,%04x): old 2.x resources are not supported!\n",
1466 hResource, hModule, hRsrc);
1467 return (HGLOBAL16)0;
1470 /**********************************************************************
1471 * LoadDIBIconHandler (USER.357)
1473 * RT_ICON resource loader, installed by USER_SignalProc when module
1476 HGLOBAL16 WINAPI LoadDIBIconHandler16( HGLOBAL16 hMemObj, HMODULE16 hModule, HRSRC16 hRsrc )
1478 /* If hResource is zero we must allocate a new memory block, if it's
1479 * non-zero but GlobalLock() returns NULL then it was discarded and
1480 * we have to recommit some memory, otherwise we just need to check
1481 * the block size. See LoadProc() in 16-bit SDK for more.
1484 hMemObj = NE_DefResourceHandler( hMemObj, hModule, hRsrc );
1487 LPBYTE bits = (LPBYTE)GlobalLock16( hMemObj );
1488 hMemObj = CURSORICON_CreateFromResource( hModule, hMemObj, bits,
1489 SizeofResource16(hModule, hRsrc), TRUE, 0x00030000,
1490 SYSMETRICS_CXICON, SYSMETRICS_CYICON, LR_DEFAULTCOLOR );
1495 /**********************************************************************
1496 * LoadDIBCursorHandler (USER.356)
1498 * RT_CURSOR resource loader. Same as above.
1500 HGLOBAL16 WINAPI LoadDIBCursorHandler16( HGLOBAL16 hMemObj, HMODULE16 hModule, HRSRC16 hRsrc )
1502 hMemObj = NE_DefResourceHandler( hMemObj, hModule, hRsrc );
1505 LPBYTE bits = (LPBYTE)GlobalLock16( hMemObj );
1506 hMemObj = CURSORICON_CreateFromResource( hModule, hMemObj, bits,
1507 SizeofResource16(hModule, hRsrc), FALSE, 0x00030000,
1508 SYSMETRICS_CXCURSOR, SYSMETRICS_CYCURSOR, LR_MONOCHROME );
1513 /**********************************************************************
1514 * LoadIconHandler (USER.456)
1516 HICON16 WINAPI LoadIconHandler16( HGLOBAL16 hResource, BOOL16 bNew )
1518 LPBYTE bits = (LPBYTE)LockResource16( hResource );
1520 TRACE(cursor,"hRes=%04x\n",hResource);
1522 return CURSORICON_CreateFromResource( 0, 0, bits, 0, TRUE,
1523 bNew ? 0x00030000 : 0x00020000, 0, 0, LR_DEFAULTCOLOR );
1526 /***********************************************************************
1527 * LoadCursorW (USER32.362)
1529 HCURSOR WINAPI LoadCursorW(HINSTANCE hInstance, LPCWSTR name)
1531 return LoadImageW( hInstance, name, IMAGE_CURSOR, 0, 0,
1532 LR_SHARED | LR_DEFAULTSIZE );
1535 /***********************************************************************
1536 * LoadCursorA (USER32.359)
1538 HCURSOR WINAPI LoadCursorA(HINSTANCE hInstance, LPCSTR name)
1540 return LoadImageA( hInstance, name, IMAGE_CURSOR, 0, 0,
1541 LR_SHARED | LR_DEFAULTSIZE );
1544 /***********************************************************************
1545 * LoadCursorFromFileW (USER32.361)
1547 HCURSOR WINAPI LoadCursorFromFileW (LPCWSTR name)
1549 return LoadImageW( 0, name, IMAGE_CURSOR, 0, 0,
1550 LR_LOADFROMFILE | LR_DEFAULTSIZE );
1553 /***********************************************************************
1554 * LoadCursorFromFileA (USER32.360)
1556 HCURSOR WINAPI LoadCursorFromFileA (LPCSTR name)
1558 return LoadImageA( 0, name, IMAGE_CURSOR, 0, 0,
1559 LR_LOADFROMFILE | LR_DEFAULTSIZE );
1562 /***********************************************************************
1563 * LoadIconW (USER32.364)
1565 HICON WINAPI LoadIconW(HINSTANCE hInstance, LPCWSTR name)
1567 return LoadImageW( hInstance, name, IMAGE_ICON, 0, 0,
1568 LR_SHARED | LR_DEFAULTSIZE );
1571 /***********************************************************************
1572 * LoadIconA (USER32.363)
1574 HICON WINAPI LoadIconA(HINSTANCE hInstance, LPCSTR name)
1576 return LoadImageA( hInstance, name, IMAGE_ICON, 0, 0,
1577 LR_SHARED | LR_DEFAULTSIZE );
1580 /**********************************************************************
1581 * GetIconInfo16 (USER.395)
1583 BOOL16 WINAPI GetIconInfo16(HICON16 hIcon,LPICONINFO16 iconinfo)
1586 BOOL16 ret = GetIconInfo((HICON)hIcon, &ii32);
1588 iconinfo->fIcon = ii32.fIcon;
1589 iconinfo->xHotspot = ii32.xHotspot;
1590 iconinfo->yHotspot = ii32.yHotspot;
1591 iconinfo->hbmMask = ii32.hbmMask;
1592 iconinfo->hbmColor = ii32.hbmColor;
1596 /**********************************************************************
1597 * GetIconInfo32 (USER32.242)
1599 BOOL WINAPI GetIconInfo(HICON hIcon,LPICONINFO iconinfo) {
1600 CURSORICONINFO *ciconinfo;
1602 ciconinfo = GlobalLock16(hIcon);
1605 iconinfo->xHotspot = ciconinfo->ptHotSpot.x;
1606 iconinfo->yHotspot = ciconinfo->ptHotSpot.y;
1607 iconinfo->fIcon = TRUE; /* hmm */
1609 iconinfo->hbmColor = CreateBitmap ( ciconinfo->nWidth, ciconinfo->nHeight,
1610 ciconinfo->bPlanes, ciconinfo->bBitsPerPixel,
1611 (char *)(ciconinfo + 1)
1612 + ciconinfo->nHeight *
1613 BITMAP_GetWidthBytes (ciconinfo->nWidth,1) );
1614 iconinfo->hbmMask = CreateBitmap ( ciconinfo->nWidth, ciconinfo->nHeight,
1615 1, 1, (char *)(ciconinfo + 1));
1617 GlobalUnlock16(hIcon);
1622 /**********************************************************************
1623 * CreateIconIndirect (USER32.78)
1625 HICON WINAPI CreateIconIndirect(LPICONINFO iconinfo) {
1626 BITMAPOBJ *bmpXor,*bmpAnd;
1628 int sizeXor,sizeAnd;
1630 bmpXor = (BITMAPOBJ *) GDI_GetObjPtr( iconinfo->hbmColor, BITMAP_MAGIC );
1631 bmpAnd = (BITMAPOBJ *) GDI_GetObjPtr( iconinfo->hbmMask, BITMAP_MAGIC );
1633 sizeXor = bmpXor->bitmap.bmHeight * bmpXor->bitmap.bmWidthBytes;
1634 sizeAnd = bmpAnd->bitmap.bmHeight * bmpAnd->bitmap.bmWidthBytes;
1636 hObj = GlobalAlloc16( GMEM_MOVEABLE,
1637 sizeof(CURSORICONINFO) + sizeXor + sizeAnd );
1640 CURSORICONINFO *info;
1642 info = (CURSORICONINFO *)GlobalLock16( hObj );
1643 info->ptHotSpot.x = iconinfo->xHotspot;
1644 info->ptHotSpot.y = iconinfo->yHotspot;
1645 info->nWidth = bmpXor->bitmap.bmWidth;
1646 info->nHeight = bmpXor->bitmap.bmHeight;
1647 info->nWidthBytes = bmpXor->bitmap.bmWidthBytes;
1648 info->bPlanes = bmpXor->bitmap.bmPlanes;
1649 info->bBitsPerPixel = bmpXor->bitmap.bmBitsPixel;
1651 /* Transfer the bitmap bits to the CURSORICONINFO structure */
1653 GetBitmapBits( iconinfo->hbmMask ,sizeAnd,(char*)(info + 1) );
1654 GetBitmapBits( iconinfo->hbmColor,sizeXor,(char*)(info + 1) +sizeAnd);
1655 GlobalUnlock16( hObj );
1661 /**********************************************************************
1663 DrawIconEx16 (USER.394)
1665 BOOL16 WINAPI DrawIconEx16 (HDC16 hdc, INT16 xLeft, INT16 yTop, HICON16 hIcon,
1666 INT16 cxWidth, INT16 cyWidth, UINT16 istep,
1667 HBRUSH16 hbr, UINT16 flags)
1669 return DrawIconEx(hdc, xLeft, yTop, hIcon, cxWidth, cyWidth,
1674 /******************************************************************************
1675 * DrawIconEx32 [USER32.160] Draws an icon or cursor on device context
1678 * Why is this using SM_CXICON instead of SM_CXCURSOR?
1681 * hdc [I] Handle to device context
1682 * x0 [I] X coordinate of upper left corner
1683 * y0 [I] Y coordinate of upper left corner
1684 * hIcon [I] Handle to icon to draw
1685 * cxWidth [I] Width of icon
1686 * cyWidth [I] Height of icon
1687 * istep [I] Index of frame in animated cursor
1688 * hbr [I] Handle to background brush
1689 * flags [I] Icon-drawing flags
1695 BOOL WINAPI DrawIconEx( HDC hdc, INT x0, INT y0, HICON hIcon,
1696 INT cxWidth, INT cyWidth, UINT istep,
1697 HBRUSH hbr, UINT flags )
1699 CURSORICONINFO *ptr = (CURSORICONINFO *)GlobalLock16 (hIcon);
1700 HDC hDC_off = 0, hMemDC = CreateCompatibleDC (hdc);
1701 BOOL result = FALSE, DoOffscreen = FALSE;
1702 HBITMAP hB_off = 0, hOld = 0;
1704 if (!ptr) return FALSE;
1707 FIXME(icon, "Ignoring istep=%d\n", istep);
1708 if (flags & DI_COMPAT)
1709 FIXME(icon, "Ignoring flag DI_COMPAT\n");
1711 /* Calculate the size of the destination image. */
1714 if (flags & DI_DEFAULTSIZE)
1715 cxWidth = GetSystemMetrics (SM_CXICON);
1717 cxWidth = ptr->nWidth;
1721 if (flags & DI_DEFAULTSIZE)
1722 cyWidth = GetSystemMetrics (SM_CYICON);
1724 cyWidth = ptr->nHeight;
1727 if (!(DoOffscreen = (hbr >= STOCK_WHITE_BRUSH) && (hbr <=
1728 STOCK_HOLLOW_BRUSH)))
1730 GDIOBJHDR *object = (GDIOBJHDR *) GDI_HEAP_LOCK(hbr);
1733 UINT16 magic = object->wMagic;
1734 GDI_HEAP_UNLOCK(hbr);
1735 DoOffscreen = magic == BRUSH_MAGIC;
1739 RECT r = {0, 0, cxWidth, cxWidth};
1741 hDC_off = CreateCompatibleDC(hdc);
1742 hB_off = CreateCompatibleBitmap(hdc, cxWidth, cyWidth);
1743 if (hDC_off && hB_off) {
1744 hOld = SelectObject(hDC_off, hB_off);
1745 FillRect(hDC_off, &r, hbr);
1749 if (hMemDC && (!DoOffscreen || (hDC_off && hB_off)))
1751 HBITMAP hXorBits, hAndBits;
1752 COLORREF oldFg, oldBg;
1755 nStretchMode = SetStretchBltMode (hdc, STRETCH_DELETESCANS);
1757 hXorBits = CreateBitmap ( ptr->nWidth, ptr->nHeight,
1758 ptr->bPlanes, ptr->bBitsPerPixel,
1761 BITMAP_GetWidthBytes(ptr->nWidth,1) );
1762 hAndBits = CreateBitmap ( ptr->nWidth, ptr->nHeight,
1763 1, 1, (char *)(ptr+1) );
1764 oldFg = SetTextColor( hdc, RGB(0,0,0) );
1765 oldBg = SetBkColor( hdc, RGB(255,255,255) );
1767 if (hXorBits && hAndBits)
1769 HBITMAP hBitTemp = SelectObject( hMemDC, hAndBits );
1770 if (flags & DI_MASK)
1773 StretchBlt (hDC_off, 0, 0, cxWidth, cyWidth,
1774 hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCAND);
1776 StretchBlt (hdc, x0, y0, cxWidth, cyWidth,
1777 hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCAND);
1779 SelectObject( hMemDC, hXorBits );
1780 if (flags & DI_IMAGE)
1783 StretchBlt (hDC_off, 0, 0, cxWidth, cyWidth,
1784 hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCPAINT);
1786 StretchBlt (hdc, x0, y0, cxWidth, cyWidth,
1787 hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCPAINT);
1789 SelectObject( hMemDC, hBitTemp );
1793 SetTextColor( hdc, oldFg );
1794 SetBkColor( hdc, oldBg );
1795 if (hXorBits) DeleteObject( hXorBits );
1796 if (hAndBits) DeleteObject( hAndBits );
1797 SetStretchBltMode (hdc, nStretchMode);
1799 BitBlt(hdc, x0, y0, cxWidth, cyWidth, hDC_off, 0, 0, SRCCOPY);
1800 SelectObject(hDC_off, hOld);
1803 if (hMemDC) DeleteDC( hMemDC );
1804 if (hDC_off) DeleteDC(hDC_off);
1805 if (hB_off) DeleteObject(hB_off);
1806 GlobalUnlock16( hIcon );