Adapted to new input event handling.
[wine] / objects / 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 #include "heap.h"
35 #include "windows.h"
36 #include "peexe.h"
37 #include "color.h"
38 #include "bitmap.h"
39 #include "callback.h"
40 #include "cursoricon.h"
41 #include "sysmetrics.h"
42 #include "global.h"
43 #include "module.h"
44 #include "win.h"
45 #include "debug.h"
46 #include "task.h"
47 #include "user.h"
48 #include "input.h"
49 #include "x11drv.h"
50 #include "winerror.h"
51
52 Cursor CURSORICON_XCursor = None;    /* Current X cursor */
53 static HCURSOR32 hActiveCursor = 0;  /* Active cursor */
54 static INT32 CURSOR_ShowCount = 0;   /* Cursor display count */
55 static RECT32 CURSOR_ClipRect;       /* Cursor clipping rect */
56
57 /**********************************************************************
58  *          CURSORICON_FindBestIcon
59  *
60  * Find the icon closest to the requested size and number of colors.
61  */
62 static ICONDIRENTRY *CURSORICON_FindBestIcon( CURSORICONDIR *dir, int width,
63                                               int height, int colors )
64 {
65     int i, maxcolors, maxwidth, maxheight;
66     ICONDIRENTRY *entry, *bestEntry = NULL;
67
68     if (dir->idCount < 1)
69     {
70         WARN(icon, "Empty directory!\n" );
71         return NULL;
72     }
73     if (dir->idCount == 1) return &dir->idEntries[0].icon;  /* No choice... */
74
75     /* First find the exact size with less colors */
76
77     maxcolors = 0;
78     for (i = 0, entry = &dir->idEntries[0].icon; i < dir->idCount; i++,entry++)
79         if ((entry->bWidth == width) && (entry->bHeight == height) &&
80             (entry->bColorCount <= colors) && (entry->bColorCount > maxcolors))
81         {
82             bestEntry = entry;
83             maxcolors = entry->bColorCount;
84         }
85     if (bestEntry) return bestEntry;
86
87     /* First find the exact size with more colors */
88
89     maxcolors = 255;
90     for (i = 0, entry = &dir->idEntries[0].icon; i < dir->idCount; i++,entry++)
91         if ((entry->bWidth == width) && (entry->bHeight == height) &&
92             (entry->bColorCount > colors) && (entry->bColorCount <= maxcolors))
93         {
94             bestEntry = entry;
95             maxcolors = entry->bColorCount;
96         }
97     if (bestEntry) return bestEntry;
98
99     /* Now find a smaller one with less colors */
100
101     maxcolors = maxwidth = maxheight = 0;
102     for (i = 0, entry = &dir->idEntries[0].icon; i < dir->idCount; i++,entry++)
103         if ((entry->bWidth <= width) && (entry->bHeight <= height) &&
104             (entry->bWidth >= maxwidth) && (entry->bHeight >= maxheight) &&
105             (entry->bColorCount <= colors) && (entry->bColorCount > maxcolors))
106         {
107             bestEntry = entry;
108             maxwidth  = entry->bWidth;
109             maxheight = entry->bHeight;
110             maxcolors = entry->bColorCount;
111         }
112     if (bestEntry) return bestEntry;
113
114     /* Now find a smaller one with more colors */
115
116     maxcolors = 255;
117     maxwidth = maxheight = 0;
118     for (i = 0, entry = &dir->idEntries[0].icon; i < dir->idCount; i++,entry++)
119         if ((entry->bWidth <= width) && (entry->bHeight <= height) &&
120             (entry->bWidth >= maxwidth) && (entry->bHeight >= maxheight) &&
121             (entry->bColorCount > colors) && (entry->bColorCount <= maxcolors))
122         {
123             bestEntry = entry;
124             maxwidth  = entry->bWidth;
125             maxheight = entry->bHeight;
126             maxcolors = entry->bColorCount;
127         }
128     if (bestEntry) return bestEntry;
129
130     /* Now find a larger one with less colors */
131
132     maxcolors = 0;
133     maxwidth = maxheight = 255;
134     for (i = 0, entry = &dir->idEntries[0].icon; i < dir->idCount; i++,entry++)
135         if ((entry->bWidth <= maxwidth) && (entry->bHeight <= maxheight) &&
136             (entry->bColorCount <= colors) && (entry->bColorCount > maxcolors))
137         {
138             bestEntry = entry;
139             maxwidth  = entry->bWidth;
140             maxheight = entry->bHeight;
141             maxcolors = entry->bColorCount;
142         }
143     if (bestEntry) return bestEntry;
144
145     /* Now find a larger one with more colors */
146
147     maxcolors = maxwidth = maxheight = 255;
148     for (i = 0, entry = &dir->idEntries[0].icon; i < dir->idCount; i++,entry++)
149         if ((entry->bWidth <= maxwidth) && (entry->bHeight <= maxheight) &&
150             (entry->bColorCount > colors) && (entry->bColorCount <= maxcolors))
151         {
152             bestEntry = entry;
153             maxwidth  = entry->bWidth;
154             maxheight = entry->bHeight;
155             maxcolors = entry->bColorCount;
156         }
157
158     return bestEntry;
159 }
160
161
162 /**********************************************************************
163  *          CURSORICON_FindBestCursor
164  *
165  * Find the cursor closest to the requested size.
166  * FIXME: parameter 'color' ignored and entries with more than 1 bpp
167  *        ignored too
168  */
169 static CURSORDIRENTRY *CURSORICON_FindBestCursor( CURSORICONDIR *dir,
170                                                   int width, int height, int color)
171 {
172     int i, maxwidth, maxheight;
173     CURSORDIRENTRY *entry, *bestEntry = NULL;
174
175     if (dir->idCount < 1)
176     {
177         WARN(cursor, "Empty directory!\n" );
178         return NULL;
179     }
180     if (dir->idCount == 1) return &dir->idEntries[0].cursor; /* No choice... */
181
182     /* First find the largest one smaller than or equal to the requested size*/
183
184     maxwidth = maxheight = 0;
185     for(i = 0,entry = &dir->idEntries[0].cursor; i < dir->idCount; i++,entry++)
186         if ((entry->wWidth <= width) && (entry->wHeight <= height) &&
187             (entry->wWidth > maxwidth) && (entry->wHeight > maxheight) &&
188             (entry->wBitCount == 1))
189         {
190             bestEntry = entry;
191             maxwidth  = entry->wWidth;
192             maxheight = entry->wHeight;
193         }
194     if (bestEntry) return bestEntry;
195
196     /* Now find the smallest one larger than the requested size */
197
198     maxwidth = maxheight = 255;
199     for(i = 0,entry = &dir->idEntries[0].cursor; i < dir->idCount; i++,entry++)
200         if ((entry->wWidth < maxwidth) && (entry->wHeight < maxheight) &&
201             (entry->wBitCount == 1))
202         {
203             bestEntry = entry;
204             maxwidth  = entry->wWidth;
205             maxheight = entry->wHeight;
206         }
207
208     return bestEntry;
209 }
210
211 /*********************************************************************
212  * The main purpose of this function is to create fake resource directory
213  * and fake resource entries. There are several reasons for this:
214  *      -       CURSORICONDIR and CURSORICONFILEDIR differ in sizes and their
215  *              fields
216  *      There are some "bad" cursor files which do not have
217  *              bColorCount initialized but instead one must read this info
218  *              directly from corresponding DIB sections
219  * Note: wResId is index to array of pointer returned in ptrs (origin is 1)
220  */
221 BOOL32 CURSORICON_SimulateLoadingFromResourceW( LPWSTR filename, BOOL32 fCursor,
222                                                 CURSORICONDIR **res, LPBYTE **ptr)
223 {
224     LPBYTE   _free;
225     CURSORICONFILEDIR *bits;
226     int      entries, size, i;
227
228     *res = NULL;
229     *ptr = NULL;
230     if (!(bits = (CURSORICONFILEDIR *)VIRTUAL_MapFileW( filename ))) return FALSE;
231     if (!(entries = bits->idCount)) goto fail;
232     (int)_free = size = sizeof(CURSORICONDIR) + sizeof(CURSORICONDIRENTRY) * 
233                                                 (entries - 1);
234     for (i=0; i < entries; i++)
235       size += bits->idEntries[i].dwDIBSize + (fCursor ? sizeof(POINT16): 0);
236     
237     if (!(*ptr = HeapAlloc( GetProcessHeap(), 0,
238                             entries * sizeof (CURSORICONDIRENTRY*)))) goto fail;
239     if (!(*res = HeapAlloc( GetProcessHeap(), 0, size))) goto fail;
240
241     _free = (LPBYTE)(*res) + (int)_free;
242     memcpy((*res), bits, 6);
243     for (i=0; i<entries; i++)
244     {
245       ((LPBYTE*)(*ptr))[i] = _free;
246       if (fCursor) {
247         (*res)->idEntries[i].cursor.wWidth=bits->idEntries[i].bWidth;
248         (*res)->idEntries[i].cursor.wHeight=bits->idEntries[i].bHeight;
249         (*res)->idEntries[i].cursor.wPlanes=1;
250         (*res)->idEntries[i].cursor.wBitCount = ((LPBITMAPINFOHEADER)((LPBYTE)bits +
251                                                    bits->idEntries[i].dwDIBOffset))->biBitCount;
252         (*res)->idEntries[i].cursor.dwBytesInRes = bits->idEntries[i].dwDIBSize;
253         (*res)->idEntries[i].cursor.wResId=i+1;
254         ((LPPOINT16)_free)->x=bits->idEntries[i].xHotspot;
255         ((LPPOINT16)_free)->y=bits->idEntries[i].yHotspot;
256         _free+=sizeof(POINT16);
257       } else {
258         (*res)->idEntries[i].icon.bWidth=bits->idEntries[i].bWidth;
259         (*res)->idEntries[i].icon.bHeight=bits->idEntries[i].bHeight;
260         (*res)->idEntries[i].icon.bColorCount = bits->idEntries[i].bColorCount;
261         (*res)->idEntries[i].icon.wPlanes=1;
262         (*res)->idEntries[i].icon.wBitCount= ((LPBITMAPINFOHEADER)((LPBYTE)bits +
263                                              bits->idEntries[i].dwDIBOffset))->biBitCount;
264         (*res)->idEntries[i].icon.dwBytesInRes = bits->idEntries[i].dwDIBSize;
265         (*res)->idEntries[i].icon.wResId=i+1;
266       }
267       memcpy(_free,(LPBYTE)bits +bits->idEntries[i].dwDIBOffset,
268              (*res)->idEntries[i].icon.dwBytesInRes);
269       _free += (*res)->idEntries[i].icon.dwBytesInRes;
270     }
271     UnmapViewOfFile( bits );
272     return TRUE;    
273 fail:
274     if (*res) HeapFree( GetProcessHeap(), 0, *res );
275     if (*ptr) HeapFree( GetProcessHeap(), 0, *ptr );
276     UnmapViewOfFile( bits );
277     return FALSE;
278 }
279
280 /**********************************************************************
281  *          CURSORICON_LoadDirEntry16
282  *
283  * Load the icon/cursor directory for a given resource name and find the
284  * best matching entry.
285  */
286 static BOOL32 CURSORICON_LoadDirEntry16( HINSTANCE32 hInstance, SEGPTR name,
287                                          INT32 width, INT32 height, INT32 colors, 
288                                          BOOL32 fCursor, CURSORICONDIRENTRY *dirEntry )
289 {
290     HRSRC16 hRsrc;
291     HGLOBAL16 hMem;
292     CURSORICONDIR *dir;
293     CURSORICONDIRENTRY *entry = NULL;
294
295     if (!(hRsrc = FindResource16( hInstance, name,
296                               fCursor ? RT_GROUP_CURSOR16 : RT_GROUP_ICON16 )))
297         return FALSE;
298     if (!(hMem = LoadResource16( hInstance, hRsrc ))) return FALSE;
299     if ((dir = (CURSORICONDIR *)LockResource16( hMem )))
300     {
301         if (fCursor)
302             entry = (CURSORICONDIRENTRY *)CURSORICON_FindBestCursor( dir,
303                                                                width, height, 1);
304         else
305             entry = (CURSORICONDIRENTRY *)CURSORICON_FindBestIcon( dir,
306                                                        width, height, colors );
307         if (entry) *dirEntry = *entry;
308     }
309     FreeResource16( hMem );
310     return (entry != NULL);
311 }
312
313
314 /**********************************************************************
315  *          CURSORICON_LoadDirEntry32
316  *
317  * Load the icon/cursor directory for a given resource name and find the
318  * best matching entry.
319  */
320 static BOOL32 CURSORICON_LoadDirEntry32( HINSTANCE32 hInstance, LPCWSTR name,
321                                          INT32 width, INT32 height, INT32 colors,
322                                          BOOL32 fCursor, CURSORICONDIRENTRY *dirEntry )
323 {
324     HANDLE32 hRsrc;
325     HANDLE32 hMem;
326     CURSORICONDIR *dir;
327     CURSORICONDIRENTRY *entry = NULL;
328
329     if (!(hRsrc = FindResource32W( hInstance, name,
330                             fCursor ? RT_GROUP_CURSOR32W : RT_GROUP_ICON32W )))
331         return FALSE;
332     if (!(hMem = LoadResource32( hInstance, hRsrc ))) return FALSE;
333     if ((dir = (CURSORICONDIR*)LockResource32( hMem )))
334     {
335         if (fCursor)
336             entry = (CURSORICONDIRENTRY *)CURSORICON_FindBestCursor( dir,
337                                                                width, height, 1);
338         else
339             entry = (CURSORICONDIRENTRY *)CURSORICON_FindBestIcon( dir,
340                                                        width, height, colors );
341         if (entry) *dirEntry = *entry;
342     }
343     FreeResource32( hMem );
344     return (entry != NULL);
345 }
346
347
348 /**********************************************************************
349  *          CURSORICON_CreateFromResource
350  *
351  * Create a cursor or icon from in-memory resource template. 
352  *
353  * FIXME: Convert to mono when cFlag is LR_MONOCHROME. Do something
354  *        with cbSize parameter as well.
355  */
356 static HGLOBAL16 CURSORICON_CreateFromResource( HINSTANCE16 hInstance, HGLOBAL16 hObj, LPBYTE bits,
357                                                 UINT32 cbSize, BOOL32 bIcon, DWORD dwVersion, 
358                                                 INT32 width, INT32 height, UINT32 loadflags )
359 {
360     int sizeAnd, sizeXor;
361     HBITMAP32 hAndBits = 0, hXorBits = 0; /* error condition for later */
362     BITMAPOBJ *bmpXor, *bmpAnd;
363     POINT16 hotspot = { 0 ,0 };
364     BITMAPINFO *bmi;
365     HDC32 hdc;
366     BOOL32 DoStretch;
367     INT32 size;
368
369     TRACE(cursor,"%08x (%u bytes), ver %08x, %ix%i %s %s\n",
370                         (unsigned)bits, cbSize, (unsigned)dwVersion, width, height,
371                                   bIcon ? "icon" : "cursor", (loadflags & LR_MONOCHROME) ? "mono" : "" );
372     if (dwVersion == 0x00020000)
373     {
374         FIXME(cursor,"\t2.xx resources are not supported\n");
375         return 0;
376     }
377
378     if (bIcon)
379         bmi = (BITMAPINFO *)bits;
380     else /* get the hotspot */
381     {
382         POINT16 *pt = (POINT16 *)bits;
383         hotspot = *pt;
384         bmi = (BITMAPINFO *)(pt + 1);
385     }
386     size = DIB_BitmapInfoSize( bmi, DIB_RGB_COLORS );
387
388     if (!width) width = bmi->bmiHeader.biWidth;
389     if (!height) height = bmi->bmiHeader.biHeight/2;
390     DoStretch = (bmi->bmiHeader.biHeight/2 != height) ||
391       (bmi->bmiHeader.biWidth != width);
392
393     /* Check bitmap header */
394
395     if ( (bmi->bmiHeader.biSize != sizeof(BITMAPCOREHEADER)) &&
396          (bmi->bmiHeader.biSize != sizeof(BITMAPINFOHEADER)  ||
397           bmi->bmiHeader.biCompression != BI_RGB) )
398     {
399           WARN(cursor,"\tinvalid resource bitmap header.\n");
400           return 0;
401     }
402
403     if( (hdc = GetDC32( 0 )) )
404     {
405         BITMAPINFO* pInfo;
406
407         /* Make sure we have room for the monochrome bitmap later on.
408          * Note that BITMAPINFOINFO and BITMAPCOREHEADER are the same
409          * up to and including the biBitCount. In-memory icon resource 
410          * format is as follows:
411          *
412          *   BITMAPINFOHEADER   icHeader  // DIB header
413          *   RGBQUAD         icColors[]   // Color table
414          *   BYTE            icXOR[]      // DIB bits for XOR mask
415          *   BYTE            icAND[]      // DIB bits for AND mask
416          */
417
418         if ((pInfo = (BITMAPINFO *)HeapAlloc( GetProcessHeap(), 0, 
419           MAX(size, sizeof(BITMAPINFOHEADER) + 2*sizeof(RGBQUAD)))))
420         {       
421             memcpy( pInfo, bmi, size ); 
422             pInfo->bmiHeader.biHeight /= 2;
423
424             /* Create the XOR bitmap */
425
426             if (DoStretch) {
427               if ((hXorBits = CreateCompatibleBitmap32(hdc, width, height))) {
428                 HBITMAP32 hOld;
429                 HDC32 hMem = CreateCompatibleDC32(hdc);
430                 BOOL32 res;
431
432                 if (hMem) {
433                   hOld = SelectObject32(hMem, hXorBits);
434                   res = StretchDIBits32(hMem, 0, 0, width, height, 0, 0,
435                     bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight/2,
436                     (char*)bmi + size, pInfo, DIB_RGB_COLORS, SRCCOPY);
437                   SelectObject32(hMem, hOld);
438                   DeleteDC32(hMem);
439                 } else res = FALSE;
440                 if (!res) { DeleteObject32(hXorBits); hXorBits = 0; }
441               }
442             } else hXorBits = CreateDIBitmap32( hdc, &pInfo->bmiHeader,
443                 CBM_INIT, (char*)bmi + size, pInfo, DIB_RGB_COLORS );
444             if( hXorBits )
445             {
446                 char* bits = (char *)bmi + size + bmi->bmiHeader.biHeight *
447                                 DIB_GetDIBWidthBytes(bmi->bmiHeader.biWidth,
448                                                      bmi->bmiHeader.biBitCount) / 2;
449
450                 pInfo->bmiHeader.biBitCount = 1;
451                 if (pInfo->bmiHeader.biSize == sizeof(BITMAPINFOHEADER))
452                 {
453                     RGBQUAD *rgb = pInfo->bmiColors;
454
455                     pInfo->bmiHeader.biClrUsed = pInfo->bmiHeader.biClrImportant = 2;
456                     rgb[0].rgbBlue = rgb[0].rgbGreen = rgb[0].rgbRed = 0x00;
457                     rgb[1].rgbBlue = rgb[1].rgbGreen = rgb[1].rgbRed = 0xff;
458                     rgb[0].rgbReserved = rgb[1].rgbReserved = 0;
459                 }
460                 else
461                 {
462                     RGBTRIPLE *rgb = (RGBTRIPLE *)(((BITMAPCOREHEADER *)pInfo) + 1);
463
464                     rgb[0].rgbtBlue = rgb[0].rgbtGreen = rgb[0].rgbtRed = 0x00;
465                     rgb[1].rgbtBlue = rgb[1].rgbtGreen = rgb[1].rgbtRed = 0xff;
466                 }
467
468                 /* Create the AND bitmap */
469
470             if (DoStretch) {
471               if ((hAndBits = CreateBitmap32(width, height, 1, 1, NULL))) {
472                 HBITMAP32 hOld;
473                 HDC32 hMem = CreateCompatibleDC32(hdc);
474                 BOOL32 res;
475
476                 if (hMem) {
477                   hOld = SelectObject32(hMem, hAndBits);
478                   res = StretchDIBits32(hMem, 0, 0, width, height, 0, 0,
479                     pInfo->bmiHeader.biWidth, pInfo->bmiHeader.biHeight,
480                     bits, pInfo, DIB_RGB_COLORS, SRCCOPY);
481                   SelectObject32(hMem, hOld);
482                   DeleteDC32(hMem);
483                 } else res = FALSE;
484                 if (!res) { DeleteObject32(hAndBits); hAndBits = 0; }
485               }
486             } else hAndBits = CreateDIBitmap32( hdc, &pInfo->bmiHeader,
487               CBM_INIT, bits, pInfo, DIB_RGB_COLORS );
488
489                 if( !hAndBits ) DeleteObject32( hXorBits );
490             }
491             HeapFree( GetProcessHeap(), 0, pInfo ); 
492         }
493         ReleaseDC32( 0, hdc );
494     }
495
496     if( !hXorBits || !hAndBits ) 
497     {
498         WARN(cursor,"\tunable to create an icon bitmap.\n");
499         return 0;
500     }
501
502     /* Now create the CURSORICONINFO structure */
503     bmpXor = (BITMAPOBJ *) GDI_GetObjPtr( hXorBits, BITMAP_MAGIC );
504     bmpAnd = (BITMAPOBJ *) GDI_GetObjPtr( hAndBits, BITMAP_MAGIC );
505     sizeXor = bmpXor->bitmap.bmHeight * bmpXor->bitmap.bmWidthBytes;
506     sizeAnd = bmpAnd->bitmap.bmHeight * bmpAnd->bitmap.bmWidthBytes;
507
508     if (hObj) hObj = GlobalReAlloc16( hObj, 
509                      sizeof(CURSORICONINFO) + sizeXor + sizeAnd, GMEM_MOVEABLE );
510     if (!hObj) hObj = GlobalAlloc16( GMEM_MOVEABLE, 
511                      sizeof(CURSORICONINFO) + sizeXor + sizeAnd );
512     if (hObj)
513     {
514         CURSORICONINFO *info;
515
516         /* Make it owned by the module */
517         if (hInstance) FarSetOwner( hObj, GetExePtr(hInstance) );
518
519         info = (CURSORICONINFO *)GlobalLock16( hObj );
520         info->ptHotSpot.x   = hotspot.x;
521         info->ptHotSpot.y   = hotspot.y;
522         info->nWidth        = bmpXor->bitmap.bmWidth;
523         info->nHeight       = bmpXor->bitmap.bmHeight;
524         info->nWidthBytes   = bmpXor->bitmap.bmWidthBytes;
525         info->bPlanes       = bmpXor->bitmap.bmPlanes;
526         info->bBitsPerPixel = bmpXor->bitmap.bmBitsPixel;
527
528         /* Transfer the bitmap bits to the CURSORICONINFO structure */
529
530         GetBitmapBits32( hAndBits, sizeAnd, (char *)(info + 1) );
531         GetBitmapBits32( hXorBits, sizeXor, (char *)(info + 1) + sizeAnd );
532         GlobalUnlock16( hObj );
533     }
534
535     DeleteObject32( hXorBits );
536     DeleteObject32( hAndBits );
537     return hObj;
538 }
539
540
541 /**********************************************************************
542  *          CreateIconFromResourceEx16          (USER.450)
543  *
544  * FIXME: not sure about exact parameter types
545  */
546 HICON16 WINAPI CreateIconFromResourceEx16( LPBYTE bits, UINT16 cbSize, BOOL16 bIcon,
547                                     DWORD dwVersion, INT16 width, INT16 height, UINT16 cFlag )
548 {
549     return CreateIconFromResourceEx32(bits, cbSize, bIcon, dwVersion, 
550       width, height, cFlag);
551 }
552
553
554 /**********************************************************************
555  *          CreateIconFromResource          (USER32.76)
556  */
557 HICON32 WINAPI CreateIconFromResource32( LPBYTE bits, UINT32 cbSize,
558                                            BOOL32 bIcon, DWORD dwVersion)
559 {
560     return CreateIconFromResourceEx32( bits, cbSize, bIcon, dwVersion, 0,0,0);
561 }
562
563
564 /**********************************************************************
565  *          CreateIconFromResourceEx32          (USER32.77)
566  */
567 HICON32 WINAPI CreateIconFromResourceEx32( LPBYTE bits, UINT32 cbSize,
568                                            BOOL32 bIcon, DWORD dwVersion,
569                                            INT32 width, INT32 height,
570                                            UINT32 cFlag )
571 {
572     TDB* pTask = (TDB*)GlobalLock16( GetCurrentTask() );
573     if( pTask )
574         return CURSORICON_CreateFromResource( pTask->hInstance, 0, bits, cbSize, bIcon, dwVersion,
575                                               width, height, cFlag );
576     return 0;
577 }
578
579
580 /**********************************************************************
581  *          CURSORICON_Load16
582  *
583  * Load a cursor or icon from a 16-bit resource.
584  */
585 static HGLOBAL16 CURSORICON_Load16( HINSTANCE16 hInstance, SEGPTR name,
586                                     INT32 width, INT32 height, INT32 colors,
587                                     BOOL32 fCursor, UINT32 loadflags)
588 {
589     HGLOBAL16 handle;
590     HRSRC16 hRsrc;
591     CURSORICONDIRENTRY dirEntry;
592
593     if (!hInstance)  /* OEM cursor/icon */
594     {
595         if (HIWORD(name))  /* Check for '#xxx' name */
596         {
597             char *ptr = PTR_SEG_TO_LIN( name );
598             if (ptr[0] != '#') return 0;
599             if (!(name = (SEGPTR)atoi( ptr + 1 ))) return 0;
600         }
601         return OBM_LoadCursorIcon( LOWORD(name), fCursor );
602     }
603
604     /* Find the best entry in the directory */
605
606     if ( !CURSORICON_LoadDirEntry16( hInstance, name, width, height,
607                                     colors, fCursor, &dirEntry ) )  return 0;
608     /* Load the resource */
609
610     if ( (hRsrc = FindResource16( hInstance,
611                                 MAKEINTRESOURCE16( dirEntry.icon.wResId ),
612                                 fCursor ? RT_CURSOR16 : RT_ICON16 )) )
613     {
614         /* 16-bit icon or cursor resources are processed
615          * transparently by the LoadResource16() via custom
616          * resource handlers set by SetResourceHandler().
617          */
618
619         if ( (handle = LoadResource16( hInstance, hRsrc )) )
620             return handle;
621     }
622     return 0;
623 }
624
625 /**********************************************************************
626  *          CURSORICON_Load32
627  *
628  * Load a cursor or icon from a 32-bit resource.
629  */
630 HGLOBAL32 CURSORICON_Load32( HINSTANCE32 hInstance, LPCWSTR name,
631                              int width, int height, int colors,
632                              BOOL32 fCursor, UINT32 loadflags )
633 {
634     HANDLE32 handle, h = 0;
635     HANDLE32 hRsrc;
636     CURSORICONDIRENTRY dirEntry;
637     LPBYTE bits;
638
639     if (!(loadflags & LR_LOADFROMFILE))
640     {
641         if (!hInstance)  /* OEM cursor/icon */
642         {
643             WORD resid;
644             if(HIWORD(name))
645             {
646                 LPSTR ansi = HEAP_strdupWtoA(GetProcessHeap(),0,name);
647                 if( ansi[0]=='#')        /*Check for '#xxx' name */
648                 {
649                     resid = atoi(ansi+1);
650                     HeapFree( GetProcessHeap(), 0, ansi );
651                 }
652                 else
653                 {
654                     HeapFree( GetProcessHeap(), 0, ansi );
655                     return 0;
656                 }
657             }
658             else resid = LOWORD(name);
659             return OBM_LoadCursorIcon(resid, fCursor);
660         }
661
662         /* Find the best entry in the directory */
663  
664         if (!CURSORICON_LoadDirEntry32( hInstance, name, width, height,
665                                         colors, fCursor, &dirEntry ) )  return 0;
666         /* Load the resource */
667
668         if (!(hRsrc = FindResource32W(hInstance,MAKEINTRESOURCE32W(dirEntry.icon.wResId),
669                                       fCursor ? RT_CURSOR32W : RT_ICON32W ))) return 0;
670         if (!(handle = LoadResource32( hInstance, hRsrc ))) return 0;
671         /* Hack to keep LoadCursor/Icon32() from spawning multiple
672          * copies of the same object.
673          */
674 #define pRsrcEntry ((PIMAGE_RESOURCE_DATA_ENTRY)hRsrc)
675         if( pRsrcEntry->ResourceHandle ) return pRsrcEntry->ResourceHandle;
676         bits = (LPBYTE)LockResource32( handle );
677         h = CURSORICON_CreateFromResource( 0, 0, bits, dirEntry.icon.dwBytesInRes, 
678                                            !fCursor, 0x00030000, width, height, loadflags);
679         pRsrcEntry->ResourceHandle = h;
680     }
681     else
682     {
683         CURSORICONDIR *res;
684         LPBYTE *ptr;
685         if (!CURSORICON_SimulateLoadingFromResourceW((LPWSTR)name, fCursor, &res, &ptr))
686             return 0;
687         if (fCursor)
688             dirEntry = *(CURSORICONDIRENTRY *)CURSORICON_FindBestCursor(res, width, height, 1);
689         else
690             dirEntry = *(CURSORICONDIRENTRY *)CURSORICON_FindBestIcon(res, width, height, colors);
691         bits = ptr[dirEntry.icon.wResId-1];
692         h = CURSORICON_CreateFromResource( 0, 0, bits, dirEntry.icon.dwBytesInRes, 
693                                            !fCursor, 0x00030000, width, height, loadflags);
694         HeapFree( GetProcessHeap(), 0, res );
695         HeapFree( GetProcessHeap(), 0, ptr );
696     }
697     return h;
698 #undef  pRsrcEntry
699 }
700
701
702 /***********************************************************************
703  *           CURSORICON_Copy
704  *
705  * Make a copy of a cursor or icon.
706  */
707 static HGLOBAL16 CURSORICON_Copy( HINSTANCE16 hInstance, HGLOBAL16 handle )
708 {
709     char *ptrOld, *ptrNew;
710     int size;
711     HGLOBAL16 hNew;
712
713     if (!(ptrOld = (char *)GlobalLock16( handle ))) return 0;
714     if (!(hInstance = GetExePtr( hInstance ))) return 0;
715     size = GlobalSize16( handle );
716     hNew = GlobalAlloc16( GMEM_MOVEABLE, size );
717     FarSetOwner( hNew, hInstance );
718     ptrNew = (char *)GlobalLock16( hNew );
719     memcpy( ptrNew, ptrOld, size );
720     GlobalUnlock16( handle );
721     GlobalUnlock16( hNew );
722     return hNew;
723 }
724
725 /***********************************************************************
726  *           CURSORICON_IconToCursor
727  *
728  * Converts bitmap to mono and truncates if icon is too large (should
729  * probably do StretchBlt() instead).
730  */
731 HCURSOR16 CURSORICON_IconToCursor(HICON16 hIcon, BOOL32 bSemiTransparent)
732 {
733  HCURSOR16       hRet = 0;
734  CURSORICONINFO *pIcon = NULL;
735  HTASK16         hTask = GetCurrentTask();
736  TDB*            pTask = (TDB *)GlobalLock16(hTask);
737
738  if(hIcon && pTask)
739     if (!(pIcon = (CURSORICONINFO*)GlobalLock16( hIcon ))) return FALSE;
740        if (pIcon->bPlanes * pIcon->bBitsPerPixel == 1)
741            hRet = CURSORICON_Copy( pTask->hInstance, hIcon );
742        else
743        {
744            BYTE  pAndBits[128];
745            BYTE  pXorBits[128];
746            int   maxx, maxy, ix, iy, bpp = pIcon->bBitsPerPixel;
747            BYTE* psPtr, *pxbPtr = pXorBits;
748            unsigned xor_width, and_width, val_base = 0xffffffff >> (32 - bpp);
749            BYTE* pbc = NULL;
750
751            COLORREF       col;
752            CURSORICONINFO cI;
753
754            TRACE(icon, "[%04x] %ix%i %ibpp (bogus %ibps)\n", 
755                 hIcon, pIcon->nWidth, pIcon->nHeight, pIcon->bBitsPerPixel, pIcon->nWidthBytes );
756
757            xor_width = BITMAP_GetWidthBytes( pIcon->nWidth, bpp );
758            and_width = BITMAP_GetWidthBytes( pIcon->nWidth, 1 );
759            psPtr = (BYTE *)(pIcon + 1) + pIcon->nHeight * and_width;
760
761            memset(pXorBits, 0, 128);
762            cI.bBitsPerPixel = 1; cI.bPlanes = 1;
763            cI.ptHotSpot.x = cI.ptHotSpot.y = 15;
764            cI.nWidth = 32; cI.nHeight = 32;
765            cI.nWidthBytes = 4;  /* 32x1bpp */
766
767            maxx = (pIcon->nWidth > 32) ? 32 : pIcon->nWidth;
768            maxy = (pIcon->nHeight > 32) ? 32 : pIcon->nHeight;
769
770            for( iy = 0; iy < maxy; iy++ )
771            {
772               unsigned shift = iy % 2; 
773
774               memcpy( pAndBits + iy * 4, (BYTE *)(pIcon + 1) + iy * and_width, 
775                                          (and_width > 4) ? 4 : and_width );
776               for( ix = 0; ix < maxx; ix++ )
777               {
778                 if( bSemiTransparent && ((ix+shift)%2) )
779                 {
780                     /* set AND bit, XOR bit stays 0 */
781
782                     pbc = pAndBits + iy * 4 + ix/8;
783                    *pbc |= 0x80 >> (ix%8);
784                 }
785                 else
786                 {
787                     /* keep AND bit, set XOR bit */
788
789                   unsigned *psc = (unsigned*)(psPtr + (ix * bpp)/8);
790                   unsigned  val = ((*psc) >> (ix * bpp)%8) & val_base;
791                   col = COLOR_ToLogical(val);
792                   if( (GetRValue(col) + GetGValue(col) + GetBValue(col)) > 0x180 )
793                   {
794                     pbc = pxbPtr + ix/8;
795                    *pbc |= 0x80 >> (ix%8);
796                   }
797                 }
798               }
799               psPtr += xor_width;
800               pxbPtr += 4;
801            }
802
803            hRet = CreateCursorIconIndirect( pTask->hInstance , &cI, pAndBits, pXorBits);
804
805            if( !hRet ) /* fall back on default drag cursor */
806                 hRet = CURSORICON_Copy( pTask->hInstance ,
807                               CURSORICON_Load16(0,MAKEINTRESOURCE16(OCR_DRAGOBJECT),
808                                          SYSMETRICS_CXCURSOR, SYSMETRICS_CYCURSOR, 1, TRUE, 0) );
809        }
810
811  return hRet;
812 }
813
814
815 /***********************************************************************
816  *           LoadCursor16    (USER.173)
817  */
818 HCURSOR16 WINAPI LoadCursor16( HINSTANCE16 hInstance, SEGPTR name )
819 {
820     if (HIWORD(name))
821         TRACE(cursor, "%04x '%s'\n",
822                         hInstance, (char *)PTR_SEG_TO_LIN( name ) );
823     else
824         TRACE(cursor, "%04x %04x\n",
825                         hInstance, LOWORD(name) );
826
827     return CURSORICON_Load16( hInstance, name,
828                               SYSMETRICS_CXCURSOR, SYSMETRICS_CYCURSOR, 1, TRUE, 0);
829 }
830
831
832 /***********************************************************************
833  *           LoadIcon16    (USER.174)
834  */
835 HICON16 WINAPI LoadIcon16( HINSTANCE16 hInstance, SEGPTR name )
836 {
837     if (HIWORD(name))
838         TRACE(icon, "%04x '%s'\n",
839                       hInstance, (char *)PTR_SEG_TO_LIN( name ) );
840     else
841         TRACE(icon, "%04x %04x\n",
842                       hInstance, LOWORD(name) );
843
844     return CURSORICON_Load16( hInstance, name,
845                               SYSMETRICS_CXICON, SYSMETRICS_CYICON,
846                               MIN( 16, COLOR_GetSystemPaletteSize() ), FALSE, 0);
847 }
848
849
850 /***********************************************************************
851  *           CreateCursor16    (USER.406)
852  */
853 HCURSOR16 WINAPI CreateCursor16( HINSTANCE16 hInstance,
854                                  INT16 xHotSpot, INT16 yHotSpot,
855                                  INT16 nWidth, INT16 nHeight,
856                                  LPCVOID lpANDbits, LPCVOID lpXORbits )
857 {
858     CURSORICONINFO info = { { xHotSpot, yHotSpot }, nWidth, nHeight, 0, 1, 1 };
859
860     TRACE(cursor, "%dx%d spot=%d,%d xor=%p and=%p\n",
861                     nWidth, nHeight, xHotSpot, yHotSpot, lpXORbits, lpANDbits);
862     return CreateCursorIconIndirect( hInstance, &info, lpANDbits, lpXORbits );
863 }
864
865
866 /***********************************************************************
867  *           CreateCursor32    (USER32.67)
868  */
869 HCURSOR32 WINAPI CreateCursor32( HINSTANCE32 hInstance,
870                                  INT32 xHotSpot, INT32 yHotSpot,
871                                  INT32 nWidth, INT32 nHeight,
872                                  LPCVOID lpANDbits, LPCVOID lpXORbits )
873 {
874     CURSORICONINFO info = { { xHotSpot, yHotSpot }, nWidth, nHeight, 0, 1, 1 };
875
876     TRACE(cursor, "%dx%d spot=%d,%d xor=%p and=%p\n",
877                     nWidth, nHeight, xHotSpot, yHotSpot, lpXORbits, lpANDbits);
878     return CreateCursorIconIndirect( 0, &info, lpANDbits, lpXORbits );
879 }
880
881
882 /***********************************************************************
883  *           CreateIcon16    (USER.407)
884  */
885 HICON16 WINAPI CreateIcon16( HINSTANCE16 hInstance, INT16 nWidth,
886                              INT16 nHeight, BYTE bPlanes, BYTE bBitsPixel,
887                              LPCVOID lpANDbits, LPCVOID lpXORbits )
888 {
889     CURSORICONINFO info = { { 0, 0 }, nWidth, nHeight, 0, bPlanes, bBitsPixel};
890
891     TRACE(icon, "%dx%dx%d, xor=%p, and=%p\n",
892                   nWidth, nHeight, bPlanes * bBitsPixel, lpXORbits, lpANDbits);
893     return CreateCursorIconIndirect( hInstance, &info, lpANDbits, lpXORbits );
894 }
895
896
897 /***********************************************************************
898  *           CreateIcon32    (USER32.75)
899  */
900 HICON32 WINAPI CreateIcon32( HINSTANCE32 hInstance, INT32 nWidth,
901                              INT32 nHeight, BYTE bPlanes, BYTE bBitsPixel,
902                              LPCVOID lpANDbits, LPCVOID lpXORbits )
903 {
904     CURSORICONINFO info = { { 0, 0 }, nWidth, nHeight, 0, bPlanes, bBitsPixel};
905
906     TRACE(icon, "%dx%dx%d, xor=%p, and=%p\n",
907                   nWidth, nHeight, bPlanes * bBitsPixel, lpXORbits, lpANDbits);
908     return CreateCursorIconIndirect( 0, &info, lpANDbits, lpXORbits );
909 }
910
911
912 /***********************************************************************
913  *           CreateCursorIconIndirect    (USER.408)
914  */
915 HGLOBAL16 WINAPI CreateCursorIconIndirect( HINSTANCE16 hInstance,
916                                            CURSORICONINFO *info,
917                                            LPCVOID lpANDbits,
918                                            LPCVOID lpXORbits )
919 {
920     HGLOBAL16 handle;
921     char *ptr;
922     int sizeAnd, sizeXor;
923
924     hInstance = GetExePtr( hInstance );  /* Make it a module handle */
925     if (!lpXORbits || !lpANDbits || info->bPlanes != 1) return 0;
926     info->nWidthBytes = BITMAP_GetWidthBytes(info->nWidth,info->bBitsPerPixel);
927     sizeXor = info->nHeight * info->nWidthBytes;
928     sizeAnd = info->nHeight * BITMAP_GetWidthBytes( info->nWidth, 1 );
929     if (!(handle = GlobalAlloc16( GMEM_MOVEABLE,
930                                   sizeof(CURSORICONINFO) + sizeXor + sizeAnd)))
931         return 0;
932     if (hInstance) FarSetOwner( handle, hInstance );
933     ptr = (char *)GlobalLock16( handle );
934     memcpy( ptr, info, sizeof(*info) );
935     memcpy( ptr + sizeof(CURSORICONINFO), lpANDbits, sizeAnd );
936     memcpy( ptr + sizeof(CURSORICONINFO) + sizeAnd, lpXORbits, sizeXor );
937     GlobalUnlock16( handle );
938     return handle;
939 }
940
941
942 /***********************************************************************
943  *           CopyIcon16    (USER.368)
944  */
945 HICON16 WINAPI CopyIcon16( HINSTANCE16 hInstance, HICON16 hIcon )
946 {
947     TRACE(icon, "%04x %04x\n", hInstance, hIcon );
948     return CURSORICON_Copy( hInstance, hIcon );
949 }
950
951
952 /***********************************************************************
953  *           CopyIcon32    (USER32.60)
954  */
955 HICON32 WINAPI CopyIcon32( HICON32 hIcon )
956 {
957   HTASK16 hTask = GetCurrentTask ();
958   TDB* pTask = (TDB *) GlobalLock16 (hTask);
959     TRACE(icon, "%04x\n", hIcon );
960   return CURSORICON_Copy( pTask->hInstance, hIcon );
961 }
962
963
964 /***********************************************************************
965  *           CopyCursor16    (USER.369)
966  */
967 HCURSOR16 WINAPI CopyCursor16( HINSTANCE16 hInstance, HCURSOR16 hCursor )
968 {
969     TRACE(cursor, "%04x %04x\n", hInstance, hCursor );
970     return CURSORICON_Copy( hInstance, hCursor );
971 }
972
973
974 /***********************************************************************
975  *           DestroyIcon16    (USER.457)
976  */
977 BOOL16 WINAPI DestroyIcon16( HICON16 hIcon )
978 {
979     TRACE(icon, "%04x\n", hIcon );
980     /* FIXME: should check for OEM/global heap icon here */
981     return (FreeResource16( hIcon ) == 0);
982 }
983
984
985 /***********************************************************************
986  *           DestroyIcon32    (USER32.133)
987  */
988 BOOL32 WINAPI DestroyIcon32( HICON32 hIcon )
989 {
990     TRACE(icon, "%04x\n", hIcon );
991     /* FIXME: should check for OEM/global heap icon here */
992     /* Unlike DestroyIcon16, only icons created with CreateIcon32
993        are valid for DestroyIcon32, so don't use FreeResource32 */
994     return (GlobalFree16( hIcon ) == 0);
995 }
996
997
998 /***********************************************************************
999  *           DestroyCursor16    (USER.458)
1000  */
1001 BOOL16 WINAPI DestroyCursor16( HCURSOR16 hCursor )
1002 {
1003     TRACE(cursor, "%04x\n", hCursor );
1004     if (FreeResource16( hCursor ) == 0)
1005       return TRUE;
1006     else
1007       /* I believe this very same line should be added for every function
1008          where appears the comment:
1009
1010          "FIXME: should check for OEM/global heap cursor here"
1011
1012          which are most (all?) the ones that call FreeResource, at least
1013          in this module. Maybe this should go to a wrapper to avoid
1014          repetition. Or: couldn't it go to FreeResoutce itself?
1015          
1016          I'll let this to someone savvy on the subject.
1017          */
1018       return (GlobalFree16 (hCursor) == 0);
1019 }
1020
1021
1022 /***********************************************************************
1023  *           DestroyCursor32    (USER32.132)
1024  */
1025 BOOL32 WINAPI DestroyCursor32( HCURSOR32 hCursor )
1026 {
1027     TRACE(cursor, "%04x\n", hCursor );
1028     /* FIXME: should check for OEM/global heap cursor here */
1029     /* Unlike DestroyCursor16, only cursors created with CreateCursor32
1030        are valid for DestroyCursor32, so don't use FreeResource32 */
1031     return (GlobalFree16( hCursor ) == 0);
1032 }
1033
1034
1035 /***********************************************************************
1036  *           DrawIcon16    (USER.84)
1037  */
1038 BOOL16 WINAPI DrawIcon16( HDC16 hdc, INT16 x, INT16 y, HICON16 hIcon )
1039 {
1040     return DrawIcon32( hdc, x, y, hIcon );
1041 }
1042
1043
1044 /***********************************************************************
1045  *           DrawIcon32    (USER32.159)
1046  */
1047 BOOL32 WINAPI DrawIcon32( HDC32 hdc, INT32 x, INT32 y, HICON32 hIcon )
1048 {
1049     CURSORICONINFO *ptr;
1050     HDC32 hMemDC;
1051     HBITMAP32 hXorBits, hAndBits;
1052     COLORREF oldFg, oldBg;
1053
1054     if (!(ptr = (CURSORICONINFO *)GlobalLock16( hIcon ))) return FALSE;
1055     if (!(hMemDC = CreateCompatibleDC32( hdc ))) return FALSE;
1056     hAndBits = CreateBitmap32( ptr->nWidth, ptr->nHeight, 1, 1,
1057                                (char *)(ptr+1) );
1058     hXorBits = CreateBitmap32( ptr->nWidth, ptr->nHeight, ptr->bPlanes,
1059                                ptr->bBitsPerPixel, (char *)(ptr + 1)
1060                         + ptr->nHeight * BITMAP_GetWidthBytes(ptr->nWidth,1) );
1061     oldFg = SetTextColor32( hdc, RGB(0,0,0) );
1062     oldBg = SetBkColor32( hdc, RGB(255,255,255) );
1063
1064     if (hXorBits && hAndBits)
1065     {
1066         HBITMAP32 hBitTemp = SelectObject32( hMemDC, hAndBits );
1067         BitBlt32( hdc, x, y, ptr->nWidth, ptr->nHeight, hMemDC, 0, 0, SRCAND );
1068         SelectObject32( hMemDC, hXorBits );
1069         BitBlt32(hdc, x, y, ptr->nWidth, ptr->nHeight, hMemDC, 0, 0,SRCINVERT);
1070         SelectObject32( hMemDC, hBitTemp );
1071     }
1072     DeleteDC32( hMemDC );
1073     if (hXorBits) DeleteObject32( hXorBits );
1074     if (hAndBits) DeleteObject32( hAndBits );
1075     GlobalUnlock16( hIcon );
1076     SetTextColor32( hdc, oldFg );
1077     SetBkColor32( hdc, oldBg );
1078     return TRUE;
1079 }
1080
1081
1082 /***********************************************************************
1083  *           DumpIcon    (USER.459)
1084  */
1085 DWORD WINAPI DumpIcon( SEGPTR pInfo, WORD *lpLen,
1086                        SEGPTR *lpXorBits, SEGPTR *lpAndBits )
1087 {
1088     CURSORICONINFO *info = PTR_SEG_TO_LIN( pInfo );
1089     int sizeAnd, sizeXor;
1090
1091     if (!info) return 0;
1092     sizeXor = info->nHeight * info->nWidthBytes;
1093     sizeAnd = info->nHeight * BITMAP_GetWidthBytes( info->nWidth, 1 );
1094     if (lpAndBits) *lpAndBits = pInfo + sizeof(CURSORICONINFO);
1095     if (lpXorBits) *lpXorBits = pInfo + sizeof(CURSORICONINFO) + sizeAnd;
1096     if (lpLen) *lpLen = sizeof(CURSORICONINFO) + sizeAnd + sizeXor;
1097     return MAKELONG( sizeXor, sizeXor );
1098 }
1099
1100
1101 /***********************************************************************
1102  *           CURSORICON_SetCursor
1103  *
1104  * Change the X cursor. Helper function for SetCursor() and ShowCursor().
1105  * The Xlib critical section must be entered before calling this function.
1106  */
1107 static BOOL32 CURSORICON_SetCursor( HCURSOR16 hCursor )
1108 {
1109     Pixmap pixmapBits, pixmapMask, pixmapAll;
1110     XColor fg, bg;
1111     Cursor cursor = None;
1112
1113     if (!hCursor)  /* Create an empty cursor */
1114     {
1115         static const char data[] = { 0 };
1116
1117         bg.red = bg.green = bg.blue = 0x0000;
1118         pixmapBits = XCreateBitmapFromData( display, rootWindow, data, 1, 1 );
1119         if (pixmapBits)
1120         {
1121             cursor = XCreatePixmapCursor( display, pixmapBits, pixmapBits,
1122                                           &bg, &bg, 0, 0 );
1123             XFreePixmap( display, pixmapBits );
1124         }
1125     }
1126     else  /* Create the X cursor from the bits */
1127     {
1128         CURSORICONINFO *ptr;
1129         XImage *image;
1130
1131         if (!(ptr = (CURSORICONINFO*)GlobalLock16( hCursor ))) return FALSE;
1132         if (ptr->bPlanes * ptr->bBitsPerPixel != 1)
1133         {
1134             WARN(cursor, "Cursor %04x has more than 1 bpp!\n", hCursor );
1135             return FALSE;
1136         }
1137
1138         /* Create a pixmap and transfer all the bits to it */
1139
1140         /* NOTE: Following hack works, but only because XFree depth
1141          *       1 images really use 1 bit/pixel (and so the same layout
1142          *       as the Windows cursor data). Perhaps use a more generic
1143          *       algorithm here.
1144          */
1145         pixmapAll = XCreatePixmap( display, rootWindow,
1146                                    ptr->nWidth, ptr->nHeight * 2, 1 );
1147         image = XCreateImage( display, DefaultVisualOfScreen(screen),
1148                               1, ZPixmap, 0, (char *)(ptr + 1), ptr->nWidth,
1149                               ptr->nHeight * 2, 16, ptr->nWidthBytes);
1150         if (image)
1151         {
1152             image->byte_order = MSBFirst;
1153             image->bitmap_bit_order = MSBFirst;
1154             image->bitmap_unit = 16;
1155             _XInitImageFuncPtrs(image);
1156             if (pixmapAll)
1157                 XPutImage( display, pixmapAll, BITMAP_monoGC, image,
1158                            0, 0, 0, 0, ptr->nWidth, ptr->nHeight * 2 );
1159             image->data = NULL;
1160             XDestroyImage( image );
1161         }
1162
1163         /* Now create the 2 pixmaps for bits and mask */
1164
1165         pixmapBits = XCreatePixmap( display, rootWindow,
1166                                     ptr->nWidth, ptr->nHeight, 1 );
1167         pixmapMask = XCreatePixmap( display, rootWindow,
1168                                     ptr->nWidth, ptr->nHeight, 1 );
1169
1170         /* Make sure everything went OK so far */
1171
1172         if (pixmapBits && pixmapMask && pixmapAll)
1173         {
1174             /* We have to do some magic here, as cursors are not fully
1175              * compatible between Windows and X11. Under X11, there
1176              * are only 3 possible color cursor: black, white and
1177              * masked. So we map the 4th Windows color (invert the
1178              * bits on the screen) to black. This require some boolean
1179              * arithmetic:
1180              *
1181              *         Windows          |          X11
1182              * Xor    And      Result   |   Bits     Mask     Result
1183              *  0      0     black      |    0        1     background
1184              *  0      1     no change  |    X        0     no change
1185              *  1      0     white      |    1        1     foreground
1186              *  1      1     inverted   |    0        1     background
1187              *
1188              * which gives:
1189              *  Bits = 'Xor' and not 'And'
1190              *  Mask = 'Xor' or not 'And'
1191              *
1192              * FIXME: apparently some servers do support 'inverted' color.
1193              * I don't know if it's correct per the X spec, but maybe
1194              * we ought to take advantage of it.  -- AJ
1195              */
1196             XCopyArea( display, pixmapAll, pixmapBits, BITMAP_monoGC,
1197                        0, 0, ptr->nWidth, ptr->nHeight, 0, 0 );
1198             XCopyArea( display, pixmapAll, pixmapMask, BITMAP_monoGC,
1199                        0, 0, ptr->nWidth, ptr->nHeight, 0, 0 );
1200             XSetFunction( display, BITMAP_monoGC, GXandReverse );
1201             XCopyArea( display, pixmapAll, pixmapBits, BITMAP_monoGC,
1202                        0, ptr->nHeight, ptr->nWidth, ptr->nHeight, 0, 0 );
1203             XSetFunction( display, BITMAP_monoGC, GXorReverse );
1204             XCopyArea( display, pixmapAll, pixmapMask, BITMAP_monoGC,
1205                        0, ptr->nHeight, ptr->nWidth, ptr->nHeight, 0, 0 );
1206             XSetFunction( display, BITMAP_monoGC, GXcopy );
1207             fg.red = fg.green = fg.blue = 0xffff;
1208             bg.red = bg.green = bg.blue = 0x0000;
1209             cursor = XCreatePixmapCursor( display, pixmapBits, pixmapMask,
1210                                 &fg, &bg, ptr->ptHotSpot.x, ptr->ptHotSpot.y );
1211         }
1212
1213         /* Now free everything */
1214
1215         if (pixmapAll) XFreePixmap( display, pixmapAll );
1216         if (pixmapBits) XFreePixmap( display, pixmapBits );
1217         if (pixmapMask) XFreePixmap( display, pixmapMask );
1218         GlobalUnlock16( hCursor );
1219     }
1220
1221     if (cursor == None) return FALSE;
1222     if (CURSORICON_XCursor != None) XFreeCursor( display, CURSORICON_XCursor );
1223     CURSORICON_XCursor = cursor;
1224
1225     if (rootWindow != DefaultRootWindow(display))
1226     {
1227         /* Set the cursor on the desktop window */
1228         XDefineCursor( display, rootWindow, cursor );
1229     }
1230     else
1231     {
1232         /* Set the same cursor for all top-level windows */
1233         HWND32 hwnd = GetWindow32( GetDesktopWindow32(), GW_CHILD );
1234         while(hwnd)
1235         {
1236             Window win = WIN_GetXWindow( hwnd );
1237             if (win && win!=DefaultRootWindow(display))
1238                 XDefineCursor( display, win, cursor );
1239             hwnd = GetWindow32( hwnd, GW_HWNDNEXT );
1240         }
1241     }
1242     return TRUE;
1243 }
1244
1245
1246 /***********************************************************************
1247  *           SetCursor16    (USER.69)
1248  */
1249 HCURSOR16 WINAPI SetCursor16( HCURSOR16 hCursor )
1250 {
1251     return (HCURSOR16)SetCursor32( hCursor );
1252 }
1253
1254
1255 /***********************************************************************
1256  *           SetCursor32    (USER32.472)
1257  * RETURNS:
1258  *      A handle to the previous cursor shape.
1259  */
1260 HCURSOR32 WINAPI SetCursor32(
1261                  HCURSOR32 hCursor /* Handle of cursor to show */
1262 ) {
1263     HCURSOR32 hOldCursor;
1264
1265     if (hCursor == hActiveCursor) return hActiveCursor;  /* No change */
1266     TRACE(cursor, "%04x\n", hCursor );
1267     hOldCursor = hActiveCursor;
1268     hActiveCursor = hCursor;
1269     /* Change the cursor shape only if it is visible */
1270     if (CURSOR_ShowCount >= 0)
1271     {
1272         EnterCriticalSection( &X11DRV_CritSection );
1273         CALL_LARGE_STACK( CURSORICON_SetCursor, hActiveCursor );
1274         LeaveCriticalSection( &X11DRV_CritSection );
1275     }
1276     return hOldCursor;
1277 }
1278
1279
1280 /***********************************************************************
1281  *           SetCursorPos16    (USER.70)
1282  */
1283 void WINAPI SetCursorPos16( INT16 x, INT16 y )
1284 {
1285     SetCursorPos32( x, y );
1286 }
1287
1288
1289 /***********************************************************************
1290  *           SetCursorPos32    (USER32.474)
1291  */
1292 BOOL32 WINAPI SetCursorPos32( INT32 x, INT32 y )
1293 {
1294     TRACE(cursor, "x=%d y=%d\n", x, y );
1295     TSXWarpPointer( display, rootWindow, rootWindow, 0, 0, 0, 0, x, y );
1296     return TRUE;
1297 }
1298
1299
1300 /***********************************************************************
1301  *           ShowCursor16    (USER.71)
1302  */
1303 INT16 WINAPI ShowCursor16( BOOL16 bShow )
1304 {
1305     return ShowCursor32( bShow );
1306 }
1307
1308
1309 /***********************************************************************
1310  *           ShowCursor32    (USER32.530)
1311  */
1312 INT32 WINAPI ShowCursor32( BOOL32 bShow )
1313 {
1314     TRACE(cursor, "%d, count=%d\n",
1315                     bShow, CURSOR_ShowCount );
1316
1317     EnterCriticalSection( &X11DRV_CritSection );
1318     if (bShow)
1319     {
1320         if (++CURSOR_ShowCount == 0)  /* Show it */
1321             CALL_LARGE_STACK( CURSORICON_SetCursor, hActiveCursor );
1322     }
1323     else
1324     {
1325         if (--CURSOR_ShowCount == -1)  /* Hide it */
1326             CALL_LARGE_STACK( CURSORICON_SetCursor, 0 );
1327     }
1328     LeaveCriticalSection( &X11DRV_CritSection );
1329     return CURSOR_ShowCount;
1330 }
1331
1332
1333 /***********************************************************************
1334  *           GetCursor16    (USER.247)
1335  */
1336 HCURSOR16 WINAPI GetCursor16(void)
1337 {
1338     return hActiveCursor;
1339 }
1340
1341
1342 /***********************************************************************
1343  *           GetCursor32    (USER32.227)
1344  */
1345 HCURSOR32 WINAPI GetCursor32(void)
1346 {
1347     return hActiveCursor;
1348 }
1349
1350
1351 /***********************************************************************
1352  *           ClipCursor16    (USER.16)
1353  */
1354 BOOL16 WINAPI ClipCursor16( const RECT16 *rect )
1355 {
1356     if (!rect) SetRectEmpty32( &CURSOR_ClipRect );
1357     else CONV_RECT16TO32( rect, &CURSOR_ClipRect );
1358     return TRUE;
1359 }
1360
1361
1362 /***********************************************************************
1363  *           ClipCursor32    (USER32.53)
1364  */
1365 BOOL32 WINAPI ClipCursor32( const RECT32 *rect )
1366 {
1367     if (!rect) SetRectEmpty32( &CURSOR_ClipRect );
1368     else CopyRect32( &CURSOR_ClipRect, rect );
1369     return TRUE;
1370 }
1371
1372
1373 /***********************************************************************
1374  *           GetCursorPos16    (USER.17)
1375  */
1376 void WINAPI GetCursorPos16( POINT16 *pt )
1377 {
1378     Window root, child;
1379     int rootX, rootY, childX, childY;
1380     unsigned int mousebut;
1381
1382     if (!pt) return;
1383     if (!TSXQueryPointer( display, rootWindow, &root, &child,
1384                         &rootX, &rootY, &childX, &childY, &mousebut ))
1385         pt->x = pt->y = 0;
1386     else
1387     {
1388         pt->x = childX;
1389         pt->y = childY;
1390         if (mousebut & Button1Mask)
1391             AsyncMouseButtonsStates[0] = MouseButtonsStates[0] = TRUE;
1392         else
1393             MouseButtonsStates[0] = FALSE;
1394         if (mousebut & Button2Mask)
1395             AsyncMouseButtonsStates[1] = MouseButtonsStates[1] = TRUE;
1396         else       
1397             MouseButtonsStates[1] = FALSE;
1398         if (mousebut & Button3Mask)
1399             AsyncMouseButtonsStates[2] = MouseButtonsStates[2] = TRUE;
1400         else
1401             MouseButtonsStates[2] = FALSE;
1402     }
1403     TRACE(cursor, "ret=%d,%d\n", pt->x, pt->y );
1404 }
1405
1406
1407 /***********************************************************************
1408  *           GetCursorPos32    (USER32.229)
1409  */
1410 void WINAPI GetCursorPos32( POINT32 *pt )
1411 {
1412     POINT16 pt16;
1413     GetCursorPos16( &pt16 );
1414     if (pt) CONV_POINT16TO32( &pt16, pt );
1415 }
1416
1417
1418 /***********************************************************************
1419  *           GetClipCursor16    (USER.309)
1420  */
1421 void WINAPI GetClipCursor16( RECT16 *rect )
1422 {
1423     if (rect) CONV_RECT32TO16( &CURSOR_ClipRect, rect );
1424 }
1425
1426
1427 /***********************************************************************
1428  *           GetClipCursor32    (USER32.221)
1429  */
1430 void WINAPI GetClipCursor32( RECT32 *rect )
1431 {
1432     if (rect) CopyRect32( rect, &CURSOR_ClipRect );
1433 }
1434
1435 /**********************************************************************
1436  *          LookupIconIdFromDirectoryEx16       (USER.364)
1437  *
1438  * FIXME: exact parameter sizes
1439  */
1440 INT16 WINAPI LookupIconIdFromDirectoryEx16( LPBYTE xdir, BOOL16 bIcon,
1441              INT16 width, INT16 height, UINT16 cFlag )
1442 {
1443     CURSORICONDIR       *dir = (CURSORICONDIR*)xdir;
1444     UINT16 retVal = 0;
1445     if( dir && !dir->idReserved && (dir->idType & 3) )
1446     {
1447         int colors = (cFlag & LR_MONOCHROME) ? 2 : COLOR_GetSystemPaletteSize();
1448         if( bIcon )
1449         {
1450             ICONDIRENTRY* entry;
1451             entry = CURSORICON_FindBestIcon( dir, width, height, colors );
1452             if( entry ) retVal = entry->wResId;
1453         }
1454         else
1455         {
1456             CURSORDIRENTRY* entry;
1457             entry = CURSORICON_FindBestCursor( dir, width, height, 1);
1458             if( entry ) retVal = entry->wResId;
1459         }
1460     }
1461     else WARN(cursor, "invalid resource directory\n");
1462     return retVal;
1463 }
1464
1465 /**********************************************************************
1466  *          LookupIconIdFromDirectoryEx32       (USER32.380)
1467  */
1468 INT32 WINAPI LookupIconIdFromDirectoryEx32( LPBYTE dir, BOOL32 bIcon,
1469              INT32 width, INT32 height, UINT32 cFlag )
1470 {
1471     return LookupIconIdFromDirectoryEx16( dir, bIcon, width, height, cFlag );
1472 }
1473
1474 /**********************************************************************
1475  *          LookupIconIdFromDirectory           (USER.???)
1476  */
1477 INT16 WINAPI LookupIconIdFromDirectory16( LPBYTE dir, BOOL16 bIcon )
1478 {
1479     return LookupIconIdFromDirectoryEx16( dir, bIcon, 
1480            bIcon ? SYSMETRICS_CXICON : SYSMETRICS_CXCURSOR,
1481            bIcon ? SYSMETRICS_CYICON : SYSMETRICS_CYCURSOR, bIcon ? 0 : LR_MONOCHROME );
1482 }
1483
1484 /**********************************************************************
1485  *          LookupIconIdFromDirectory           (USER32.379)
1486  */
1487 INT32 WINAPI LookupIconIdFromDirectory32( LPBYTE dir, BOOL32 bIcon )
1488 {
1489     return LookupIconIdFromDirectoryEx32( dir, bIcon, 
1490            bIcon ? SYSMETRICS_CXICON : SYSMETRICS_CXCURSOR,
1491            bIcon ? SYSMETRICS_CYICON : SYSMETRICS_CYCURSOR, bIcon ? 0 : LR_MONOCHROME );
1492 }
1493
1494 /**********************************************************************
1495  *          GetIconID    (USER.455)
1496  */
1497 WORD WINAPI GetIconID( HGLOBAL16 hResource, DWORD resType )
1498 {
1499     LPBYTE lpDir = (LPBYTE)GlobalLock16(hResource);
1500
1501     TRACE(cursor, "hRes=%04x, entries=%i\n",
1502                     hResource, lpDir ? ((CURSORICONDIR*)lpDir)->idCount : 0);
1503
1504     switch(resType)
1505     {
1506         case RT_CURSOR16:
1507              return (WORD)LookupIconIdFromDirectoryEx16( lpDir, FALSE, 
1508                           SYSMETRICS_CXCURSOR, SYSMETRICS_CYCURSOR, LR_MONOCHROME );
1509         case RT_ICON16:
1510              return (WORD)LookupIconIdFromDirectoryEx16( lpDir, TRUE,
1511                           SYSMETRICS_CXICON, SYSMETRICS_CYICON, 0 );
1512         default:
1513              WARN(cursor, "invalid res type %ld\n", resType );
1514     }
1515     return 0;
1516 }
1517
1518 /**********************************************************************
1519  *          LoadCursorIconHandler    (USER.336)
1520  *
1521  * Supposed to load resources of Windows 2.x applications.
1522  */
1523 HGLOBAL16 WINAPI LoadCursorIconHandler( HGLOBAL16 hResource, HMODULE16 hModule, HRSRC16 hRsrc )
1524 {
1525     FIXME(cursor,"(%04x,%04x,%04x): old 2.x resources are not supported!\n", 
1526           hResource, hModule, hRsrc);
1527     return (HGLOBAL16)0;
1528 }
1529
1530 /**********************************************************************
1531  *          LoadDIBIconHandler    (USER.357)
1532  * 
1533  * RT_ICON resource loader, installed by USER_SignalProc when module
1534  * is initialized.
1535  */
1536 HGLOBAL16 WINAPI LoadDIBIconHandler( HGLOBAL16 hMemObj, HMODULE16 hModule, HRSRC16 hRsrc )
1537 {
1538     /* If hResource is zero we must allocate a new memory block, if it's
1539      * non-zero but GlobalLock() returns NULL then it was discarded and
1540      * we have to recommit some memory, otherwise we just need to check 
1541      * the block size. See LoadProc() in 16-bit SDK for more.
1542      */
1543
1544      hMemObj = USER_CallDefaultRsrcHandler( hMemObj, hModule, hRsrc );
1545      if( hMemObj )
1546      {
1547          LPBYTE bits = (LPBYTE)GlobalLock16( hMemObj );
1548          hMemObj = CURSORICON_CreateFromResource( hModule, hMemObj, bits, 
1549                    SizeofResource16(hModule, hRsrc), TRUE, 0x00030000, 
1550                    SYSMETRICS_CXICON, SYSMETRICS_CYICON, LR_DEFAULTCOLOR );
1551      }
1552      return hMemObj;
1553 }
1554
1555 /**********************************************************************
1556  *          LoadDIBCursorHandler    (USER.356)
1557  *
1558  * RT_CURSOR resource loader. Same as above.
1559  */
1560 HGLOBAL16 WINAPI LoadDIBCursorHandler( HGLOBAL16 hMemObj, HMODULE16 hModule, HRSRC16 hRsrc )
1561 {
1562     hMemObj = USER_CallDefaultRsrcHandler( hMemObj, hModule, hRsrc );
1563     if( hMemObj )
1564     {
1565         LPBYTE bits = (LPBYTE)GlobalLock16( hMemObj );
1566         hMemObj = CURSORICON_CreateFromResource( hModule, hMemObj, bits,
1567                   SizeofResource16(hModule, hRsrc), FALSE, 0x00030000,
1568                   SYSMETRICS_CXCURSOR, SYSMETRICS_CYCURSOR, LR_MONOCHROME );
1569     }
1570     return hMemObj;
1571 }
1572
1573 /**********************************************************************
1574  *          LoadIconHandler    (USER.456)
1575  */
1576 HICON16 WINAPI LoadIconHandler( HGLOBAL16 hResource, BOOL16 bNew )
1577 {
1578     LPBYTE bits = (LPBYTE)LockResource16( hResource );
1579
1580     TRACE(cursor,"hRes=%04x\n",hResource);
1581
1582     return CURSORICON_CreateFromResource( 0, 0, bits, 0, TRUE, 
1583                       bNew ? 0x00030000 : 0x00020000, 0, 0, LR_DEFAULTCOLOR );
1584 }
1585
1586 /***********************************************************************
1587  *           LoadCursorW                (USER32.362)
1588  */
1589 HCURSOR32 WINAPI LoadCursor32W(HINSTANCE32 hInstance, LPCWSTR name)
1590 {
1591     return CURSORICON_Load32( hInstance, name,
1592                               SYSMETRICS_CXCURSOR, SYSMETRICS_CYCURSOR, 1, TRUE, 0);
1593 }
1594
1595 /***********************************************************************
1596  *           LoadCursorA                (USER32.359)
1597  */
1598 HCURSOR32 WINAPI LoadCursor32A(HINSTANCE32 hInstance, LPCSTR name)
1599 {
1600         HCURSOR32 res=0;
1601         if(!HIWORD(name))
1602                 return LoadCursor32W(hInstance,(LPCWSTR)name);
1603         else
1604         {
1605             LPWSTR uni = HEAP_strdupAtoW( GetProcessHeap(), 0, name );
1606             res = LoadCursor32W(hInstance, uni);
1607             HeapFree( GetProcessHeap(), 0, uni);
1608         }
1609         return res;
1610 }
1611 /***********************************************************************
1612 *            LoadCursorFromFile32W    (USER32.361)
1613 */
1614 HCURSOR32 WINAPI LoadCursorFromFile32W (LPCWSTR name)
1615 {
1616     return LoadImage32W(0, name, IMAGE_CURSOR, SYSMETRICS_CXCURSOR,
1617       SYSMETRICS_CYCURSOR, LR_LOADFROMFILE);
1618 }
1619
1620 /***********************************************************************
1621 *            LoadCursorFromFile32A    (USER32.360)
1622 */
1623 HCURSOR32 WINAPI LoadCursorFromFile32A (LPCSTR name)
1624 {
1625     HCURSOR32 hcur;
1626     LPWSTR u_name = HEAP_strdupAtoW( GetProcessHeap(), 0, name );
1627     hcur = LoadCursorFromFile32W(u_name);
1628     HeapFree( GetProcessHeap(), 0, u_name );
1629     return hcur;
1630 }
1631   
1632 /***********************************************************************
1633  *           LoadIconW          (USER32.364)
1634  */
1635 HICON32 WINAPI LoadIcon32W(HINSTANCE32 hInstance, LPCWSTR name)
1636 {
1637     return CURSORICON_Load32( hInstance, name,
1638                               SYSMETRICS_CXICON, SYSMETRICS_CYICON,
1639                               MIN( 16, COLOR_GetSystemPaletteSize() ), FALSE, 0);
1640 }
1641
1642 /***********************************************************************
1643  *           LoadIconA          (USER32.363)
1644  */
1645 HICON32 WINAPI LoadIcon32A(HINSTANCE32 hInstance, LPCSTR name)
1646 {
1647     HICON32 res=0;
1648
1649     if( !HIWORD(name) )
1650         return LoadIcon32W(hInstance, (LPCWSTR)name);
1651     else
1652     {
1653         LPWSTR uni = HEAP_strdupAtoW( GetProcessHeap(), 0, name );
1654         res = LoadIcon32W( hInstance, uni );
1655         HeapFree( GetProcessHeap(), 0, uni );
1656     }
1657     return res;
1658 }
1659
1660 /**********************************************************************
1661  *          GetIconInfo         (USER32.242)
1662  */
1663 BOOL32 WINAPI GetIconInfo(HICON32 hIcon,LPICONINFO iconinfo) {
1664     CURSORICONINFO      *ciconinfo;
1665
1666     ciconinfo = GlobalLock16(hIcon);
1667     if (!ciconinfo)
1668         return FALSE;
1669     iconinfo->xHotspot = ciconinfo->ptHotSpot.x;
1670     iconinfo->yHotspot = ciconinfo->ptHotSpot.y;
1671     iconinfo->fIcon    = TRUE; /* hmm */
1672
1673     iconinfo->hbmColor = CreateBitmap32 ( ciconinfo->nWidth, ciconinfo->nHeight,
1674                                 ciconinfo->bPlanes, ciconinfo->bBitsPerPixel,
1675                                 (char *)(ciconinfo + 1)
1676                                 + ciconinfo->nHeight *
1677                                 BITMAP_GetWidthBytes (ciconinfo->nWidth,1) );
1678     iconinfo->hbmMask = CreateBitmap32 ( ciconinfo->nWidth, ciconinfo->nHeight,
1679                                 1, 1, (char *)(ciconinfo + 1));
1680
1681     GlobalUnlock16(hIcon);
1682
1683     return TRUE;
1684 }
1685
1686 /**********************************************************************
1687  *          CreateIconIndirect          (USER32.78)
1688  */
1689 HICON32 WINAPI CreateIconIndirect(LPICONINFO iconinfo) {
1690     BITMAPOBJ *bmpXor,*bmpAnd;
1691     HICON32 hObj;
1692     int sizeXor,sizeAnd;
1693
1694     bmpXor = (BITMAPOBJ *) GDI_GetObjPtr( iconinfo->hbmColor, BITMAP_MAGIC );
1695     bmpAnd = (BITMAPOBJ *) GDI_GetObjPtr( iconinfo->hbmMask, BITMAP_MAGIC );
1696
1697     sizeXor = bmpXor->bitmap.bmHeight * bmpXor->bitmap.bmWidthBytes;
1698     sizeAnd = bmpAnd->bitmap.bmHeight * bmpAnd->bitmap.bmWidthBytes;
1699
1700     hObj = GlobalAlloc16( GMEM_MOVEABLE, 
1701                      sizeof(CURSORICONINFO) + sizeXor + sizeAnd );
1702     if (hObj)
1703     {
1704         CURSORICONINFO *info;
1705
1706         info = (CURSORICONINFO *)GlobalLock16( hObj );
1707         info->ptHotSpot.x   = iconinfo->xHotspot;
1708         info->ptHotSpot.y   = iconinfo->yHotspot;
1709         info->nWidth        = bmpXor->bitmap.bmWidth;
1710         info->nHeight       = bmpXor->bitmap.bmHeight;
1711         info->nWidthBytes   = bmpXor->bitmap.bmWidthBytes;
1712         info->bPlanes       = bmpXor->bitmap.bmPlanes;
1713         info->bBitsPerPixel = bmpXor->bitmap.bmBitsPixel;
1714
1715         /* Transfer the bitmap bits to the CURSORICONINFO structure */
1716
1717         GetBitmapBits32( iconinfo->hbmMask ,sizeAnd,(char*)(info + 1) );
1718         GetBitmapBits32( iconinfo->hbmColor,sizeXor,(char*)(info + 1) +sizeAnd);
1719         GlobalUnlock16( hObj );
1720     }
1721     return hObj;
1722 }
1723
1724
1725 /**********************************************************************
1726  *          
1727  DrawIconEx16           (USER.394)
1728  */
1729 BOOL16 WINAPI DrawIconEx16 (HDC16 hdc, INT16 xLeft, INT16 yTop, HICON16 hIcon,
1730                             INT16 cxWidth, INT16 cyWidth, UINT16 istep,
1731                             HBRUSH16 hbr, UINT16 flags)
1732 {
1733     return DrawIconEx32(hdc, xLeft, yTop, hIcon, cxWidth, cyWidth,
1734                         istep, hbr, flags);
1735 }
1736
1737
1738 /******************************************************************************
1739  * DrawIconEx32 [USER32.160]  Draws an icon or cursor on device context
1740  *
1741  * NOTES
1742  *    Why is this using SM_CXICON instead of SM_CXCURSOR?
1743  *
1744  * PARAMS
1745  *    hdc     [I] Handle to device context
1746  *    x0      [I] X coordinate of upper left corner
1747  *    y0      [I] Y coordinate of upper left corner
1748  *    hIcon   [I] Handle to icon to draw
1749  *    cxWidth [I] Width of icon
1750  *    cyWidth [I] Height of icon
1751  *    istep   [I] Index of frame in animated cursor
1752  *    hbr     [I] Handle to background brush
1753  *    flags   [I] Icon-drawing flags
1754  *
1755  * RETURNS
1756  *    Success: TRUE
1757  *    Failure: FALSE
1758  */
1759 BOOL32 WINAPI DrawIconEx32( HDC32 hdc, INT32 x0, INT32 y0, HICON32 hIcon,
1760                             INT32 cxWidth, INT32 cyWidth, UINT32 istep, 
1761                             HBRUSH32 hbr, UINT32 flags )
1762 {
1763     CURSORICONINFO *ptr = (CURSORICONINFO *)GlobalLock16 (hIcon);
1764     HDC32 hDC_off = 0, hMemDC = CreateCompatibleDC32 (hdc);
1765     BOOL32 result = FALSE, DoOffscreen = FALSE;
1766     HBITMAP32 hB_off = 0, hOld = 0;
1767
1768     if (!ptr) return FALSE;
1769
1770     if (istep)
1771         FIXME(icon, "Ignoring istep=%d\n", istep);
1772     if (flags & DI_COMPAT)
1773         FIXME(icon, "Ignoring flag DI_COMPAT\n");
1774
1775     /* Calculate the size of the destination image.  */
1776     if (cxWidth == 0)
1777     {
1778       if (flags & DI_DEFAULTSIZE)
1779         cxWidth = GetSystemMetrics32 (SM_CXICON);
1780       else
1781         cxWidth = ptr->nWidth;
1782     }
1783     if (cyWidth == 0)
1784     {
1785       if (flags & DI_DEFAULTSIZE)
1786         cyWidth = GetSystemMetrics32 (SM_CYICON);
1787       else
1788         cyWidth = ptr->nHeight;
1789     }
1790
1791     if (!(DoOffscreen = (hbr >= STOCK_WHITE_BRUSH) && (hbr <= 
1792       STOCK_HOLLOW_BRUSH)))
1793     {
1794         GDIOBJHDR *object = (GDIOBJHDR *) GDI_HEAP_LOCK(hbr);
1795         if (object)
1796         {
1797             UINT16 magic = object->wMagic;
1798             GDI_HEAP_UNLOCK(hbr);
1799             DoOffscreen = magic == BRUSH_MAGIC;
1800         }
1801     }
1802     if (DoOffscreen) {
1803       RECT32 r = {0, 0, cxWidth, cxWidth};
1804
1805       hDC_off = CreateCompatibleDC32(hdc);
1806       hB_off = CreateCompatibleBitmap32(hdc, cxWidth, cyWidth);
1807       if (hDC_off && hB_off) {
1808         hOld = SelectObject32(hDC_off, hB_off);
1809         FillRect32(hDC_off, &r, hbr);
1810       }
1811     };
1812
1813     if (hMemDC && (!DoOffscreen || (hDC_off && hB_off)))
1814     {
1815         HBITMAP32 hXorBits, hAndBits;
1816         COLORREF  oldFg, oldBg;
1817         INT32     nStretchMode;
1818
1819         nStretchMode = SetStretchBltMode32 (hdc, STRETCH_DELETESCANS);
1820
1821         hXorBits = CreateBitmap32 ( ptr->nWidth, ptr->nHeight,
1822                                     ptr->bPlanes, ptr->bBitsPerPixel,
1823                                     (char *)(ptr + 1)
1824                                     + ptr->nHeight *
1825                                     BITMAP_GetWidthBytes(ptr->nWidth,1) );
1826         hAndBits = CreateBitmap32 ( ptr->nWidth, ptr->nHeight,
1827                                     1, 1, (char *)(ptr+1) );
1828         oldFg = SetTextColor32( hdc, RGB(0,0,0) );
1829         oldBg = SetBkColor32( hdc, RGB(255,255,255) );
1830
1831         if (hXorBits && hAndBits)
1832         {
1833             HBITMAP32 hBitTemp = SelectObject32( hMemDC, hAndBits );
1834             if (flags & DI_MASK)
1835             {
1836               if (DoOffscreen) 
1837                 StretchBlt32 (hDC_off, 0, 0, cxWidth, cyWidth,
1838                               hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCAND);
1839               else 
1840                 StretchBlt32 (hdc, x0, y0, cxWidth, cyWidth,
1841                               hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCAND);
1842             }
1843             SelectObject32( hMemDC, hXorBits );
1844             if (flags & DI_IMAGE)
1845             {
1846               if (DoOffscreen) 
1847                 StretchBlt32 (hDC_off, 0, 0, cxWidth, cyWidth,
1848                           hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCPAINT);
1849               else
1850                 StretchBlt32 (hdc, x0, y0, cxWidth, cyWidth,
1851                               hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCPAINT);
1852             }
1853             SelectObject32( hMemDC, hBitTemp );
1854             result = TRUE;
1855         }
1856
1857         SetTextColor32( hdc, oldFg );
1858         SetBkColor32( hdc, oldBg );
1859         if (hXorBits) DeleteObject32( hXorBits );
1860         if (hAndBits) DeleteObject32( hAndBits );
1861         SetStretchBltMode32 (hdc, nStretchMode);
1862         if (DoOffscreen) {
1863           BitBlt32(hdc, x0, y0, cxWidth, cyWidth, hDC_off, 0, 0, SRCCOPY);
1864           SelectObject32(hDC_off, hOld);
1865         }
1866     }
1867     if (hMemDC) DeleteDC32( hMemDC );
1868     if (hDC_off) DeleteDC32(hDC_off);
1869     if (hB_off) DeleteObject32(hB_off);
1870     GlobalUnlock16( hIcon );
1871     return result;
1872 }