Added some missing interfaces.
[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 for each 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("IconCrst");
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( GetProcessHeap(), 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( GetProcessHeap(), 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 straight 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             /* Retrieve 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,  /* [in] the application's hInstance, currently unused */
1165     INT       nWidth,     /* [in] the width of the provided bitmaps */
1166     INT       nHeight,    /* [in] the height of the provided bitmaps */
1167     BYTE      bPlanes,    /* [in] the number of planes in the provided bitmaps */
1168     BYTE      bBitsPixel, /* [in] the number of bits per pixel of the lpXORbits bitmap */
1169     LPCVOID   lpANDbits,  /* [in] a monochrome bitmap representing the icon's mask */
1170     LPCVOID   lpXORbits)  /* [in] the icon's 'color' bitmap */
1171 {
1172     HICON hIcon;
1173     HDC hdc;
1174
1175     TRACE_(icon)("%dx%dx%d, xor=%p, and=%p\n",
1176                  nWidth, nHeight, bPlanes * bBitsPixel, lpXORbits, lpANDbits);
1177
1178     hdc=GetDC(0);
1179     if (!hdc)
1180         return 0;
1181
1182     if (GetDeviceCaps(hdc,BITSPIXEL)==bBitsPixel) {
1183         CURSORICONINFO info;
1184
1185         info.ptHotSpot.x = ICON_HOTSPOT;
1186         info.ptHotSpot.y = ICON_HOTSPOT;
1187         info.nWidth = nWidth;
1188         info.nHeight = nHeight;
1189         info.nWidthBytes = 0;
1190         info.bPlanes = bPlanes;
1191         info.bBitsPerPixel = bBitsPixel;
1192
1193         hIcon=CreateCursorIconIndirect16( 0, &info, lpANDbits, lpXORbits );
1194     } else {
1195         ICONINFO iinfo;
1196         BITMAPINFO bmi;
1197
1198         iinfo.fIcon=TRUE;
1199         iinfo.xHotspot=ICON_HOTSPOT;
1200         iinfo.yHotspot=ICON_HOTSPOT;
1201         iinfo.hbmMask=CreateBitmap(nWidth,nHeight,1,1,lpANDbits);
1202
1203         bmi.bmiHeader.biSize=sizeof(bmi.bmiHeader);
1204         bmi.bmiHeader.biWidth=nWidth;
1205         bmi.bmiHeader.biHeight=-nHeight;
1206         bmi.bmiHeader.biPlanes=bPlanes;
1207         bmi.bmiHeader.biBitCount=bBitsPixel;
1208         bmi.bmiHeader.biCompression=BI_RGB;
1209         bmi.bmiHeader.biSizeImage=0;
1210         bmi.bmiHeader.biXPelsPerMeter=0;
1211         bmi.bmiHeader.biYPelsPerMeter=0;
1212         bmi.bmiHeader.biClrUsed=0;
1213         bmi.bmiHeader.biClrImportant=0;
1214
1215         iinfo.hbmColor = CreateDIBitmap( hdc, &bmi.bmiHeader,
1216                                          CBM_INIT, lpXORbits,
1217                                          &bmi, DIB_RGB_COLORS );
1218
1219         hIcon=CreateIconIndirect(&iinfo);
1220         DeleteObject(iinfo.hbmMask);
1221         DeleteObject(iinfo.hbmColor);
1222     }
1223     ReleaseDC(0,hdc);
1224     return hIcon;
1225 }
1226
1227
1228 /***********************************************************************
1229  *              CreateCursorIconIndirect (USER.408)
1230  */
1231 HGLOBAL16 WINAPI CreateCursorIconIndirect16( HINSTANCE16 hInstance,
1232                                            CURSORICONINFO *info,
1233                                            LPCVOID lpANDbits,
1234                                            LPCVOID lpXORbits )
1235 {
1236     HGLOBAL16 handle;
1237     char *ptr;
1238     int sizeAnd, sizeXor;
1239
1240     hInstance = GetExePtr( hInstance );  /* Make it a module handle */
1241     if (!lpXORbits || !lpANDbits || info->bPlanes != 1) return 0;
1242     info->nWidthBytes = BITMAP_GetWidthBytes(info->nWidth,info->bBitsPerPixel);
1243     sizeXor = info->nHeight * info->nWidthBytes;
1244     sizeAnd = info->nHeight * BITMAP_GetWidthBytes( info->nWidth, 1 );
1245     if (!(handle = GlobalAlloc16( GMEM_MOVEABLE,
1246                                   sizeof(CURSORICONINFO) + sizeXor + sizeAnd)))
1247         return 0;
1248     FarSetOwner16( handle, hInstance );
1249     ptr = (char *)GlobalLock16( handle );
1250     memcpy( ptr, info, sizeof(*info) );
1251     memcpy( ptr + sizeof(CURSORICONINFO), lpANDbits, sizeAnd );
1252     memcpy( ptr + sizeof(CURSORICONINFO) + sizeAnd, lpXORbits, sizeXor );
1253     GlobalUnlock16( handle );
1254     return handle;
1255 }
1256
1257
1258 /***********************************************************************
1259  *              CopyIcon (USER.368)
1260  */
1261 HICON16 WINAPI CopyIcon16( HINSTANCE16 hInstance, HICON16 hIcon )
1262 {
1263     TRACE_(icon)("%04x %04x\n", hInstance, hIcon );
1264     return CURSORICON_Copy( hInstance, hIcon );
1265 }
1266
1267
1268 /***********************************************************************
1269  *              CopyIcon (USER32.@)
1270  */
1271 HICON WINAPI CopyIcon( HICON hIcon )
1272 {
1273     TRACE_(icon)("%04x\n", hIcon );
1274     return CURSORICON_Copy( 0, hIcon );
1275 }
1276
1277
1278 /***********************************************************************
1279  *              CopyCursor (USER.369)
1280  */
1281 HCURSOR16 WINAPI CopyCursor16( HINSTANCE16 hInstance, HCURSOR16 hCursor )
1282 {
1283     TRACE_(cursor)("%04x %04x\n", hInstance, hCursor );
1284     return CURSORICON_Copy( hInstance, hCursor );
1285 }
1286
1287 /**********************************************************************
1288  *              DestroyIcon32 (USER.610)
1289  *
1290  * This routine is actually exported from Win95 USER under the name
1291  * DestroyIcon32 ...  The behaviour implemented here should mimic 
1292  * the Win95 one exactly, especially the return values, which 
1293  * depend on the setting of various flags.
1294  */
1295 WORD WINAPI CURSORICON_Destroy( HGLOBAL16 handle, UINT16 flags )
1296 {
1297     WORD retv;
1298
1299     TRACE_(icon)("(%04x, %04x)\n", handle, flags );
1300
1301     /* Check whether destroying active cursor */
1302
1303     if ( hActiveCursor == handle )
1304     {
1305         ERR_(cursor)("Destroying active cursor!\n" );
1306         SetCursor( 0 );
1307     }
1308
1309     /* Try shared cursor/icon first */
1310
1311     if ( !(flags & CID_NONSHARED) )
1312     {
1313         INT count = CURSORICON_DelSharedIcon( handle );
1314
1315         if ( count != -1 )
1316             return (flags & CID_WIN32)? TRUE : (count == 0);
1317
1318         /* FIXME: OEM cursors/icons should be recognized */
1319     }
1320
1321     /* Now assume non-shared cursor/icon */
1322
1323     retv = GlobalFree16( handle );
1324     return (flags & CID_RESOURCE)? retv : TRUE;
1325 }
1326
1327 /***********************************************************************
1328  *              DestroyIcon (USER.457)
1329  */
1330 BOOL16 WINAPI DestroyIcon16( HICON16 hIcon )
1331 {
1332     return CURSORICON_Destroy( hIcon, 0 );
1333 }
1334
1335 /***********************************************************************
1336  *              DestroyIcon (USER32.@)
1337  */
1338 BOOL WINAPI DestroyIcon( HICON hIcon )
1339 {
1340     return CURSORICON_Destroy( hIcon, CID_WIN32 );
1341 }
1342
1343 /***********************************************************************
1344  *              DestroyCursor (USER.458)
1345  */
1346 BOOL16 WINAPI DestroyCursor16( HCURSOR16 hCursor )
1347 {
1348     return CURSORICON_Destroy( hCursor, 0 );
1349 }
1350
1351 /***********************************************************************
1352  *              DestroyCursor (USER32.@)
1353  */
1354 BOOL WINAPI DestroyCursor( HCURSOR hCursor )
1355 {
1356     return CURSORICON_Destroy( hCursor, CID_WIN32 );
1357 }
1358
1359
1360 /***********************************************************************
1361  *              DrawIcon (USER.84)
1362  */
1363 BOOL16 WINAPI DrawIcon16( HDC16 hdc, INT16 x, INT16 y, HICON16 hIcon )
1364 {
1365     return DrawIcon( hdc, x, y, hIcon );
1366 }
1367
1368
1369 /***********************************************************************
1370  *              DrawIcon (USER32.@)
1371  */
1372 BOOL WINAPI DrawIcon( HDC hdc, INT x, INT y, HICON hIcon )
1373 {
1374     CURSORICONINFO *ptr;
1375     HDC hMemDC;
1376     HBITMAP hXorBits, hAndBits;
1377     COLORREF oldFg, oldBg;
1378
1379     if (!(ptr = (CURSORICONINFO *)GlobalLock16( hIcon ))) return FALSE;
1380     if (!(hMemDC = CreateCompatibleDC( hdc ))) return FALSE;
1381     hAndBits = CreateBitmap( ptr->nWidth, ptr->nHeight, 1, 1,
1382                                (char *)(ptr+1) );
1383     hXorBits = CreateBitmap( ptr->nWidth, ptr->nHeight, ptr->bPlanes,
1384                                ptr->bBitsPerPixel, (char *)(ptr + 1)
1385                         + ptr->nHeight * BITMAP_GetWidthBytes(ptr->nWidth,1) );
1386     oldFg = SetTextColor( hdc, RGB(0,0,0) );
1387     oldBg = SetBkColor( hdc, RGB(255,255,255) );
1388
1389     if (hXorBits && hAndBits)
1390     {
1391         HBITMAP hBitTemp = SelectObject( hMemDC, hAndBits );
1392         BitBlt( hdc, x, y, ptr->nWidth, ptr->nHeight, hMemDC, 0, 0, SRCAND );
1393         SelectObject( hMemDC, hXorBits );
1394         BitBlt(hdc, x, y, ptr->nWidth, ptr->nHeight, hMemDC, 0, 0,SRCINVERT);
1395         SelectObject( hMemDC, hBitTemp );
1396     }
1397     DeleteDC( hMemDC );
1398     if (hXorBits) DeleteObject( hXorBits );
1399     if (hAndBits) DeleteObject( hAndBits );
1400     GlobalUnlock16( hIcon );
1401     SetTextColor( hdc, oldFg );
1402     SetBkColor( hdc, oldBg );
1403     return TRUE;
1404 }
1405
1406
1407 /***********************************************************************
1408  *              IconSize (USER.86)
1409  *
1410  * See "Undocumented Windows". Used by W2.0 paint.exe.
1411  */
1412 DWORD WINAPI IconSize16( void )
1413 {
1414     return MAKELONG(GetSystemMetrics(SM_CYICON), GetSystemMetrics(SM_CXICON));
1415 }
1416
1417
1418 /***********************************************************************
1419  *              DumpIcon (USER.459)
1420  */
1421 DWORD WINAPI DumpIcon16( SEGPTR pInfo, WORD *lpLen,
1422                        SEGPTR *lpXorBits, SEGPTR *lpAndBits )
1423 {
1424     CURSORICONINFO *info = MapSL( pInfo );
1425     int sizeAnd, sizeXor;
1426
1427     if (!info) return 0;
1428     sizeXor = info->nHeight * info->nWidthBytes;
1429     sizeAnd = info->nHeight * BITMAP_GetWidthBytes( info->nWidth, 1 );
1430     if (lpAndBits) *lpAndBits = pInfo + sizeof(CURSORICONINFO);
1431     if (lpXorBits) *lpXorBits = pInfo + sizeof(CURSORICONINFO) + sizeAnd;
1432     if (lpLen) *lpLen = sizeof(CURSORICONINFO) + sizeAnd + sizeXor;
1433     return MAKELONG( sizeXor, sizeXor );
1434 }
1435
1436
1437 /***********************************************************************
1438  *              SetCursor (USER.69)
1439  */
1440 HCURSOR16 WINAPI SetCursor16( HCURSOR16 hCursor )
1441 {
1442     return (HCURSOR16)SetCursor( hCursor );
1443 }
1444
1445
1446 /***********************************************************************
1447  *              SetCursor (USER32.@)
1448  * RETURNS:
1449  *      A handle to the previous cursor shape.
1450  */
1451 HCURSOR WINAPI SetCursor(
1452                  HCURSOR hCursor /* [in] Handle of cursor to show */
1453 ) {
1454     HCURSOR hOldCursor;
1455
1456     if (hCursor == hActiveCursor) return hActiveCursor;  /* No change */
1457     TRACE_(cursor)("%04x\n", hCursor );
1458     hOldCursor = hActiveCursor;
1459     hActiveCursor = hCursor;
1460     /* Change the cursor shape only if it is visible */
1461     if (CURSOR_ShowCount >= 0)
1462     {
1463         USER_Driver.pSetCursor( (CURSORICONINFO*)GlobalLock16( hActiveCursor ) );
1464         GlobalUnlock16( hActiveCursor );
1465     }
1466     return hOldCursor;
1467 }
1468
1469
1470 /***********************************************************************
1471  *              ShowCursor (USER.71)
1472  */
1473 INT16 WINAPI ShowCursor16( BOOL16 bShow )
1474 {
1475     return ShowCursor( bShow );
1476 }
1477
1478
1479 /***********************************************************************
1480  *              ShowCursor (USER32.@)
1481  */
1482 INT WINAPI ShowCursor( BOOL bShow )
1483 {
1484     TRACE_(cursor)("%d, count=%d\n",
1485                     bShow, CURSOR_ShowCount );
1486
1487     if (bShow)
1488     {
1489         if (++CURSOR_ShowCount == 0)  /* Show it */
1490         {
1491             USER_Driver.pSetCursor( (CURSORICONINFO*)GlobalLock16( hActiveCursor ) );
1492             GlobalUnlock16( hActiveCursor );
1493         }
1494     }
1495     else
1496     {
1497         if (--CURSOR_ShowCount == -1)  /* Hide it */
1498             USER_Driver.pSetCursor( NULL );
1499     }
1500     return CURSOR_ShowCount;
1501 }
1502
1503
1504 /***********************************************************************
1505  *              GetCursor (USER.247)
1506  */
1507 HCURSOR16 WINAPI GetCursor16(void)
1508 {
1509     return hActiveCursor;
1510 }
1511
1512
1513 /***********************************************************************
1514  *              GetCursor (USER32.@)
1515  */
1516 HCURSOR WINAPI GetCursor(void)
1517 {
1518     return hActiveCursor;
1519 }
1520
1521
1522 /***********************************************************************
1523  *              ClipCursor (USER.16)
1524  */
1525 BOOL16 WINAPI ClipCursor16( const RECT16 *rect )
1526 {
1527     if (!rect) SetRectEmpty( &CURSOR_ClipRect );
1528     else CONV_RECT16TO32( rect, &CURSOR_ClipRect );
1529     return TRUE;
1530 }
1531
1532
1533 /***********************************************************************
1534  *              ClipCursor (USER32.@)
1535  */
1536 BOOL WINAPI ClipCursor( const RECT *rect )
1537 {
1538     if (!rect) SetRectEmpty( &CURSOR_ClipRect );
1539     else CopyRect( &CURSOR_ClipRect, rect );
1540     return TRUE;
1541 }
1542
1543
1544 /***********************************************************************
1545  *              GetClipCursor (USER.309)
1546  */
1547 void WINAPI GetClipCursor16( RECT16 *rect )
1548 {
1549     if (rect) CONV_RECT32TO16( &CURSOR_ClipRect, rect );
1550 }
1551
1552
1553 /***********************************************************************
1554  *              GetClipCursor (USER32.@)
1555  */
1556 BOOL WINAPI GetClipCursor( RECT *rect )
1557 {
1558     if (rect) 
1559     {
1560        CopyRect( rect, &CURSOR_ClipRect );
1561        return TRUE;
1562     }
1563     return FALSE;
1564 }
1565
1566 /**********************************************************************
1567  *              LookupIconIdFromDirectoryEx (USER.364)
1568  *
1569  * FIXME: exact parameter sizes
1570  */
1571 INT16 WINAPI LookupIconIdFromDirectoryEx16( LPBYTE xdir, BOOL16 bIcon,
1572              INT16 width, INT16 height, UINT16 cFlag )
1573 {
1574     CURSORICONDIR       *dir = (CURSORICONDIR*)xdir;
1575     UINT16 retVal = 0;
1576     if( dir && !dir->idReserved && (dir->idType & 3) )
1577     {
1578         CURSORICONDIRENTRY* entry;
1579         HDC hdc;
1580         UINT palEnts;
1581         int colors;
1582         hdc = GetDC(0);
1583         palEnts = GetSystemPaletteEntries(hdc, 0, 0, NULL);
1584         if (palEnts == 0)
1585             palEnts = 256;
1586         colors = (cFlag & LR_MONOCHROME) ? 2 : palEnts;
1587
1588         ReleaseDC(0, hdc);
1589
1590         if( bIcon )
1591             entry = CURSORICON_FindBestIcon( dir, width, height, colors );
1592         else
1593             entry = CURSORICON_FindBestCursor( dir, width, height, 1);
1594
1595         if( entry ) retVal = entry->wResId;
1596     }
1597     else WARN_(cursor)("invalid resource directory\n");
1598     return retVal;
1599 }
1600
1601 /**********************************************************************
1602  *              LookupIconIdFromDirectoryEx (USER32.@)
1603  */
1604 INT WINAPI LookupIconIdFromDirectoryEx( LPBYTE dir, BOOL bIcon,
1605              INT width, INT height, UINT cFlag )
1606 {
1607     return LookupIconIdFromDirectoryEx16( dir, bIcon, width, height, cFlag );
1608 }
1609
1610 /**********************************************************************
1611  *              LookupIconIdFromDirectory (USER.?)
1612  */
1613 INT16 WINAPI LookupIconIdFromDirectory16( LPBYTE dir, BOOL16 bIcon )
1614 {
1615     return LookupIconIdFromDirectoryEx16( dir, bIcon, 
1616            bIcon ? GetSystemMetrics(SM_CXICON) : GetSystemMetrics(SM_CXCURSOR),
1617            bIcon ? GetSystemMetrics(SM_CYICON) : GetSystemMetrics(SM_CYCURSOR), bIcon ? 0 : LR_MONOCHROME );
1618 }
1619
1620 /**********************************************************************
1621  *              LookupIconIdFromDirectory (USER32.@)
1622  */
1623 INT WINAPI LookupIconIdFromDirectory( LPBYTE dir, BOOL bIcon )
1624 {
1625     return LookupIconIdFromDirectoryEx( dir, bIcon, 
1626            bIcon ? GetSystemMetrics(SM_CXICON) : GetSystemMetrics(SM_CXCURSOR),
1627            bIcon ? GetSystemMetrics(SM_CYICON) : GetSystemMetrics(SM_CYCURSOR), bIcon ? 0 : LR_MONOCHROME );
1628 }
1629
1630 /**********************************************************************
1631  *              GetIconID (USER.455)
1632  */
1633 WORD WINAPI GetIconID16( HGLOBAL16 hResource, DWORD resType )
1634 {
1635     LPBYTE lpDir = (LPBYTE)GlobalLock16(hResource);
1636
1637     TRACE_(cursor)("hRes=%04x, entries=%i\n",
1638                     hResource, lpDir ? ((CURSORICONDIR*)lpDir)->idCount : 0);
1639
1640     switch(resType)
1641     {
1642         case RT_CURSOR16:
1643              return (WORD)LookupIconIdFromDirectoryEx16( lpDir, FALSE, 
1644                           GetSystemMetrics(SM_CXCURSOR), GetSystemMetrics(SM_CYCURSOR), LR_MONOCHROME );
1645         case RT_ICON16:
1646              return (WORD)LookupIconIdFromDirectoryEx16( lpDir, TRUE,
1647                           GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), 0 );
1648         default:
1649              WARN_(cursor)("invalid res type %ld\n", resType );
1650     }
1651     return 0;
1652 }
1653
1654 /**********************************************************************
1655  *              LoadCursorIconHandler (USER.336)
1656  *
1657  * Supposed to load resources of Windows 2.x applications.
1658  */
1659 HGLOBAL16 WINAPI LoadCursorIconHandler16( HGLOBAL16 hResource, HMODULE16 hModule, HRSRC16 hRsrc )
1660 {
1661     FIXME_(cursor)("(%04x,%04x,%04x): old 2.x resources are not supported!\n", 
1662           hResource, hModule, hRsrc);
1663     return (HGLOBAL16)0;
1664 }
1665
1666 /**********************************************************************
1667  *              LoadDIBIconHandler (USER.357)
1668  * 
1669  * RT_ICON resource loader, installed by USER_SignalProc when module
1670  * is initialized.
1671  */
1672 HGLOBAL16 WINAPI LoadDIBIconHandler16( HGLOBAL16 hMemObj, HMODULE16 hModule, HRSRC16 hRsrc )
1673 {
1674     /* If hResource is zero we must allocate a new memory block, if it's
1675      * non-zero but GlobalLock() returns NULL then it was discarded and
1676      * we have to recommit some memory, otherwise we just need to check 
1677      * the block size. See LoadProc() in 16-bit SDK for more.
1678      */
1679
1680      hMemObj = NE_DefResourceHandler( hMemObj, hModule, hRsrc );
1681      if( hMemObj )
1682      {
1683          LPBYTE bits = (LPBYTE)GlobalLock16( hMemObj );
1684          hMemObj = CURSORICON_CreateFromResource( hModule, hMemObj, bits, 
1685                    SizeofResource16(hModule, hRsrc), TRUE, 0x00030000, 
1686                    GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), LR_DEFAULTCOLOR );
1687      }
1688      return hMemObj;
1689 }
1690
1691 /**********************************************************************
1692  *              LoadDIBCursorHandler (USER.356)
1693  *
1694  * RT_CURSOR resource loader. Same as above.
1695  */
1696 HGLOBAL16 WINAPI LoadDIBCursorHandler16( HGLOBAL16 hMemObj, HMODULE16 hModule, HRSRC16 hRsrc )
1697 {
1698     hMemObj = NE_DefResourceHandler( hMemObj, hModule, hRsrc );
1699     if( hMemObj )
1700     {
1701         LPBYTE bits = (LPBYTE)GlobalLock16( hMemObj );
1702         hMemObj = CURSORICON_CreateFromResource( hModule, hMemObj, bits,
1703                   SizeofResource16(hModule, hRsrc), FALSE, 0x00030000,
1704                   GetSystemMetrics(SM_CXCURSOR), GetSystemMetrics(SM_CYCURSOR), LR_MONOCHROME );
1705     }
1706     return hMemObj;
1707 }
1708
1709 /**********************************************************************
1710  *              LoadIconHandler (USER.456)
1711  */
1712 HICON16 WINAPI LoadIconHandler16( HGLOBAL16 hResource, BOOL16 bNew )
1713 {
1714     LPBYTE bits = (LPBYTE)LockResource16( hResource );
1715
1716     TRACE_(cursor)("hRes=%04x\n",hResource);
1717
1718     return CURSORICON_CreateFromResource( 0, 0, bits, 0, TRUE, 
1719                       bNew ? 0x00030000 : 0x00020000, 0, 0, LR_DEFAULTCOLOR );
1720 }
1721
1722 /***********************************************************************
1723  *              LoadCursorW (USER32.@)
1724  */
1725 HCURSOR WINAPI LoadCursorW(HINSTANCE hInstance, LPCWSTR name)
1726 {
1727     return LoadImageW( hInstance, name, IMAGE_CURSOR, 0, 0, 
1728                        LR_SHARED | LR_DEFAULTSIZE );
1729 }
1730
1731 /***********************************************************************
1732  *              LoadCursorA (USER32.@)
1733  */
1734 HCURSOR WINAPI LoadCursorA(HINSTANCE hInstance, LPCSTR name)
1735 {
1736     return LoadImageA( hInstance, name, IMAGE_CURSOR, 0, 0, 
1737                        LR_SHARED | LR_DEFAULTSIZE );
1738 }
1739
1740 /***********************************************************************
1741  *              LoadCursorFromFileW (USER32.@)
1742  */
1743 HCURSOR WINAPI LoadCursorFromFileW (LPCWSTR name)
1744 {
1745     return LoadImageW( 0, name, IMAGE_CURSOR, 0, 0, 
1746                        LR_LOADFROMFILE | LR_DEFAULTSIZE );
1747 }
1748
1749 /***********************************************************************
1750  *              LoadCursorFromFileA (USER32.@)
1751  */
1752 HCURSOR WINAPI LoadCursorFromFileA (LPCSTR name)
1753 {
1754     return LoadImageA( 0, name, IMAGE_CURSOR, 0, 0, 
1755                        LR_LOADFROMFILE | LR_DEFAULTSIZE );
1756 }
1757   
1758 /***********************************************************************
1759  *              LoadIconW (USER32.@)
1760  */
1761 HICON WINAPI LoadIconW(HINSTANCE hInstance, LPCWSTR name)
1762 {
1763     return LoadImageW( hInstance, name, IMAGE_ICON, 0, 0, 
1764                        LR_SHARED | LR_DEFAULTSIZE );
1765 }
1766
1767 /***********************************************************************
1768  *              LoadIconA (USER32.@)
1769  */
1770 HICON WINAPI LoadIconA(HINSTANCE hInstance, LPCSTR name)
1771 {
1772     return LoadImageA( hInstance, name, IMAGE_ICON, 0, 0, 
1773                        LR_SHARED | LR_DEFAULTSIZE );
1774 }
1775
1776 /**********************************************************************
1777  *              GetIconInfo (USER.395)
1778  */
1779 BOOL16 WINAPI GetIconInfo16(HICON16 hIcon,LPICONINFO16 iconinfo)
1780 {
1781     ICONINFO    ii32;
1782     BOOL16      ret = GetIconInfo((HICON)hIcon, &ii32);
1783
1784     iconinfo->fIcon = ii32.fIcon;
1785     iconinfo->xHotspot = ii32.xHotspot;
1786     iconinfo->yHotspot = ii32.yHotspot;
1787     iconinfo->hbmMask = ii32.hbmMask;
1788     iconinfo->hbmColor = ii32.hbmColor;
1789     return ret;
1790 }
1791
1792 /**********************************************************************
1793  *              GetIconInfo (USER32.@)
1794  */
1795 BOOL WINAPI GetIconInfo(HICON hIcon,PICONINFO iconinfo) {
1796     CURSORICONINFO      *ciconinfo;
1797
1798     ciconinfo = GlobalLock16(hIcon);
1799     if (!ciconinfo)
1800         return FALSE;
1801
1802     if ( (ciconinfo->ptHotSpot.x == ICON_HOTSPOT) &&
1803          (ciconinfo->ptHotSpot.y == ICON_HOTSPOT) )
1804     {
1805       iconinfo->fIcon    = TRUE;
1806       iconinfo->xHotspot = ciconinfo->nWidth / 2;
1807       iconinfo->yHotspot = ciconinfo->nHeight / 2;
1808     }
1809     else
1810     {
1811       iconinfo->fIcon    = FALSE;
1812       iconinfo->xHotspot = ciconinfo->ptHotSpot.x;
1813       iconinfo->yHotspot = ciconinfo->ptHotSpot.y;
1814     }
1815
1816     iconinfo->hbmColor = CreateBitmap ( ciconinfo->nWidth, ciconinfo->nHeight,
1817                                 ciconinfo->bPlanes, ciconinfo->bBitsPerPixel,
1818                                 (char *)(ciconinfo + 1)
1819                                 + ciconinfo->nHeight *
1820                                 BITMAP_GetWidthBytes (ciconinfo->nWidth,1) );
1821     iconinfo->hbmMask = CreateBitmap ( ciconinfo->nWidth, ciconinfo->nHeight,
1822                                 1, 1, (char *)(ciconinfo + 1));
1823
1824     GlobalUnlock16(hIcon);
1825
1826     return TRUE;
1827 }
1828
1829 /**********************************************************************
1830  *              CreateIconIndirect (USER32.@)
1831  */
1832 HICON WINAPI CreateIconIndirect(PICONINFO iconinfo)
1833 {
1834     BITMAP bmpXor,bmpAnd;
1835     HICON hObj;
1836     int sizeXor,sizeAnd;
1837
1838     GetObjectA( iconinfo->hbmColor, sizeof(bmpXor), &bmpXor );
1839     GetObjectA( iconinfo->hbmMask, sizeof(bmpAnd), &bmpAnd );
1840
1841     sizeXor = bmpXor.bmHeight * bmpXor.bmWidthBytes;
1842     sizeAnd = bmpAnd.bmHeight * bmpAnd.bmWidthBytes;
1843
1844     hObj = GlobalAlloc16( GMEM_MOVEABLE, 
1845                      sizeof(CURSORICONINFO) + sizeXor + sizeAnd );
1846     if (hObj)
1847     {
1848         CURSORICONINFO *info;
1849
1850         info = (CURSORICONINFO *)GlobalLock16( hObj );
1851
1852         /* If we are creating an icon, the hotspot is unused */
1853         if (iconinfo->fIcon)
1854         {
1855           info->ptHotSpot.x   = ICON_HOTSPOT;
1856           info->ptHotSpot.y   = ICON_HOTSPOT;
1857         }
1858         else
1859         {
1860           info->ptHotSpot.x   = iconinfo->xHotspot;
1861           info->ptHotSpot.y   = iconinfo->yHotspot;
1862         }
1863
1864         info->nWidth        = bmpXor.bmWidth;
1865         info->nHeight       = bmpXor.bmHeight;
1866         info->nWidthBytes   = bmpXor.bmWidthBytes;
1867         info->bPlanes       = bmpXor.bmPlanes;
1868         info->bBitsPerPixel = bmpXor.bmBitsPixel;
1869
1870         /* Transfer the bitmap bits to the CURSORICONINFO structure */
1871
1872         GetBitmapBits( iconinfo->hbmMask ,sizeAnd,(char*)(info + 1) );
1873         GetBitmapBits( iconinfo->hbmColor,sizeXor,(char*)(info + 1) +sizeAnd);
1874         GlobalUnlock16( hObj );
1875     }
1876     return hObj;
1877 }
1878
1879
1880 /**********************************************************************
1881  *              DrawIconEx (USER.394)
1882  */
1883 BOOL16 WINAPI DrawIconEx16 (HDC16 hdc, INT16 xLeft, INT16 yTop, HICON16 hIcon,
1884                             INT16 cxWidth, INT16 cyWidth, UINT16 istep,
1885                             HBRUSH16 hbr, UINT16 flags)
1886 {
1887     return DrawIconEx(hdc, xLeft, yTop, hIcon, cxWidth, cyWidth,
1888                         istep, hbr, flags);
1889 }
1890
1891
1892 /******************************************************************************
1893  *              DrawIconEx (USER32.@) Draws an icon or cursor on device context
1894  *
1895  * NOTES
1896  *    Why is this using SM_CXICON instead of SM_CXCURSOR?
1897  *
1898  * PARAMS
1899  *    hdc     [I] Handle to device context
1900  *    x0      [I] X coordinate of upper left corner
1901  *    y0      [I] Y coordinate of upper left corner
1902  *    hIcon   [I] Handle to icon to draw
1903  *    cxWidth [I] Width of icon
1904  *    cyWidth [I] Height of icon
1905  *    istep   [I] Index of frame in animated cursor
1906  *    hbr     [I] Handle to background brush
1907  *    flags   [I] Icon-drawing flags
1908  *
1909  * RETURNS
1910  *    Success: TRUE
1911  *    Failure: FALSE
1912  */
1913 BOOL WINAPI DrawIconEx( HDC hdc, INT x0, INT y0, HICON hIcon,
1914                             INT cxWidth, INT cyWidth, UINT istep, 
1915                             HBRUSH hbr, UINT flags )
1916 {
1917     CURSORICONINFO *ptr = (CURSORICONINFO *)GlobalLock16 (hIcon);
1918     HDC hDC_off = 0, hMemDC = CreateCompatibleDC (hdc);
1919     BOOL result = FALSE, DoOffscreen;
1920     HBITMAP hB_off = 0, hOld = 0;
1921
1922     if (!ptr) return FALSE;
1923     TRACE_(icon)("(hdc=%x,pos=%d.%d,hicon=%x,extend=%d.%d,istep=%d,br=%x,flags=0x%08x)\n",
1924             hdc,x0,y0,hIcon,cxWidth,cyWidth,istep,hbr,flags
1925     );
1926
1927     if (istep)
1928         FIXME_(icon)("Ignoring istep=%d\n", istep);
1929     if (flags & DI_COMPAT)
1930         FIXME_(icon)("Ignoring flag DI_COMPAT\n");
1931
1932     if (!flags) {
1933         FIXME_(icon)("no flags set? setting to DI_NORMAL\n");
1934         flags = DI_NORMAL;
1935     }
1936
1937     /* Calculate the size of the destination image.  */
1938     if (cxWidth == 0)
1939     {
1940       if (flags & DI_DEFAULTSIZE)
1941         cxWidth = GetSystemMetrics (SM_CXICON);
1942       else
1943         cxWidth = ptr->nWidth;
1944     }
1945     if (cyWidth == 0)
1946     {
1947       if (flags & DI_DEFAULTSIZE)
1948         cyWidth = GetSystemMetrics (SM_CYICON);
1949       else
1950         cyWidth = ptr->nHeight;
1951     }
1952
1953     DoOffscreen = (GetObjectType( hbr ) == OBJ_BRUSH);
1954
1955     if (DoOffscreen) {
1956       RECT r;
1957
1958       r.left = 0;
1959       r.top = 0;
1960       r.right = cxWidth;
1961       r.bottom = cxWidth;
1962
1963       hDC_off = CreateCompatibleDC(hdc);
1964       hB_off = CreateCompatibleBitmap(hdc, cxWidth, cyWidth);
1965       if (hDC_off && hB_off) {
1966         hOld = SelectObject(hDC_off, hB_off);
1967         FillRect(hDC_off, &r, hbr);
1968       }
1969     }
1970
1971     if (hMemDC && (!DoOffscreen || (hDC_off && hB_off)))
1972     {
1973         HBITMAP hXorBits, hAndBits;
1974         COLORREF  oldFg, oldBg;
1975         INT     nStretchMode;
1976
1977         nStretchMode = SetStretchBltMode (hdc, STRETCH_DELETESCANS);
1978
1979         hXorBits = CreateBitmap ( ptr->nWidth, ptr->nHeight,
1980                                     ptr->bPlanes, ptr->bBitsPerPixel,
1981                                     (char *)(ptr + 1)
1982                                     + ptr->nHeight *
1983                                     BITMAP_GetWidthBytes(ptr->nWidth,1) );
1984         hAndBits = CreateBitmap ( ptr->nWidth, ptr->nHeight,
1985                                     1, 1, (char *)(ptr+1) );
1986         oldFg = SetTextColor( hdc, RGB(0,0,0) );
1987         oldBg = SetBkColor( hdc, RGB(255,255,255) );
1988
1989         if (hXorBits && hAndBits)
1990         {
1991             HBITMAP hBitTemp = SelectObject( hMemDC, hAndBits );
1992             if (flags & DI_MASK)
1993             {
1994               if (DoOffscreen) 
1995                 StretchBlt (hDC_off, 0, 0, cxWidth, cyWidth,
1996                               hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCAND);
1997               else 
1998                 StretchBlt (hdc, x0, y0, cxWidth, cyWidth,
1999                               hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCAND);
2000             }
2001             SelectObject( hMemDC, hXorBits );
2002             if (flags & DI_IMAGE)
2003             {
2004               if (DoOffscreen) 
2005                 StretchBlt (hDC_off, 0, 0, cxWidth, cyWidth,
2006                           hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCPAINT);
2007               else
2008                 StretchBlt (hdc, x0, y0, cxWidth, cyWidth,
2009                               hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCPAINT);
2010             }
2011             SelectObject( hMemDC, hBitTemp );
2012             result = TRUE;
2013         }
2014
2015         SetTextColor( hdc, oldFg );
2016         SetBkColor( hdc, oldBg );
2017         if (hXorBits) DeleteObject( hXorBits );
2018         if (hAndBits) DeleteObject( hAndBits );
2019         SetStretchBltMode (hdc, nStretchMode);
2020         if (DoOffscreen) {
2021           BitBlt(hdc, x0, y0, cxWidth, cyWidth, hDC_off, 0, 0, SRCCOPY);
2022           SelectObject(hDC_off, hOld);
2023         }
2024     }
2025     if (hMemDC) DeleteDC( hMemDC );
2026     if (hDC_off) DeleteDC(hDC_off);
2027     if (hB_off) DeleteObject(hB_off);
2028     GlobalUnlock16( hIcon );
2029     return result;
2030 }
2031
2032 /***********************************************************************
2033  *           DIB_FixColorsToLoadflags
2034  *
2035  * Change color table entries when LR_LOADTRANSPARENT or LR_LOADMAP3DCOLORS
2036  * are in loadflags
2037  */
2038 static void DIB_FixColorsToLoadflags(BITMAPINFO * bmi, UINT loadflags, BYTE pix)
2039 {
2040   int colors;
2041   COLORREF c_W, c_S, c_F, c_L, c_C;
2042   int incr,i;
2043   RGBQUAD *ptr;
2044
2045   if (bmi->bmiHeader.biBitCount > 8) return;
2046   if (bmi->bmiHeader.biSize == sizeof(BITMAPINFOHEADER)) incr = 4;
2047   else if (bmi->bmiHeader.biSize == sizeof(BITMAPCOREHEADER)) incr = 3;
2048   else {
2049     WARN_(resource)("Wrong bitmap header size!\n");
2050     return;
2051   }
2052   colors = bmi->bmiHeader.biClrUsed;
2053   if (!colors && (bmi->bmiHeader.biBitCount <= 8))
2054     colors = 1 << bmi->bmiHeader.biBitCount;
2055   c_W = GetSysColor(COLOR_WINDOW);
2056   c_S = GetSysColor(COLOR_3DSHADOW);
2057   c_F = GetSysColor(COLOR_3DFACE);
2058   c_L = GetSysColor(COLOR_3DLIGHT);
2059   if (loadflags & LR_LOADTRANSPARENT) {
2060     switch (bmi->bmiHeader.biBitCount) {
2061       case 1: pix = pix >> 7; break;
2062       case 4: pix = pix >> 4; break;
2063       case 8: break;
2064       default: 
2065         WARN_(resource)("(%d): Unsupported depth\n", bmi->bmiHeader.biBitCount); 
2066         return;
2067     }
2068     if (pix >= colors) {
2069       WARN_(resource)("pixel has color index greater than biClrUsed!\n");
2070       return;
2071     }
2072     if (loadflags & LR_LOADMAP3DCOLORS) c_W = c_F;
2073     ptr = (RGBQUAD*)((char*)bmi->bmiColors+pix*incr);
2074     ptr->rgbBlue = GetBValue(c_W);
2075     ptr->rgbGreen = GetGValue(c_W);
2076     ptr->rgbRed = GetRValue(c_W);
2077   }
2078   if (loadflags & LR_LOADMAP3DCOLORS)
2079     for (i=0; i<colors; i++) {
2080       ptr = (RGBQUAD*)((char*)bmi->bmiColors+i*incr);
2081       c_C = RGB(ptr->rgbRed, ptr->rgbGreen, ptr->rgbBlue);
2082       if (c_C == RGB(128, 128, 128)) { 
2083         ptr->rgbRed = GetRValue(c_S);
2084         ptr->rgbGreen = GetGValue(c_S);
2085         ptr->rgbBlue = GetBValue(c_S);
2086       } else if (c_C == RGB(192, 192, 192)) { 
2087         ptr->rgbRed = GetRValue(c_F);
2088         ptr->rgbGreen = GetGValue(c_F);
2089         ptr->rgbBlue = GetBValue(c_F);
2090       } else if (c_C == RGB(223, 223, 223)) { 
2091         ptr->rgbRed = GetRValue(c_L);
2092         ptr->rgbGreen = GetGValue(c_L);
2093         ptr->rgbBlue = GetBValue(c_L);
2094       } 
2095     }
2096 }
2097
2098
2099 /**********************************************************************
2100  *       BITMAP_Load
2101  */
2102 static HBITMAP BITMAP_Load( HINSTANCE instance,LPCWSTR name, UINT loadflags )
2103 {
2104     HBITMAP hbitmap = 0;
2105     HRSRC hRsrc;
2106     HGLOBAL handle;
2107     char *ptr = NULL;
2108     BITMAPINFO *info, *fix_info=NULL;
2109     HGLOBAL hFix;
2110     int size;
2111
2112     if (!(loadflags & LR_LOADFROMFILE)) {
2113       if (!instance)  /* OEM bitmap */
2114       {
2115           if (HIWORD((int)name)) return 0;
2116           return USER_Driver.pLoadOEMResource( LOWORD((int)name), OEM_BITMAP );
2117       }
2118
2119       if (!(hRsrc = FindResourceW( instance, name, RT_BITMAPW ))) return 0;
2120       if (!(handle = LoadResource( instance, hRsrc ))) return 0;
2121
2122       if ((info = (BITMAPINFO *)LockResource( handle )) == NULL) return 0;
2123     }
2124     else
2125     {
2126         if (!(ptr = map_fileW( name ))) return 0;
2127         info = (BITMAPINFO *)(ptr + sizeof(BITMAPFILEHEADER));
2128     }
2129     size = DIB_BitmapInfoSize(info, DIB_RGB_COLORS);
2130     if ((hFix = GlobalAlloc(0, size))) fix_info=GlobalLock(hFix);
2131     if (fix_info) {
2132       BYTE pix;
2133
2134       memcpy(fix_info, info, size);
2135       pix = *((LPBYTE)info+DIB_BitmapInfoSize(info, DIB_RGB_COLORS));
2136       DIB_FixColorsToLoadflags(fix_info, loadflags, pix);
2137       if (!screen_dc) screen_dc = CreateDCA( "DISPLAY", NULL, NULL, NULL );
2138       if (screen_dc)
2139       {
2140         char *bits = (char *)info + size;
2141         if (loadflags & LR_CREATEDIBSECTION) {
2142           DIBSECTION dib;
2143           hbitmap = CreateDIBSection(screen_dc, fix_info, DIB_RGB_COLORS, NULL, 0, 0);
2144           GetObjectA(hbitmap, sizeof(DIBSECTION), &dib);
2145           SetDIBits(screen_dc, hbitmap, 0, dib.dsBm.bmHeight, bits, info,
2146                     DIB_RGB_COLORS);
2147         }
2148         else {
2149           hbitmap = CreateDIBitmap( screen_dc, &fix_info->bmiHeader, CBM_INIT,
2150                                       bits, fix_info, DIB_RGB_COLORS );
2151         }
2152       }
2153       GlobalUnlock(hFix);
2154       GlobalFree(hFix);
2155     }
2156     if (loadflags & LR_LOADFROMFILE) UnmapViewOfFile( ptr );
2157     return hbitmap;
2158 }
2159
2160
2161 /***********************************************************************
2162  *              LoadImage (USER.389)
2163  *
2164  */
2165 HANDLE16 WINAPI LoadImage16( HINSTANCE16 hinst, LPCSTR name, UINT16 type,
2166                              INT16 desiredx, INT16 desiredy, UINT16 loadflags)
2167 {
2168     return LoadImageA( hinst, name, type, desiredx, desiredy, loadflags );
2169 }
2170
2171 /**********************************************************************
2172  *              LoadImageA (USER32.@)
2173  * 
2174  * FIXME: implementation lacks some features, see LR_ defines in windows.h
2175  */
2176
2177 HANDLE WINAPI LoadImageA( HINSTANCE hinst, LPCSTR name, UINT type,
2178                               INT desiredx, INT desiredy, UINT loadflags)
2179 {
2180     HANDLE res;
2181     LPWSTR u_name;
2182
2183     if (HIWORD(name)) u_name = HEAP_strdupAtoW(GetProcessHeap(), 0, name);
2184     else u_name=(LPWSTR)name;
2185     res = LoadImageW(hinst, u_name, type, desiredx, desiredy, loadflags);
2186     if (HIWORD(name)) HeapFree(GetProcessHeap(), 0, u_name);
2187     return res;
2188 }
2189
2190
2191 /******************************************************************************
2192  *              LoadImageW (USER32.@) Loads an icon, cursor, or bitmap
2193  *
2194  * PARAMS
2195  *    hinst     [I] Handle of instance that contains image
2196  *    name      [I] Name of image
2197  *    type      [I] Type of image
2198  *    desiredx  [I] Desired width
2199  *    desiredy  [I] Desired height
2200  *    loadflags [I] Load flags
2201  *
2202  * RETURNS
2203  *    Success: Handle to newly loaded image
2204  *    Failure: NULL
2205  *
2206  * FIXME: Implementation lacks some features, see LR_ defines in windows.h
2207  */
2208 HANDLE WINAPI LoadImageW( HINSTANCE hinst, LPCWSTR name, UINT type,
2209                 INT desiredx, INT desiredy, UINT loadflags )
2210 {
2211     if (HIWORD(name)) {
2212         TRACE_(resource)("(0x%04x,%p,%d,%d,%d,0x%08x)\n",
2213               hinst,name,type,desiredx,desiredy,loadflags);
2214     } else {
2215         TRACE_(resource)("(0x%04x,%p,%d,%d,%d,0x%08x)\n",
2216               hinst,name,type,desiredx,desiredy,loadflags);
2217     }
2218     if (loadflags & LR_DEFAULTSIZE) {
2219         if (type == IMAGE_ICON) {
2220             if (!desiredx) desiredx = GetSystemMetrics(SM_CXICON);
2221             if (!desiredy) desiredy = GetSystemMetrics(SM_CYICON);
2222         } else if (type == IMAGE_CURSOR) {
2223             if (!desiredx) desiredx = GetSystemMetrics(SM_CXCURSOR);
2224             if (!desiredy) desiredy = GetSystemMetrics(SM_CYCURSOR);
2225         }
2226     }
2227     if (loadflags & LR_LOADFROMFILE) loadflags &= ~LR_SHARED;
2228     switch (type) {
2229     case IMAGE_BITMAP:
2230         return BITMAP_Load( hinst, name, loadflags );
2231
2232     case IMAGE_ICON:
2233         if (!screen_dc) screen_dc = CreateDCA( "DISPLAY", NULL, NULL, NULL );
2234         if (screen_dc)
2235         {
2236             UINT palEnts = GetSystemPaletteEntries(screen_dc, 0, 0, NULL);
2237             if (palEnts == 0) palEnts = 256;
2238             return CURSORICON_Load(hinst, name, desiredx, desiredy,
2239                                    palEnts, FALSE, loadflags);
2240         }
2241         break;
2242
2243     case IMAGE_CURSOR:
2244         return CURSORICON_Load(hinst, name, desiredx, desiredy,
2245                                  1, TRUE, loadflags);
2246     }
2247     return 0;
2248 }
2249
2250
2251 /******************************************************************************
2252  *              CopyImage (USER.390) Creates new image and copies attributes to it
2253  *
2254  */
2255 HICON16 WINAPI CopyImage16( HANDLE16 hnd, UINT16 type, INT16 desiredx,
2256                              INT16 desiredy, UINT16 flags )
2257 {
2258     return (HICON16)CopyImage((HANDLE)hnd, (UINT)type, (INT)desiredx,
2259                                 (INT)desiredy, (UINT)flags);
2260 }
2261
2262 /******************************************************************************
2263  *              CopyImage (USER32.@) Creates new image and copies attributes to it
2264  *
2265  * PARAMS
2266  *    hnd      [I] Handle to image to copy
2267  *    type     [I] Type of image to copy
2268  *    desiredx [I] Desired width of new image
2269  *    desiredy [I] Desired height of new image
2270  *    flags    [I] Copy flags
2271  *
2272  * RETURNS
2273  *    Success: Handle to newly created image
2274  *    Failure: NULL
2275  *
2276  * FIXME: implementation still lacks nearly all features, see LR_*
2277  * defines in windows.h
2278  */
2279 HICON WINAPI CopyImage( HANDLE hnd, UINT type, INT desiredx,
2280                              INT desiredy, UINT flags )
2281 {
2282     switch (type)
2283     {
2284         case IMAGE_BITMAP:
2285                 return BITMAP_CopyBitmap(hnd);
2286         case IMAGE_ICON:
2287                 return CURSORICON_ExtCopy(hnd,type, desiredx, desiredy, flags);
2288         case IMAGE_CURSOR:
2289                 /* Should call CURSORICON_ExtCopy but more testing
2290                  * needs to be done before we change this
2291                  */
2292                 return CopyCursor(hnd);
2293     }
2294     return 0;
2295 }
2296
2297
2298 /******************************************************************************
2299  *              LoadBitmapW (USER32.@) Loads bitmap from the executable file
2300  *
2301  * RETURNS
2302  *    Success: Handle to specified bitmap
2303  *    Failure: NULL
2304  */
2305 HBITMAP WINAPI LoadBitmapW(
2306     HINSTANCE instance, /* [in] Handle to application instance */
2307     LPCWSTR name)         /* [in] Address of bitmap resource name */
2308 {
2309     return LoadImageW( instance, name, IMAGE_BITMAP, 0, 0, 0 );
2310 }
2311
2312 /**********************************************************************
2313  *              LoadBitmapA (USER32.@)
2314  */
2315 HBITMAP WINAPI LoadBitmapA( HINSTANCE instance, LPCSTR name )
2316 {
2317     return LoadImageA( instance, name, IMAGE_BITMAP, 0, 0, 0 );
2318 }
2319
2320 /**********************************************************************
2321  *              LoadBitmap (USER.175)
2322  */
2323 HBITMAP16 WINAPI LoadBitmap16( HINSTANCE16 instance, LPCSTR name )
2324 {
2325     return LoadBitmapA( instance, name );
2326 }