Exception for allowing the parent to set the cursor for a child wnd is
[wine] / windows / cursoricon.c
1 /*
2  * Cursor and icon support
3  *
4  * Copyright 1995 Alexandre Julliard
5  *           1996 Martin Von Loewis
6  *           1997 Alex Korobka
7  *           1998 Turchanov Sergey
8  */
9
10 /*
11  * Theory:
12  *
13  * http://www.microsoft.com/win32dev/ui/icons.htm
14  *
15  * Cursors and icons are stored in a global heap block, with the
16  * following layout:
17  *
18  * CURSORICONINFO info;
19  * BYTE[]         ANDbits;
20  * BYTE[]         XORbits;
21  *
22  * The bits structures are in the format of a device-dependent bitmap.
23  *
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 :-(
28  *
29  * FIXME: what are we going to do with animation and color (bpp > 1) cursors ?!
30  */
31
32 #include <string.h>
33 #include <stdlib.h>
34
35 #include "windef.h"
36 #include "wingdi.h"
37 #include "wine/winbase16.h"
38 #include "wine/winuser16.h"
39 #include "heap.h"
40 #include "palette.h"
41 #include "bitmap.h"
42 #include "cursoricon.h"
43 #include "module.h"
44 #include "debugtools.h"
45 #include "user.h"
46 #include "input.h"
47 #include "message.h"
48 #include "winerror.h"
49
50 DECLARE_DEBUG_CHANNEL(cursor);
51 DECLARE_DEBUG_CHANNEL(icon);
52 DECLARE_DEBUG_CHANNEL(resource);
53
54 static HCURSOR hActiveCursor = 0;  /* Active cursor */
55 static INT CURSOR_ShowCount = 0;   /* Cursor display count */
56 static RECT CURSOR_ClipRect;       /* Cursor clipping rect */
57
58 static HDC screen_dc;
59
60 /**********************************************************************
61  * ICONCACHE for cursors/icons loaded with LR_SHARED.
62  *
63  * FIXME: This should not be allocated on the system heap, but on a
64  *        subsystem-global heap (i.e. one for all Win16 processes,
65  *        and one each for every Win32 process).
66  */
67 typedef struct tagICONCACHE
68 {
69     struct tagICONCACHE *next;
70
71     HMODULE              hModule;
72     HRSRC                hRsrc;
73     HRSRC                hGroupRsrc;
74     HANDLE               handle;
75
76     INT                  count;
77
78 } ICONCACHE;
79
80 static ICONCACHE *IconAnchor = NULL;
81 static CRITICAL_SECTION IconCrst = CRITICAL_SECTION_INIT;
82 static WORD ICON_HOTSPOT = 0x4242;
83
84
85 /***********************************************************************
86  *             map_fileW
87  *
88  * Helper function to map a file to memory:
89  *  name                        -       file name 
90  *  [RETURN] ptr                -       pointer to mapped file
91  */
92 static void *map_fileW( LPCWSTR name )
93 {
94     HANDLE hFile, hMapping;
95     LPVOID ptr = NULL;
96
97     hFile = CreateFileW( name, GENERIC_READ, FILE_SHARE_READ, NULL,
98                          OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, 0 );
99     if (hFile != INVALID_HANDLE_VALUE)
100     {
101         hMapping = CreateFileMappingA( hFile, NULL, PAGE_READONLY, 0, 0, NULL );
102         CloseHandle( hFile );
103         if (hMapping)
104         {
105             ptr = MapViewOfFile( hMapping, FILE_MAP_READ, 0, 0, 0 );
106             CloseHandle( hMapping );
107         }
108     }
109     return ptr;
110 }
111
112
113 /**********************************************************************
114  *          CURSORICON_FindSharedIcon
115  */
116 static HANDLE CURSORICON_FindSharedIcon( HMODULE hModule, HRSRC hRsrc )
117 {
118     HANDLE handle = 0;
119     ICONCACHE *ptr;
120
121     EnterCriticalSection( &IconCrst );
122
123     for ( ptr = IconAnchor; ptr; ptr = ptr->next )
124         if ( ptr->hModule == hModule && ptr->hRsrc == hRsrc )
125         {
126             ptr->count++;
127             handle = ptr->handle;
128             break;
129         }
130
131     LeaveCriticalSection( &IconCrst );
132
133     return handle;
134 }
135
136 /*************************************************************************
137  * CURSORICON_FindCache 
138  *
139  * Given a handle, find the corresponding cache element
140  *
141  * PARAMS
142  *      Handle     [I] handle to an Image 
143  *
144  * RETURNS
145  *     Success: The cache entry
146  *     Failure: NULL
147  *
148  */
149 static ICONCACHE* CURSORICON_FindCache(HANDLE handle)
150 {
151     ICONCACHE *ptr;
152     ICONCACHE *pRet=NULL;
153     BOOL IsFound = FALSE;
154     int count;
155
156     EnterCriticalSection( &IconCrst );
157
158     for (count = 0, ptr = IconAnchor; ptr != NULL && !IsFound; ptr = ptr->next, count++ )
159     {
160         if ( handle == ptr->handle )
161         {
162             IsFound = TRUE;
163             pRet = ptr;
164         }
165     }
166
167     LeaveCriticalSection( &IconCrst );
168
169     return pRet;
170 }
171
172 /**********************************************************************
173  *          CURSORICON_AddSharedIcon
174  */
175 static void CURSORICON_AddSharedIcon( HMODULE hModule, HRSRC hRsrc, HRSRC hGroupRsrc, HANDLE handle )
176 {
177     ICONCACHE *ptr = HeapAlloc( SystemHeap, 0, sizeof(ICONCACHE) );
178     if ( !ptr ) return;
179
180     ptr->hModule = hModule;
181     ptr->hRsrc   = hRsrc;
182     ptr->handle  = handle;
183     ptr->hGroupRsrc = hGroupRsrc;
184     ptr->count   = 1;
185
186     EnterCriticalSection( &IconCrst );
187     ptr->next    = IconAnchor;
188     IconAnchor   = ptr;
189     LeaveCriticalSection( &IconCrst );
190 }
191
192 /**********************************************************************
193  *          CURSORICON_DelSharedIcon
194  */
195 static INT CURSORICON_DelSharedIcon( HANDLE handle )
196 {
197     INT count = -1;
198     ICONCACHE *ptr;
199
200     EnterCriticalSection( &IconCrst );
201
202     for ( ptr = IconAnchor; ptr; ptr = ptr->next )
203         if ( ptr->handle == handle )
204         {
205             if ( ptr->count > 0 ) ptr->count--;
206             count = ptr->count;
207             break;
208         }
209
210     LeaveCriticalSection( &IconCrst );
211
212     return count;
213 }
214
215 /**********************************************************************
216  *          CURSORICON_FreeModuleIcons
217  */
218 void CURSORICON_FreeModuleIcons( HMODULE hModule )
219 {
220     ICONCACHE **ptr = &IconAnchor;
221
222     if ( HIWORD( hModule ) )
223         hModule = MapHModuleLS( hModule );
224     else
225         hModule = GetExePtr( hModule );
226
227     EnterCriticalSection( &IconCrst );
228
229     while ( *ptr )
230     {
231         if ( (*ptr)->hModule == hModule )
232         {
233             ICONCACHE *freePtr = *ptr;
234             *ptr = freePtr->next;
235             
236             GlobalFree16( freePtr->handle );
237             HeapFree( SystemHeap, 0, freePtr );
238             continue;
239         }
240         ptr = &(*ptr)->next;
241     }
242
243     LeaveCriticalSection( &IconCrst );
244 }
245
246 /**********************************************************************
247  *          CURSORICON_FindBestIcon
248  *
249  * Find the icon closest to the requested size and number of colors.
250  */
251 static CURSORICONDIRENTRY *CURSORICON_FindBestIcon( CURSORICONDIR *dir, int width,
252                                               int height, int colors )
253 {
254     int i; 
255     CURSORICONDIRENTRY *entry, *bestEntry = NULL;
256     UINT iTotalDiff, iXDiff=0, iYDiff=0, iColorDiff;
257     UINT iTempXDiff, iTempYDiff, iTempColorDiff;
258
259     if (dir->idCount < 1)
260     {
261         WARN_(icon)("Empty directory!\n" );
262         return NULL;
263     }
264     if (dir->idCount == 1) return &dir->idEntries[0];  /* No choice... */
265
266     /* Find Best Fit */
267     iTotalDiff = 0xFFFFFFFF;
268     iColorDiff = 0xFFFFFFFF;
269     for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
270         {
271         iTempXDiff = abs(width - entry->ResInfo.icon.bWidth);
272         iTempYDiff = abs(height - entry->ResInfo.icon.bHeight);
273
274         if(iTotalDiff > (iTempXDiff + iTempYDiff))
275         {
276             iXDiff = iTempXDiff;
277             iYDiff = iTempYDiff;
278             iTotalDiff = iXDiff + iYDiff;
279         }
280         }
281
282     /* Find Best Colors for Best Fit */
283     for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
284         {
285         if(abs(width - entry->ResInfo.icon.bWidth) == iXDiff &&
286             abs(height - entry->ResInfo.icon.bHeight) == iYDiff)
287         {
288             iTempColorDiff = abs(colors - entry->ResInfo.icon.bColorCount);
289             if(iColorDiff > iTempColorDiff)
290         {
291             bestEntry = entry;
292                 iColorDiff = iTempColorDiff;
293         }
294         }
295     }
296
297     return bestEntry;
298 }
299
300
301 /**********************************************************************
302  *          CURSORICON_FindBestCursor
303  *
304  * Find the cursor closest to the requested size.
305  * FIXME: parameter 'color' ignored and entries with more than 1 bpp
306  *        ignored too
307  */
308 static CURSORICONDIRENTRY *CURSORICON_FindBestCursor( CURSORICONDIR *dir,
309                                                   int width, int height, int color)
310 {
311     int i, maxwidth, maxheight;
312     CURSORICONDIRENTRY *entry, *bestEntry = NULL;
313
314     if (dir->idCount < 1)
315     {
316         WARN_(cursor)("Empty directory!\n" );
317         return NULL;
318     }
319     if (dir->idCount == 1) return &dir->idEntries[0]; /* No choice... */
320
321     /* Double height to account for AND and XOR masks */
322
323     height *= 2;
324
325     /* First find the largest one smaller than or equal to the requested size*/
326
327     maxwidth = maxheight = 0;
328     for(i = 0,entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
329         if ((entry->ResInfo.cursor.wWidth <= width) && (entry->ResInfo.cursor.wHeight <= height) &&
330             (entry->ResInfo.cursor.wWidth > maxwidth) && (entry->ResInfo.cursor.wHeight > maxheight) &&
331             (entry->wBitCount == 1))
332         {
333             bestEntry = entry;
334             maxwidth  = entry->ResInfo.cursor.wWidth;
335             maxheight = entry->ResInfo.cursor.wHeight;
336         }
337     if (bestEntry) return bestEntry;
338
339     /* Now find the smallest one larger than the requested size */
340
341     maxwidth = maxheight = 255;
342     for(i = 0,entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
343         if ((entry->ResInfo.cursor.wWidth < maxwidth) && (entry->ResInfo.cursor.wHeight < maxheight) &&
344             (entry->wBitCount == 1))
345         {
346             bestEntry = entry;
347             maxwidth  = entry->ResInfo.cursor.wWidth;
348             maxheight = entry->ResInfo.cursor.wHeight;
349         }
350
351     return bestEntry;
352 }
353
354 /*********************************************************************
355  * The main purpose of this function is to create fake resource directory
356  * and fake resource entries. There are several reasons for this:
357  *      -       CURSORICONDIR and CURSORICONFILEDIR differ in sizes and their
358  *              fields
359  *      There are some "bad" cursor files which do not have
360  *              bColorCount initialized but instead one must read this info
361  *              directly from corresponding DIB sections
362  * Note: wResId is index to array of pointer returned in ptrs (origin is 1)
363  */
364 BOOL CURSORICON_SimulateLoadingFromResourceW( LPWSTR filename, BOOL fCursor,
365                                                 CURSORICONDIR **res, LPBYTE **ptr)
366 {
367     LPBYTE   _free;
368     CURSORICONFILEDIR *bits;
369     int      entries, size, i;
370
371     *res = NULL;
372     *ptr = NULL;
373     if (!(bits = map_fileW( filename ))) return FALSE;
374
375     /* FIXME: test for inimated icons
376      * hack to load the first icon from the *.ani file
377      */
378     if ( *(LPDWORD)bits==0x46464952 ) /* "RIFF" */
379     { LPBYTE pos = (LPBYTE) bits;
380       FIXME_(cursor)("Animated icons not correctly implemented! %p \n", bits);
381         
382       for (;;)
383       { if (*(LPDWORD)pos==0x6e6f6369)          /* "icon" */
384         { FIXME_(cursor)("icon entry found! %p\n", bits);
385           pos+=4;
386           if ( !*(LPWORD) pos==0x2fe)           /* iconsize */
387           { goto fail;
388           }
389           bits=(CURSORICONFILEDIR*)(pos+4);
390           FIXME_(cursor)("icon size ok. offset=%p \n", bits);
391           break;
392         }
393         pos+=2;
394         if (pos>=(LPBYTE)bits+766) goto fail;
395       }
396     }
397     if (!(entries = bits->idCount)) goto fail;
398     size = sizeof(CURSORICONDIR) + sizeof(CURSORICONDIRENTRY) * (entries - 1);
399     _free = (LPBYTE) size;
400
401     for (i=0; i < entries; i++)
402       size += bits->idEntries[i].dwDIBSize + (fCursor ? sizeof(POINT16): 0);
403     
404     if (!(*ptr = HeapAlloc( GetProcessHeap(), 0,
405                             entries * sizeof (CURSORICONDIRENTRY*)))) goto fail;
406     if (!(*res = HeapAlloc( GetProcessHeap(), 0, size))) goto fail;
407
408     _free = (LPBYTE)(*res) + (int)_free;
409     memcpy((*res), bits, 6);
410     for (i=0; i<entries; i++)
411     {
412       ((LPBYTE*)(*ptr))[i] = _free;
413       if (fCursor) {
414         (*res)->idEntries[i].ResInfo.cursor.wWidth=bits->idEntries[i].bWidth;
415         (*res)->idEntries[i].ResInfo.cursor.wHeight=bits->idEntries[i].bHeight;
416         ((LPPOINT16)_free)->x=bits->idEntries[i].xHotspot;
417         ((LPPOINT16)_free)->y=bits->idEntries[i].yHotspot;
418         _free+=sizeof(POINT16);
419       } else {
420         (*res)->idEntries[i].ResInfo.icon.bWidth=bits->idEntries[i].bWidth;
421         (*res)->idEntries[i].ResInfo.icon.bHeight=bits->idEntries[i].bHeight;
422         (*res)->idEntries[i].ResInfo.icon.bColorCount = bits->idEntries[i].bColorCount;
423       }
424       (*res)->idEntries[i].wPlanes=1;
425       (*res)->idEntries[i].wBitCount = ((LPBITMAPINFOHEADER)((LPBYTE)bits +
426                                                    bits->idEntries[i].dwDIBOffset))->biBitCount;
427       (*res)->idEntries[i].dwBytesInRes = bits->idEntries[i].dwDIBSize;
428       (*res)->idEntries[i].wResId=i+1;
429
430       memcpy(_free,(LPBYTE)bits +bits->idEntries[i].dwDIBOffset,
431              (*res)->idEntries[i].dwBytesInRes);
432       _free += (*res)->idEntries[i].dwBytesInRes;
433     }
434     UnmapViewOfFile( bits );
435     return TRUE;    
436 fail:
437     if (*res) HeapFree( GetProcessHeap(), 0, *res );
438     if (*ptr) HeapFree( GetProcessHeap(), 0, *ptr );
439     UnmapViewOfFile( bits );
440     return FALSE;
441 }
442
443
444 /**********************************************************************
445  *          CURSORICON_CreateFromResource
446  *
447  * Create a cursor or icon from in-memory resource template. 
448  *
449  * FIXME: Convert to mono when cFlag is LR_MONOCHROME. Do something
450  *        with cbSize parameter as well.
451  */
452 static HGLOBAL16 CURSORICON_CreateFromResource( HINSTANCE16 hInstance, HGLOBAL16 hObj, LPBYTE bits,
453                                                 UINT cbSize, BOOL bIcon, DWORD dwVersion, 
454                                                 INT width, INT height, UINT loadflags )
455 {
456     static HDC hdcMem;
457     int sizeAnd, sizeXor;
458     HBITMAP hAndBits = 0, hXorBits = 0; /* error condition for later */
459     BITMAP bmpXor, bmpAnd;
460     POINT16 hotspot;
461     BITMAPINFO *bmi;
462     BOOL DoStretch;
463     INT size;
464
465     hotspot.x = ICON_HOTSPOT;
466     hotspot.y = ICON_HOTSPOT;
467
468     TRACE_(cursor)("%08x (%u bytes), ver %08x, %ix%i %s %s\n",
469                         (unsigned)bits, cbSize, (unsigned)dwVersion, width, height,
470                                   bIcon ? "icon" : "cursor", (loadflags & LR_MONOCHROME) ? "mono" : "" );
471     if (dwVersion == 0x00020000)
472     {
473         FIXME_(cursor)("\t2.xx resources are not supported\n");
474         return 0;
475     }
476
477     if (bIcon)
478         bmi = (BITMAPINFO *)bits;
479     else /* get the hotspot */
480     {
481         POINT16 *pt = (POINT16 *)bits;
482         hotspot = *pt;
483         bmi = (BITMAPINFO *)(pt + 1);
484     }
485     size = DIB_BitmapInfoSize( bmi, DIB_RGB_COLORS );
486
487     if (!width) width = bmi->bmiHeader.biWidth;
488     if (!height) height = bmi->bmiHeader.biHeight/2;
489     DoStretch = (bmi->bmiHeader.biHeight/2 != height) ||
490       (bmi->bmiHeader.biWidth != width);
491
492     /* Check bitmap header */
493
494     if ( (bmi->bmiHeader.biSize != sizeof(BITMAPCOREHEADER)) &&
495          (bmi->bmiHeader.biSize != sizeof(BITMAPINFOHEADER)  ||
496           bmi->bmiHeader.biCompression != BI_RGB) )
497     {
498           WARN_(cursor)("\tinvalid resource bitmap header.\n");
499           return 0;
500     }
501
502     if (!screen_dc) screen_dc = CreateDCA( "DISPLAY", NULL, NULL, NULL );
503     if (screen_dc)
504     {
505         BITMAPINFO* pInfo;
506
507         /* Make sure we have room for the monochrome bitmap later on.
508          * Note that BITMAPINFOINFO and BITMAPCOREHEADER are the same
509          * up to and including the biBitCount. In-memory icon resource 
510          * format is as follows:
511          *
512          *   BITMAPINFOHEADER   icHeader  // DIB header
513          *   RGBQUAD         icColors[]   // Color table
514          *   BYTE            icXOR[]      // DIB bits for XOR mask
515          *   BYTE            icAND[]      // DIB bits for AND mask
516          */
517
518         if ((pInfo = (BITMAPINFO *)HeapAlloc( GetProcessHeap(), 0, 
519           max(size, sizeof(BITMAPINFOHEADER) + 2*sizeof(RGBQUAD)))))
520         {       
521             memcpy( pInfo, bmi, size ); 
522             pInfo->bmiHeader.biHeight /= 2;
523
524             /* Create the XOR bitmap */
525
526             if (DoStretch) {
527                 if(bIcon)
528                 {
529                     hXorBits = CreateCompatibleBitmap(screen_dc, width, height);
530                 }
531                 else
532                 {
533                     hXorBits = CreateBitmap(width, height, 1, 1, NULL);
534                 }
535                 if(hXorBits)
536                 {
537                 HBITMAP hOld;
538                 BOOL res = FALSE;
539
540                 if (!hdcMem) hdcMem = CreateCompatibleDC(screen_dc);
541                 if (hdcMem) {
542                     hOld = SelectObject(hdcMem, hXorBits);
543                     res = StretchDIBits(hdcMem, 0, 0, width, height, 0, 0,
544                                         bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight/2,
545                                         (char*)bmi + size, pInfo, DIB_RGB_COLORS, SRCCOPY);
546                     SelectObject(hdcMem, hOld);
547                 }
548                 if (!res) { DeleteObject(hXorBits); hXorBits = 0; }
549               }
550             } else hXorBits = CreateDIBitmap( screen_dc, &pInfo->bmiHeader,
551                 CBM_INIT, (char*)bmi + size, pInfo, DIB_RGB_COLORS );
552             if( hXorBits )
553             {
554                 char* xbits = (char *)bmi + size +
555                         DIB_GetDIBImageBytes(bmi->bmiHeader.biWidth,
556                                              bmi->bmiHeader.biHeight,
557                                              bmi->bmiHeader.biBitCount) / 2;
558
559                 pInfo->bmiHeader.biBitCount = 1;
560                 if (pInfo->bmiHeader.biSize == sizeof(BITMAPINFOHEADER))
561                 {
562                     RGBQUAD *rgb = pInfo->bmiColors;
563
564                     pInfo->bmiHeader.biClrUsed = pInfo->bmiHeader.biClrImportant = 2;
565                     rgb[0].rgbBlue = rgb[0].rgbGreen = rgb[0].rgbRed = 0x00;
566                     rgb[1].rgbBlue = rgb[1].rgbGreen = rgb[1].rgbRed = 0xff;
567                     rgb[0].rgbReserved = rgb[1].rgbReserved = 0;
568                 }
569                 else
570                 {
571                     RGBTRIPLE *rgb = (RGBTRIPLE *)(((BITMAPCOREHEADER *)pInfo) + 1);
572
573                     rgb[0].rgbtBlue = rgb[0].rgbtGreen = rgb[0].rgbtRed = 0x00;
574                     rgb[1].rgbtBlue = rgb[1].rgbtGreen = rgb[1].rgbtRed = 0xff;
575                 }
576
577                 /* Create the AND bitmap */
578
579             if (DoStretch) {
580               if ((hAndBits = CreateBitmap(width, height, 1, 1, NULL))) {
581                 HBITMAP hOld;
582                 BOOL res = FALSE;
583
584                 if (!hdcMem) hdcMem = CreateCompatibleDC(screen_dc);
585                 if (hdcMem) {
586                     hOld = SelectObject(hdcMem, hAndBits);
587                     res = StretchDIBits(hdcMem, 0, 0, width, height, 0, 0,
588                                         pInfo->bmiHeader.biWidth, pInfo->bmiHeader.biHeight,
589                                         xbits, pInfo, DIB_RGB_COLORS, SRCCOPY);
590                     SelectObject(hdcMem, hOld);
591                 }
592                 if (!res) { DeleteObject(hAndBits); hAndBits = 0; }
593               }
594             } else hAndBits = CreateDIBitmap( screen_dc, &pInfo->bmiHeader,
595               CBM_INIT, xbits, pInfo, DIB_RGB_COLORS );
596
597                 if( !hAndBits ) DeleteObject( hXorBits );
598             }
599             HeapFree( GetProcessHeap(), 0, pInfo ); 
600         }
601     }
602
603     if( !hXorBits || !hAndBits ) 
604     {
605         WARN_(cursor)("\tunable to create an icon bitmap.\n");
606         return 0;
607     }
608
609     /* Now create the CURSORICONINFO structure */
610     GetObjectA( hXorBits, sizeof(bmpXor), &bmpXor );
611     GetObjectA( hAndBits, sizeof(bmpAnd), &bmpAnd );
612     sizeXor = bmpXor.bmHeight * bmpXor.bmWidthBytes;
613     sizeAnd = bmpAnd.bmHeight * bmpAnd.bmWidthBytes;
614
615     if (hObj) hObj = GlobalReAlloc16( hObj, 
616                      sizeof(CURSORICONINFO) + sizeXor + sizeAnd, GMEM_MOVEABLE );
617     if (!hObj) hObj = GlobalAlloc16( GMEM_MOVEABLE, 
618                      sizeof(CURSORICONINFO) + sizeXor + sizeAnd );
619     if (hObj)
620     {
621         CURSORICONINFO *info;
622
623         /* Make it owned by the module */
624         if (hInstance) hInstance = GetExePtr(hInstance);
625         FarSetOwner16( hObj, hInstance );
626
627         info = (CURSORICONINFO *)GlobalLock16( hObj );
628         info->ptHotSpot.x   = hotspot.x;
629         info->ptHotSpot.y   = hotspot.y;
630         info->nWidth        = bmpXor.bmWidth;
631         info->nHeight       = bmpXor.bmHeight;
632         info->nWidthBytes   = bmpXor.bmWidthBytes;
633         info->bPlanes       = bmpXor.bmPlanes;
634         info->bBitsPerPixel = bmpXor.bmBitsPixel;
635
636         /* Transfer the bitmap bits to the CURSORICONINFO structure */
637
638         GetBitmapBits( hAndBits, sizeAnd, (char *)(info + 1) );
639         GetBitmapBits( hXorBits, sizeXor, (char *)(info + 1) + sizeAnd );
640         GlobalUnlock16( hObj );
641     }
642
643     DeleteObject( hAndBits );
644     DeleteObject( hXorBits );
645     return hObj;
646 }
647
648
649 /**********************************************************************
650  *              CreateIconFromResourceEx (USER.450)
651  *
652  * FIXME: not sure about exact parameter types
653  */
654 HICON16 WINAPI CreateIconFromResourceEx16( LPBYTE bits, UINT16 cbSize, BOOL16 bIcon,
655                                     DWORD dwVersion, INT16 width, INT16 height, UINT16 cFlag )
656 {
657     return CreateIconFromResourceEx(bits, cbSize, bIcon, dwVersion, 
658       width, height, cFlag);
659 }
660
661
662 /**********************************************************************
663  *              CreateIconFromResource (USER32.@)
664  */
665 HICON WINAPI CreateIconFromResource( LPBYTE bits, UINT cbSize,
666                                            BOOL bIcon, DWORD dwVersion)
667 {
668     return CreateIconFromResourceEx( bits, cbSize, bIcon, dwVersion, 0,0,0);
669 }
670
671
672 /**********************************************************************
673  *              CreateIconFromResourceEx (USER32.@)
674  */
675 HICON WINAPI CreateIconFromResourceEx( LPBYTE bits, UINT cbSize,
676                                            BOOL bIcon, DWORD dwVersion,
677                                            INT width, INT height,
678                                            UINT cFlag )
679 {
680     return CURSORICON_CreateFromResource( 0, 0, bits, cbSize, bIcon, dwVersion,
681                                           width, height, cFlag );
682 }
683
684 /**********************************************************************
685  *          CURSORICON_Load
686  *
687  * Load a cursor or icon from resource or file.
688  */
689 HGLOBAL CURSORICON_Load( HINSTANCE hInstance, LPCWSTR name,
690                          INT width, INT height, INT colors,
691                          BOOL fCursor, UINT loadflags )
692 {
693     HANDLE handle = 0, h = 0;
694     HANDLE hRsrc;
695     CURSORICONDIR *dir;
696     CURSORICONDIRENTRY *dirEntry;
697     LPBYTE bits;
698
699     if ( loadflags & LR_LOADFROMFILE )    /* Load from file */
700     {
701         LPBYTE *ptr;
702         if (!CURSORICON_SimulateLoadingFromResourceW((LPWSTR)name, fCursor, &dir, &ptr))
703             return 0;
704         if (fCursor)
705             dirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestCursor(dir, width, height, 1);
706         else
707             dirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestIcon(dir, width, height, colors);
708         bits = ptr[dirEntry->wResId-1];
709         h = CURSORICON_CreateFromResource( 0, 0, bits, dirEntry->dwBytesInRes, 
710                                            !fCursor, 0x00030000, width, height, loadflags);
711         HeapFree( GetProcessHeap(), 0, dir );
712         HeapFree( GetProcessHeap(), 0, ptr );
713     }
714     else  /* Load from resource */
715     {
716         HANDLE hGroupRsrc;
717         WORD wResId;
718         DWORD dwBytesInRes;
719
720         if (!hInstance)  /* Load OEM cursor/icon */
721         {
722             if (!(hInstance = GetModuleHandleA( "user32.dll" ))) return 0;
723         }
724
725         /* Normalize hInstance (must be uniquely represented for icon cache) */
726         
727         if ( HIWORD( hInstance ) )
728             hInstance = MapHModuleLS( hInstance );
729         else
730             hInstance = GetExePtr( hInstance );
731
732         /* Get directory resource ID */
733
734         if (!(hRsrc = FindResourceW( hInstance, name,
735                           fCursor ? RT_GROUP_CURSORW : RT_GROUP_ICONW )))
736             return 0;
737         hGroupRsrc = hRsrc;
738
739         /* Find the best entry in the directory */
740  
741         if (!(handle = LoadResource( hInstance, hRsrc ))) return 0;
742         if (!(dir = (CURSORICONDIR*)LockResource( handle ))) return 0;
743         if (fCursor)
744             dirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestCursor( dir,
745                                                               width, height, 1);
746         else
747             dirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestIcon( dir,
748                                                        width, height, colors );
749         if (!dirEntry) return 0;
750         wResId = dirEntry->wResId;
751         dwBytesInRes = dirEntry->dwBytesInRes;
752         FreeResource( handle );
753
754         /* Load the resource */
755
756         if (!(hRsrc = FindResourceW(hInstance,MAKEINTRESOURCEW(wResId),
757                                       fCursor ? RT_CURSORW : RT_ICONW ))) return 0;
758         
759         /* If shared icon, check whether it was already loaded */
760         if (    (loadflags & LR_SHARED) 
761              && (h = CURSORICON_FindSharedIcon( hInstance, hRsrc ) ) != 0 )
762             return h;
763         
764         if (!(handle = LoadResource( hInstance, hRsrc ))) return 0;
765         bits = (LPBYTE)LockResource( handle );
766         h = CURSORICON_CreateFromResource( 0, 0, bits, dwBytesInRes, 
767                                            !fCursor, 0x00030000, width, height, loadflags);
768         FreeResource( handle );
769
770         /* If shared icon, add to icon cache */
771
772         if ( h && (loadflags & LR_SHARED) )
773             CURSORICON_AddSharedIcon( hInstance, hRsrc, hGroupRsrc, h );
774     }
775
776     return h;
777 }
778
779 /***********************************************************************
780  *           CURSORICON_Copy
781  *
782  * Make a copy of a cursor or icon.
783  */
784 static HGLOBAL16 CURSORICON_Copy( HINSTANCE16 hInstance, HGLOBAL16 handle )
785 {
786     char *ptrOld, *ptrNew;
787     int size;
788     HGLOBAL16 hNew;
789
790     if (!(ptrOld = (char *)GlobalLock16( handle ))) return 0;
791     if (hInstance && !(hInstance = GetExePtr( hInstance ))) return 0;
792     size = GlobalSize16( handle );
793     hNew = GlobalAlloc16( GMEM_MOVEABLE, size );
794     FarSetOwner16( hNew, hInstance );
795     ptrNew = (char *)GlobalLock16( hNew );
796     memcpy( ptrNew, ptrOld, size );
797     GlobalUnlock16( handle );
798     GlobalUnlock16( hNew );
799     return hNew;
800 }
801
802 /*************************************************************************
803  * CURSORICON_ExtCopy 
804  *
805  * Copies an Image from the Cache if LR_COPYFROMRESOURCE is specified
806  *
807  * PARAMS
808  *      Handle     [I] handle to an Image 
809  *      nType      [I] Type of Handle (IMAGE_CURSOR | IMAGE_ICON)
810  *      iDesiredCX [I] The Desired width of the Image
811  *      iDesiredCY [I] The desired height of the Image
812  *      nFlags     [I] The flags from CopyImage
813  *
814  * RETURNS
815  *     Success: The new handle of the Image
816  *
817  * NOTES
818  *     LR_COPYDELETEORG and LR_MONOCHROME are currently not implemented.
819  *     LR_MONOCHROME should be implemented by CURSORICON_CreateFromResource.
820  *     LR_COPYFROMRESOURCE will only work if the Image is in the Cache.
821  *
822  *     
823  */
824
825 HGLOBAL CURSORICON_ExtCopy(HGLOBAL Handle, UINT nType, 
826                            INT iDesiredCX, INT iDesiredCY, 
827                            UINT nFlags)
828 {
829     HGLOBAL16 hNew=0;
830
831     TRACE_(icon)("Handle %u, uType %u, iDesiredCX %i, iDesiredCY %i, nFlags %u\n", 
832         Handle, nType, iDesiredCX, iDesiredCY, nFlags);
833
834     if(Handle == 0)
835     {
836         return 0;
837     }
838
839     /* Best Fit or Monochrome */
840     if( (nFlags & LR_COPYFROMRESOURCE
841         && (iDesiredCX > 0 || iDesiredCY > 0))
842         || nFlags & LR_MONOCHROME) 
843     {
844         ICONCACHE* pIconCache = CURSORICON_FindCache(Handle);
845
846         /* Not Found in Cache, then do a strait copy
847         */
848         if(pIconCache == NULL)
849         {
850             hNew = CURSORICON_Copy(0, Handle);
851             if(nFlags & LR_COPYFROMRESOURCE)
852             {
853                 TRACE_(icon)("LR_COPYFROMRESOURCE: Failed to load from cache\n");
854             }
855         }
856         else
857         {
858             int iTargetCY = iDesiredCY, iTargetCX = iDesiredCX;
859             LPBYTE pBits;
860             HANDLE hMem;
861             HRSRC hRsrc;
862             DWORD dwBytesInRes;
863             WORD wResId;
864             CURSORICONDIR *pDir;
865             CURSORICONDIRENTRY *pDirEntry;
866             BOOL bIsIcon = (nType == IMAGE_ICON);
867
868             /* Completing iDesiredCX CY for Monochrome Bitmaps if needed
869             */
870             if(((nFlags & LR_MONOCHROME) && !(nFlags & LR_COPYFROMRESOURCE))
871                 || (iDesiredCX == 0 && iDesiredCY == 0))
872             {
873                 iDesiredCY = GetSystemMetrics(bIsIcon ? 
874                     SM_CYICON : SM_CYCURSOR);
875                 iDesiredCX = GetSystemMetrics(bIsIcon ? 
876                     SM_CXICON : SM_CXCURSOR);
877             }
878
879             /* Retreive the CURSORICONDIRENTRY 
880             */
881             if (!(hMem = LoadResource( pIconCache->hModule , 
882                             pIconCache->hGroupRsrc))) 
883             {
884                 return 0;
885             }
886             if (!(pDir = (CURSORICONDIR*)LockResource( hMem ))) 
887             {
888                 return 0;
889             }
890
891             /* Find Best Fit 
892             */
893             if(bIsIcon)
894             {
895                 pDirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestIcon(
896                                 pDir, iDesiredCX, iDesiredCY, 256);
897             }
898             else
899             {
900                 pDirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestCursor( 
901                                 pDir, iDesiredCX, iDesiredCY, 1);
902             }
903
904             wResId = pDirEntry->wResId;
905             dwBytesInRes = pDirEntry->dwBytesInRes;
906             FreeResource(hMem);
907
908             TRACE_(icon)("ResID %u, BytesInRes %lu, Width %d, Height %d DX %d, DY %d\n", 
909                 wResId, dwBytesInRes,  pDirEntry->ResInfo.icon.bWidth, 
910                 pDirEntry->ResInfo.icon.bHeight, iDesiredCX, iDesiredCY);
911
912             /* Get the Best Fit
913             */
914             if (!(hRsrc = FindResourceW(pIconCache->hModule ,
915                 MAKEINTRESOURCEW(wResId), bIsIcon ? RT_ICONW : RT_CURSORW))) 
916             {
917                 return 0;
918             }
919             if (!(hMem = LoadResource( pIconCache->hModule , hRsrc ))) 
920             {
921                 return 0;
922             }
923
924             pBits = (LPBYTE)LockResource( hMem );
925          
926             if(nFlags & LR_DEFAULTSIZE)
927             {
928                 iTargetCY = GetSystemMetrics(SM_CYICON);
929                 iTargetCX = GetSystemMetrics(SM_CXICON);
930             }
931
932             /* Create a New Icon with the proper dimension
933             */
934             hNew = CURSORICON_CreateFromResource( 0, 0, pBits, dwBytesInRes, 
935                        bIsIcon, 0x00030000, iTargetCX, iTargetCY, nFlags);
936             FreeResource(hMem);
937         }
938     }
939     else hNew = CURSORICON_Copy(0, Handle);
940     return hNew;
941 }
942
943 /***********************************************************************
944  *           CURSORICON_IconToCursor
945  *
946  * Converts bitmap to mono and truncates if icon is too large (should
947  * probably do StretchBlt() instead).
948  */
949 HCURSOR16 CURSORICON_IconToCursor(HICON16 hIcon, BOOL bSemiTransparent)
950 {
951  HCURSOR16       hRet = 0;
952  CURSORICONINFO *pIcon = NULL;
953
954  if(hIcon)
955     if (!(pIcon = (CURSORICONINFO*)GlobalLock16( hIcon ))) return FALSE;
956        if (pIcon->bPlanes * pIcon->bBitsPerPixel == 1)
957        {
958            hRet = CURSORICON_Copy( 0, hIcon );
959
960  
961            pIcon = GlobalLock16(hRet);
962
963            pIcon->ptHotSpot.x = pIcon->ptHotSpot.y = 15;
964  
965            GlobalUnlock16(hRet);
966        }
967        else
968        {
969            BYTE  pAndBits[128];
970            BYTE  pXorBits[128];
971            int   maxx, maxy, ix, iy, bpp = pIcon->bBitsPerPixel;
972            BYTE* psPtr, *pxbPtr = pXorBits;
973            unsigned xor_width, and_width, val_base = 0xffffffff >> (32 - bpp);
974            BYTE* pbc = NULL;
975
976            CURSORICONINFO cI;
977
978            TRACE_(icon)("[%04x] %ix%i %ibpp (bogus %ibps)\n", 
979                 hIcon, pIcon->nWidth, pIcon->nHeight, pIcon->bBitsPerPixel, pIcon->nWidthBytes );
980
981            xor_width = BITMAP_GetWidthBytes( pIcon->nWidth, bpp );
982            and_width = BITMAP_GetWidthBytes( pIcon->nWidth, 1 );
983            psPtr = (BYTE *)(pIcon + 1) + pIcon->nHeight * and_width;
984
985            memset(pXorBits, 0, 128);
986            cI.bBitsPerPixel = 1; cI.bPlanes = 1;
987            cI.ptHotSpot.x = cI.ptHotSpot.y = 15;
988            cI.nWidth = 32; cI.nHeight = 32;
989            cI.nWidthBytes = 4;  /* 32x1bpp */
990
991            maxx = (pIcon->nWidth > 32) ? 32 : pIcon->nWidth;
992            maxy = (pIcon->nHeight > 32) ? 32 : pIcon->nHeight;
993
994            for( iy = 0; iy < maxy; iy++ )
995            {
996               unsigned shift = iy % 2; 
997
998               memcpy( pAndBits + iy * 4, (BYTE *)(pIcon + 1) + iy * and_width, 
999                                          (and_width > 4) ? 4 : and_width );
1000               for( ix = 0; ix < maxx; ix++ )
1001               {
1002                 if( bSemiTransparent && ((ix+shift)%2) )
1003                 {
1004                     /* set AND bit, XOR bit stays 0 */
1005
1006                     pbc = pAndBits + iy * 4 + ix/8;
1007                    *pbc |= 0x80 >> (ix%8);
1008                 }
1009                 else
1010                 {
1011                     /* keep AND bit, set XOR bit */
1012
1013                   unsigned *psc = (unsigned*)(psPtr + (ix * bpp)/8);
1014                   unsigned  val = ((*psc) >> (ix * bpp)%8) & val_base;
1015                   if(!PALETTE_Driver->pIsDark(val))
1016                   {
1017                     pbc = pxbPtr + ix/8;
1018                    *pbc |= 0x80 >> (ix%8);
1019                   }
1020                 }
1021               }
1022               psPtr += xor_width;
1023               pxbPtr += 4;
1024            }
1025
1026            hRet = CreateCursorIconIndirect16( 0 , &cI, pAndBits, pXorBits);
1027
1028            if( !hRet ) /* fall back on default drag cursor */
1029                 hRet = CURSORICON_Copy( 0 ,
1030                               CURSORICON_Load(0,MAKEINTRESOURCEW(OCR_DRAGOBJECT),
1031                                          GetSystemMetrics(SM_CXCURSOR),
1032                                          GetSystemMetrics(SM_CYCURSOR), 1, TRUE, 0) );
1033        }
1034
1035  return hRet;
1036 }
1037
1038
1039 /***********************************************************************
1040  *              LoadCursor (USER.173)
1041  */
1042 HCURSOR16 WINAPI LoadCursor16( HINSTANCE16 hInstance, LPCSTR name )
1043 {
1044     return LoadCursorA( hInstance, name );
1045 }
1046
1047
1048 /***********************************************************************
1049  *              LoadIcon (USER.174)
1050  */
1051 HICON16 WINAPI LoadIcon16( HINSTANCE16 hInstance, LPCSTR name )
1052 {
1053     return LoadIconA( hInstance, name );
1054 }
1055
1056
1057 /***********************************************************************
1058  *              CreateCursor (USER.406)
1059  */
1060 HCURSOR16 WINAPI CreateCursor16( HINSTANCE16 hInstance,
1061                                  INT16 xHotSpot, INT16 yHotSpot,
1062                                  INT16 nWidth, INT16 nHeight,
1063                                  LPCVOID lpANDbits, LPCVOID lpXORbits )
1064 {
1065     CURSORICONINFO info;
1066
1067     TRACE_(cursor)("%dx%d spot=%d,%d xor=%p and=%p\n",
1068                     nWidth, nHeight, xHotSpot, yHotSpot, lpXORbits, lpANDbits);
1069
1070     info.ptHotSpot.x = xHotSpot;
1071     info.ptHotSpot.y = yHotSpot;
1072     info.nWidth = nWidth;
1073     info.nHeight = nHeight;
1074     info.nWidthBytes = 0;
1075     info.bPlanes = 1;
1076     info.bBitsPerPixel = 1;
1077
1078     return CreateCursorIconIndirect16( hInstance, &info, lpANDbits, lpXORbits );
1079 }
1080
1081
1082 /***********************************************************************
1083  *              CreateCursor (USER32.@)
1084  */
1085 HCURSOR WINAPI CreateCursor( HINSTANCE hInstance,
1086                                  INT xHotSpot, INT yHotSpot,
1087                                  INT nWidth, INT nHeight,
1088                                  LPCVOID lpANDbits, LPCVOID lpXORbits )
1089 {
1090     CURSORICONINFO info;
1091
1092     TRACE_(cursor)("%dx%d spot=%d,%d xor=%p and=%p\n",
1093                     nWidth, nHeight, xHotSpot, yHotSpot, lpXORbits, lpANDbits);
1094
1095     info.ptHotSpot.x = xHotSpot;
1096     info.ptHotSpot.y = yHotSpot;
1097     info.nWidth = nWidth;
1098     info.nHeight = nHeight;
1099     info.nWidthBytes = 0;
1100     info.bPlanes = 1;
1101     info.bBitsPerPixel = 1;
1102
1103     return CreateCursorIconIndirect16( 0, &info, lpANDbits, lpXORbits );
1104 }
1105
1106
1107 /***********************************************************************
1108  *              CreateIcon (USER.407)
1109  */
1110 HICON16 WINAPI CreateIcon16( HINSTANCE16 hInstance, INT16 nWidth,
1111                              INT16 nHeight, BYTE bPlanes, BYTE bBitsPixel,
1112                              LPCVOID lpANDbits, LPCVOID lpXORbits )
1113 {
1114     CURSORICONINFO info;
1115
1116     TRACE_(icon)("%dx%dx%d, xor=%p, and=%p\n",
1117                   nWidth, nHeight, bPlanes * bBitsPixel, lpXORbits, lpANDbits);
1118
1119     info.ptHotSpot.x = ICON_HOTSPOT;
1120     info.ptHotSpot.y = ICON_HOTSPOT;
1121     info.nWidth = nWidth;
1122     info.nHeight = nHeight;
1123     info.nWidthBytes = 0;
1124     info.bPlanes = bPlanes;
1125     info.bBitsPerPixel = bBitsPixel;
1126
1127     return CreateCursorIconIndirect16( hInstance, &info, lpANDbits, lpXORbits );
1128 }
1129
1130
1131 /***********************************************************************
1132  *              CreateIcon (USER32.@)
1133  *
1134  *  Creates an icon based on the specified bitmaps. The bitmaps must be 
1135  *  provided in a device dependent format and will be resized to 
1136  *  (SM_CXICON,SM_CYICON) and depth converted to match the screen's color 
1137  *  depth. The provided bitmaps must be top-down bitmaps.
1138  *  Although Windows does not support 15bpp(*) this API must support it 
1139  *  for Winelib applications.
1140  *
1141  *  (*) Windows does not support 15bpp but it supports the 555 RGB 16bpp 
1142  *      format!
1143  *
1144  * BUGS
1145  *
1146  *  - The provided bitmaps are not resized!
1147  *  - The documentation says the lpXORbits bitmap must be in a device 
1148  *    dependent format. But we must still resize it and perform depth 
1149  *    conversions if necessary.
1150  *  - I'm a bit unsure about the how the 'device dependent format' thing works.
1151  *    I did some tests on windows and found that if you provide a 16bpp bitmap 
1152  *    in lpXORbits, then its format but be 565 RGB if the screen's bit depth 
1153  *    is 16bpp but it must be 555 RGB if the screen's bit depth is anything
1154  *    else. I don't know if this is part of the GDI specs or if this is a 
1155  *    quirk of the graphics card driver.
1156  *  - You may think that we check whether the bit depths match or not 
1157  *    as an optimization. But the truth is that the conversion using 
1158  *    CreateDIBitmap does not work for some bit depth (e.g. 8bpp) and I have 
1159  *    no idea why.
1160  *  - I'm pretty sure that all the things we do in CreateIcon should 
1161  *    also be done in CreateIconIndirect...
1162  */
1163 HICON WINAPI CreateIcon(
1164     HINSTANCE hInstance, /* the application's hInstance, currently unused */
1165     INT nWidth, /* the width of the provided bitmaps */
1166     INT nHeight, /* the height of the provided bitmaps */
1167     BYTE bPlanes, /* the number of planes in the provided bitmaps */
1168     BYTE bBitsPixel, /* the number of bits per pixel of the lpXORbits bitmap */
1169     LPCVOID lpANDbits, /* a monochrome bitmap representing the icon's mask */
1170     LPCVOID lpXORbits /* the icon's 'color' bitmap */
1171     )
1172 {
1173     HICON hIcon;
1174     HDC hdc;
1175
1176     TRACE_(icon)("%dx%dx%d, xor=%p, and=%p\n",
1177                  nWidth, nHeight, bPlanes * bBitsPixel, lpXORbits, lpANDbits);
1178
1179     hdc=GetDC(0);
1180     if (!hdc)
1181         return 0;
1182
1183     if (GetDeviceCaps(hdc,BITSPIXEL)==bBitsPixel) {
1184         CURSORICONINFO info;
1185
1186         info.ptHotSpot.x = ICON_HOTSPOT;
1187         info.ptHotSpot.y = ICON_HOTSPOT;
1188         info.nWidth = nWidth;
1189         info.nHeight = nHeight;
1190         info.nWidthBytes = 0;
1191         info.bPlanes = bPlanes;
1192         info.bBitsPerPixel = bBitsPixel;
1193
1194         hIcon=CreateCursorIconIndirect16( 0, &info, lpANDbits, lpXORbits );
1195     } else {
1196         ICONINFO iinfo;
1197         BITMAPINFO bmi;
1198
1199         iinfo.fIcon=TRUE;
1200         iinfo.xHotspot=ICON_HOTSPOT;
1201         iinfo.yHotspot=ICON_HOTSPOT;
1202         iinfo.hbmMask=CreateBitmap(nWidth,nHeight,1,1,lpANDbits);
1203
1204         bmi.bmiHeader.biSize=sizeof(bmi.bmiHeader);
1205         bmi.bmiHeader.biWidth=nWidth;
1206         bmi.bmiHeader.biHeight=-nHeight;
1207         bmi.bmiHeader.biPlanes=bPlanes;
1208         bmi.bmiHeader.biBitCount=bBitsPixel;
1209         bmi.bmiHeader.biCompression=BI_RGB;
1210         bmi.bmiHeader.biSizeImage=0;
1211         bmi.bmiHeader.biXPelsPerMeter=0;
1212         bmi.bmiHeader.biYPelsPerMeter=0;
1213         bmi.bmiHeader.biClrUsed=0;
1214         bmi.bmiHeader.biClrImportant=0;
1215
1216         iinfo.hbmColor = CreateDIBitmap( hdc, &bmi.bmiHeader,
1217                                          CBM_INIT, lpXORbits,
1218                                          &bmi, DIB_RGB_COLORS );
1219
1220         hIcon=CreateIconIndirect(&iinfo);
1221         DeleteObject(iinfo.hbmMask);
1222         DeleteObject(iinfo.hbmColor);
1223     }
1224     ReleaseDC(0,hdc);
1225     return hIcon;
1226 }
1227
1228
1229 /***********************************************************************
1230  *              CreateCursorIconIndirect (USER.408)
1231  */
1232 HGLOBAL16 WINAPI CreateCursorIconIndirect16( HINSTANCE16 hInstance,
1233                                            CURSORICONINFO *info,
1234                                            LPCVOID lpANDbits,
1235                                            LPCVOID lpXORbits )
1236 {
1237     HGLOBAL16 handle;
1238     char *ptr;
1239     int sizeAnd, sizeXor;
1240
1241     hInstance = GetExePtr( hInstance );  /* Make it a module handle */
1242     if (!lpXORbits || !lpANDbits || info->bPlanes != 1) return 0;
1243     info->nWidthBytes = BITMAP_GetWidthBytes(info->nWidth,info->bBitsPerPixel);
1244     sizeXor = info->nHeight * info->nWidthBytes;
1245     sizeAnd = info->nHeight * BITMAP_GetWidthBytes( info->nWidth, 1 );
1246     if (!(handle = GlobalAlloc16( GMEM_MOVEABLE,
1247                                   sizeof(CURSORICONINFO) + sizeXor + sizeAnd)))
1248         return 0;
1249     FarSetOwner16( handle, hInstance );
1250     ptr = (char *)GlobalLock16( handle );
1251     memcpy( ptr, info, sizeof(*info) );
1252     memcpy( ptr + sizeof(CURSORICONINFO), lpANDbits, sizeAnd );
1253     memcpy( ptr + sizeof(CURSORICONINFO) + sizeAnd, lpXORbits, sizeXor );
1254     GlobalUnlock16( handle );
1255     return handle;
1256 }
1257
1258
1259 /***********************************************************************
1260  *              CopyIcon (USER.368)
1261  */
1262 HICON16 WINAPI CopyIcon16( HINSTANCE16 hInstance, HICON16 hIcon )
1263 {
1264     TRACE_(icon)("%04x %04x\n", hInstance, hIcon );
1265     return CURSORICON_Copy( hInstance, hIcon );
1266 }
1267
1268
1269 /***********************************************************************
1270  *              CopyIcon (USER32.@)
1271  */
1272 HICON WINAPI CopyIcon( HICON hIcon )
1273 {
1274     TRACE_(icon)("%04x\n", hIcon );
1275     return CURSORICON_Copy( 0, hIcon );
1276 }
1277
1278
1279 /***********************************************************************
1280  *              CopyCursor (USER.369)
1281  */
1282 HCURSOR16 WINAPI CopyCursor16( HINSTANCE16 hInstance, HCURSOR16 hCursor )
1283 {
1284     TRACE_(cursor)("%04x %04x\n", hInstance, hCursor );
1285     return CURSORICON_Copy( hInstance, hCursor );
1286 }
1287
1288 /**********************************************************************
1289  *              DestroyIcon32 (USER.610)
1290  *
1291  * This routine is actually exported from Win95 USER under the name
1292  * DestroyIcon32 ...  The behaviour implemented here should mimic 
1293  * the Win95 one exactly, especially the return values, which 
1294  * depend on the setting of various flags.
1295  */
1296 WORD WINAPI CURSORICON_Destroy( HGLOBAL16 handle, UINT16 flags )
1297 {
1298     WORD retv;
1299
1300     TRACE_(icon)("(%04x, %04x)\n", handle, flags );
1301
1302     /* Check whether destroying active cursor */
1303
1304     if ( hActiveCursor == handle )
1305     {
1306         ERR_(cursor)("Destroying active cursor!\n" );
1307         SetCursor( 0 );
1308     }
1309
1310     /* Try shared cursor/icon first */
1311
1312     if ( !(flags & CID_NONSHARED) )
1313     {
1314         INT count = CURSORICON_DelSharedIcon( handle );
1315
1316         if ( count != -1 )
1317             return (flags & CID_WIN32)? TRUE : (count == 0);
1318
1319         /* FIXME: OEM cursors/icons should be recognized */
1320     }
1321
1322     /* Now assume non-shared cursor/icon */
1323
1324     retv = GlobalFree16( handle );
1325     return (flags & CID_RESOURCE)? retv : TRUE;
1326 }
1327
1328 /***********************************************************************
1329  *              DestroyIcon (USER.457)
1330  */
1331 BOOL16 WINAPI DestroyIcon16( HICON16 hIcon )
1332 {
1333     return CURSORICON_Destroy( hIcon, 0 );
1334 }
1335
1336 /***********************************************************************
1337  *              DestroyIcon (USER32.@)
1338  */
1339 BOOL WINAPI DestroyIcon( HICON hIcon )
1340 {
1341     return CURSORICON_Destroy( hIcon, CID_WIN32 );
1342 }
1343
1344 /***********************************************************************
1345  *              DestroyCursor (USER.458)
1346  */
1347 BOOL16 WINAPI DestroyCursor16( HCURSOR16 hCursor )
1348 {
1349     return CURSORICON_Destroy( hCursor, 0 );
1350 }
1351
1352 /***********************************************************************
1353  *              DestroyCursor (USER32.@)
1354  */
1355 BOOL WINAPI DestroyCursor( HCURSOR hCursor )
1356 {
1357     return CURSORICON_Destroy( hCursor, CID_WIN32 );
1358 }
1359
1360
1361 /***********************************************************************
1362  *              DrawIcon (USER.84)
1363  */
1364 BOOL16 WINAPI DrawIcon16( HDC16 hdc, INT16 x, INT16 y, HICON16 hIcon )
1365 {
1366     return DrawIcon( hdc, x, y, hIcon );
1367 }
1368
1369
1370 /***********************************************************************
1371  *              DrawIcon (USER32.@)
1372  */
1373 BOOL WINAPI DrawIcon( HDC hdc, INT x, INT y, HICON hIcon )
1374 {
1375     CURSORICONINFO *ptr;
1376     HDC hMemDC;
1377     HBITMAP hXorBits, hAndBits;
1378     COLORREF oldFg, oldBg;
1379
1380     if (!(ptr = (CURSORICONINFO *)GlobalLock16( hIcon ))) return FALSE;
1381     if (!(hMemDC = CreateCompatibleDC( hdc ))) return FALSE;
1382     hAndBits = CreateBitmap( ptr->nWidth, ptr->nHeight, 1, 1,
1383                                (char *)(ptr+1) );
1384     hXorBits = CreateBitmap( ptr->nWidth, ptr->nHeight, ptr->bPlanes,
1385                                ptr->bBitsPerPixel, (char *)(ptr + 1)
1386                         + ptr->nHeight * BITMAP_GetWidthBytes(ptr->nWidth,1) );
1387     oldFg = SetTextColor( hdc, RGB(0,0,0) );
1388     oldBg = SetBkColor( hdc, RGB(255,255,255) );
1389
1390     if (hXorBits && hAndBits)
1391     {
1392         HBITMAP hBitTemp = SelectObject( hMemDC, hAndBits );
1393         BitBlt( hdc, x, y, ptr->nWidth, ptr->nHeight, hMemDC, 0, 0, SRCAND );
1394         SelectObject( hMemDC, hXorBits );
1395         BitBlt(hdc, x, y, ptr->nWidth, ptr->nHeight, hMemDC, 0, 0,SRCINVERT);
1396         SelectObject( hMemDC, hBitTemp );
1397     }
1398     DeleteDC( hMemDC );
1399     if (hXorBits) DeleteObject( hXorBits );
1400     if (hAndBits) DeleteObject( hAndBits );
1401     GlobalUnlock16( hIcon );
1402     SetTextColor( hdc, oldFg );
1403     SetBkColor( hdc, oldBg );
1404     return TRUE;
1405 }
1406
1407
1408 /***********************************************************************
1409  *              IconSize (USER.86)
1410  *
1411  * See "Undocumented Windows". Used by W2.0 paint.exe.
1412  */
1413 DWORD WINAPI IconSize16( void )
1414 {
1415     return MAKELONG(GetSystemMetrics(SM_CYICON), GetSystemMetrics(SM_CXICON));
1416 }
1417
1418
1419 /***********************************************************************
1420  *              DumpIcon (USER.459)
1421  */
1422 DWORD WINAPI DumpIcon16( SEGPTR pInfo, WORD *lpLen,
1423                        SEGPTR *lpXorBits, SEGPTR *lpAndBits )
1424 {
1425     CURSORICONINFO *info = MapSL( pInfo );
1426     int sizeAnd, sizeXor;
1427
1428     if (!info) return 0;
1429     sizeXor = info->nHeight * info->nWidthBytes;
1430     sizeAnd = info->nHeight * BITMAP_GetWidthBytes( info->nWidth, 1 );
1431     if (lpAndBits) *lpAndBits = pInfo + sizeof(CURSORICONINFO);
1432     if (lpXorBits) *lpXorBits = pInfo + sizeof(CURSORICONINFO) + sizeAnd;
1433     if (lpLen) *lpLen = sizeof(CURSORICONINFO) + sizeAnd + sizeXor;
1434     return MAKELONG( sizeXor, sizeXor );
1435 }
1436
1437
1438 /***********************************************************************
1439  *              SetCursor (USER.69)
1440  */
1441 HCURSOR16 WINAPI SetCursor16( HCURSOR16 hCursor )
1442 {
1443     return (HCURSOR16)SetCursor( hCursor );
1444 }
1445
1446
1447 /***********************************************************************
1448  *              SetCursor (USER32.@)
1449  * RETURNS:
1450  *      A handle to the previous cursor shape.
1451  */
1452 HCURSOR WINAPI SetCursor(
1453                  HCURSOR hCursor /* [in] Handle of cursor to show */
1454 ) {
1455     HCURSOR hOldCursor;
1456
1457     if (hCursor == hActiveCursor) return hActiveCursor;  /* No change */
1458     TRACE_(cursor)("%04x\n", hCursor );
1459     hOldCursor = hActiveCursor;
1460     hActiveCursor = hCursor;
1461     /* Change the cursor shape only if it is visible */
1462     if (CURSOR_ShowCount >= 0)
1463     {
1464         USER_Driver.pSetCursor( (CURSORICONINFO*)GlobalLock16( hActiveCursor ) );
1465         GlobalUnlock16( hActiveCursor );
1466     }
1467     return hOldCursor;
1468 }
1469
1470
1471 /***********************************************************************
1472  *              SetCursorPos (USER.70)
1473  */
1474 void WINAPI SetCursorPos16( INT16 x, INT16 y )
1475 {
1476     SetCursorPos( x, y );
1477 }
1478
1479
1480 /***********************************************************************
1481  *              SetCursorPos (USER32.@)
1482  */
1483 BOOL WINAPI SetCursorPos( INT x, INT y )
1484 {
1485     USER_Driver.pMoveCursor( x, y );
1486     return TRUE;
1487 }
1488
1489
1490 /***********************************************************************
1491  *              ShowCursor (USER.71)
1492  */
1493 INT16 WINAPI ShowCursor16( BOOL16 bShow )
1494 {
1495     return ShowCursor( bShow );
1496 }
1497
1498
1499 /***********************************************************************
1500  *              ShowCursor (USER32.@)
1501  */
1502 INT WINAPI ShowCursor( BOOL bShow )
1503 {
1504     TRACE_(cursor)("%d, count=%d\n",
1505                     bShow, CURSOR_ShowCount );
1506
1507     if (bShow)
1508     {
1509         if (++CURSOR_ShowCount == 0)  /* Show it */
1510         {
1511             USER_Driver.pSetCursor( (CURSORICONINFO*)GlobalLock16( hActiveCursor ) );
1512             GlobalUnlock16( hActiveCursor );
1513         }
1514     }
1515     else
1516     {
1517         if (--CURSOR_ShowCount == -1)  /* Hide it */
1518             USER_Driver.pSetCursor( NULL );
1519     }
1520     return CURSOR_ShowCount;
1521 }
1522
1523
1524 /***********************************************************************
1525  *              GetCursor (USER.247)
1526  */
1527 HCURSOR16 WINAPI GetCursor16(void)
1528 {
1529     return hActiveCursor;
1530 }
1531
1532
1533 /***********************************************************************
1534  *              GetCursor (USER32.@)
1535  */
1536 HCURSOR WINAPI GetCursor(void)
1537 {
1538     return hActiveCursor;
1539 }
1540
1541
1542 /***********************************************************************
1543  *              ClipCursor (USER.16)
1544  */
1545 BOOL16 WINAPI ClipCursor16( const RECT16 *rect )
1546 {
1547     if (!rect) SetRectEmpty( &CURSOR_ClipRect );
1548     else CONV_RECT16TO32( rect, &CURSOR_ClipRect );
1549     return TRUE;
1550 }
1551
1552
1553 /***********************************************************************
1554  *              ClipCursor (USER32.@)
1555  */
1556 BOOL WINAPI ClipCursor( const RECT *rect )
1557 {
1558     if (!rect) SetRectEmpty( &CURSOR_ClipRect );
1559     else CopyRect( &CURSOR_ClipRect, rect );
1560     return TRUE;
1561 }
1562
1563
1564 /***********************************************************************
1565  *              GetClipCursor (USER.309)
1566  */
1567 void WINAPI GetClipCursor16( RECT16 *rect )
1568 {
1569     if (rect) CONV_RECT32TO16( &CURSOR_ClipRect, rect );
1570 }
1571
1572
1573 /***********************************************************************
1574  *              GetClipCursor (USER32.@)
1575  */
1576 BOOL WINAPI GetClipCursor( RECT *rect )
1577 {
1578     if (rect) 
1579     {
1580        CopyRect( rect, &CURSOR_ClipRect );
1581        return TRUE;
1582     }
1583     return FALSE;
1584 }
1585
1586 /**********************************************************************
1587  *              LookupIconIdFromDirectoryEx (USER.364)
1588  *
1589  * FIXME: exact parameter sizes
1590  */
1591 INT16 WINAPI LookupIconIdFromDirectoryEx16( LPBYTE xdir, BOOL16 bIcon,
1592              INT16 width, INT16 height, UINT16 cFlag )
1593 {
1594     CURSORICONDIR       *dir = (CURSORICONDIR*)xdir;
1595     UINT16 retVal = 0;
1596     if( dir && !dir->idReserved && (dir->idType & 3) )
1597     {
1598         CURSORICONDIRENTRY* entry;
1599         HDC hdc;
1600         UINT palEnts;
1601         int colors;
1602         hdc = GetDC(0);
1603         palEnts = GetSystemPaletteEntries(hdc, 0, 0, NULL);
1604         if (palEnts == 0)
1605             palEnts = 256;
1606         colors = (cFlag & LR_MONOCHROME) ? 2 : palEnts;
1607
1608         ReleaseDC(0, hdc);
1609
1610         if( bIcon )
1611             entry = CURSORICON_FindBestIcon( dir, width, height, colors );
1612         else
1613             entry = CURSORICON_FindBestCursor( dir, width, height, 1);
1614
1615         if( entry ) retVal = entry->wResId;
1616     }
1617     else WARN_(cursor)("invalid resource directory\n");
1618     return retVal;
1619 }
1620
1621 /**********************************************************************
1622  *              LookupIconIdFromDirectoryEx (USER32.@)
1623  */
1624 INT WINAPI LookupIconIdFromDirectoryEx( LPBYTE dir, BOOL bIcon,
1625              INT width, INT height, UINT cFlag )
1626 {
1627     return LookupIconIdFromDirectoryEx16( dir, bIcon, width, height, cFlag );
1628 }
1629
1630 /**********************************************************************
1631  *              LookupIconIdFromDirectory (USER.???)
1632  */
1633 INT16 WINAPI LookupIconIdFromDirectory16( LPBYTE dir, BOOL16 bIcon )
1634 {
1635     return LookupIconIdFromDirectoryEx16( dir, bIcon, 
1636            bIcon ? GetSystemMetrics(SM_CXICON) : GetSystemMetrics(SM_CXCURSOR),
1637            bIcon ? GetSystemMetrics(SM_CYICON) : GetSystemMetrics(SM_CYCURSOR), bIcon ? 0 : LR_MONOCHROME );
1638 }
1639
1640 /**********************************************************************
1641  *              LookupIconIdFromDirectory (USER32.@)
1642  */
1643 INT WINAPI LookupIconIdFromDirectory( LPBYTE dir, BOOL bIcon )
1644 {
1645     return LookupIconIdFromDirectoryEx( dir, bIcon, 
1646            bIcon ? GetSystemMetrics(SM_CXICON) : GetSystemMetrics(SM_CXCURSOR),
1647            bIcon ? GetSystemMetrics(SM_CYICON) : GetSystemMetrics(SM_CYCURSOR), bIcon ? 0 : LR_MONOCHROME );
1648 }
1649
1650 /**********************************************************************
1651  *              GetIconID (USER.455)
1652  */
1653 WORD WINAPI GetIconID16( HGLOBAL16 hResource, DWORD resType )
1654 {
1655     LPBYTE lpDir = (LPBYTE)GlobalLock16(hResource);
1656
1657     TRACE_(cursor)("hRes=%04x, entries=%i\n",
1658                     hResource, lpDir ? ((CURSORICONDIR*)lpDir)->idCount : 0);
1659
1660     switch(resType)
1661     {
1662         case RT_CURSOR16:
1663              return (WORD)LookupIconIdFromDirectoryEx16( lpDir, FALSE, 
1664                           GetSystemMetrics(SM_CXCURSOR), GetSystemMetrics(SM_CYCURSOR), LR_MONOCHROME );
1665         case RT_ICON16:
1666              return (WORD)LookupIconIdFromDirectoryEx16( lpDir, TRUE,
1667                           GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), 0 );
1668         default:
1669              WARN_(cursor)("invalid res type %ld\n", resType );
1670     }
1671     return 0;
1672 }
1673
1674 /**********************************************************************
1675  *              LoadCursorIconHandler (USER.336)
1676  *
1677  * Supposed to load resources of Windows 2.x applications.
1678  */
1679 HGLOBAL16 WINAPI LoadCursorIconHandler16( HGLOBAL16 hResource, HMODULE16 hModule, HRSRC16 hRsrc )
1680 {
1681     FIXME_(cursor)("(%04x,%04x,%04x): old 2.x resources are not supported!\n", 
1682           hResource, hModule, hRsrc);
1683     return (HGLOBAL16)0;
1684 }
1685
1686 /**********************************************************************
1687  *              LoadDIBIconHandler (USER.357)
1688  * 
1689  * RT_ICON resource loader, installed by USER_SignalProc when module
1690  * is initialized.
1691  */
1692 HGLOBAL16 WINAPI LoadDIBIconHandler16( HGLOBAL16 hMemObj, HMODULE16 hModule, HRSRC16 hRsrc )
1693 {
1694     /* If hResource is zero we must allocate a new memory block, if it's
1695      * non-zero but GlobalLock() returns NULL then it was discarded and
1696      * we have to recommit some memory, otherwise we just need to check 
1697      * the block size. See LoadProc() in 16-bit SDK for more.
1698      */
1699
1700      hMemObj = NE_DefResourceHandler( hMemObj, hModule, hRsrc );
1701      if( hMemObj )
1702      {
1703          LPBYTE bits = (LPBYTE)GlobalLock16( hMemObj );
1704          hMemObj = CURSORICON_CreateFromResource( hModule, hMemObj, bits, 
1705                    SizeofResource16(hModule, hRsrc), TRUE, 0x00030000, 
1706                    GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), LR_DEFAULTCOLOR );
1707      }
1708      return hMemObj;
1709 }
1710
1711 /**********************************************************************
1712  *              LoadDIBCursorHandler (USER.356)
1713  *
1714  * RT_CURSOR resource loader. Same as above.
1715  */
1716 HGLOBAL16 WINAPI LoadDIBCursorHandler16( HGLOBAL16 hMemObj, HMODULE16 hModule, HRSRC16 hRsrc )
1717 {
1718     hMemObj = NE_DefResourceHandler( hMemObj, hModule, hRsrc );
1719     if( hMemObj )
1720     {
1721         LPBYTE bits = (LPBYTE)GlobalLock16( hMemObj );
1722         hMemObj = CURSORICON_CreateFromResource( hModule, hMemObj, bits,
1723                   SizeofResource16(hModule, hRsrc), FALSE, 0x00030000,
1724                   GetSystemMetrics(SM_CXCURSOR), GetSystemMetrics(SM_CYCURSOR), LR_MONOCHROME );
1725     }
1726     return hMemObj;
1727 }
1728
1729 /**********************************************************************
1730  *              LoadIconHandler (USER.456)
1731  */
1732 HICON16 WINAPI LoadIconHandler16( HGLOBAL16 hResource, BOOL16 bNew )
1733 {
1734     LPBYTE bits = (LPBYTE)LockResource16( hResource );
1735
1736     TRACE_(cursor)("hRes=%04x\n",hResource);
1737
1738     return CURSORICON_CreateFromResource( 0, 0, bits, 0, TRUE, 
1739                       bNew ? 0x00030000 : 0x00020000, 0, 0, LR_DEFAULTCOLOR );
1740 }
1741
1742 /***********************************************************************
1743  *              LoadCursorW (USER32.@)
1744  */
1745 HCURSOR WINAPI LoadCursorW(HINSTANCE hInstance, LPCWSTR name)
1746 {
1747     return LoadImageW( hInstance, name, IMAGE_CURSOR, 0, 0, 
1748                        LR_SHARED | LR_DEFAULTSIZE );
1749 }
1750
1751 /***********************************************************************
1752  *              LoadCursorA (USER32.@)
1753  */
1754 HCURSOR WINAPI LoadCursorA(HINSTANCE hInstance, LPCSTR name)
1755 {
1756     return LoadImageA( hInstance, name, IMAGE_CURSOR, 0, 0, 
1757                        LR_SHARED | LR_DEFAULTSIZE );
1758 }
1759
1760 /***********************************************************************
1761  *              LoadCursorFromFileW (USER32.@)
1762  */
1763 HCURSOR WINAPI LoadCursorFromFileW (LPCWSTR name)
1764 {
1765     return LoadImageW( 0, name, IMAGE_CURSOR, 0, 0, 
1766                        LR_LOADFROMFILE | LR_DEFAULTSIZE );
1767 }
1768
1769 /***********************************************************************
1770  *              LoadCursorFromFileA (USER32.@)
1771  */
1772 HCURSOR WINAPI LoadCursorFromFileA (LPCSTR name)
1773 {
1774     return LoadImageA( 0, name, IMAGE_CURSOR, 0, 0, 
1775                        LR_LOADFROMFILE | LR_DEFAULTSIZE );
1776 }
1777   
1778 /***********************************************************************
1779  *              LoadIconW (USER32.@)
1780  */
1781 HICON WINAPI LoadIconW(HINSTANCE hInstance, LPCWSTR name)
1782 {
1783     return LoadImageW( hInstance, name, IMAGE_ICON, 0, 0, 
1784                        LR_SHARED | LR_DEFAULTSIZE );
1785 }
1786
1787 /***********************************************************************
1788  *              LoadIconA (USER32.@)
1789  */
1790 HICON WINAPI LoadIconA(HINSTANCE hInstance, LPCSTR name)
1791 {
1792     return LoadImageA( hInstance, name, IMAGE_ICON, 0, 0, 
1793                        LR_SHARED | LR_DEFAULTSIZE );
1794 }
1795
1796 /**********************************************************************
1797  *              GetIconInfo (USER.395)
1798  */
1799 BOOL16 WINAPI GetIconInfo16(HICON16 hIcon,LPICONINFO16 iconinfo)
1800 {
1801     ICONINFO    ii32;
1802     BOOL16      ret = GetIconInfo((HICON)hIcon, &ii32);
1803
1804     iconinfo->fIcon = ii32.fIcon;
1805     iconinfo->xHotspot = ii32.xHotspot;
1806     iconinfo->yHotspot = ii32.yHotspot;
1807     iconinfo->hbmMask = ii32.hbmMask;
1808     iconinfo->hbmColor = ii32.hbmColor;
1809     return ret;
1810 }
1811
1812 /**********************************************************************
1813  *              GetIconInfo (USER32.@)
1814  */
1815 BOOL WINAPI GetIconInfo(HICON hIcon,PICONINFO iconinfo) {
1816     CURSORICONINFO      *ciconinfo;
1817
1818     ciconinfo = GlobalLock16(hIcon);
1819     if (!ciconinfo)
1820         return FALSE;
1821
1822     if ( (ciconinfo->ptHotSpot.x == ICON_HOTSPOT) &&
1823          (ciconinfo->ptHotSpot.y == ICON_HOTSPOT) )
1824     {
1825       iconinfo->fIcon    = TRUE;
1826       iconinfo->xHotspot = ciconinfo->nWidth / 2;
1827       iconinfo->yHotspot = ciconinfo->nHeight / 2;
1828     }
1829     else
1830     {
1831       iconinfo->fIcon    = FALSE;
1832       iconinfo->xHotspot = ciconinfo->ptHotSpot.x;
1833       iconinfo->yHotspot = ciconinfo->ptHotSpot.y;
1834     }
1835
1836     iconinfo->hbmColor = CreateBitmap ( ciconinfo->nWidth, ciconinfo->nHeight,
1837                                 ciconinfo->bPlanes, ciconinfo->bBitsPerPixel,
1838                                 (char *)(ciconinfo + 1)
1839                                 + ciconinfo->nHeight *
1840                                 BITMAP_GetWidthBytes (ciconinfo->nWidth,1) );
1841     iconinfo->hbmMask = CreateBitmap ( ciconinfo->nWidth, ciconinfo->nHeight,
1842                                 1, 1, (char *)(ciconinfo + 1));
1843
1844     GlobalUnlock16(hIcon);
1845
1846     return TRUE;
1847 }
1848
1849 /**********************************************************************
1850  *              CreateIconIndirect (USER32.@)
1851  */
1852 HICON WINAPI CreateIconIndirect(PICONINFO iconinfo)
1853 {
1854     BITMAP bmpXor,bmpAnd;
1855     HICON hObj;
1856     int sizeXor,sizeAnd;
1857
1858     GetObjectA( iconinfo->hbmColor, sizeof(bmpXor), &bmpXor );
1859     GetObjectA( iconinfo->hbmMask, sizeof(bmpAnd), &bmpAnd );
1860
1861     sizeXor = bmpXor.bmHeight * bmpXor.bmWidthBytes;
1862     sizeAnd = bmpAnd.bmHeight * bmpAnd.bmWidthBytes;
1863
1864     hObj = GlobalAlloc16( GMEM_MOVEABLE, 
1865                      sizeof(CURSORICONINFO) + sizeXor + sizeAnd );
1866     if (hObj)
1867     {
1868         CURSORICONINFO *info;
1869
1870         info = (CURSORICONINFO *)GlobalLock16( hObj );
1871
1872         /* If we are creating an icon, the hotspot is unused */
1873         if (iconinfo->fIcon)
1874         {
1875           info->ptHotSpot.x   = ICON_HOTSPOT;
1876           info->ptHotSpot.y   = ICON_HOTSPOT;
1877         }
1878         else
1879         {
1880           info->ptHotSpot.x   = iconinfo->xHotspot;
1881           info->ptHotSpot.y   = iconinfo->yHotspot;
1882         }
1883
1884         info->nWidth        = bmpXor.bmWidth;
1885         info->nHeight       = bmpXor.bmHeight;
1886         info->nWidthBytes   = bmpXor.bmWidthBytes;
1887         info->bPlanes       = bmpXor.bmPlanes;
1888         info->bBitsPerPixel = bmpXor.bmBitsPixel;
1889
1890         /* Transfer the bitmap bits to the CURSORICONINFO structure */
1891
1892         GetBitmapBits( iconinfo->hbmMask ,sizeAnd,(char*)(info + 1) );
1893         GetBitmapBits( iconinfo->hbmColor,sizeXor,(char*)(info + 1) +sizeAnd);
1894         GlobalUnlock16( hObj );
1895     }
1896     return hObj;
1897 }
1898
1899
1900 /**********************************************************************
1901  *              DrawIconEx (USER.394)
1902  */
1903 BOOL16 WINAPI DrawIconEx16 (HDC16 hdc, INT16 xLeft, INT16 yTop, HICON16 hIcon,
1904                             INT16 cxWidth, INT16 cyWidth, UINT16 istep,
1905                             HBRUSH16 hbr, UINT16 flags)
1906 {
1907     return DrawIconEx(hdc, xLeft, yTop, hIcon, cxWidth, cyWidth,
1908                         istep, hbr, flags);
1909 }
1910
1911
1912 /******************************************************************************
1913  *              DrawIconEx (USER32.@) Draws an icon or cursor on device context
1914  *
1915  * NOTES
1916  *    Why is this using SM_CXICON instead of SM_CXCURSOR?
1917  *
1918  * PARAMS
1919  *    hdc     [I] Handle to device context
1920  *    x0      [I] X coordinate of upper left corner
1921  *    y0      [I] Y coordinate of upper left corner
1922  *    hIcon   [I] Handle to icon to draw
1923  *    cxWidth [I] Width of icon
1924  *    cyWidth [I] Height of icon
1925  *    istep   [I] Index of frame in animated cursor
1926  *    hbr     [I] Handle to background brush
1927  *    flags   [I] Icon-drawing flags
1928  *
1929  * RETURNS
1930  *    Success: TRUE
1931  *    Failure: FALSE
1932  */
1933 BOOL WINAPI DrawIconEx( HDC hdc, INT x0, INT y0, HICON hIcon,
1934                             INT cxWidth, INT cyWidth, UINT istep, 
1935                             HBRUSH hbr, UINT flags )
1936 {
1937     CURSORICONINFO *ptr = (CURSORICONINFO *)GlobalLock16 (hIcon);
1938     HDC hDC_off = 0, hMemDC = CreateCompatibleDC (hdc);
1939     BOOL result = FALSE, DoOffscreen;
1940     HBITMAP hB_off = 0, hOld = 0;
1941
1942     if (!ptr) return FALSE;
1943     TRACE_(icon)("(hdc=%x,pos=%d.%d,hicon=%x,extend=%d.%d,istep=%d,br=%x,flags=0x%08x)\n",
1944             hdc,x0,y0,hIcon,cxWidth,cyWidth,istep,hbr,flags
1945     );
1946
1947     if (istep)
1948         FIXME_(icon)("Ignoring istep=%d\n", istep);
1949     if (flags & DI_COMPAT)
1950         FIXME_(icon)("Ignoring flag DI_COMPAT\n");
1951
1952     if (!flags) {
1953         FIXME_(icon)("no flags set? setting to DI_NORMAL\n");
1954         flags = DI_NORMAL;
1955     }
1956
1957     /* Calculate the size of the destination image.  */
1958     if (cxWidth == 0)
1959     {
1960       if (flags & DI_DEFAULTSIZE)
1961         cxWidth = GetSystemMetrics (SM_CXICON);
1962       else
1963         cxWidth = ptr->nWidth;
1964     }
1965     if (cyWidth == 0)
1966     {
1967       if (flags & DI_DEFAULTSIZE)
1968         cyWidth = GetSystemMetrics (SM_CYICON);
1969       else
1970         cyWidth = ptr->nHeight;
1971     }
1972
1973     DoOffscreen = (GetObjectType( hbr ) == OBJ_BRUSH);
1974
1975     if (DoOffscreen) {
1976       RECT r;
1977
1978       r.left = 0;
1979       r.top = 0;
1980       r.right = cxWidth;
1981       r.bottom = cxWidth;
1982
1983       hDC_off = CreateCompatibleDC(hdc);
1984       hB_off = CreateCompatibleBitmap(hdc, cxWidth, cyWidth);
1985       if (hDC_off && hB_off) {
1986         hOld = SelectObject(hDC_off, hB_off);
1987         FillRect(hDC_off, &r, hbr);
1988       }
1989     }
1990
1991     if (hMemDC && (!DoOffscreen || (hDC_off && hB_off)))
1992     {
1993         HBITMAP hXorBits, hAndBits;
1994         COLORREF  oldFg, oldBg;
1995         INT     nStretchMode;
1996
1997         nStretchMode = SetStretchBltMode (hdc, STRETCH_DELETESCANS);
1998
1999         hXorBits = CreateBitmap ( ptr->nWidth, ptr->nHeight,
2000                                     ptr->bPlanes, ptr->bBitsPerPixel,
2001                                     (char *)(ptr + 1)
2002                                     + ptr->nHeight *
2003                                     BITMAP_GetWidthBytes(ptr->nWidth,1) );
2004         hAndBits = CreateBitmap ( ptr->nWidth, ptr->nHeight,
2005                                     1, 1, (char *)(ptr+1) );
2006         oldFg = SetTextColor( hdc, RGB(0,0,0) );
2007         oldBg = SetBkColor( hdc, RGB(255,255,255) );
2008
2009         if (hXorBits && hAndBits)
2010         {
2011             HBITMAP hBitTemp = SelectObject( hMemDC, hAndBits );
2012             if (flags & DI_MASK)
2013             {
2014               if (DoOffscreen) 
2015                 StretchBlt (hDC_off, 0, 0, cxWidth, cyWidth,
2016                               hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCAND);
2017               else 
2018                 StretchBlt (hdc, x0, y0, cxWidth, cyWidth,
2019                               hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCAND);
2020             }
2021             SelectObject( hMemDC, hXorBits );
2022             if (flags & DI_IMAGE)
2023             {
2024               if (DoOffscreen) 
2025                 StretchBlt (hDC_off, 0, 0, cxWidth, cyWidth,
2026                           hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCPAINT);
2027               else
2028                 StretchBlt (hdc, x0, y0, cxWidth, cyWidth,
2029                               hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCPAINT);
2030             }
2031             SelectObject( hMemDC, hBitTemp );
2032             result = TRUE;
2033         }
2034
2035         SetTextColor( hdc, oldFg );
2036         SetBkColor( hdc, oldBg );
2037         if (hXorBits) DeleteObject( hXorBits );
2038         if (hAndBits) DeleteObject( hAndBits );
2039         SetStretchBltMode (hdc, nStretchMode);
2040         if (DoOffscreen) {
2041           BitBlt(hdc, x0, y0, cxWidth, cyWidth, hDC_off, 0, 0, SRCCOPY);
2042           SelectObject(hDC_off, hOld);
2043         }
2044     }
2045     if (hMemDC) DeleteDC( hMemDC );
2046     if (hDC_off) DeleteDC(hDC_off);
2047     if (hB_off) DeleteObject(hB_off);
2048     GlobalUnlock16( hIcon );
2049     return result;
2050 }
2051
2052 /***********************************************************************
2053  *           DIB_FixColorsToLoadflags
2054  *
2055  * Change color table entries when LR_LOADTRANSPARENT or LR_LOADMAP3DCOLORS
2056  * are in loadflags
2057  */
2058 static void DIB_FixColorsToLoadflags(BITMAPINFO * bmi, UINT loadflags, BYTE pix)
2059 {
2060   int colors;
2061   COLORREF c_W, c_S, c_F, c_L, c_C;
2062   int incr,i;
2063   RGBQUAD *ptr;
2064
2065   if (bmi->bmiHeader.biBitCount > 8) return;
2066   if (bmi->bmiHeader.biSize == sizeof(BITMAPINFOHEADER)) incr = 4;
2067   else if (bmi->bmiHeader.biSize == sizeof(BITMAPCOREHEADER)) incr = 3;
2068   else {
2069     WARN_(resource)("Wrong bitmap header size!\n");
2070     return;
2071   }
2072   colors = bmi->bmiHeader.biClrUsed;
2073   if (!colors && (bmi->bmiHeader.biBitCount <= 8))
2074     colors = 1 << bmi->bmiHeader.biBitCount;
2075   c_W = GetSysColor(COLOR_WINDOW);
2076   c_S = GetSysColor(COLOR_3DSHADOW);
2077   c_F = GetSysColor(COLOR_3DFACE);
2078   c_L = GetSysColor(COLOR_3DLIGHT);
2079   if (loadflags & LR_LOADTRANSPARENT) {
2080     switch (bmi->bmiHeader.biBitCount) {
2081       case 1: pix = pix >> 7; break;
2082       case 4: pix = pix >> 4; break;
2083       case 8: break;
2084       default: 
2085         WARN_(resource)("(%d): Unsupported depth\n", bmi->bmiHeader.biBitCount); 
2086         return;
2087     }
2088     if (pix >= colors) {
2089       WARN_(resource)("pixel has color index greater than biClrUsed!\n");
2090       return;
2091     }
2092     if (loadflags & LR_LOADMAP3DCOLORS) c_W = c_F;
2093     ptr = (RGBQUAD*)((char*)bmi->bmiColors+pix*incr);
2094     ptr->rgbBlue = GetBValue(c_W);
2095     ptr->rgbGreen = GetGValue(c_W);
2096     ptr->rgbRed = GetRValue(c_W);
2097   }
2098   if (loadflags & LR_LOADMAP3DCOLORS)
2099     for (i=0; i<colors; i++) {
2100       ptr = (RGBQUAD*)((char*)bmi->bmiColors+i*incr);
2101       c_C = RGB(ptr->rgbRed, ptr->rgbGreen, ptr->rgbBlue);
2102       if (c_C == RGB(128, 128, 128)) { 
2103         ptr->rgbRed = GetRValue(c_S);
2104         ptr->rgbGreen = GetGValue(c_S);
2105         ptr->rgbBlue = GetBValue(c_S);
2106       } else if (c_C == RGB(192, 192, 192)) { 
2107         ptr->rgbRed = GetRValue(c_F);
2108         ptr->rgbGreen = GetGValue(c_F);
2109         ptr->rgbBlue = GetBValue(c_F);
2110       } else if (c_C == RGB(223, 223, 223)) { 
2111         ptr->rgbRed = GetRValue(c_L);
2112         ptr->rgbGreen = GetGValue(c_L);
2113         ptr->rgbBlue = GetBValue(c_L);
2114       } 
2115     }
2116 }
2117
2118
2119 /**********************************************************************
2120  *       BITMAP_Load
2121  */
2122 static HBITMAP BITMAP_Load( HINSTANCE instance,LPCWSTR name, UINT loadflags )
2123 {
2124     HBITMAP hbitmap = 0;
2125     HRSRC hRsrc;
2126     HGLOBAL handle;
2127     char *ptr = NULL;
2128     BITMAPINFO *info, *fix_info=NULL;
2129     HGLOBAL hFix;
2130     int size;
2131
2132     if (!(loadflags & LR_LOADFROMFILE)) {
2133       if (!instance)  /* OEM bitmap */
2134       {
2135           if (HIWORD((int)name)) return 0;
2136           return USER_Driver.pLoadOEMResource( LOWORD((int)name), OEM_BITMAP );
2137       }
2138
2139       if (!(hRsrc = FindResourceW( instance, name, RT_BITMAPW ))) return 0;
2140       if (!(handle = LoadResource( instance, hRsrc ))) return 0;
2141
2142       if ((info = (BITMAPINFO *)LockResource( handle )) == NULL) return 0;
2143     }
2144     else
2145     {
2146         if (!(ptr = map_fileW( name ))) return 0;
2147         info = (BITMAPINFO *)(ptr + sizeof(BITMAPFILEHEADER));
2148     }
2149     size = DIB_BitmapInfoSize(info, DIB_RGB_COLORS);
2150     if ((hFix = GlobalAlloc(0, size))) fix_info=GlobalLock(hFix);
2151     if (fix_info) {
2152       BYTE pix;
2153
2154       memcpy(fix_info, info, size);
2155       pix = *((LPBYTE)info+DIB_BitmapInfoSize(info, DIB_RGB_COLORS));
2156       DIB_FixColorsToLoadflags(fix_info, loadflags, pix);
2157       if (!screen_dc) screen_dc = CreateDCA( "DISPLAY", NULL, NULL, NULL );
2158       if (screen_dc)
2159       {
2160         char *bits = (char *)info + size;
2161         if (loadflags & LR_CREATEDIBSECTION) {
2162           DIBSECTION dib;
2163           hbitmap = CreateDIBSection(screen_dc, fix_info, DIB_RGB_COLORS, NULL, 0, 0);
2164           GetObjectA(hbitmap, sizeof(DIBSECTION), &dib);
2165           SetDIBits(screen_dc, hbitmap, 0, dib.dsBm.bmHeight, bits, info,
2166                     DIB_RGB_COLORS);
2167         }
2168         else {
2169           hbitmap = CreateDIBitmap( screen_dc, &fix_info->bmiHeader, CBM_INIT,
2170                                       bits, fix_info, DIB_RGB_COLORS );
2171         }
2172       }
2173       GlobalUnlock(hFix);
2174       GlobalFree(hFix);
2175     }
2176     if (loadflags & LR_LOADFROMFILE) UnmapViewOfFile( ptr );
2177     return hbitmap;
2178 }
2179
2180
2181 /***********************************************************************
2182  *              LoadImage (USER.389)
2183  *
2184  */
2185 HANDLE16 WINAPI LoadImage16( HINSTANCE16 hinst, LPCSTR name, UINT16 type,
2186                              INT16 desiredx, INT16 desiredy, UINT16 loadflags)
2187 {
2188     return LoadImageA( hinst, name, type, desiredx, desiredy, loadflags );
2189 }
2190
2191 /**********************************************************************
2192  *              LoadImageA (USER32.@)
2193  * 
2194  * FIXME: implementation lacks some features, see LR_ defines in windows.h
2195  */
2196
2197 HANDLE WINAPI LoadImageA( HINSTANCE hinst, LPCSTR name, UINT type,
2198                               INT desiredx, INT desiredy, UINT loadflags)
2199 {
2200     HANDLE res;
2201     LPWSTR u_name;
2202
2203     if (HIWORD(name)) u_name = HEAP_strdupAtoW(GetProcessHeap(), 0, name);
2204     else u_name=(LPWSTR)name;
2205     res = LoadImageW(hinst, u_name, type, desiredx, desiredy, loadflags);
2206     if (HIWORD(name)) HeapFree(GetProcessHeap(), 0, u_name);
2207     return res;
2208 }
2209
2210
2211 /******************************************************************************
2212  *              LoadImageW (USER32.@) Loads an icon, cursor, or bitmap
2213  *
2214  * PARAMS
2215  *    hinst     [I] Handle of instance that contains image
2216  *    name      [I] Name of image
2217  *    type      [I] Type of image
2218  *    desiredx  [I] Desired width
2219  *    desiredy  [I] Desired height
2220  *    loadflags [I] Load flags
2221  *
2222  * RETURNS
2223  *    Success: Handle to newly loaded image
2224  *    Failure: NULL
2225  *
2226  * FIXME: Implementation lacks some features, see LR_ defines in windows.h
2227  */
2228 HANDLE WINAPI LoadImageW( HINSTANCE hinst, LPCWSTR name, UINT type,
2229                 INT desiredx, INT desiredy, UINT loadflags )
2230 {
2231     if (HIWORD(name)) {
2232         TRACE_(resource)("(0x%04x,%p,%d,%d,%d,0x%08x)\n",
2233               hinst,name,type,desiredx,desiredy,loadflags);
2234     } else {
2235         TRACE_(resource)("(0x%04x,%p,%d,%d,%d,0x%08x)\n",
2236               hinst,name,type,desiredx,desiredy,loadflags);
2237     }
2238     if (loadflags & LR_DEFAULTSIZE) {
2239         if (type == IMAGE_ICON) {
2240             if (!desiredx) desiredx = GetSystemMetrics(SM_CXICON);
2241             if (!desiredy) desiredy = GetSystemMetrics(SM_CYICON);
2242         } else if (type == IMAGE_CURSOR) {
2243             if (!desiredx) desiredx = GetSystemMetrics(SM_CXCURSOR);
2244             if (!desiredy) desiredy = GetSystemMetrics(SM_CYCURSOR);
2245         }
2246     }
2247     if (loadflags & LR_LOADFROMFILE) loadflags &= ~LR_SHARED;
2248     switch (type) {
2249     case IMAGE_BITMAP:
2250         return BITMAP_Load( hinst, name, loadflags );
2251
2252     case IMAGE_ICON:
2253         if (!screen_dc) screen_dc = CreateDCA( "DISPLAY", NULL, NULL, NULL );
2254         if (screen_dc)
2255         {
2256             UINT palEnts = GetSystemPaletteEntries(screen_dc, 0, 0, NULL);
2257             if (palEnts == 0) palEnts = 256;
2258             return CURSORICON_Load(hinst, name, desiredx, desiredy,
2259                                    palEnts, FALSE, loadflags);
2260         }
2261         break;
2262
2263     case IMAGE_CURSOR:
2264         return CURSORICON_Load(hinst, name, desiredx, desiredy,
2265                                  1, TRUE, loadflags);
2266     }
2267     return 0;
2268 }
2269
2270
2271 /******************************************************************************
2272  *              CopyImage (USER.390) Creates new image and copies attributes to it
2273  *
2274  */
2275 HICON16 WINAPI CopyImage16( HANDLE16 hnd, UINT16 type, INT16 desiredx,
2276                              INT16 desiredy, UINT16 flags )
2277 {
2278     return (HICON16)CopyImage((HANDLE)hnd, (UINT)type, (INT)desiredx,
2279                                 (INT)desiredy, (UINT)flags);
2280 }
2281
2282 /******************************************************************************
2283  *              CopyImage (USER32.@) Creates new image and copies attributes to it
2284  *
2285  * PARAMS
2286  *    hnd      [I] Handle to image to copy
2287  *    type     [I] Type of image to copy
2288  *    desiredx [I] Desired width of new image
2289  *    desiredy [I] Desired height of new image
2290  *    flags    [I] Copy flags
2291  *
2292  * RETURNS
2293  *    Success: Handle to newly created image
2294  *    Failure: NULL
2295  *
2296  * FIXME: implementation still lacks nearly all features, see LR_*
2297  * defines in windows.h
2298  */
2299 HICON WINAPI CopyImage( HANDLE hnd, UINT type, INT desiredx,
2300                              INT desiredy, UINT flags )
2301 {
2302     switch (type)
2303     {
2304         case IMAGE_BITMAP:
2305                 return BITMAP_CopyBitmap(hnd);
2306         case IMAGE_ICON:
2307                 return CURSORICON_ExtCopy(hnd,type, desiredx, desiredy, flags);
2308         case IMAGE_CURSOR:
2309                 /* Should call CURSORICON_ExtCopy but more testing
2310                  * needs to be done before we change this
2311                  */
2312                 return CopyCursor(hnd);
2313     }
2314     return 0;
2315 }
2316
2317
2318 /******************************************************************************
2319  *              LoadBitmapW (USER32.@) Loads bitmap from the executable file
2320  *
2321  * RETURNS
2322  *    Success: Handle to specified bitmap
2323  *    Failure: NULL
2324  */
2325 HBITMAP WINAPI LoadBitmapW(
2326     HINSTANCE instance, /* [in] Handle to application instance */
2327     LPCWSTR name)         /* [in] Address of bitmap resource name */
2328 {
2329     return LoadImageW( instance, name, IMAGE_BITMAP, 0, 0, 0 );
2330 }
2331
2332 /**********************************************************************
2333  *              LoadBitmapA (USER32.@)
2334  */
2335 HBITMAP WINAPI LoadBitmapA( HINSTANCE instance, LPCSTR name )
2336 {
2337     return LoadImageA( instance, name, IMAGE_BITMAP, 0, 0, 0 );
2338 }
2339
2340 /**********************************************************************
2341  *              LoadBitmap (USER.175)
2342  */
2343 HBITMAP16 WINAPI LoadBitmap16( HINSTANCE16 instance, LPCSTR name )
2344 {
2345     return LoadBitmapA( instance, name );
2346 }