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