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