Authors: Chris Morgan <cmorgan@wpi.edu>, James Abbatiello <abbeyj@wpi.edu>
[wine.git] / objects / cursoricon.c
blob66b4de6ea97b50bac48fb932715a93b7200a7212
1 /*
2 * Cursor and icon support
4 * Copyright 1995 Alexandre Julliard
5 * 1996 Martin Von Loewis
6 * 1997 Alex Korobka
7 * 1998 Turchanov Sergey
8 */
11 * Theory:
13 * http://www.microsoft.com/win32dev/ui/icons.htm
15 * Cursors and icons are stored in a global heap block, with the
16 * following layout:
18 * CURSORICONINFO info;
19 * BYTE[] ANDbits;
20 * BYTE[] XORbits;
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 ?!
32 #include <string.h>
33 #include <stdlib.h>
35 #include "wine/winbase16.h"
36 #include "wine/winuser16.h"
37 #include "heap.h"
38 #include "color.h"
39 #include "bitmap.h"
40 #include "cursoricon.h"
41 #include "dc.h"
42 #include "gdi.h"
43 #include "global.h"
44 #include "module.h"
45 #include "debugtools.h"
46 #include "task.h"
47 #include "user.h"
48 #include "input.h"
49 #include "display.h"
50 #include "message.h"
51 #include "winerror.h"
53 DECLARE_DEBUG_CHANNEL(cursor)
54 DECLARE_DEBUG_CHANNEL(icon)
56 static HCURSOR hActiveCursor = 0; /* Active cursor */
57 static INT CURSOR_ShowCount = 0; /* Cursor display count */
58 static RECT CURSOR_ClipRect; /* Cursor clipping rect */
61 /**********************************************************************
62 * ICONCACHE for cursors/icons loaded with LR_SHARED.
64 * FIXME: This should not be allocated on the system heap, but on a
65 * subsystem-global heap (i.e. one for all Win16 processes,
66 * and one each for every Win32 process).
68 typedef struct tagICONCACHE
70 struct tagICONCACHE *next;
72 HMODULE hModule;
73 HRSRC hRsrc;
74 HANDLE handle;
76 INT count;
78 } ICONCACHE;
80 static ICONCACHE *IconAnchor = NULL;
81 static CRITICAL_SECTION IconCrst;
83 /**********************************************************************
84 * CURSORICON_Init
86 void CURSORICON_Init( void )
88 InitializeCriticalSection( &IconCrst );
89 MakeCriticalSectionGlobal( &IconCrst );
92 /**********************************************************************
93 * CURSORICON_FindSharedIcon
95 static HANDLE CURSORICON_FindSharedIcon( HMODULE hModule, HRSRC hRsrc )
97 HANDLE handle = 0;
98 ICONCACHE *ptr;
100 EnterCriticalSection( &IconCrst );
102 for ( ptr = IconAnchor; ptr; ptr = ptr->next )
103 if ( ptr->hModule == hModule && ptr->hRsrc == hRsrc )
105 ptr->count++;
106 handle = ptr->handle;
107 break;
110 LeaveCriticalSection( &IconCrst );
112 return handle;
115 /**********************************************************************
116 * CURSORICON_AddSharedIcon
118 static void CURSORICON_AddSharedIcon( HMODULE hModule, HRSRC hRsrc, HANDLE handle )
120 ICONCACHE *ptr = HeapAlloc( SystemHeap, 0, sizeof(ICONCACHE) );
121 if ( !ptr ) return;
123 ptr->hModule = hModule;
124 ptr->hRsrc = hRsrc;
125 ptr->handle = handle;
126 ptr->count = 1;
128 EnterCriticalSection( &IconCrst );
129 ptr->next = IconAnchor;
130 IconAnchor = ptr;
131 LeaveCriticalSection( &IconCrst );
134 /**********************************************************************
135 * CURSORICON_DelSharedIcon
137 static INT CURSORICON_DelSharedIcon( HANDLE handle )
139 INT count = -1;
140 ICONCACHE *ptr;
142 EnterCriticalSection( &IconCrst );
144 for ( ptr = IconAnchor; ptr; ptr = ptr->next )
145 if ( ptr->handle == handle )
147 if ( ptr->count > 0 ) ptr->count--;
148 count = ptr->count;
149 break;
152 LeaveCriticalSection( &IconCrst );
154 return count;
157 /**********************************************************************
158 * CURSORICON_FreeModuleIcons
160 void CURSORICON_FreeModuleIcons( HMODULE hModule )
162 ICONCACHE **ptr = &IconAnchor;
164 if ( HIWORD( hModule ) )
165 hModule = MapHModuleLS( hModule );
166 else
167 hModule = GetExePtr( hModule );
169 EnterCriticalSection( &IconCrst );
171 while ( *ptr )
173 if ( (*ptr)->hModule == hModule )
175 ICONCACHE *freePtr = *ptr;
176 *ptr = freePtr->next;
178 GlobalFree16( freePtr->handle );
179 HeapFree( SystemHeap, 0, freePtr );
180 continue;
182 ptr = &(*ptr)->next;
185 LeaveCriticalSection( &IconCrst );
188 /**********************************************************************
189 * CURSORICON_FindBestIcon
191 * Find the icon closest to the requested size and number of colors.
193 static CURSORICONDIRENTRY *CURSORICON_FindBestIcon( CURSORICONDIR *dir, int width,
194 int height, int colors )
196 int i, maxcolors, maxwidth, maxheight;
197 CURSORICONDIRENTRY *entry, *bestEntry = NULL;
199 if (dir->idCount < 1)
201 WARN_(icon)("Empty directory!\n" );
202 return NULL;
204 if (dir->idCount == 1) return &dir->idEntries[0]; /* No choice... */
206 /* First find the exact size with less colors */
208 maxcolors = 0;
209 for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
210 if ((entry->ResInfo.icon.bWidth == width) && (entry->ResInfo.icon.bHeight == height) &&
211 (entry->ResInfo.icon.bColorCount <= colors) && (entry->ResInfo.icon.bColorCount > maxcolors))
213 bestEntry = entry;
214 maxcolors = entry->ResInfo.icon.bColorCount;
216 if (bestEntry) return bestEntry;
218 /* First find the exact size with more colors */
220 maxcolors = 255;
221 for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
222 if ((entry->ResInfo.icon.bWidth == width) && (entry->ResInfo.icon.bHeight == height) &&
223 (entry->ResInfo.icon.bColorCount > colors) && (entry->ResInfo.icon.bColorCount <= maxcolors))
225 bestEntry = entry;
226 maxcolors = entry->ResInfo.icon.bColorCount;
228 if (bestEntry) return bestEntry;
230 /* Now find a smaller one with less colors */
232 maxcolors = maxwidth = maxheight = 0;
233 for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
234 if ((entry->ResInfo.icon.bWidth <= width) && (entry->ResInfo.icon.bHeight <= height) &&
235 (entry->ResInfo.icon.bWidth >= maxwidth) && (entry->ResInfo.icon.bHeight >= maxheight) &&
236 (entry->ResInfo.icon.bColorCount <= colors) && (entry->ResInfo.icon.bColorCount > maxcolors))
238 bestEntry = entry;
239 maxwidth = entry->ResInfo.icon.bWidth;
240 maxheight = entry->ResInfo.icon.bHeight;
241 maxcolors = entry->ResInfo.icon.bColorCount;
243 if (bestEntry) return bestEntry;
245 /* Now find a smaller one with more colors */
247 maxcolors = 255;
248 maxwidth = maxheight = 0;
249 for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
250 if ((entry->ResInfo.icon.bWidth <= width) && (entry->ResInfo.icon.bHeight <= height) &&
251 (entry->ResInfo.icon.bWidth >= maxwidth) && (entry->ResInfo.icon.bHeight >= maxheight) &&
252 (entry->ResInfo.icon.bColorCount > colors) && (entry->ResInfo.icon.bColorCount <= maxcolors))
254 bestEntry = entry;
255 maxwidth = entry->ResInfo.icon.bWidth;
256 maxheight = entry->ResInfo.icon.bHeight;
257 maxcolors = entry->ResInfo.icon.bColorCount;
259 if (bestEntry) return bestEntry;
261 /* Now find a larger one with less colors */
263 maxcolors = 0;
264 maxwidth = maxheight = 255;
265 for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
266 if ((entry->ResInfo.icon.bWidth <= maxwidth) && (entry->ResInfo.icon.bHeight <= maxheight) &&
267 (entry->ResInfo.icon.bColorCount <= colors) && (entry->ResInfo.icon.bColorCount > maxcolors))
269 bestEntry = entry;
270 maxwidth = entry->ResInfo.icon.bWidth;
271 maxheight = entry->ResInfo.icon.bHeight;
272 maxcolors = entry->ResInfo.icon.bColorCount;
274 if (bestEntry) return bestEntry;
276 /* Now find a larger one with more colors */
278 maxcolors = maxwidth = maxheight = 255;
279 for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
280 if ((entry->ResInfo.icon.bWidth <= maxwidth) && (entry->ResInfo.icon.bHeight <= maxheight) &&
281 (entry->ResInfo.icon.bColorCount > colors) && (entry->ResInfo.icon.bColorCount <= maxcolors))
283 bestEntry = entry;
284 maxwidth = entry->ResInfo.icon.bWidth;
285 maxheight = entry->ResInfo.icon.bHeight;
286 maxcolors = entry->ResInfo.icon.bColorCount;
289 return bestEntry;
293 /**********************************************************************
294 * CURSORICON_FindBestCursor
296 * Find the cursor closest to the requested size.
297 * FIXME: parameter 'color' ignored and entries with more than 1 bpp
298 * ignored too
300 static CURSORICONDIRENTRY *CURSORICON_FindBestCursor( CURSORICONDIR *dir,
301 int width, int height, int color)
303 int i, maxwidth, maxheight;
304 CURSORICONDIRENTRY *entry, *bestEntry = NULL;
306 if (dir->idCount < 1)
308 WARN_(cursor)("Empty directory!\n" );
309 return NULL;
311 if (dir->idCount == 1) return &dir->idEntries[0]; /* No choice... */
313 /* First find the largest one smaller than or equal to the requested size*/
315 maxwidth = maxheight = 0;
316 for(i = 0,entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
317 if ((entry->ResInfo.cursor.wWidth <= width) && (entry->ResInfo.cursor.wHeight <= height) &&
318 (entry->ResInfo.cursor.wWidth > maxwidth) && (entry->ResInfo.cursor.wHeight > maxheight) &&
319 (entry->wBitCount == 1))
321 bestEntry = entry;
322 maxwidth = entry->ResInfo.cursor.wWidth;
323 maxheight = entry->ResInfo.cursor.wHeight;
325 if (bestEntry) return bestEntry;
327 /* Now find the smallest one larger than the requested size */
329 maxwidth = maxheight = 255;
330 for(i = 0,entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
331 if ((entry->ResInfo.cursor.wWidth < maxwidth) && (entry->ResInfo.cursor.wHeight < maxheight) &&
332 (entry->wBitCount == 1))
334 bestEntry = entry;
335 maxwidth = entry->ResInfo.cursor.wWidth;
336 maxheight = entry->ResInfo.cursor.wHeight;
339 return bestEntry;
342 /*********************************************************************
343 * The main purpose of this function is to create fake resource directory
344 * and fake resource entries. There are several reasons for this:
345 * - CURSORICONDIR and CURSORICONFILEDIR differ in sizes and their
346 * fields
347 * There are some "bad" cursor files which do not have
348 * bColorCount initialized but instead one must read this info
349 * directly from corresponding DIB sections
350 * Note: wResId is index to array of pointer returned in ptrs (origin is 1)
352 BOOL CURSORICON_SimulateLoadingFromResourceW( LPWSTR filename, BOOL fCursor,
353 CURSORICONDIR **res, LPBYTE **ptr)
355 LPBYTE _free;
356 CURSORICONFILEDIR *bits;
357 int entries, size, i;
359 *res = NULL;
360 *ptr = NULL;
361 if (!(bits = (CURSORICONFILEDIR *)VIRTUAL_MapFileW( filename ))) return FALSE;
363 /* FIXME: test for inimated icons
364 * hack to load the first icon from the *.ani file
366 if ( *(LPDWORD)bits==0x46464952 ) /* "RIFF" */
367 { LPBYTE pos = (LPBYTE) bits;
368 FIXME_(cursor)("Animated icons not correctly implemented! %p \n", bits);
370 for (;;)
371 { if (*(LPDWORD)pos==0x6e6f6369) /* "icon" */
372 { FIXME_(cursor)("icon entry found! %p\n", bits);
373 pos+=4;
374 if ( !*(LPWORD) pos==0x2fe) /* iconsize */
375 { goto fail;
377 bits+=2;
378 FIXME_(cursor)("icon size ok %p \n", bits);
379 break;
381 pos+=2;
382 if (pos>=(LPBYTE)bits+766) goto fail;
385 if (!(entries = bits->idCount)) goto fail;
386 size = sizeof(CURSORICONDIR) + sizeof(CURSORICONDIRENTRY) * (entries - 1);
387 _free = (LPBYTE) size;
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;
401 if (fCursor) {
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);
407 } else {
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 );
423 return TRUE;
424 fail:
425 if (*res) HeapFree( GetProcessHeap(), 0, *res );
426 if (*ptr) HeapFree( GetProcessHeap(), 0, *ptr );
427 UnmapViewOfFile( bits );
428 return FALSE;
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 };
448 BITMAPINFO *bmi;
449 HDC hdc;
450 BOOL DoStretch;
451 INT size;
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");
459 return 0;
462 if (bIcon)
463 bmi = (BITMAPINFO *)bits;
464 else /* get the hotspot */
466 POINT16 *pt = (POINT16 *)bits;
467 hotspot = *pt;
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");
484 return 0;
487 if( (hdc = GetDC( 0 )) )
489 BITMAPINFO* pInfo;
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 */
510 if (DoStretch) {
511 if ((hXorBits = CreateCompatibleBitmap(hdc, width, height))) {
512 HBITMAP hOld;
513 HDC hMem = CreateCompatibleDC(hdc);
514 BOOL res;
516 if (hMem) {
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);
522 DeleteDC(hMem);
523 } else res = FALSE;
524 if (!res) { DeleteObject(hXorBits); hXorBits = 0; }
526 } else hXorBits = CreateDIBitmap( hdc, &pInfo->bmiHeader,
527 CBM_INIT, (char*)bmi + size, pInfo, DIB_RGB_COLORS );
528 if( hXorBits )
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;
545 else
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 */
555 if (DoStretch) {
556 if ((hAndBits = CreateBitmap(width, height, 1, 1, NULL))) {
557 HBITMAP hOld;
558 HDC hMem = CreateCompatibleDC(hdc);
559 BOOL res;
561 if (hMem) {
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);
567 DeleteDC(hMem);
568 } else res = FALSE;
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 );
578 ReleaseDC( 0, hdc );
581 if( !hXorBits || !hAndBits )
583 WARN_(cursor)("\tunable to create an icon bitmap.\n");
584 return 0;
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 );
597 if (hObj)
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 );
622 return hObj;
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,
655 UINT cFlag )
657 TDB* pTask = (TDB*)GlobalLock16( GetCurrentTask() );
658 if( pTask )
659 return CURSORICON_CreateFromResource( pTask->hInstance, 0, bits, cbSize, bIcon, dwVersion,
660 width, height, cFlag );
661 return 0;
664 /**********************************************************************
665 * CURSORICON_Load
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;
674 HANDLE hRsrc;
675 CURSORICONDIR *dir;
676 CURSORICONDIRENTRY *dirEntry;
677 LPBYTE bits;
679 if ( loadflags & LR_LOADFROMFILE ) /* Load from file */
681 LPBYTE *ptr;
682 if (!CURSORICON_SimulateLoadingFromResourceW((LPWSTR)name, fCursor, &dir, &ptr))
683 return 0;
684 if (fCursor)
685 dirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestCursor(dir, width, height, 1);
686 else
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 */
697 WORD resid;
698 HDC hdc;
699 DC *dc;
701 if ( HIWORD(name) )
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 );
709 else
711 HeapFree( GetProcessHeap(), 0, ansi );
712 return 0;
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 );
722 DeleteDC( hdc );
725 else /* Load from resource */
727 WORD wResId;
728 DWORD dwBytesInRes;
730 /* Normalize hInstance (must be uniquely represented for icon cache) */
732 if ( HIWORD( hInstance ) )
733 hInstance = MapHModuleLS( hInstance );
734 else
735 hInstance = GetExePtr( hInstance );
737 /* Get directory resource ID */
739 if (!(hRsrc = FindResourceW( hInstance, name,
740 fCursor ? RT_GROUP_CURSORW : RT_GROUP_ICONW )))
741 return 0;
743 /* If shared icon, check whether it was already loaded */
745 if ( (loadflags & LR_SHARED)
746 && (h = CURSORICON_FindSharedIcon( hInstance, hRsrc ) ) != 0 )
747 return h;
749 /* Find the best entry in the directory */
751 if (!(handle = LoadResource( hInstance, hRsrc ))) return 0;
752 if (!(dir = (CURSORICONDIR*)LockResource( handle ))) return 0;
753 if (fCursor)
754 dirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestCursor( dir,
755 width, height, 1);
756 else
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 );
780 return h;
783 /***********************************************************************
784 * CURSORICON_Copy
786 * Make a copy of a cursor or icon.
788 static HGLOBAL16 CURSORICON_Copy( HINSTANCE16 hInstance, HGLOBAL16 handle )
790 char *ptrOld, *ptrNew;
791 int size;
792 HGLOBAL16 hNew;
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 );
803 return 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)
814 HCURSOR16 hRet = 0;
815 CURSORICONINFO *pIcon = NULL;
816 HTASK16 hTask = GetCurrentTask();
817 TDB* pTask = (TDB *)GlobalLock16(hTask);
819 if(hIcon && pTask)
820 if (!(pIcon = (CURSORICONINFO*)GlobalLock16( hIcon ))) return FALSE;
821 if (pIcon->bPlanes * pIcon->bBitsPerPixel == 1)
822 hRet = CURSORICON_Copy( pTask->hInstance, hIcon );
823 else
825 BYTE pAndBits[128];
826 BYTE pXorBits[128];
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);
830 BYTE* pbc = NULL;
832 CURSORICONINFO cI;
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);
865 else
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))
873 pbc = pxbPtr + ix/8;
874 *pbc |= 0x80 >> (ix%8);
878 psPtr += xor_width;
879 pxbPtr += 4;
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 GetSystemMetrics(SM_CXCURSOR),
888 GetSystemMetrics(SM_CYCURSOR), 1, TRUE, 0) );
891 return hRet;
895 /***********************************************************************
896 * LoadCursor16 (USER.173)
898 HCURSOR16 WINAPI LoadCursor16( HINSTANCE16 hInstance, SEGPTR name )
900 LPCSTR nameStr = HIWORD(name)? PTR_SEG_TO_LIN(name) : (LPCSTR)name;
901 return LoadCursorA( hInstance, nameStr );
905 /***********************************************************************
906 * LoadIcon16 (USER.174)
908 HICON16 WINAPI LoadIcon16( HINSTANCE16 hInstance, SEGPTR name )
910 LPCSTR nameStr = HIWORD(name)? PTR_SEG_TO_LIN(name) : (LPCSTR)name;
911 return LoadIconA( hInstance, nameStr );
915 /***********************************************************************
916 * CreateCursor16 (USER.406)
918 HCURSOR16 WINAPI CreateCursor16( HINSTANCE16 hInstance,
919 INT16 xHotSpot, INT16 yHotSpot,
920 INT16 nWidth, INT16 nHeight,
921 LPCVOID lpANDbits, LPCVOID lpXORbits )
923 CURSORICONINFO info;
925 TRACE_(cursor)("%dx%d spot=%d,%d xor=%p and=%p\n",
926 nWidth, nHeight, xHotSpot, yHotSpot, lpXORbits, lpANDbits);
928 info.ptHotSpot.x = xHotSpot;
929 info.ptHotSpot.y = yHotSpot;
930 info.nWidth = nWidth;
931 info.nHeight = nHeight;
932 info.nWidthBytes = 0;
933 info.bPlanes = 1;
934 info.bBitsPerPixel = 1;
936 return CreateCursorIconIndirect16( hInstance, &info, lpANDbits, lpXORbits );
940 /***********************************************************************
941 * CreateCursor32 (USER32.67)
943 HCURSOR WINAPI CreateCursor( HINSTANCE hInstance,
944 INT xHotSpot, INT yHotSpot,
945 INT nWidth, INT nHeight,
946 LPCVOID lpANDbits, LPCVOID lpXORbits )
948 CURSORICONINFO info;
950 TRACE_(cursor)("%dx%d spot=%d,%d xor=%p and=%p\n",
951 nWidth, nHeight, xHotSpot, yHotSpot, lpXORbits, lpANDbits);
953 info.ptHotSpot.x = xHotSpot;
954 info.ptHotSpot.y = yHotSpot;
955 info.nWidth = nWidth;
956 info.nHeight = nHeight;
957 info.nWidthBytes = 0;
958 info.bPlanes = 1;
959 info.bBitsPerPixel = 1;
961 return CreateCursorIconIndirect16( 0, &info, lpANDbits, lpXORbits );
965 /***********************************************************************
966 * CreateIcon16 (USER.407)
968 HICON16 WINAPI CreateIcon16( HINSTANCE16 hInstance, INT16 nWidth,
969 INT16 nHeight, BYTE bPlanes, BYTE bBitsPixel,
970 LPCVOID lpANDbits, LPCVOID lpXORbits )
972 CURSORICONINFO info;
974 TRACE_(icon)("%dx%dx%d, xor=%p, and=%p\n",
975 nWidth, nHeight, bPlanes * bBitsPixel, lpXORbits, lpANDbits);
977 info.ptHotSpot.x = 0;
978 info.ptHotSpot.y = 0;
979 info.nWidth = nWidth;
980 info.nHeight = nHeight;
981 info.nWidthBytes = 0;
982 info.bPlanes = bPlanes;
983 info.bBitsPerPixel = bBitsPixel;
985 return CreateCursorIconIndirect16( hInstance, &info, lpANDbits, lpXORbits );
989 /***********************************************************************
990 * CreateIcon32 (USER32.75)
992 HICON WINAPI CreateIcon( HINSTANCE hInstance, INT nWidth,
993 INT nHeight, BYTE bPlanes, BYTE bBitsPixel,
994 LPCVOID lpANDbits, LPCVOID lpXORbits )
996 CURSORICONINFO info;
998 TRACE_(icon)("%dx%dx%d, xor=%p, and=%p\n",
999 nWidth, nHeight, bPlanes * bBitsPixel, lpXORbits, lpANDbits);
1001 info.ptHotSpot.x = 0;
1002 info.ptHotSpot.y = 0;
1003 info.nWidth = nWidth;
1004 info.nHeight = nHeight;
1005 info.nWidthBytes = 0;
1006 info.bPlanes = bPlanes;
1007 info.bBitsPerPixel = bBitsPixel;
1009 return CreateCursorIconIndirect16( 0, &info, lpANDbits, lpXORbits );
1013 /***********************************************************************
1014 * CreateCursorIconIndirect (USER.408)
1016 HGLOBAL16 WINAPI CreateCursorIconIndirect16( HINSTANCE16 hInstance,
1017 CURSORICONINFO *info,
1018 LPCVOID lpANDbits,
1019 LPCVOID lpXORbits )
1021 HGLOBAL16 handle;
1022 char *ptr;
1023 int sizeAnd, sizeXor;
1025 hInstance = GetExePtr( hInstance ); /* Make it a module handle */
1026 if (!lpXORbits || !lpANDbits || info->bPlanes != 1) return 0;
1027 info->nWidthBytes = BITMAP_GetWidthBytes(info->nWidth,info->bBitsPerPixel);
1028 sizeXor = info->nHeight * info->nWidthBytes;
1029 sizeAnd = info->nHeight * BITMAP_GetWidthBytes( info->nWidth, 1 );
1030 if (!(handle = GlobalAlloc16( GMEM_MOVEABLE,
1031 sizeof(CURSORICONINFO) + sizeXor + sizeAnd)))
1032 return 0;
1033 if (hInstance) FarSetOwner16( handle, hInstance );
1034 ptr = (char *)GlobalLock16( handle );
1035 memcpy( ptr, info, sizeof(*info) );
1036 memcpy( ptr + sizeof(CURSORICONINFO), lpANDbits, sizeAnd );
1037 memcpy( ptr + sizeof(CURSORICONINFO) + sizeAnd, lpXORbits, sizeXor );
1038 GlobalUnlock16( handle );
1039 return handle;
1043 /***********************************************************************
1044 * CopyIcon16 (USER.368)
1046 HICON16 WINAPI CopyIcon16( HINSTANCE16 hInstance, HICON16 hIcon )
1048 TRACE_(icon)("%04x %04x\n", hInstance, hIcon );
1049 return CURSORICON_Copy( hInstance, hIcon );
1053 /***********************************************************************
1054 * CopyIcon32 (USER32.60)
1056 HICON WINAPI CopyIcon( HICON hIcon )
1058 HTASK16 hTask = GetCurrentTask ();
1059 TDB* pTask = (TDB *) GlobalLock16 (hTask);
1060 TRACE_(icon)("%04x\n", hIcon );
1061 return CURSORICON_Copy( pTask->hInstance, hIcon );
1065 /***********************************************************************
1066 * CopyCursor16 (USER.369)
1068 HCURSOR16 WINAPI CopyCursor16( HINSTANCE16 hInstance, HCURSOR16 hCursor )
1070 TRACE_(cursor)("%04x %04x\n", hInstance, hCursor );
1071 return CURSORICON_Copy( hInstance, hCursor );
1074 /**********************************************************************
1075 * CURSORICON_Destroy (USER.610)
1077 * This routine is actually exported from Win95 USER under the name
1078 * DestroyIcon32 ... The behaviour implemented here should mimic
1079 * the Win95 one exactly, especially the return values, which
1080 * depend on the setting of various flags.
1082 WORD WINAPI CURSORICON_Destroy( HGLOBAL16 handle, UINT16 flags )
1084 WORD retv;
1086 TRACE_(icon)("(%04x, %04x)\n", handle, flags );
1088 /* Check whether destroying active cursor */
1090 if ( hActiveCursor == handle )
1092 ERR_(cursor)("Destroying active cursor!\n" );
1093 SetCursor( 0 );
1096 /* Try shared cursor/icon first */
1098 if ( !(flags & CID_NONSHARED) )
1100 INT count = CURSORICON_DelSharedIcon( handle );
1102 if ( count != -1 )
1103 return (flags & CID_WIN32)? TRUE : (count == 0);
1105 /* FIXME: OEM cursors/icons should be recognized */
1108 /* Now assume non-shared cursor/icon */
1110 retv = GlobalFree16( handle );
1111 return (flags & CID_RESOURCE)? retv : TRUE;
1114 /***********************************************************************
1115 * DestroyIcon16 (USER.457)
1117 BOOL16 WINAPI DestroyIcon16( HICON16 hIcon )
1119 return CURSORICON_Destroy( hIcon, 0 );
1122 /***********************************************************************
1123 * DestroyIcon (USER32.133)
1125 BOOL WINAPI DestroyIcon( HICON hIcon )
1127 return CURSORICON_Destroy( hIcon, CID_WIN32 );
1130 /***********************************************************************
1131 * DestroyCursor16 (USER.458)
1133 BOOL16 WINAPI DestroyCursor16( HCURSOR16 hCursor )
1135 return CURSORICON_Destroy( hCursor, 0 );
1138 /***********************************************************************
1139 * DestroyCursor (USER32.132)
1141 BOOL WINAPI DestroyCursor( HCURSOR hCursor )
1143 return CURSORICON_Destroy( hCursor, CID_WIN32 );
1147 /***********************************************************************
1148 * DrawIcon16 (USER.84)
1150 BOOL16 WINAPI DrawIcon16( HDC16 hdc, INT16 x, INT16 y, HICON16 hIcon )
1152 return DrawIcon( hdc, x, y, hIcon );
1156 /***********************************************************************
1157 * DrawIcon32 (USER32.159)
1159 BOOL WINAPI DrawIcon( HDC hdc, INT x, INT y, HICON hIcon )
1161 CURSORICONINFO *ptr;
1162 HDC hMemDC;
1163 HBITMAP hXorBits, hAndBits;
1164 COLORREF oldFg, oldBg;
1166 if (!(ptr = (CURSORICONINFO *)GlobalLock16( hIcon ))) return FALSE;
1167 if (!(hMemDC = CreateCompatibleDC( hdc ))) return FALSE;
1168 hAndBits = CreateBitmap( ptr->nWidth, ptr->nHeight, 1, 1,
1169 (char *)(ptr+1) );
1170 hXorBits = CreateBitmap( ptr->nWidth, ptr->nHeight, ptr->bPlanes,
1171 ptr->bBitsPerPixel, (char *)(ptr + 1)
1172 + ptr->nHeight * BITMAP_GetWidthBytes(ptr->nWidth,1) );
1173 oldFg = SetTextColor( hdc, RGB(0,0,0) );
1174 oldBg = SetBkColor( hdc, RGB(255,255,255) );
1176 if (hXorBits && hAndBits)
1178 HBITMAP hBitTemp = SelectObject( hMemDC, hAndBits );
1179 BitBlt( hdc, x, y, ptr->nWidth, ptr->nHeight, hMemDC, 0, 0, SRCAND );
1180 SelectObject( hMemDC, hXorBits );
1181 BitBlt(hdc, x, y, ptr->nWidth, ptr->nHeight, hMemDC, 0, 0,SRCINVERT);
1182 SelectObject( hMemDC, hBitTemp );
1184 DeleteDC( hMemDC );
1185 if (hXorBits) DeleteObject( hXorBits );
1186 if (hAndBits) DeleteObject( hAndBits );
1187 GlobalUnlock16( hIcon );
1188 SetTextColor( hdc, oldFg );
1189 SetBkColor( hdc, oldBg );
1190 return TRUE;
1194 /***********************************************************************
1195 * DumpIcon (USER.459)
1197 DWORD WINAPI DumpIcon16( SEGPTR pInfo, WORD *lpLen,
1198 SEGPTR *lpXorBits, SEGPTR *lpAndBits )
1200 CURSORICONINFO *info = PTR_SEG_TO_LIN( pInfo );
1201 int sizeAnd, sizeXor;
1203 if (!info) return 0;
1204 sizeXor = info->nHeight * info->nWidthBytes;
1205 sizeAnd = info->nHeight * BITMAP_GetWidthBytes( info->nWidth, 1 );
1206 if (lpAndBits) *lpAndBits = pInfo + sizeof(CURSORICONINFO);
1207 if (lpXorBits) *lpXorBits = pInfo + sizeof(CURSORICONINFO) + sizeAnd;
1208 if (lpLen) *lpLen = sizeof(CURSORICONINFO) + sizeAnd + sizeXor;
1209 return MAKELONG( sizeXor, sizeXor );
1213 /***********************************************************************
1214 * SetCursor16 (USER.69)
1216 HCURSOR16 WINAPI SetCursor16( HCURSOR16 hCursor )
1218 return (HCURSOR16)SetCursor( hCursor );
1222 /***********************************************************************
1223 * SetCursor32 (USER32.472)
1224 * RETURNS:
1225 * A handle to the previous cursor shape.
1227 HCURSOR WINAPI SetCursor(
1228 HCURSOR hCursor /* Handle of cursor to show */
1230 HCURSOR hOldCursor;
1232 if (hCursor == hActiveCursor) return hActiveCursor; /* No change */
1233 TRACE_(cursor)("%04x\n", hCursor );
1234 hOldCursor = hActiveCursor;
1235 hActiveCursor = hCursor;
1236 /* Change the cursor shape only if it is visible */
1237 if (CURSOR_ShowCount >= 0)
1239 DISPLAY_SetCursor( (CURSORICONINFO*)GlobalLock16( hActiveCursor ) );
1240 GlobalUnlock16( hActiveCursor );
1242 return hOldCursor;
1246 /***********************************************************************
1247 * SetCursorPos16 (USER.70)
1249 void WINAPI SetCursorPos16( INT16 x, INT16 y )
1251 SetCursorPos( x, y );
1255 /***********************************************************************
1256 * SetCursorPos32 (USER32.474)
1258 BOOL WINAPI SetCursorPos( INT x, INT y )
1260 DISPLAY_MoveCursor( x, y );
1261 return TRUE;
1265 /***********************************************************************
1266 * ShowCursor16 (USER.71)
1268 INT16 WINAPI ShowCursor16( BOOL16 bShow )
1270 return ShowCursor( bShow );
1274 /***********************************************************************
1275 * ShowCursor32 (USER32.530)
1277 INT WINAPI ShowCursor( BOOL bShow )
1279 TRACE_(cursor)("%d, count=%d\n",
1280 bShow, CURSOR_ShowCount );
1282 if (bShow)
1284 if (++CURSOR_ShowCount == 0) /* Show it */
1286 DISPLAY_SetCursor((CURSORICONINFO*)GlobalLock16( hActiveCursor ));
1287 GlobalUnlock16( hActiveCursor );
1290 else
1292 if (--CURSOR_ShowCount == -1) /* Hide it */
1293 DISPLAY_SetCursor( NULL );
1295 return CURSOR_ShowCount;
1299 /***********************************************************************
1300 * GetCursor16 (USER.247)
1302 HCURSOR16 WINAPI GetCursor16(void)
1304 return hActiveCursor;
1308 /***********************************************************************
1309 * GetCursor32 (USER32.227)
1311 HCURSOR WINAPI GetCursor(void)
1313 return hActiveCursor;
1317 /***********************************************************************
1318 * ClipCursor16 (USER.16)
1320 BOOL16 WINAPI ClipCursor16( const RECT16 *rect )
1322 if (!rect) SetRectEmpty( &CURSOR_ClipRect );
1323 else CONV_RECT16TO32( rect, &CURSOR_ClipRect );
1324 return TRUE;
1328 /***********************************************************************
1329 * ClipCursor32 (USER32.53)
1331 BOOL WINAPI ClipCursor( const RECT *rect )
1333 if (!rect) SetRectEmpty( &CURSOR_ClipRect );
1334 else CopyRect( &CURSOR_ClipRect, rect );
1335 return TRUE;
1339 /***********************************************************************
1340 * GetCursorPos16 (USER.17)
1342 BOOL16 WINAPI GetCursorPos16( POINT16 *pt )
1344 DWORD posX, posY, state;
1346 if (!pt) return 0;
1347 if (!EVENT_QueryPointer( &posX, &posY, &state ))
1348 pt->x = pt->y = 0;
1349 else
1351 pt->x = posX;
1352 pt->y = posY;
1353 if (state & MK_LBUTTON)
1354 AsyncMouseButtonsStates[0] = MouseButtonsStates[0] = TRUE;
1355 else
1356 MouseButtonsStates[0] = FALSE;
1357 if (state & MK_MBUTTON)
1358 AsyncMouseButtonsStates[1] = MouseButtonsStates[1] = TRUE;
1359 else
1360 MouseButtonsStates[1] = FALSE;
1361 if (state & MK_RBUTTON)
1362 AsyncMouseButtonsStates[2] = MouseButtonsStates[2] = TRUE;
1363 else
1364 MouseButtonsStates[2] = FALSE;
1366 TRACE_(cursor)("ret=%d,%d\n", pt->x, pt->y );
1367 return 1;
1371 /***********************************************************************
1372 * GetCursorPos32 (USER32.229)
1374 BOOL WINAPI GetCursorPos( POINT *pt )
1376 BOOL ret;
1378 POINT16 pt16;
1379 ret = GetCursorPos16( &pt16 );
1380 if (pt) CONV_POINT16TO32( &pt16, pt );
1381 return ((pt) ? ret : 0);
1385 /***********************************************************************
1386 * GetClipCursor16 (USER.309)
1388 void WINAPI GetClipCursor16( RECT16 *rect )
1390 if (rect) CONV_RECT32TO16( &CURSOR_ClipRect, rect );
1394 /***********************************************************************
1395 * GetClipCursor32 (USER32.221)
1397 BOOL WINAPI GetClipCursor( RECT *rect )
1399 if (rect)
1401 CopyRect( rect, &CURSOR_ClipRect );
1402 return TRUE;
1404 return FALSE;
1407 /**********************************************************************
1408 * LookupIconIdFromDirectoryEx16 (USER.364)
1410 * FIXME: exact parameter sizes
1412 INT16 WINAPI LookupIconIdFromDirectoryEx16( LPBYTE xdir, BOOL16 bIcon,
1413 INT16 width, INT16 height, UINT16 cFlag )
1415 CURSORICONDIR *dir = (CURSORICONDIR*)xdir;
1416 UINT16 retVal = 0;
1417 if( dir && !dir->idReserved && (dir->idType & 3) )
1419 CURSORICONDIRENTRY* entry;
1420 HDC hdc;
1421 UINT palEnts;
1422 int colors;
1423 hdc = GetDC(0);
1424 palEnts = GetSystemPaletteEntries(hdc, 0, 0, NULL);
1425 if (palEnts == 0)
1426 palEnts = 256;
1427 colors = (cFlag & LR_MONOCHROME) ? 2 : palEnts;
1429 ReleaseDC(0, hdc);
1431 if( bIcon )
1432 entry = CURSORICON_FindBestIcon( dir, width, height, colors );
1433 else
1434 entry = CURSORICON_FindBestCursor( dir, width, height, 1);
1436 if( entry ) retVal = entry->wResId;
1438 else WARN_(cursor)("invalid resource directory\n");
1439 return retVal;
1442 /**********************************************************************
1443 * LookupIconIdFromDirectoryEx32 (USER32.380)
1445 INT WINAPI LookupIconIdFromDirectoryEx( LPBYTE dir, BOOL bIcon,
1446 INT width, INT height, UINT cFlag )
1448 return LookupIconIdFromDirectoryEx16( dir, bIcon, width, height, cFlag );
1451 /**********************************************************************
1452 * LookupIconIdFromDirectory (USER.???)
1454 INT16 WINAPI LookupIconIdFromDirectory16( LPBYTE dir, BOOL16 bIcon )
1456 return LookupIconIdFromDirectoryEx16( dir, bIcon,
1457 bIcon ? GetSystemMetrics(SM_CXICON) : GetSystemMetrics(SM_CXCURSOR),
1458 bIcon ? GetSystemMetrics(SM_CYICON) : GetSystemMetrics(SM_CYCURSOR), bIcon ? 0 : LR_MONOCHROME );
1461 /**********************************************************************
1462 * LookupIconIdFromDirectory (USER32.379)
1464 INT WINAPI LookupIconIdFromDirectory( LPBYTE dir, BOOL bIcon )
1466 return LookupIconIdFromDirectoryEx( dir, bIcon,
1467 bIcon ? GetSystemMetrics(SM_CXICON) : GetSystemMetrics(SM_CXCURSOR),
1468 bIcon ? GetSystemMetrics(SM_CYICON) : GetSystemMetrics(SM_CYCURSOR), bIcon ? 0 : LR_MONOCHROME );
1471 /**********************************************************************
1472 * GetIconID (USER.455)
1474 WORD WINAPI GetIconID16( HGLOBAL16 hResource, DWORD resType )
1476 LPBYTE lpDir = (LPBYTE)GlobalLock16(hResource);
1478 TRACE_(cursor)("hRes=%04x, entries=%i\n",
1479 hResource, lpDir ? ((CURSORICONDIR*)lpDir)->idCount : 0);
1481 switch(resType)
1483 case RT_CURSOR16:
1484 return (WORD)LookupIconIdFromDirectoryEx16( lpDir, FALSE,
1485 GetSystemMetrics(SM_CXCURSOR), GetSystemMetrics(SM_CYCURSOR), LR_MONOCHROME );
1486 case RT_ICON16:
1487 return (WORD)LookupIconIdFromDirectoryEx16( lpDir, TRUE,
1488 GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), 0 );
1489 default:
1490 WARN_(cursor)("invalid res type %ld\n", resType );
1492 return 0;
1495 /**********************************************************************
1496 * LoadCursorIconHandler (USER.336)
1498 * Supposed to load resources of Windows 2.x applications.
1500 HGLOBAL16 WINAPI LoadCursorIconHandler16( HGLOBAL16 hResource, HMODULE16 hModule, HRSRC16 hRsrc )
1502 FIXME_(cursor)("(%04x,%04x,%04x): old 2.x resources are not supported!\n",
1503 hResource, hModule, hRsrc);
1504 return (HGLOBAL16)0;
1507 /**********************************************************************
1508 * LoadDIBIconHandler (USER.357)
1510 * RT_ICON resource loader, installed by USER_SignalProc when module
1511 * is initialized.
1513 HGLOBAL16 WINAPI LoadDIBIconHandler16( HGLOBAL16 hMemObj, HMODULE16 hModule, HRSRC16 hRsrc )
1515 /* If hResource is zero we must allocate a new memory block, if it's
1516 * non-zero but GlobalLock() returns NULL then it was discarded and
1517 * we have to recommit some memory, otherwise we just need to check
1518 * the block size. See LoadProc() in 16-bit SDK for more.
1521 hMemObj = NE_DefResourceHandler( hMemObj, hModule, hRsrc );
1522 if( hMemObj )
1524 LPBYTE bits = (LPBYTE)GlobalLock16( hMemObj );
1525 hMemObj = CURSORICON_CreateFromResource( hModule, hMemObj, bits,
1526 SizeofResource16(hModule, hRsrc), TRUE, 0x00030000,
1527 GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), LR_DEFAULTCOLOR );
1529 return hMemObj;
1532 /**********************************************************************
1533 * LoadDIBCursorHandler (USER.356)
1535 * RT_CURSOR resource loader. Same as above.
1537 HGLOBAL16 WINAPI LoadDIBCursorHandler16( HGLOBAL16 hMemObj, HMODULE16 hModule, HRSRC16 hRsrc )
1539 hMemObj = NE_DefResourceHandler( hMemObj, hModule, hRsrc );
1540 if( hMemObj )
1542 LPBYTE bits = (LPBYTE)GlobalLock16( hMemObj );
1543 hMemObj = CURSORICON_CreateFromResource( hModule, hMemObj, bits,
1544 SizeofResource16(hModule, hRsrc), FALSE, 0x00030000,
1545 GetSystemMetrics(SM_CXCURSOR), GetSystemMetrics(SM_CYCURSOR), LR_MONOCHROME );
1547 return hMemObj;
1550 /**********************************************************************
1551 * LoadIconHandler (USER.456)
1553 HICON16 WINAPI LoadIconHandler16( HGLOBAL16 hResource, BOOL16 bNew )
1555 LPBYTE bits = (LPBYTE)LockResource16( hResource );
1557 TRACE_(cursor)("hRes=%04x\n",hResource);
1559 return CURSORICON_CreateFromResource( 0, 0, bits, 0, TRUE,
1560 bNew ? 0x00030000 : 0x00020000, 0, 0, LR_DEFAULTCOLOR );
1563 /***********************************************************************
1564 * LoadCursorW (USER32.362)
1566 HCURSOR WINAPI LoadCursorW(HINSTANCE hInstance, LPCWSTR name)
1568 return LoadImageW( hInstance, name, IMAGE_CURSOR, 0, 0,
1569 LR_SHARED | LR_DEFAULTSIZE );
1572 /***********************************************************************
1573 * LoadCursorA (USER32.359)
1575 HCURSOR WINAPI LoadCursorA(HINSTANCE hInstance, LPCSTR name)
1577 return LoadImageA( hInstance, name, IMAGE_CURSOR, 0, 0,
1578 LR_SHARED | LR_DEFAULTSIZE );
1581 /***********************************************************************
1582 * LoadCursorFromFileW (USER32.361)
1584 HCURSOR WINAPI LoadCursorFromFileW (LPCWSTR name)
1586 return LoadImageW( 0, name, IMAGE_CURSOR, 0, 0,
1587 LR_LOADFROMFILE | LR_DEFAULTSIZE );
1590 /***********************************************************************
1591 * LoadCursorFromFileA (USER32.360)
1593 HCURSOR WINAPI LoadCursorFromFileA (LPCSTR name)
1595 return LoadImageA( 0, name, IMAGE_CURSOR, 0, 0,
1596 LR_LOADFROMFILE | LR_DEFAULTSIZE );
1599 /***********************************************************************
1600 * LoadIconW (USER32.364)
1602 HICON WINAPI LoadIconW(HINSTANCE hInstance, LPCWSTR name)
1604 return LoadImageW( hInstance, name, IMAGE_ICON, 0, 0,
1605 LR_SHARED | LR_DEFAULTSIZE );
1608 /***********************************************************************
1609 * LoadIconA (USER32.363)
1611 HICON WINAPI LoadIconA(HINSTANCE hInstance, LPCSTR name)
1613 return LoadImageA( hInstance, name, IMAGE_ICON, 0, 0,
1614 LR_SHARED | LR_DEFAULTSIZE );
1617 /**********************************************************************
1618 * GetIconInfo16 (USER.395)
1620 BOOL16 WINAPI GetIconInfo16(HICON16 hIcon,LPICONINFO16 iconinfo)
1622 ICONINFO ii32;
1623 BOOL16 ret = GetIconInfo((HICON)hIcon, &ii32);
1625 iconinfo->fIcon = ii32.fIcon;
1626 iconinfo->xHotspot = ii32.xHotspot;
1627 iconinfo->yHotspot = ii32.yHotspot;
1628 iconinfo->hbmMask = ii32.hbmMask;
1629 iconinfo->hbmColor = ii32.hbmColor;
1630 return ret;
1633 /**********************************************************************
1634 * GetIconInfo32 (USER32.242)
1636 BOOL WINAPI GetIconInfo(HICON hIcon,LPICONINFO iconinfo) {
1637 CURSORICONINFO *ciconinfo;
1639 ciconinfo = GlobalLock16(hIcon);
1640 if (!ciconinfo)
1641 return FALSE;
1642 iconinfo->xHotspot = ciconinfo->ptHotSpot.x;
1643 iconinfo->yHotspot = ciconinfo->ptHotSpot.y;
1644 iconinfo->fIcon = TRUE; /* hmm */
1646 iconinfo->hbmColor = CreateBitmap ( ciconinfo->nWidth, ciconinfo->nHeight,
1647 ciconinfo->bPlanes, ciconinfo->bBitsPerPixel,
1648 (char *)(ciconinfo + 1)
1649 + ciconinfo->nHeight *
1650 BITMAP_GetWidthBytes (ciconinfo->nWidth,1) );
1651 iconinfo->hbmMask = CreateBitmap ( ciconinfo->nWidth, ciconinfo->nHeight,
1652 1, 1, (char *)(ciconinfo + 1));
1654 GlobalUnlock16(hIcon);
1656 return TRUE;
1659 /**********************************************************************
1660 * CreateIconIndirect (USER32.78)
1662 HICON WINAPI CreateIconIndirect(LPICONINFO iconinfo) {
1663 BITMAPOBJ *bmpXor,*bmpAnd;
1664 HICON hObj;
1665 int sizeXor,sizeAnd;
1667 bmpXor = (BITMAPOBJ *) GDI_GetObjPtr( iconinfo->hbmColor, BITMAP_MAGIC );
1668 bmpAnd = (BITMAPOBJ *) GDI_GetObjPtr( iconinfo->hbmMask, BITMAP_MAGIC );
1670 sizeXor = bmpXor->bitmap.bmHeight * bmpXor->bitmap.bmWidthBytes;
1671 sizeAnd = bmpAnd->bitmap.bmHeight * bmpAnd->bitmap.bmWidthBytes;
1673 hObj = GlobalAlloc16( GMEM_MOVEABLE,
1674 sizeof(CURSORICONINFO) + sizeXor + sizeAnd );
1675 if (hObj)
1677 CURSORICONINFO *info;
1679 info = (CURSORICONINFO *)GlobalLock16( hObj );
1680 info->ptHotSpot.x = iconinfo->xHotspot;
1681 info->ptHotSpot.y = iconinfo->yHotspot;
1682 info->nWidth = bmpXor->bitmap.bmWidth;
1683 info->nHeight = bmpXor->bitmap.bmHeight;
1684 info->nWidthBytes = bmpXor->bitmap.bmWidthBytes;
1685 info->bPlanes = bmpXor->bitmap.bmPlanes;
1686 info->bBitsPerPixel = bmpXor->bitmap.bmBitsPixel;
1688 /* Transfer the bitmap bits to the CURSORICONINFO structure */
1690 GetBitmapBits( iconinfo->hbmMask ,sizeAnd,(char*)(info + 1) );
1691 GetBitmapBits( iconinfo->hbmColor,sizeXor,(char*)(info + 1) +sizeAnd);
1692 GlobalUnlock16( hObj );
1694 return hObj;
1698 /**********************************************************************
1700 DrawIconEx16 (USER.394)
1702 BOOL16 WINAPI DrawIconEx16 (HDC16 hdc, INT16 xLeft, INT16 yTop, HICON16 hIcon,
1703 INT16 cxWidth, INT16 cyWidth, UINT16 istep,
1704 HBRUSH16 hbr, UINT16 flags)
1706 return DrawIconEx(hdc, xLeft, yTop, hIcon, cxWidth, cyWidth,
1707 istep, hbr, flags);
1711 /******************************************************************************
1712 * DrawIconEx32 [USER32.160] Draws an icon or cursor on device context
1714 * NOTES
1715 * Why is this using SM_CXICON instead of SM_CXCURSOR?
1717 * PARAMS
1718 * hdc [I] Handle to device context
1719 * x0 [I] X coordinate of upper left corner
1720 * y0 [I] Y coordinate of upper left corner
1721 * hIcon [I] Handle to icon to draw
1722 * cxWidth [I] Width of icon
1723 * cyWidth [I] Height of icon
1724 * istep [I] Index of frame in animated cursor
1725 * hbr [I] Handle to background brush
1726 * flags [I] Icon-drawing flags
1728 * RETURNS
1729 * Success: TRUE
1730 * Failure: FALSE
1732 BOOL WINAPI DrawIconEx( HDC hdc, INT x0, INT y0, HICON hIcon,
1733 INT cxWidth, INT cyWidth, UINT istep,
1734 HBRUSH hbr, UINT flags )
1736 CURSORICONINFO *ptr = (CURSORICONINFO *)GlobalLock16 (hIcon);
1737 HDC hDC_off = 0, hMemDC = CreateCompatibleDC (hdc);
1738 BOOL result = FALSE, DoOffscreen = FALSE;
1739 HBITMAP hB_off = 0, hOld = 0;
1741 if (!ptr) return FALSE;
1743 if (istep)
1744 FIXME_(icon)("Ignoring istep=%d\n", istep);
1745 if (flags & DI_COMPAT)
1746 FIXME_(icon)("Ignoring flag DI_COMPAT\n");
1748 /* Calculate the size of the destination image. */
1749 if (cxWidth == 0)
1751 if (flags & DI_DEFAULTSIZE)
1752 cxWidth = GetSystemMetrics (SM_CXICON);
1753 else
1754 cxWidth = ptr->nWidth;
1756 if (cyWidth == 0)
1758 if (flags & DI_DEFAULTSIZE)
1759 cyWidth = GetSystemMetrics (SM_CYICON);
1760 else
1761 cyWidth = ptr->nHeight;
1764 if (!(DoOffscreen = (hbr >= STOCK_WHITE_BRUSH) && (hbr <=
1765 STOCK_HOLLOW_BRUSH)))
1767 GDIOBJHDR *object = (GDIOBJHDR *) GDI_HEAP_LOCK(hbr);
1768 if (object)
1770 UINT16 magic = object->wMagic;
1771 GDI_HEAP_UNLOCK(hbr);
1772 DoOffscreen = magic == BRUSH_MAGIC;
1775 if (DoOffscreen) {
1776 RECT r;
1778 r.left = 0;
1779 r.top = 0;
1780 r.right = cxWidth;
1781 r.bottom = cxWidth;
1783 hDC_off = CreateCompatibleDC(hdc);
1784 hB_off = CreateCompatibleBitmap(hdc, cxWidth, cyWidth);
1785 if (hDC_off && hB_off) {
1786 hOld = SelectObject(hDC_off, hB_off);
1787 FillRect(hDC_off, &r, hbr);
1791 if (hMemDC && (!DoOffscreen || (hDC_off && hB_off)))
1793 HBITMAP hXorBits, hAndBits;
1794 COLORREF oldFg, oldBg;
1795 INT nStretchMode;
1797 nStretchMode = SetStretchBltMode (hdc, STRETCH_DELETESCANS);
1799 hXorBits = CreateBitmap ( ptr->nWidth, ptr->nHeight,
1800 ptr->bPlanes, ptr->bBitsPerPixel,
1801 (char *)(ptr + 1)
1802 + ptr->nHeight *
1803 BITMAP_GetWidthBytes(ptr->nWidth,1) );
1804 hAndBits = CreateBitmap ( ptr->nWidth, ptr->nHeight,
1805 1, 1, (char *)(ptr+1) );
1806 oldFg = SetTextColor( hdc, RGB(0,0,0) );
1807 oldBg = SetBkColor( hdc, RGB(255,255,255) );
1809 if (hXorBits && hAndBits)
1811 HBITMAP hBitTemp = SelectObject( hMemDC, hAndBits );
1812 if (flags & DI_MASK)
1814 if (DoOffscreen)
1815 StretchBlt (hDC_off, 0, 0, cxWidth, cyWidth,
1816 hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCAND);
1817 else
1818 StretchBlt (hdc, x0, y0, cxWidth, cyWidth,
1819 hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCAND);
1821 SelectObject( hMemDC, hXorBits );
1822 if (flags & DI_IMAGE)
1824 if (DoOffscreen)
1825 StretchBlt (hDC_off, 0, 0, cxWidth, cyWidth,
1826 hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCPAINT);
1827 else
1828 StretchBlt (hdc, x0, y0, cxWidth, cyWidth,
1829 hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCPAINT);
1831 SelectObject( hMemDC, hBitTemp );
1832 result = TRUE;
1835 SetTextColor( hdc, oldFg );
1836 SetBkColor( hdc, oldBg );
1837 if (hXorBits) DeleteObject( hXorBits );
1838 if (hAndBits) DeleteObject( hAndBits );
1839 SetStretchBltMode (hdc, nStretchMode);
1840 if (DoOffscreen) {
1841 BitBlt(hdc, x0, y0, cxWidth, cyWidth, hDC_off, 0, 0, SRCCOPY);
1842 SelectObject(hDC_off, hOld);
1845 if (hMemDC) DeleteDC( hMemDC );
1846 if (hDC_off) DeleteDC(hDC_off);
1847 if (hB_off) DeleteObject(hB_off);
1848 GlobalUnlock16( hIcon );
1849 return result;