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