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