Fixed ANSI compabillity.
[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 "sysmetrics.h"
44 #include "global.h"
45 #include "module.h"
46 #include "debug.h"
47 #include "task.h"
48 #include "user.h"
49 #include "input.h"
50 #include "display.h"
51 #include "message.h"
52 #include "winerror.h"
53
54 DECLARE_DEBUG_CHANNEL(cursor)
55 DECLARE_DEBUG_CHANNEL(icon)
56
57 static HCURSOR hActiveCursor = 0;  /* Active cursor */
58 static INT CURSOR_ShowCount = 0;   /* Cursor display count */
59 static RECT CURSOR_ClipRect;       /* Cursor clipping rect */
60
61
62 /**********************************************************************
63  * ICONCACHE for cursors/icons loaded with LR_SHARED.
64  *
65  * FIXME: This should not be allocated on the system heap, but on a
66  *        subsystem-global heap (i.e. one for all Win16 processes,
67  *        and one each for every Win32 process).
68  */
69 typedef struct tagICONCACHE
70 {
71     struct tagICONCACHE *next;
72
73     HMODULE              hModule;
74     HRSRC                hRsrc;
75     HANDLE               handle;
76
77     INT                  count;
78
79 } ICONCACHE;
80
81 static ICONCACHE *IconAnchor = NULL;
82 static CRITICAL_SECTION IconCrst;
83
84 /**********************************************************************
85  *          CURSORICON_Init
86  */
87 void CURSORICON_Init( void )
88 {
89     InitializeCriticalSection( &IconCrst );
90     MakeCriticalSectionGlobal( &IconCrst );
91 }
92
93 /**********************************************************************
94  *          CURSORICON_FindSharedIcon
95  */
96 static HANDLE CURSORICON_FindSharedIcon( HMODULE hModule, HRSRC hRsrc )
97 {
98     HANDLE handle = 0;
99     ICONCACHE *ptr;
100
101     EnterCriticalSection( &IconCrst );
102
103     for ( ptr = IconAnchor; ptr; ptr = ptr->next )
104         if ( ptr->hModule == hModule && ptr->hRsrc == hRsrc )
105         {
106             ptr->count++;
107             handle = ptr->handle;
108             break;
109         }
110
111     LeaveCriticalSection( &IconCrst );
112
113     return handle;
114 }
115
116 /**********************************************************************
117  *          CURSORICON_AddSharedIcon
118  */
119 static void CURSORICON_AddSharedIcon( HMODULE hModule, HRSRC hRsrc, HANDLE handle )
120 {
121     ICONCACHE *ptr = HeapAlloc( SystemHeap, 0, sizeof(ICONCACHE) );
122     if ( !ptr ) return;
123
124     ptr->hModule = hModule;
125     ptr->hRsrc   = hRsrc;
126     ptr->handle  = handle;
127     ptr->count   = 1;
128
129     EnterCriticalSection( &IconCrst );
130     ptr->next    = IconAnchor;
131     IconAnchor   = ptr;
132     LeaveCriticalSection( &IconCrst );
133 }
134
135 /**********************************************************************
136  *          CURSORICON_DelSharedIcon
137  */
138 static INT CURSORICON_DelSharedIcon( HANDLE handle )
139 {
140     INT count = -1;
141     ICONCACHE *ptr;
142
143     EnterCriticalSection( &IconCrst );
144
145     for ( ptr = IconAnchor; ptr; ptr = ptr->next )
146         if ( ptr->handle == handle )
147         {
148             if ( ptr->count > 0 ) ptr->count--;
149             count = ptr->count;
150             break;
151         }
152
153     LeaveCriticalSection( &IconCrst );
154
155     return count;
156 }
157
158 /**********************************************************************
159  *          CURSORICON_FreeModuleIcons
160  */
161 void CURSORICON_FreeModuleIcons( HMODULE hModule )
162 {
163     ICONCACHE **ptr = &IconAnchor;
164
165     if ( HIWORD( hModule ) )
166         hModule = MapHModuleLS( hModule );
167     else
168         hModule = GetExePtr( hModule );
169
170     EnterCriticalSection( &IconCrst );
171
172     while ( *ptr )
173     {
174         if ( (*ptr)->hModule == hModule )
175         {
176             ICONCACHE *freePtr = *ptr;
177             *ptr = freePtr->next;
178             
179             GlobalFree16( freePtr->handle );
180             HeapFree( SystemHeap, 0, freePtr );
181             continue;
182         }
183         ptr = &(*ptr)->next;
184     }
185
186     LeaveCriticalSection( &IconCrst );
187 }
188
189 /**********************************************************************
190  *          CURSORICON_FindBestIcon
191  *
192  * Find the icon closest to the requested size and number of colors.
193  */
194 static CURSORICONDIRENTRY *CURSORICON_FindBestIcon( CURSORICONDIR *dir, int width,
195                                               int height, int colors )
196 {
197     int i, maxcolors, maxwidth, maxheight;
198     CURSORICONDIRENTRY *entry, *bestEntry = NULL;
199
200     if (dir->idCount < 1)
201     {
202         WARN(icon, "Empty directory!\n" );
203         return NULL;
204     }
205     if (dir->idCount == 1) return &dir->idEntries[0];  /* No choice... */
206
207     /* First find the exact size with less colors */
208
209     maxcolors = 0;
210     for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
211         if ((entry->ResInfo.icon.bWidth == width) && (entry->ResInfo.icon.bHeight == height) &&
212             (entry->ResInfo.icon.bColorCount <= colors) && (entry->ResInfo.icon.bColorCount > maxcolors))
213         {
214             bestEntry = entry;
215             maxcolors = entry->ResInfo.icon.bColorCount;
216         }
217     if (bestEntry) return bestEntry;
218
219     /* First find the exact size with more colors */
220
221     maxcolors = 255;
222     for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
223         if ((entry->ResInfo.icon.bWidth == width) && (entry->ResInfo.icon.bHeight == height) &&
224             (entry->ResInfo.icon.bColorCount > colors) && (entry->ResInfo.icon.bColorCount <= maxcolors))
225         {
226             bestEntry = entry;
227             maxcolors = entry->ResInfo.icon.bColorCount;
228         }
229     if (bestEntry) return bestEntry;
230
231     /* Now find a smaller one with less colors */
232
233     maxcolors = maxwidth = maxheight = 0;
234     for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
235         if ((entry->ResInfo.icon.bWidth <= width) && (entry->ResInfo.icon.bHeight <= height) &&
236             (entry->ResInfo.icon.bWidth >= maxwidth) && (entry->ResInfo.icon.bHeight >= maxheight) &&
237             (entry->ResInfo.icon.bColorCount <= colors) && (entry->ResInfo.icon.bColorCount > maxcolors))
238         {
239             bestEntry = entry;
240             maxwidth  = entry->ResInfo.icon.bWidth;
241             maxheight = entry->ResInfo.icon.bHeight;
242             maxcolors = entry->ResInfo.icon.bColorCount;
243         }
244     if (bestEntry) return bestEntry;
245
246     /* Now find a smaller one with more colors */
247
248     maxcolors = 255;
249     maxwidth = maxheight = 0;
250     for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
251         if ((entry->ResInfo.icon.bWidth <= width) && (entry->ResInfo.icon.bHeight <= height) &&
252             (entry->ResInfo.icon.bWidth >= maxwidth) && (entry->ResInfo.icon.bHeight >= maxheight) &&
253             (entry->ResInfo.icon.bColorCount > colors) && (entry->ResInfo.icon.bColorCount <= maxcolors))
254         {
255             bestEntry = entry;
256             maxwidth  = entry->ResInfo.icon.bWidth;
257             maxheight = entry->ResInfo.icon.bHeight;
258             maxcolors = entry->ResInfo.icon.bColorCount;
259         }
260     if (bestEntry) return bestEntry;
261
262     /* Now find a larger one with less colors */
263
264     maxcolors = 0;
265     maxwidth = maxheight = 255;
266     for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
267         if ((entry->ResInfo.icon.bWidth <= maxwidth) && (entry->ResInfo.icon.bHeight <= maxheight) &&
268             (entry->ResInfo.icon.bColorCount <= colors) && (entry->ResInfo.icon.bColorCount > maxcolors))
269         {
270             bestEntry = entry;
271             maxwidth  = entry->ResInfo.icon.bWidth;
272             maxheight = entry->ResInfo.icon.bHeight;
273             maxcolors = entry->ResInfo.icon.bColorCount;
274         }
275     if (bestEntry) return bestEntry;
276
277     /* Now find a larger one with more colors */
278
279     maxcolors = maxwidth = maxheight = 255;
280     for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
281         if ((entry->ResInfo.icon.bWidth <= maxwidth) && (entry->ResInfo.icon.bHeight <= maxheight) &&
282             (entry->ResInfo.icon.bColorCount > colors) && (entry->ResInfo.icon.bColorCount <= maxcolors))
283         {
284             bestEntry = entry;
285             maxwidth  = entry->ResInfo.icon.bWidth;
286             maxheight = entry->ResInfo.icon.bHeight;
287             maxcolors = entry->ResInfo.icon.bColorCount;
288         }
289
290     return bestEntry;
291 }
292
293
294 /**********************************************************************
295  *          CURSORICON_FindBestCursor
296  *
297  * Find the cursor closest to the requested size.
298  * FIXME: parameter 'color' ignored and entries with more than 1 bpp
299  *        ignored too
300  */
301 static CURSORICONDIRENTRY *CURSORICON_FindBestCursor( CURSORICONDIR *dir,
302                                                   int width, int height, int color)
303 {
304     int i, maxwidth, maxheight;
305     CURSORICONDIRENTRY *entry, *bestEntry = NULL;
306
307     if (dir->idCount < 1)
308     {
309         WARN(cursor, "Empty directory!\n" );
310         return NULL;
311     }
312     if (dir->idCount == 1) return &dir->idEntries[0]; /* No choice... */
313
314     /* First find the largest one smaller than or equal to the requested size*/
315
316     maxwidth = maxheight = 0;
317     for(i = 0,entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
318         if ((entry->ResInfo.cursor.wWidth <= width) && (entry->ResInfo.cursor.wHeight <= height) &&
319             (entry->ResInfo.cursor.wWidth > maxwidth) && (entry->ResInfo.cursor.wHeight > maxheight) &&
320             (entry->wBitCount == 1))
321         {
322             bestEntry = entry;
323             maxwidth  = entry->ResInfo.cursor.wWidth;
324             maxheight = entry->ResInfo.cursor.wHeight;
325         }
326     if (bestEntry) return bestEntry;
327
328     /* Now find the smallest one larger than the requested size */
329
330     maxwidth = maxheight = 255;
331     for(i = 0,entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
332         if ((entry->ResInfo.cursor.wWidth < maxwidth) && (entry->ResInfo.cursor.wHeight < maxheight) &&
333             (entry->wBitCount == 1))
334         {
335             bestEntry = entry;
336             maxwidth  = entry->ResInfo.cursor.wWidth;
337             maxheight = entry->ResInfo.cursor.wHeight;
338         }
339
340     return bestEntry;
341 }
342
343 /*********************************************************************
344  * The main purpose of this function is to create fake resource directory
345  * and fake resource entries. There are several reasons for this:
346  *      -       CURSORICONDIR and CURSORICONFILEDIR differ in sizes and their
347  *              fields
348  *      There are some "bad" cursor files which do not have
349  *              bColorCount initialized but instead one must read this info
350  *              directly from corresponding DIB sections
351  * Note: wResId is index to array of pointer returned in ptrs (origin is 1)
352  */
353 BOOL CURSORICON_SimulateLoadingFromResourceW( LPWSTR filename, BOOL fCursor,
354                                                 CURSORICONDIR **res, LPBYTE **ptr)
355 {
356     LPBYTE   _free;
357     CURSORICONFILEDIR *bits;
358     int      entries, size, i;
359
360     *res = NULL;
361     *ptr = NULL;
362     if (!(bits = (CURSORICONFILEDIR *)VIRTUAL_MapFileW( filename ))) return FALSE;
363
364     /* FIXME: test for inimated icons
365      * hack to load the first icon from the *.ani file
366      */
367     if ( *(LPDWORD)bits==0x46464952 ) /* "RIFF" */
368     { LPBYTE pos = (LPBYTE) bits;
369       FIXME (cursor,"Animated icons not correctly implemented! %p \n", bits);
370         
371       for (;;)
372       { if (*(LPDWORD)pos==0x6e6f6369)          /* "icon" */
373         { FIXME (cursor,"icon entry found! %p\n", bits);
374           pos+=4;
375           if ( !*(LPWORD) pos==0x2fe)           /* iconsize */
376           { goto fail;
377           }
378           bits+=2;
379           FIXME (cursor,"icon size ok %p \n", bits);
380           break;
381         }
382         pos+=2;
383         if (pos>=(LPBYTE)bits+766) goto fail;
384       }
385     }
386     if (!(entries = bits->idCount)) goto fail;
387     size = sizeof(CURSORICONDIR) + sizeof(CURSORICONDIRENTRY) * (entries - 1);
388     _free = (LPBYTE) size;
389
390     for (i=0; i < entries; i++)
391       size += bits->idEntries[i].dwDIBSize + (fCursor ? sizeof(POINT16): 0);
392     
393     if (!(*ptr = HeapAlloc( GetProcessHeap(), 0,
394                             entries * sizeof (CURSORICONDIRENTRY*)))) goto fail;
395     if (!(*res = HeapAlloc( GetProcessHeap(), 0, size))) goto fail;
396
397     _free = (LPBYTE)(*res) + (int)_free;
398     memcpy((*res), bits, 6);
399     for (i=0; i<entries; i++)
400     {
401       ((LPBYTE*)(*ptr))[i] = _free;
402       if (fCursor) {
403         (*res)->idEntries[i].ResInfo.cursor.wWidth=bits->idEntries[i].bWidth;
404         (*res)->idEntries[i].ResInfo.cursor.wHeight=bits->idEntries[i].bHeight;
405         ((LPPOINT16)_free)->x=bits->idEntries[i].xHotspot;
406         ((LPPOINT16)_free)->y=bits->idEntries[i].yHotspot;
407         _free+=sizeof(POINT16);
408       } else {
409         (*res)->idEntries[i].ResInfo.icon.bWidth=bits->idEntries[i].bWidth;
410         (*res)->idEntries[i].ResInfo.icon.bHeight=bits->idEntries[i].bHeight;
411         (*res)->idEntries[i].ResInfo.icon.bColorCount = bits->idEntries[i].bColorCount;
412       }
413       (*res)->idEntries[i].wPlanes=1;
414       (*res)->idEntries[i].wBitCount = ((LPBITMAPINFOHEADER)((LPBYTE)bits +
415                                                    bits->idEntries[i].dwDIBOffset))->biBitCount;
416       (*res)->idEntries[i].dwBytesInRes = bits->idEntries[i].dwDIBSize;
417       (*res)->idEntries[i].wResId=i+1;
418
419       memcpy(_free,(LPBYTE)bits +bits->idEntries[i].dwDIBOffset,
420              (*res)->idEntries[i].dwBytesInRes);
421       _free += (*res)->idEntries[i].dwBytesInRes;
422     }
423     UnmapViewOfFile( bits );
424     return TRUE;    
425 fail:
426     if (*res) HeapFree( GetProcessHeap(), 0, *res );
427     if (*ptr) HeapFree( GetProcessHeap(), 0, *ptr );
428     UnmapViewOfFile( bits );
429     return FALSE;
430 }
431
432
433 /**********************************************************************
434  *          CURSORICON_CreateFromResource
435  *
436  * Create a cursor or icon from in-memory resource template. 
437  *
438  * FIXME: Convert to mono when cFlag is LR_MONOCHROME. Do something
439  *        with cbSize parameter as well.
440  */
441 static HGLOBAL16 CURSORICON_CreateFromResource( HINSTANCE16 hInstance, HGLOBAL16 hObj, LPBYTE bits,
442                                                 UINT cbSize, BOOL bIcon, DWORD dwVersion, 
443                                                 INT width, INT height, UINT loadflags )
444 {
445     int sizeAnd, sizeXor;
446     HBITMAP hAndBits = 0, hXorBits = 0; /* error condition for later */
447     BITMAPOBJ *bmpXor, *bmpAnd;
448     POINT16 hotspot = { 0 ,0 };
449     BITMAPINFO *bmi;
450     HDC hdc;
451     BOOL DoStretch;
452     INT size;
453
454     TRACE(cursor,"%08x (%u bytes), ver %08x, %ix%i %s %s\n",
455                         (unsigned)bits, cbSize, (unsigned)dwVersion, width, height,
456                                   bIcon ? "icon" : "cursor", (loadflags & LR_MONOCHROME) ? "mono" : "" );
457     if (dwVersion == 0x00020000)
458     {
459         FIXME(cursor,"\t2.xx resources are not supported\n");
460         return 0;
461     }
462
463     if (bIcon)
464         bmi = (BITMAPINFO *)bits;
465     else /* get the hotspot */
466     {
467         POINT16 *pt = (POINT16 *)bits;
468         hotspot = *pt;
469         bmi = (BITMAPINFO *)(pt + 1);
470     }
471     size = DIB_BitmapInfoSize( bmi, DIB_RGB_COLORS );
472
473     if (!width) width = bmi->bmiHeader.biWidth;
474     if (!height) height = bmi->bmiHeader.biHeight/2;
475     DoStretch = (bmi->bmiHeader.biHeight/2 != height) ||
476       (bmi->bmiHeader.biWidth != width);
477
478     /* Check bitmap header */
479
480     if ( (bmi->bmiHeader.biSize != sizeof(BITMAPCOREHEADER)) &&
481          (bmi->bmiHeader.biSize != sizeof(BITMAPINFOHEADER)  ||
482           bmi->bmiHeader.biCompression != BI_RGB) )
483     {
484           WARN(cursor,"\tinvalid resource bitmap header.\n");
485           return 0;
486     }
487
488     if( (hdc = GetDC( 0 )) )
489     {
490         BITMAPINFO* pInfo;
491
492         /* Make sure we have room for the monochrome bitmap later on.
493          * Note that BITMAPINFOINFO and BITMAPCOREHEADER are the same
494          * up to and including the biBitCount. In-memory icon resource 
495          * format is as follows:
496          *
497          *   BITMAPINFOHEADER   icHeader  // DIB header
498          *   RGBQUAD         icColors[]   // Color table
499          *   BYTE            icXOR[]      // DIB bits for XOR mask
500          *   BYTE            icAND[]      // DIB bits for AND mask
501          */
502
503         if ((pInfo = (BITMAPINFO *)HeapAlloc( GetProcessHeap(), 0, 
504           MAX(size, sizeof(BITMAPINFOHEADER) + 2*sizeof(RGBQUAD)))))
505         {       
506             memcpy( pInfo, bmi, size ); 
507             pInfo->bmiHeader.biHeight /= 2;
508
509             /* Create the XOR bitmap */
510
511             if (DoStretch) {
512               if ((hXorBits = CreateCompatibleBitmap(hdc, width, height))) {
513                 HBITMAP hOld;
514                 HDC hMem = CreateCompatibleDC(hdc);
515                 BOOL res;
516
517                 if (hMem) {
518                   hOld = SelectObject(hMem, hXorBits);
519                   res = StretchDIBits(hMem, 0, 0, width, height, 0, 0,
520                     bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight/2,
521                     (char*)bmi + size, pInfo, DIB_RGB_COLORS, SRCCOPY);
522                   SelectObject(hMem, hOld);
523                   DeleteDC(hMem);
524                 } else res = FALSE;
525                 if (!res) { DeleteObject(hXorBits); hXorBits = 0; }
526               }
527             } else hXorBits = CreateDIBitmap( hdc, &pInfo->bmiHeader,
528                 CBM_INIT, (char*)bmi + size, pInfo, DIB_RGB_COLORS );
529             if( hXorBits )
530             {
531                 char* bits = (char *)bmi + size +
532                         DIB_GetDIBImageBytes(bmi->bmiHeader.biWidth,
533                                              bmi->bmiHeader.biHeight,
534                                              bmi->bmiHeader.biBitCount) / 2;
535
536                 pInfo->bmiHeader.biBitCount = 1;
537                 if (pInfo->bmiHeader.biSize == sizeof(BITMAPINFOHEADER))
538                 {
539                     RGBQUAD *rgb = pInfo->bmiColors;
540
541                     pInfo->bmiHeader.biClrUsed = pInfo->bmiHeader.biClrImportant = 2;
542                     rgb[0].rgbBlue = rgb[0].rgbGreen = rgb[0].rgbRed = 0x00;
543                     rgb[1].rgbBlue = rgb[1].rgbGreen = rgb[1].rgbRed = 0xff;
544                     rgb[0].rgbReserved = rgb[1].rgbReserved = 0;
545                 }
546                 else
547                 {
548                     RGBTRIPLE *rgb = (RGBTRIPLE *)(((BITMAPCOREHEADER *)pInfo) + 1);
549
550                     rgb[0].rgbtBlue = rgb[0].rgbtGreen = rgb[0].rgbtRed = 0x00;
551                     rgb[1].rgbtBlue = rgb[1].rgbtGreen = rgb[1].rgbtRed = 0xff;
552                 }
553
554                 /* Create the AND bitmap */
555
556             if (DoStretch) {
557               if ((hAndBits = CreateBitmap(width, height, 1, 1, NULL))) {
558                 HBITMAP hOld;
559                 HDC hMem = CreateCompatibleDC(hdc);
560                 BOOL res;
561
562                 if (hMem) {
563                   hOld = SelectObject(hMem, hAndBits);
564                   res = StretchDIBits(hMem, 0, 0, width, height, 0, 0,
565                     pInfo->bmiHeader.biWidth, pInfo->bmiHeader.biHeight,
566                     bits, pInfo, DIB_RGB_COLORS, SRCCOPY);
567                   SelectObject(hMem, hOld);
568                   DeleteDC(hMem);
569                 } else res = FALSE;
570                 if (!res) { DeleteObject(hAndBits); hAndBits = 0; }
571               }
572             } else hAndBits = CreateDIBitmap( hdc, &pInfo->bmiHeader,
573               CBM_INIT, bits, pInfo, DIB_RGB_COLORS );
574
575                 if( !hAndBits ) DeleteObject( hXorBits );
576             }
577             HeapFree( GetProcessHeap(), 0, pInfo ); 
578         }
579         ReleaseDC( 0, hdc );
580     }
581
582     if( !hXorBits || !hAndBits ) 
583     {
584         WARN(cursor,"\tunable to create an icon bitmap.\n");
585         return 0;
586     }
587
588     /* Now create the CURSORICONINFO structure */
589     bmpXor = (BITMAPOBJ *) GDI_GetObjPtr( hXorBits, BITMAP_MAGIC );
590     bmpAnd = (BITMAPOBJ *) GDI_GetObjPtr( hAndBits, BITMAP_MAGIC );
591     sizeXor = bmpXor->bitmap.bmHeight * bmpXor->bitmap.bmWidthBytes;
592     sizeAnd = bmpAnd->bitmap.bmHeight * bmpAnd->bitmap.bmWidthBytes;
593
594     if (hObj) hObj = GlobalReAlloc16( hObj, 
595                      sizeof(CURSORICONINFO) + sizeXor + sizeAnd, GMEM_MOVEABLE );
596     if (!hObj) hObj = GlobalAlloc16( GMEM_MOVEABLE, 
597                      sizeof(CURSORICONINFO) + sizeXor + sizeAnd );
598     if (hObj)
599     {
600         CURSORICONINFO *info;
601
602         /* Make it owned by the module */
603         if (hInstance) FarSetOwner16( hObj, GetExePtr(hInstance) );
604
605         info = (CURSORICONINFO *)GlobalLock16( hObj );
606         info->ptHotSpot.x   = hotspot.x;
607         info->ptHotSpot.y   = hotspot.y;
608         info->nWidth        = bmpXor->bitmap.bmWidth;
609         info->nHeight       = bmpXor->bitmap.bmHeight;
610         info->nWidthBytes   = bmpXor->bitmap.bmWidthBytes;
611         info->bPlanes       = bmpXor->bitmap.bmPlanes;
612         info->bBitsPerPixel = bmpXor->bitmap.bmBitsPixel;
613
614         /* Transfer the bitmap bits to the CURSORICONINFO structure */
615
616         GetBitmapBits( hAndBits, sizeAnd, (char *)(info + 1) );
617         GetBitmapBits( hXorBits, sizeXor, (char *)(info + 1) + sizeAnd );
618         GlobalUnlock16( hObj );
619     }
620
621     DeleteObject( hXorBits );
622     DeleteObject( hAndBits );
623     return hObj;
624 }
625
626
627 /**********************************************************************
628  *          CreateIconFromResourceEx16          (USER.450)
629  *
630  * FIXME: not sure about exact parameter types
631  */
632 HICON16 WINAPI CreateIconFromResourceEx16( LPBYTE bits, UINT16 cbSize, BOOL16 bIcon,
633                                     DWORD dwVersion, INT16 width, INT16 height, UINT16 cFlag )
634 {
635     return CreateIconFromResourceEx(bits, cbSize, bIcon, dwVersion, 
636       width, height, cFlag);
637 }
638
639
640 /**********************************************************************
641  *          CreateIconFromResource          (USER32.76)
642  */
643 HICON WINAPI CreateIconFromResource( LPBYTE bits, UINT cbSize,
644                                            BOOL bIcon, DWORD dwVersion)
645 {
646     return CreateIconFromResourceEx( bits, cbSize, bIcon, dwVersion, 0,0,0);
647 }
648
649
650 /**********************************************************************
651  *          CreateIconFromResourceEx32          (USER32.77)
652  */
653 HICON WINAPI CreateIconFromResourceEx( LPBYTE bits, UINT cbSize,
654                                            BOOL bIcon, DWORD dwVersion,
655                                            INT width, INT height,
656                                            UINT cFlag )
657 {
658     TDB* pTask = (TDB*)GlobalLock16( GetCurrentTask() );
659     if( pTask )
660         return CURSORICON_CreateFromResource( pTask->hInstance, 0, bits, cbSize, bIcon, dwVersion,
661                                               width, height, cFlag );
662     return 0;
663 }
664
665 /**********************************************************************
666  *          CURSORICON_Load
667  *
668  * Load a cursor or icon from resource or file.
669  */
670 HGLOBAL CURSORICON_Load( HINSTANCE hInstance, LPCWSTR name,
671                          INT width, INT height, INT colors,
672                          BOOL fCursor, UINT loadflags )
673 {
674     HANDLE handle = 0, h = 0;
675     HANDLE hRsrc;
676     CURSORICONDIR *dir;
677     CURSORICONDIRENTRY *dirEntry;
678     LPBYTE bits;
679
680     if ( loadflags & LR_LOADFROMFILE )    /* Load from file */
681     {
682         LPBYTE *ptr;
683         if (!CURSORICON_SimulateLoadingFromResourceW((LPWSTR)name, fCursor, &dir, &ptr))
684             return 0;
685         if (fCursor)
686             dirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestCursor(dir, width, height, 1);
687         else
688             dirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestIcon(dir, width, height, colors);
689         bits = ptr[dirEntry->wResId-1];
690         h = CURSORICON_CreateFromResource( 0, 0, bits, dirEntry->dwBytesInRes, 
691                                            !fCursor, 0x00030000, width, height, loadflags);
692         HeapFree( GetProcessHeap(), 0, dir );
693         HeapFree( GetProcessHeap(), 0, ptr );
694     }
695
696     else if ( !hInstance )  /* Load OEM cursor/icon */
697     {
698         WORD resid;
699         HDC hdc;
700         DC *dc;
701
702         if ( HIWORD(name) )
703         {
704             LPSTR ansi = HEAP_strdupWtoA(GetProcessHeap(),0,name);
705             if( ansi[0]=='#')        /*Check for '#xxx' name */
706             {
707                 resid = atoi(ansi+1);
708                 HeapFree( GetProcessHeap(), 0, ansi );
709             }
710             else
711             {
712                 HeapFree( GetProcessHeap(), 0, ansi );
713                 return 0;
714             }
715         }
716         else resid = LOWORD(name);
717         hdc = CreateDCA( "DISPLAY", NULL, NULL, NULL );
718         dc = DC_GetDCPtr( hdc );
719         if (dc->funcs->pLoadOEMResource)
720             h = dc->funcs->pLoadOEMResource( resid, fCursor ?
721                                                     OEM_CURSOR : OEM_ICON );
722         GDI_HEAP_UNLOCK( hdc );
723         DeleteDC(  hdc );
724     }
725
726     else  /* Load from resource */
727     {
728         WORD wResId;
729         DWORD dwBytesInRes;
730
731         /* Normalize hInstance (must be uniquely represented for icon cache) */
732         
733         if ( HIWORD( hInstance ) )
734             hInstance = MapHModuleLS( hInstance );
735         else
736             hInstance = GetExePtr( hInstance );
737
738         /* Get directory resource ID */
739
740         if (!(hRsrc = FindResourceW( hInstance, name,
741                           fCursor ? RT_GROUP_CURSORW : RT_GROUP_ICONW )))
742             return 0;
743
744         /* If shared icon, check whether it was already loaded */
745
746         if (    (loadflags & LR_SHARED) 
747              && (h = CURSORICON_FindSharedIcon( hInstance, hRsrc ) ) != 0 )
748             return h;
749
750         /* Find the best entry in the directory */
751  
752         if (!(handle = LoadResource( hInstance, hRsrc ))) return 0;
753         if (!(dir = (CURSORICONDIR*)LockResource( handle ))) return 0;
754         if (fCursor)
755             dirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestCursor( dir,
756                                                               width, height, 1);
757         else
758             dirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestIcon( dir,
759                                                        width, height, colors );
760         if (!dirEntry) return 0;
761         wResId = dirEntry->wResId;
762         dwBytesInRes = dirEntry->dwBytesInRes;
763         FreeResource( handle );
764
765         /* Load the resource */
766
767         if (!(hRsrc = FindResourceW(hInstance,MAKEINTRESOURCEW(wResId),
768                                       fCursor ? RT_CURSORW : RT_ICONW ))) return 0;
769         if (!(handle = LoadResource( hInstance, hRsrc ))) return 0;
770         bits = (LPBYTE)LockResource( handle );
771         h = CURSORICON_CreateFromResource( 0, 0, bits, dwBytesInRes, 
772                                            !fCursor, 0x00030000, width, height, loadflags);
773         FreeResource( handle );
774
775         /* If shared icon, add to icon cache */
776
777         if ( h && (loadflags & LR_SHARED) )
778             CURSORICON_AddSharedIcon( hInstance, hRsrc, h );
779     }
780
781     return h;
782 }
783
784 /***********************************************************************
785  *           CURSORICON_Copy
786  *
787  * Make a copy of a cursor or icon.
788  */
789 static HGLOBAL16 CURSORICON_Copy( HINSTANCE16 hInstance, HGLOBAL16 handle )
790 {
791     char *ptrOld, *ptrNew;
792     int size;
793     HGLOBAL16 hNew;
794
795     if (!(ptrOld = (char *)GlobalLock16( handle ))) return 0;
796     if (!(hInstance = GetExePtr( hInstance ))) return 0;
797     size = GlobalSize16( handle );
798     hNew = GlobalAlloc16( GMEM_MOVEABLE, size );
799     FarSetOwner16( hNew, hInstance );
800     ptrNew = (char *)GlobalLock16( hNew );
801     memcpy( ptrNew, ptrOld, size );
802     GlobalUnlock16( handle );
803     GlobalUnlock16( hNew );
804     return hNew;
805 }
806
807 /***********************************************************************
808  *           CURSORICON_IconToCursor
809  *
810  * Converts bitmap to mono and truncates if icon is too large (should
811  * probably do StretchBlt() instead).
812  */
813 HCURSOR16 CURSORICON_IconToCursor(HICON16 hIcon, BOOL bSemiTransparent)
814 {
815  HCURSOR16       hRet = 0;
816  CURSORICONINFO *pIcon = NULL;
817  HTASK16         hTask = GetCurrentTask();
818  TDB*            pTask = (TDB *)GlobalLock16(hTask);
819
820  if(hIcon && pTask)
821     if (!(pIcon = (CURSORICONINFO*)GlobalLock16( hIcon ))) return FALSE;
822        if (pIcon->bPlanes * pIcon->bBitsPerPixel == 1)
823            hRet = CURSORICON_Copy( pTask->hInstance, hIcon );
824        else
825        {
826            BYTE  pAndBits[128];
827            BYTE  pXorBits[128];
828            int   maxx, maxy, ix, iy, bpp = pIcon->bBitsPerPixel;
829            BYTE* psPtr, *pxbPtr = pXorBits;
830            unsigned xor_width, and_width, val_base = 0xffffffff >> (32 - bpp);
831            BYTE* pbc = NULL;
832
833            CURSORICONINFO cI;
834
835            TRACE(icon, "[%04x] %ix%i %ibpp (bogus %ibps)\n", 
836                 hIcon, pIcon->nWidth, pIcon->nHeight, pIcon->bBitsPerPixel, pIcon->nWidthBytes );
837
838            xor_width = BITMAP_GetWidthBytes( pIcon->nWidth, bpp );
839            and_width = BITMAP_GetWidthBytes( pIcon->nWidth, 1 );
840            psPtr = (BYTE *)(pIcon + 1) + pIcon->nHeight * and_width;
841
842            memset(pXorBits, 0, 128);
843            cI.bBitsPerPixel = 1; cI.bPlanes = 1;
844            cI.ptHotSpot.x = cI.ptHotSpot.y = 15;
845            cI.nWidth = 32; cI.nHeight = 32;
846            cI.nWidthBytes = 4;  /* 32x1bpp */
847
848            maxx = (pIcon->nWidth > 32) ? 32 : pIcon->nWidth;
849            maxy = (pIcon->nHeight > 32) ? 32 : pIcon->nHeight;
850
851            for( iy = 0; iy < maxy; iy++ )
852            {
853               unsigned shift = iy % 2; 
854
855               memcpy( pAndBits + iy * 4, (BYTE *)(pIcon + 1) + iy * and_width, 
856                                          (and_width > 4) ? 4 : and_width );
857               for( ix = 0; ix < maxx; ix++ )
858               {
859                 if( bSemiTransparent && ((ix+shift)%2) )
860                 {
861                     /* set AND bit, XOR bit stays 0 */
862
863                     pbc = pAndBits + iy * 4 + ix/8;
864                    *pbc |= 0x80 >> (ix%8);
865                 }
866                 else
867                 {
868                     /* keep AND bit, set XOR bit */
869
870                   unsigned *psc = (unsigned*)(psPtr + (ix * bpp)/8);
871                   unsigned  val = ((*psc) >> (ix * bpp)%8) & val_base;
872                   if(!PALETTE_Driver->pIsDark(val))
873                   {
874                     pbc = pxbPtr + ix/8;
875                    *pbc |= 0x80 >> (ix%8);
876                   }
877                 }
878               }
879               psPtr += xor_width;
880               pxbPtr += 4;
881            }
882
883            hRet = CreateCursorIconIndirect16( pTask->hInstance , &cI, pAndBits, pXorBits);
884
885            if( !hRet ) /* fall back on default drag cursor */
886                 hRet = CURSORICON_Copy( pTask->hInstance ,
887                               CURSORICON_Load(0,MAKEINTRESOURCEW(OCR_DRAGOBJECT),
888                                          SYSMETRICS_CXCURSOR, SYSMETRICS_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 ? SYSMETRICS_CXICON : SYSMETRICS_CXCURSOR,
1458            bIcon ? SYSMETRICS_CYICON : SYSMETRICS_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 ? SYSMETRICS_CXICON : SYSMETRICS_CXCURSOR,
1468            bIcon ? SYSMETRICS_CYICON : SYSMETRICS_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                           SYSMETRICS_CXCURSOR, SYSMETRICS_CYCURSOR, LR_MONOCHROME );
1486         case RT_ICON16:
1487              return (WORD)LookupIconIdFromDirectoryEx16( lpDir, TRUE,
1488                           SYSMETRICS_CXICON, SYSMETRICS_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                    SYSMETRICS_CXICON, SYSMETRICS_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                   SYSMETRICS_CXCURSOR, SYSMETRICS_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 }