Release 970804
[wine] / objects / cursoricon.c
1 /*
2  * Cursor and icon support
3  *
4  * Copyright 1995 Alexandre Julliard
5  */
6
7 /*
8  * Theory:
9  *
10  * http://www.microsoft.com/win32dev/ui/icons.htm
11  *
12  * Cursors and icons are stored in a global heap block, with the
13  * following layout:
14  *
15  * CURSORICONINFO info;
16  * BYTE[]         ANDbits;
17  * BYTE[]         XORbits;
18  *
19  * The bits structures are in the format of a device-dependent bitmap.
20  *
21  * This layout is very sub-optimal, as the bitmap bits are stored in
22  * the X client instead of in the server like other bitmaps; however,
23  * some programs (notably Paint Brush) expect to be able to manipulate
24  * the bits directly :-(
25  */
26
27 #include <string.h>
28 #include <stdlib.h>
29 #include "windows.h"
30 #include "color.h"
31 #include "bitmap.h"
32 #include "callback.h"
33 #include "cursoricon.h"
34 #include "sysmetrics.h"
35 #include "win.h"
36 #include "stddebug.h"
37 #include "debug.h"
38 #include "task.h"
39
40 extern UINT16 COLOR_GetSystemPaletteSize();
41
42 Cursor CURSORICON_XCursor = None;    /* Current X cursor */
43 static HCURSOR32 hActiveCursor = 0;  /* Active cursor */
44 static INT32 CURSOR_ShowCount = 0;   /* Cursor display count */
45 static RECT32 CURSOR_ClipRect;       /* Cursor clipping rect */
46
47 /**********************************************************************
48  *          CURSORICON_FindBestIcon
49  *
50  * Find the icon closest to the requested size and number of colors.
51  */
52 static ICONDIRENTRY *CURSORICON_FindBestIcon( CURSORICONDIR *dir, int width,
53                                               int height, int colors )
54 {
55     int i, maxcolors, maxwidth, maxheight;
56     ICONDIRENTRY *entry, *bestEntry = NULL;
57
58     if (dir->idCount < 1)
59     {
60         fprintf( stderr, "Icon: empty directory!\n" );
61         return NULL;
62     }
63     if (dir->idCount == 1) return &dir->idEntries[0].icon;  /* No choice... */
64
65     /* First find the exact size with less colors */
66
67     maxcolors = 0;
68     for (i = 0, entry = &dir->idEntries[0].icon; i < dir->idCount; i++,entry++)
69         if ((entry->bWidth == width) && (entry->bHeight == height) &&
70             (entry->bColorCount <= colors) && (entry->bColorCount > maxcolors))
71         {
72             bestEntry = entry;
73             maxcolors = entry->bColorCount;
74         }
75     if (bestEntry) return bestEntry;
76
77     /* First find the exact size with more colors */
78
79     maxcolors = 255;
80     for (i = 0, entry = &dir->idEntries[0].icon; i < dir->idCount; i++,entry++)
81         if ((entry->bWidth == width) && (entry->bHeight == height) &&
82             (entry->bColorCount > colors) && (entry->bColorCount <= maxcolors))
83         {
84             bestEntry = entry;
85             maxcolors = entry->bColorCount;
86         }
87     if (bestEntry) return bestEntry;
88
89     /* Now find a smaller one with less colors */
90
91     maxcolors = maxwidth = maxheight = 0;
92     for (i = 0, entry = &dir->idEntries[0].icon; i < dir->idCount; i++,entry++)
93         if ((entry->bWidth <= width) && (entry->bHeight <= height) &&
94             (entry->bWidth >= maxwidth) && (entry->bHeight >= maxheight) &&
95             (entry->bColorCount <= colors) && (entry->bColorCount > maxcolors))
96         {
97             bestEntry = entry;
98             maxwidth  = entry->bWidth;
99             maxheight = entry->bHeight;
100             maxcolors = entry->bColorCount;
101         }
102     if (bestEntry) return bestEntry;
103
104     /* Now find a smaller one with more colors */
105
106     maxcolors = 255;
107     maxwidth = maxheight = 0;
108     for (i = 0, entry = &dir->idEntries[0].icon; i < dir->idCount; i++,entry++)
109         if ((entry->bWidth <= width) && (entry->bHeight <= height) &&
110             (entry->bWidth >= maxwidth) && (entry->bHeight >= maxheight) &&
111             (entry->bColorCount > colors) && (entry->bColorCount <= maxcolors))
112         {
113             bestEntry = entry;
114             maxwidth  = entry->bWidth;
115             maxheight = entry->bHeight;
116             maxcolors = entry->bColorCount;
117         }
118     if (bestEntry) return bestEntry;
119
120     /* Now find a larger one with less colors */
121
122     maxcolors = 0;
123     maxwidth = maxheight = 255;
124     for (i = 0, entry = &dir->idEntries[0].icon; i < dir->idCount; i++,entry++)
125         if ((entry->bWidth <= maxwidth) && (entry->bHeight <= maxheight) &&
126             (entry->bColorCount <= colors) && (entry->bColorCount > maxcolors))
127         {
128             bestEntry = entry;
129             maxwidth  = entry->bWidth;
130             maxheight = entry->bHeight;
131             maxcolors = entry->bColorCount;
132         }
133     if (bestEntry) return bestEntry;
134
135     /* Now find a larger one with more colors */
136
137     maxcolors = maxwidth = maxheight = 255;
138     for (i = 0, entry = &dir->idEntries[0].icon; i < dir->idCount; i++,entry++)
139         if ((entry->bWidth <= maxwidth) && (entry->bHeight <= maxheight) &&
140             (entry->bColorCount > colors) && (entry->bColorCount <= maxcolors))
141         {
142             bestEntry = entry;
143             maxwidth  = entry->bWidth;
144             maxheight = entry->bHeight;
145             maxcolors = entry->bColorCount;
146         }
147
148     return bestEntry;
149 }
150
151
152 /**********************************************************************
153  *          CURSORICON_FindBestCursor
154  *
155  * Find the cursor closest to the requested size.
156  */
157 static CURSORDIRENTRY *CURSORICON_FindBestCursor( CURSORICONDIR *dir,
158                                                   int width, int height )
159 {
160     int i, maxwidth, maxheight;
161     CURSORDIRENTRY *entry, *bestEntry = NULL;
162
163     if (dir->idCount < 1)
164     {
165         fprintf( stderr, "Cursor: empty directory!\n" );
166         return NULL;
167     }
168     if (dir->idCount == 1) return &dir->idEntries[0].cursor; /* No choice... */
169
170     /* First find the largest one smaller than or equal to the requested size*/
171
172     maxwidth = maxheight = 0;
173     for(i = 0,entry = &dir->idEntries[0].cursor; i < dir->idCount; i++,entry++)
174         if ((entry->wWidth <= width) && (entry->wHeight <= height) &&
175             (entry->wWidth > maxwidth) && (entry->wHeight > maxheight))
176         {
177             bestEntry = entry;
178             maxwidth  = entry->wWidth;
179             maxheight = entry->wHeight;
180         }
181     if (bestEntry) return bestEntry;
182
183     /* Now find the smallest one larger than the requested size */
184
185     maxwidth = maxheight = 255;
186     for(i = 0,entry = &dir->idEntries[0].cursor; i < dir->idCount; i++,entry++)
187         if ((entry->wWidth < maxwidth) && (entry->wHeight < maxheight))
188         {
189             bestEntry = entry;
190             maxwidth  = entry->wWidth;
191             maxheight = entry->wHeight;
192         }
193
194     return bestEntry;
195 }
196
197
198 /**********************************************************************
199  *          CURSORICON_LoadDirEntry
200  *
201  * Load the icon/cursor directory for a given resource name and find the
202  * best matching entry.
203  */
204 static BOOL32 CURSORICON_LoadDirEntry( HINSTANCE32 hInstance, SEGPTR name,
205                                        INT32 width, INT32 height,
206                                        INT32 colors, BOOL32 fCursor,
207                                        CURSORICONDIRENTRY *dirEntry )
208 {
209     HRSRC16 hRsrc;
210     HGLOBAL16 hMem;
211     CURSORICONDIR *dir;
212     CURSORICONDIRENTRY *entry = NULL;
213
214     if (!(hRsrc = FindResource16( hInstance, name,
215                                 fCursor ? RT_GROUP_CURSOR : RT_GROUP_ICON )))
216         return FALSE;
217     if (!(hMem = LoadResource16( hInstance, hRsrc ))) return FALSE;
218     if ((dir = (CURSORICONDIR *)LockResource16( hMem )))
219     {
220         if (fCursor)
221             entry = (CURSORICONDIRENTRY *)CURSORICON_FindBestCursor( dir,
222                                                                width, height );
223         else
224             entry = (CURSORICONDIRENTRY *)CURSORICON_FindBestIcon( dir,
225                                                        width, height, colors );
226         if (entry) *dirEntry = *entry;
227     }
228     FreeResource16( hMem );
229     return (entry != NULL);
230 }
231
232
233 /**********************************************************************
234  *          CURSORICON_LoadHandler 
235  *
236  * Create a cursor or icon from a resource.
237  */
238 HGLOBAL16 CURSORICON_LoadHandler( HGLOBAL16 handle, HINSTANCE16 hInstance,
239                                   BOOL32 fCursor )
240 {
241     static char* __loadhandlerStr = "CURSORICON_LoadHandler";
242
243     int sizeAnd, sizeXor;
244     HBITMAP32 hAndBits = 0, hXorBits = 0; /* error condition for later */
245     BITMAPOBJ *bmpXor, *bmpAnd;
246     POINT16 hotspot = { 0 ,0 };
247     CURSORICONINFO *info;
248     BITMAPINFO *bmi;
249     HDC32 hdc;
250
251     if (fCursor)  /* If cursor, get the hotspot */
252     {
253         POINT16 *pt = (POINT16 *)LockResource16( handle );
254         hotspot = *pt;
255         bmi = (BITMAPINFO *)(pt + 1);
256     }
257     else bmi = (BITMAPINFO *)LockResource16( handle );
258
259     /* Check bitmap header */
260
261     if ( (bmi->bmiHeader.biSize != sizeof(BITMAPCOREHEADER)) &&
262          (bmi->bmiHeader.biSize != sizeof(BITMAPINFOHEADER)  ||
263           bmi->bmiHeader.biCompression != BI_RGB) )
264     {
265           fprintf(stderr,"%s: invalid bitmap header.\n", __loadhandlerStr);
266           return 0;
267     }
268
269     if( (hdc = GetDC32( 0 )) )
270     {
271         BITMAPINFO* pInfo;
272         INT32 size = DIB_BitmapInfoSize( bmi, DIB_RGB_COLORS );
273
274         /* Make sure we have room for the monochrome bitmap later on.
275          * Note that BITMAPINFOINFO and BITMAPCOREHEADER are the same
276          * up to and including the biBitCount. In-memory icon resource 
277          * format is as follows:
278          *
279          *   BITMAPINFOHEADER   icHeader  // DIB header
280          *   RGBQUAD         icColors[]   // Color table
281          *   BYTE            icXOR[]      // DIB bits for XOR mask
282          *   BYTE            icAND[]      // DIB bits for AND mask
283          */
284
285         if( (pInfo = (BITMAPINFO *)HeapAlloc( GetProcessHeap(), 0, 
286                           MAX(size, sizeof(BITMAPINFOHEADER) + 2*sizeof(RGBQUAD)))) )
287         {       
288             memcpy( pInfo, bmi, size ); 
289             pInfo->bmiHeader.biHeight /= 2;
290
291             /* Create the XOR bitmap */
292
293             hXorBits = CreateDIBitmap32( hdc, &pInfo->bmiHeader, CBM_INIT,
294                                     (char*)bmi + size, pInfo, DIB_RGB_COLORS );
295             if( hXorBits )
296             {
297                 char* bits = (char *)bmi + size + bmi->bmiHeader.biHeight *
298                                 DIB_GetDIBWidthBytes(bmi->bmiHeader.biWidth,
299                                                      bmi->bmiHeader.biBitCount) / 2;
300
301                 pInfo->bmiHeader.biBitCount = 1;
302                 if (pInfo->bmiHeader.biSize == sizeof(BITMAPINFOHEADER))
303                 {
304                     RGBQUAD *rgb = pInfo->bmiColors;
305
306                     pInfo->bmiHeader.biClrUsed = pInfo->bmiHeader.biClrImportant = 2;
307                     rgb[0].rgbBlue = rgb[0].rgbGreen = rgb[0].rgbRed = 0x00;
308                     rgb[1].rgbBlue = rgb[1].rgbGreen = rgb[1].rgbRed = 0xff;
309                     rgb[0].rgbReserved = rgb[1].rgbReserved = 0;
310                 }
311                 else
312                 {
313                     RGBTRIPLE *rgb = (RGBTRIPLE *)(((BITMAPCOREHEADER *)pInfo) + 1);
314
315                     rgb[0].rgbtBlue = rgb[0].rgbtGreen = rgb[0].rgbtRed = 0x00;
316                     rgb[1].rgbtBlue = rgb[1].rgbtGreen = rgb[1].rgbtRed = 0xff;
317                 }
318
319                 /* Create the AND bitmap */
320
321                 hAndBits = CreateDIBitmap32( hdc, &pInfo->bmiHeader, CBM_INIT,
322                                              bits, pInfo, DIB_RGB_COLORS );
323                 if( !hAndBits ) DeleteObject32( hXorBits );
324             }
325             HeapFree( GetProcessHeap(), 0, pInfo ); 
326         }
327         ReleaseDC32( 0, hdc );
328     }
329
330     if( !hXorBits || !hAndBits ) 
331     {
332         fprintf(stderr,"%s: unable to create a bitmap.\n", __loadhandlerStr );
333         return 0;
334     }
335
336     /* Now create the CURSORICONINFO structure */
337
338     bmpXor = (BITMAPOBJ *) GDI_GetObjPtr( hXorBits, BITMAP_MAGIC );
339     bmpAnd = (BITMAPOBJ *) GDI_GetObjPtr( hAndBits, BITMAP_MAGIC );
340     sizeXor = bmpXor->bitmap.bmHeight * bmpXor->bitmap.bmWidthBytes;
341     sizeAnd = bmpAnd->bitmap.bmHeight * bmpAnd->bitmap.bmWidthBytes;
342
343     if (!(handle = GlobalAlloc16( GMEM_MOVEABLE,
344                                   sizeof(CURSORICONINFO) + sizeXor + sizeAnd)))
345     {
346         DeleteObject32( hXorBits );
347         DeleteObject32( hAndBits );
348         return 0;
349     }
350
351     /* Make it owned by the module */
352     if (hInstance) FarSetOwner( handle, GetExePtr(hInstance) );
353
354     info = (CURSORICONINFO *)GlobalLock16( handle );
355     info->ptHotSpot.x   = hotspot.x;
356     info->ptHotSpot.y   = hotspot.y;
357     info->nWidth        = bmpXor->bitmap.bmWidth;
358     info->nHeight       = bmpXor->bitmap.bmHeight;
359     info->nWidthBytes   = bmpXor->bitmap.bmWidthBytes;
360     info->bPlanes       = bmpXor->bitmap.bmPlanes;
361     info->bBitsPerPixel = bmpXor->bitmap.bmBitsPixel;
362
363     /* Transfer the bitmap bits to the CURSORICONINFO structure */
364
365     GetBitmapBits32( hAndBits, sizeAnd, (char *)(info + 1) );
366     GetBitmapBits32( hXorBits, sizeXor, (char *)(info + 1) + sizeAnd );
367     DeleteObject32( hXorBits );
368     DeleteObject32( hAndBits );
369     GlobalUnlock16( handle );
370     return handle;
371 }
372
373 /**********************************************************************
374  *          CURSORICON_Load
375  *
376  * Load a cursor or icon.
377  */
378 static HGLOBAL16 CURSORICON_Load( HINSTANCE16 hInstance, SEGPTR name,
379                                   INT32 width, INT32 height, INT32 colors,
380                                   BOOL32 fCursor )
381 {
382     HGLOBAL16 handle, hRet;
383     HRSRC16 hRsrc;
384     CURSORICONDIRENTRY dirEntry;
385
386     if (!hInstance)  /* OEM cursor/icon */
387     {
388         if (HIWORD(name))  /* Check for '#xxx' name */
389         {
390             char *ptr = PTR_SEG_TO_LIN( name );
391             if (ptr[0] != '#') return 0;
392             if (!(name = (SEGPTR)atoi( ptr + 1 ))) return 0;
393         }
394         return OBM_LoadCursorIcon( LOWORD(name), fCursor );
395     }
396
397     /* Find the best entry in the directory */
398
399     if (!CURSORICON_LoadDirEntry( hInstance, name, width, height,
400                                   colors, fCursor, &dirEntry )) return 0;
401
402     /* Load the resource */
403
404     if (!(hRsrc = FindResource16( hInstance,
405                                 MAKEINTRESOURCE( dirEntry.icon.wResId ),
406                                 fCursor ? RT_CURSOR : RT_ICON ))) return 0;
407     if (!(handle = LoadResource16( hInstance, hRsrc ))) return 0;
408
409     hRet = CURSORICON_LoadHandler( handle, hInstance, fCursor );
410     FreeResource16(handle);
411     return hRet;
412 }
413
414
415 /***********************************************************************
416  *           CURSORICON_Copy
417  *
418  * Make a copy of a cursor or icon.
419  */
420 static HGLOBAL16 CURSORICON_Copy( HINSTANCE16 hInstance, HGLOBAL16 handle )
421 {
422     char *ptrOld, *ptrNew;
423     int size;
424     HGLOBAL16 hNew;
425
426     if (!(ptrOld = (char *)GlobalLock16( handle ))) return 0;
427     if (!(hInstance = GetExePtr( hInstance ))) return 0;
428     size = GlobalSize16( handle );
429     hNew = GlobalAlloc16( GMEM_MOVEABLE, size );
430     FarSetOwner( hNew, hInstance );
431     ptrNew = (char *)GlobalLock16( hNew );
432     memcpy( ptrNew, ptrOld, size );
433     GlobalUnlock16( handle );
434     GlobalUnlock16( hNew );
435     return hNew;
436 }
437
438 /***********************************************************************
439  *           CURSORICON_IconToCursor
440  *
441  * Converts bitmap to mono and truncates if icon is too large
442  */
443 HCURSOR16 CURSORICON_IconToCursor(HICON16 hIcon, BOOL32 bSemiTransparent)
444 {
445  HCURSOR16       hRet = 0;
446  CURSORICONINFO *ptr = NULL;
447  HTASK16         hTask = GetCurrentTask();
448  TDB*            pTask = (TDB *)GlobalLock16(hTask);
449
450  if(hIcon && pTask)
451     if (!(ptr = (CURSORICONINFO*)GlobalLock16( hIcon ))) return FALSE;
452        if (ptr->bPlanes * ptr->bBitsPerPixel == 1)
453            hRet = CURSORICON_Copy( pTask->hInstance, hIcon );
454        else
455        {
456            BYTE  pAndBits[128];
457            BYTE  pXorBits[128];
458            int   x, y, ix, iy, shift; 
459            int   bpp = (ptr->bBitsPerPixel>=24)?32:ptr->bBitsPerPixel; /* this sucks */
460            BYTE* psPtr = (BYTE *)(ptr + 1) +
461                             ptr->nHeight * BITMAP_WIDTH_BYTES(ptr->nWidth,1);
462            BYTE* pxbPtr = pXorBits;
463            unsigned *psc = NULL, val = 0;
464            unsigned val_base = 0xffffffff >> (32 - bpp);
465            BYTE* pbc = NULL;
466
467            COLORREF       col;
468            CURSORICONINFO cI;
469
470            memset(pXorBits, 0, 128);
471            cI.bBitsPerPixel = 1; cI.bPlanes = 1;
472            cI.ptHotSpot.x = cI.ptHotSpot.y = 15;
473            cI.nWidth = 32; cI.nHeight = 32;
474            cI.nWidthBytes = 4;  /* 1bpp */
475
476            x = (ptr->nWidth > 32) ? 32 : ptr->nWidth;
477            y = (ptr->nHeight > 32) ? 32 : ptr->nHeight;
478
479            for( iy = 0; iy < y; iy++ )
480            {
481               val = BITMAP_WIDTH_BYTES( ptr->nWidth, 1 );
482               memcpy( pAndBits + iy * 4,
483                      (BYTE *)(ptr + 1) + iy * val, (val>4) ? 4 : val);
484               shift = iy % 2;
485
486               for( ix = 0; ix < x; ix++ )
487               {
488                 if( bSemiTransparent && ((ix+shift)%2) )
489                 {
490                     pbc = pAndBits + iy * 4 + ix/8;
491                    *pbc |= 0x80 >> (ix%8);
492                 }
493                 else
494                 {
495                   psc = (unsigned*)(psPtr + (ix * bpp)/8);
496                   val = ((*psc) >> (ix * bpp)%8) & val_base;
497                   col = COLOR_ToLogical(val);
498                   if( GetRValue(col) > 0xa0 ||
499                       GetGValue(col) > 0x80 ||
500                       GetBValue(col) > 0xa0 )
501                   {
502                     pbc = pxbPtr + ix/8;
503                    *pbc |= 0x80 >> (ix%8);
504                   }
505                 }
506               }
507               psPtr += ptr->nWidthBytes;
508               pxbPtr += 4;
509            }
510            hRet = CreateCursorIconIndirect( pTask->hInstance , &cI, pAndBits, pXorBits);
511
512            if( !hRet ) /* fall back on default drag cursor */
513                 hRet = CURSORICON_Copy( pTask->hInstance ,
514                               CURSORICON_Load(0,MAKEINTRESOURCE(OCR_DRAGOBJECT),
515                                          SYSMETRICS_CXCURSOR, SYSMETRICS_CYCURSOR, 1, TRUE) );
516        }
517
518  return hRet;
519 }
520
521
522 /***********************************************************************
523  *           LoadCursor16    (USER.173)
524  */
525 HCURSOR16 LoadCursor16( HINSTANCE16 hInstance, SEGPTR name )
526 {
527     if (HIWORD(name))
528         dprintf_cursor( stddeb, "LoadCursor16: %04x '%s'\n",
529                         hInstance, (char *)PTR_SEG_TO_LIN( name ) );
530     else
531         dprintf_cursor( stddeb, "LoadCursor16: %04x %04x\n",
532                         hInstance, LOWORD(name) );
533
534     return CURSORICON_Load( hInstance, name,
535                             SYSMETRICS_CXCURSOR, SYSMETRICS_CYCURSOR, 1, TRUE);
536 }
537
538
539 /***********************************************************************
540  *           LoadIcon16    (USER.174)
541  */
542 HICON16 LoadIcon16( HINSTANCE16 hInstance, SEGPTR name )
543 {
544     if (HIWORD(name))
545         dprintf_icon( stddeb, "LoadIcon: %04x '%s'\n",
546                       hInstance, (char *)PTR_SEG_TO_LIN( name ) );
547     else
548         dprintf_icon( stddeb, "LoadIcon: %04x %04x\n",
549                       hInstance, LOWORD(name) );
550
551     return CURSORICON_Load( hInstance, name,
552                             SYSMETRICS_CXICON, SYSMETRICS_CYICON,
553                             MIN( 16, COLOR_GetSystemPaletteSize() ), FALSE );
554 }
555
556
557 /***********************************************************************
558  *           CreateCursor16    (USER.406)
559  */
560 HCURSOR16 CreateCursor16(HINSTANCE16 hInstance, INT16 xHotSpot, INT16 yHotSpot,
561                          INT16 nWidth, INT16 nHeight,
562                          LPCVOID lpANDbits, LPCVOID lpXORbits )
563 {
564     CURSORICONINFO info = { { xHotSpot, yHotSpot }, nWidth, nHeight, 0, 1, 1 };
565
566     dprintf_cursor( stddeb, "CreateCursor: %dx%d spot=%d,%d xor=%p and=%p\n",
567                     nWidth, nHeight, xHotSpot, yHotSpot, lpXORbits, lpANDbits);
568     return CreateCursorIconIndirect( hInstance, &info, lpANDbits, lpXORbits );
569 }
570
571
572 /***********************************************************************
573  *           CreateCursor32    (USER32.66)
574  */
575 HCURSOR32 CreateCursor32(HINSTANCE32 hInstance, INT32 xHotSpot, INT32 yHotSpot,
576                          INT32 nWidth, INT32 nHeight,
577                          LPCVOID lpANDbits, LPCVOID lpXORbits )
578 {
579     CURSORICONINFO info = { { xHotSpot, yHotSpot }, nWidth, nHeight, 0, 1, 1 };
580
581     dprintf_cursor( stddeb, "CreateCursor: %dx%d spot=%d,%d xor=%p and=%p\n",
582                     nWidth, nHeight, xHotSpot, yHotSpot, lpXORbits, lpANDbits);
583     return CreateCursorIconIndirect( hInstance, &info, lpANDbits, lpXORbits );
584 }
585
586
587 /***********************************************************************
588  *           CreateIcon16    (USER.407)
589  */
590 HICON16 CreateIcon16( HINSTANCE16 hInstance, INT16 nWidth, INT16 nHeight,
591                       BYTE bPlanes, BYTE bBitsPixel,
592                       LPCVOID lpANDbits, LPCVOID lpXORbits )
593 {
594     CURSORICONINFO info = { { 0, 0 }, nWidth, nHeight, 0, bPlanes, bBitsPixel};
595
596     dprintf_icon( stddeb, "CreateIcon: %dx%dx%d, xor=%p, and=%p\n",
597                   nWidth, nHeight, bPlanes * bBitsPixel, lpXORbits, lpANDbits);
598     return CreateCursorIconIndirect( hInstance, &info, lpANDbits, lpXORbits );
599 }
600
601
602 /***********************************************************************
603  *           CreateIcon32    (USER32.74)
604  */
605 HICON32 CreateIcon32( HINSTANCE32 hInstance, INT32 nWidth, INT32 nHeight,
606                       BYTE bPlanes, BYTE bBitsPixel,
607                       LPCVOID lpANDbits, LPCVOID lpXORbits )
608 {
609     CURSORICONINFO info = { { 0, 0 }, nWidth, nHeight, 0, bPlanes, bBitsPixel};
610
611     dprintf_icon( stddeb, "CreateIcon: %dx%dx%d, xor=%p, and=%p\n",
612                   nWidth, nHeight, bPlanes * bBitsPixel, lpXORbits, lpANDbits);
613     return CreateCursorIconIndirect( hInstance, &info, lpANDbits, lpXORbits );
614 }
615
616
617 /***********************************************************************
618  *           CreateCursorIconIndirect    (USER.408)
619  */
620 HGLOBAL16 CreateCursorIconIndirect(HINSTANCE16 hInstance, CURSORICONINFO *info,
621                                    LPCVOID lpANDbits, LPCVOID lpXORbits )
622 {
623     HGLOBAL16 handle;
624     char *ptr;
625     int sizeAnd, sizeXor;
626
627     hInstance = GetExePtr( hInstance );  /* Make it a module handle */
628     if (!hInstance || !lpXORbits || !lpANDbits || info->bPlanes != 1) return 0;
629     info->nWidthBytes = BITMAP_WIDTH_BYTES(info->nWidth,info->bBitsPerPixel);
630     sizeXor = info->nHeight * info->nWidthBytes;
631     sizeAnd = info->nHeight * BITMAP_WIDTH_BYTES( info->nWidth, 1 );
632     if (!(handle = DirectResAlloc(hInstance, 0x10,
633                                   sizeof(CURSORICONINFO) + sizeXor + sizeAnd)))
634         return 0;
635     ptr = (char *)GlobalLock16( handle );
636     memcpy( ptr, info, sizeof(*info) );
637     memcpy( ptr + sizeof(CURSORICONINFO), lpANDbits, sizeAnd );
638     memcpy( ptr + sizeof(CURSORICONINFO) + sizeAnd, lpXORbits, sizeXor );
639     GlobalUnlock16( handle );
640     return handle;
641 }
642
643
644 /***********************************************************************
645  *           CopyIcon16    (USER.368)
646  */
647 HICON16 CopyIcon16( HINSTANCE16 hInstance, HICON16 hIcon )
648 {
649     dprintf_icon( stddeb, "CopyIcon16: %04x %04x\n", hInstance, hIcon );
650     return CURSORICON_Copy( hInstance, hIcon );
651 }
652
653
654 /***********************************************************************
655  *           CopyIcon32    (USER32.59)
656  */
657 HICON32 CopyIcon32( HICON32 hIcon )
658 {
659     dprintf_icon( stddeb, "CopyIcon32: %04x\n", hIcon );
660     return CURSORICON_Copy( 0, hIcon );
661 }
662
663
664 /***********************************************************************
665  *           CopyCursor16    (USER.369)
666  */
667 HCURSOR16 CopyCursor16( HINSTANCE16 hInstance, HCURSOR16 hCursor )
668 {
669     dprintf_cursor( stddeb, "CopyCursor16: %04x %04x\n", hInstance, hCursor );
670     return CURSORICON_Copy( hInstance, hCursor );
671 }
672
673
674 /***********************************************************************
675  *           DestroyIcon16    (USER.457)
676  */
677 BOOL16 DestroyIcon16( HICON16 hIcon )
678 {
679     return DestroyIcon32( hIcon );
680 }
681
682
683 /***********************************************************************
684  *           DestroyIcon32    (USER32.132)
685  */
686 BOOL32 DestroyIcon32( HICON32 hIcon )
687 {
688     dprintf_icon( stddeb, "DestroyIcon: %04x\n", hIcon );
689     /* FIXME: should check for OEM icon here */
690     return (GlobalFree16( hIcon ) == 0);
691 }
692
693
694 /***********************************************************************
695  *           DestroyCursor16    (USER.458)
696  */
697 BOOL16 DestroyCursor16( HCURSOR16 hCursor )
698 {
699     return DestroyCursor32( hCursor );
700 }
701
702
703 /***********************************************************************
704  *           DestroyCursor32    (USER32.131)
705  */
706 BOOL32 DestroyCursor32( HCURSOR32 hCursor )
707 {
708     dprintf_cursor( stddeb, "DestroyCursor: %04x\n", hCursor );
709     /* FIXME: should check for OEM cursor here */
710     return (GlobalFree16( hCursor ) != 0);
711 }
712
713
714 /***********************************************************************
715  *           DrawIcon16    (USER.84)
716  */
717 BOOL16 DrawIcon16( HDC16 hdc, INT16 x, INT16 y, HICON16 hIcon )
718 {
719     return DrawIcon32( hdc, x, y, hIcon );
720 }
721
722
723 /***********************************************************************
724  *           DrawIcon32    (USER32.158)
725  */
726 BOOL32 DrawIcon32( HDC32 hdc, INT32 x, INT32 y, HICON32 hIcon )
727 {
728     CURSORICONINFO *ptr;
729     HDC32 hMemDC;
730     HBITMAP32 hXorBits, hAndBits;
731     COLORREF oldFg, oldBg;
732
733     if (!(ptr = (CURSORICONINFO *)GlobalLock16( hIcon ))) return FALSE;
734     if (!(hMemDC = CreateCompatibleDC32( hdc ))) return FALSE;
735     hAndBits = CreateBitmap32( ptr->nWidth, ptr->nHeight, 1, 1,
736                                (char *)(ptr+1) );
737     hXorBits = CreateBitmap32( ptr->nWidth, ptr->nHeight, ptr->bPlanes,
738                                ptr->bBitsPerPixel, (char *)(ptr + 1)
739                          + ptr->nHeight * BITMAP_WIDTH_BYTES(ptr->nWidth,1) );
740     oldFg = SetTextColor32( hdc, RGB(0,0,0) );
741     oldBg = SetBkColor32( hdc, RGB(255,255,255) );
742
743     if (hXorBits && hAndBits)
744     {
745         HBITMAP32 hBitTemp = SelectObject32( hMemDC, hAndBits );
746         BitBlt32( hdc, x, y, ptr->nWidth, ptr->nHeight, hMemDC, 0, 0, SRCAND );
747         SelectObject32( hMemDC, hXorBits );
748         BitBlt32(hdc, x, y, ptr->nWidth, ptr->nHeight, hMemDC, 0, 0,SRCINVERT);
749         SelectObject32( hMemDC, hBitTemp );
750     }
751     DeleteDC32( hMemDC );
752     if (hXorBits) DeleteObject32( hXorBits );
753     if (hAndBits) DeleteObject32( hAndBits );
754     GlobalUnlock16( hIcon );
755     SetTextColor32( hdc, oldFg );
756     SetBkColor32( hdc, oldBg );
757     return TRUE;
758 }
759
760
761 /***********************************************************************
762  *           DumpIcon    (USER.459)
763  */
764 DWORD DumpIcon( SEGPTR pInfo, WORD *lpLen,
765                 SEGPTR *lpXorBits, SEGPTR *lpAndBits )
766 {
767     CURSORICONINFO *info = PTR_SEG_TO_LIN( pInfo );
768     int sizeAnd, sizeXor;
769
770     if (!info) return 0;
771     sizeXor = info->nHeight * info->nWidthBytes;
772     sizeAnd = info->nHeight * BITMAP_WIDTH_BYTES( info->nWidth, 1 );
773     if (lpAndBits) *lpAndBits = pInfo + sizeof(CURSORICONINFO);
774     if (lpXorBits) *lpXorBits = pInfo + sizeof(CURSORICONINFO) + sizeAnd;
775     if (lpLen) *lpLen = sizeof(CURSORICONINFO) + sizeAnd + sizeXor;
776     return MAKELONG( sizeXor, sizeXor );
777 }
778
779
780 /***********************************************************************
781  *           CURSORICON_SetCursor
782  *
783  * Change the X cursor. Helper function for SetCursor() and ShowCursor().
784  */
785 static BOOL32 CURSORICON_SetCursor( HCURSOR16 hCursor )
786 {
787     Pixmap pixmapBits, pixmapMask, pixmapAll;
788     XColor fg, bg;
789     Cursor cursor = None;
790
791     if (!hCursor)  /* Create an empty cursor */
792     {
793         static const char data[] = { 0 };
794
795         bg.red = bg.green = bg.blue = 0x0000;
796         pixmapBits = XCreateBitmapFromData( display, rootWindow, data, 1, 1 );
797         if (pixmapBits)
798         {
799             cursor = XCreatePixmapCursor( display, pixmapBits, pixmapBits,
800                                           &bg, &bg, 0, 0 );
801             XFreePixmap( display, pixmapBits );
802         }
803     }
804     else  /* Create the X cursor from the bits */
805     {
806         CURSORICONINFO *ptr;
807         XImage *image;
808
809         if (!(ptr = (CURSORICONINFO*)GlobalLock16( hCursor ))) return FALSE;
810         if (ptr->bPlanes * ptr->bBitsPerPixel != 1)
811         {
812             fprintf( stderr, "Cursor %04x has more than 1 bpp!\n", hCursor );
813             return FALSE;
814         }
815
816         /* Create a pixmap and transfer all the bits to it */
817
818         /* NOTE: Following hack works, but only because XFree depth
819          *       1 images really use 1 bit/pixel (and so the same layout
820          *       as the Windows cursor data). Perhaps use a more generic
821          *       algorithm here.
822          */
823         pixmapAll = XCreatePixmap( display, rootWindow,
824                                    ptr->nWidth, ptr->nHeight * 2, 1 );
825         image = XCreateImage( display, DefaultVisualOfScreen(screen),
826                               1, ZPixmap, 0, (char *)(ptr + 1), ptr->nWidth,
827                               ptr->nHeight * 2, 16, ptr->nWidthBytes);
828         if (image)
829         {
830             extern void _XInitImageFuncPtrs( XImage* );
831             image->byte_order = MSBFirst;
832             image->bitmap_bit_order = MSBFirst;
833             image->bitmap_unit = 16;
834             _XInitImageFuncPtrs(image);
835             if (pixmapAll)
836                 CallTo32_LargeStack( XPutImage, 10,
837                                      display, pixmapAll, BITMAP_monoGC, image,
838                                      0, 0, 0, 0, ptr->nWidth, ptr->nHeight*2 );
839             image->data = NULL;
840             XDestroyImage( image );
841         }
842
843         /* Now create the 2 pixmaps for bits and mask */
844
845         pixmapBits = XCreatePixmap( display, rootWindow,
846                                     ptr->nWidth, ptr->nHeight, 1 );
847         pixmapMask = XCreatePixmap( display, rootWindow,
848                                     ptr->nWidth, ptr->nHeight, 1 );
849
850         /* Make sure everything went OK so far */
851
852         if (pixmapBits && pixmapMask && pixmapAll)
853         {
854             /* We have to do some magic here, as cursors are not fully
855              * compatible between Windows and X11. Under X11, there
856              * are only 3 possible color cursor: black, white and
857              * masked. So we map the 4th Windows color (invert the
858              * bits on the screen) to black. This require some boolean
859              * arithmetic:
860              *
861              *         Windows          |          X11
862              * Xor    And      Result   |   Bits     Mask     Result
863              *  0      0     black      |    0        1     background
864              *  0      1     no change  |    X        0     no change
865              *  1      0     white      |    1        1     foreground
866              *  1      1     inverted   |    0        1     background
867              *
868              * which gives:
869              *  Bits = 'Xor' and not 'And'
870              *  Mask = 'Xor' or not 'And'
871              *
872              * FIXME: apparently some servers do support 'inverted' color.
873              * I don't know if it's correct per the X spec, but maybe
874              * we ought to take advantage of it.  -- AJ
875              */
876             XCopyArea( display, pixmapAll, pixmapBits, BITMAP_monoGC,
877                        0, 0, ptr->nWidth, ptr->nHeight, 0, 0 );
878             XCopyArea( display, pixmapAll, pixmapMask, BITMAP_monoGC,
879                        0, 0, ptr->nWidth, ptr->nHeight, 0, 0 );
880             XSetFunction( display, BITMAP_monoGC, GXandReverse );
881             XCopyArea( display, pixmapAll, pixmapBits, BITMAP_monoGC,
882                        0, ptr->nHeight, ptr->nWidth, ptr->nHeight, 0, 0 );
883             XSetFunction( display, BITMAP_monoGC, GXorReverse );
884             XCopyArea( display, pixmapAll, pixmapMask, BITMAP_monoGC,
885                        0, ptr->nHeight, ptr->nWidth, ptr->nHeight, 0, 0 );
886             XSetFunction( display, BITMAP_monoGC, GXcopy );
887             fg.red = fg.green = fg.blue = 0xffff;
888             bg.red = bg.green = bg.blue = 0x0000;
889             cursor = XCreatePixmapCursor( display, pixmapBits, pixmapMask,
890                                 &fg, &bg, ptr->ptHotSpot.x, ptr->ptHotSpot.y );
891         }
892
893         /* Now free everything */
894
895         if (pixmapAll) XFreePixmap( display, pixmapAll );
896         if (pixmapBits) XFreePixmap( display, pixmapBits );
897         if (pixmapMask) XFreePixmap( display, pixmapMask );
898         GlobalUnlock16( hCursor );
899     }
900
901     if (cursor == None) return FALSE;
902     if (CURSORICON_XCursor != None) XFreeCursor( display, CURSORICON_XCursor );
903     CURSORICON_XCursor = cursor;
904
905     if (rootWindow != DefaultRootWindow(display))
906     {
907         /* Set the cursor on the desktop window */
908         XDefineCursor( display, rootWindow, cursor );
909     }
910     else
911     {
912         /* Set the same cursor for all top-level windows */
913         HWND32 hwnd = GetWindow32( GetDesktopWindow32(), GW_CHILD );
914         while(hwnd)
915         {
916             Window win = WIN_GetXWindow( hwnd );
917             if (win) XDefineCursor( display, win, cursor );
918             hwnd = GetWindow32( hwnd, GW_HWNDNEXT );
919         }
920     }
921     return TRUE;
922 }
923
924
925 /***********************************************************************
926  *           SetCursor16    (USER.69)
927  */
928 HCURSOR16 SetCursor16( HCURSOR16 hCursor )
929 {
930     return (HCURSOR16)SetCursor32( hCursor );
931 }
932
933
934 /***********************************************************************
935  *           SetCursor32    (USER32.471)
936  */
937 HCURSOR32 SetCursor32( HCURSOR32 hCursor )
938 {
939     HCURSOR32 hOldCursor;
940
941     if (hCursor == hActiveCursor) return hActiveCursor;  /* No change */
942     dprintf_cursor( stddeb, "SetCursor: %04x\n", hCursor );
943     hOldCursor = hActiveCursor;
944     hActiveCursor = hCursor;
945     /* Change the cursor shape only if it is visible */
946     if (CURSOR_ShowCount >= 0) CURSORICON_SetCursor( hActiveCursor );
947     return hOldCursor;
948 }
949
950
951 /***********************************************************************
952  *           SetCursorPos16    (USER.70)
953  */
954 void SetCursorPos16( INT16 x, INT16 y )
955 {
956     SetCursorPos32( x, y );
957 }
958
959
960 /***********************************************************************
961  *           SetCursorPos32    (USER32.473)
962  */
963 BOOL32 SetCursorPos32( INT32 x, INT32 y )
964 {
965     dprintf_cursor( stddeb, "SetCursorPos: x=%d y=%d\n", x, y );
966     XWarpPointer( display, rootWindow, rootWindow, 0, 0, 0, 0, x, y );
967     return TRUE;
968 }
969
970
971 /***********************************************************************
972  *           ShowCursor16    (USER.71)
973  */
974 INT16 ShowCursor16( BOOL16 bShow )
975 {
976     return ShowCursor32( bShow );
977 }
978
979
980 /***********************************************************************
981  *           ShowCursor32    (USER32.529)
982  */
983 INT32 ShowCursor32( BOOL32 bShow )
984 {
985     dprintf_cursor( stddeb, "ShowCursor: %d, count=%d\n",
986                     bShow, CURSOR_ShowCount );
987
988     if (bShow)
989     {
990         if (++CURSOR_ShowCount == 0)
991             CURSORICON_SetCursor( hActiveCursor );  /* Show it */
992     }
993     else
994     {
995         if (--CURSOR_ShowCount == -1)
996             CURSORICON_SetCursor( 0 );  /* Hide it */
997     }
998     return CURSOR_ShowCount;
999 }
1000
1001
1002 /***********************************************************************
1003  *           GetCursor16    (USER.247)
1004  */
1005 HCURSOR16 GetCursor16(void)
1006 {
1007     return hActiveCursor;
1008 }
1009
1010
1011 /***********************************************************************
1012  *           GetCursor32    (USER32.226)
1013  */
1014 HCURSOR32 GetCursor32(void)
1015 {
1016     return hActiveCursor;
1017 }
1018
1019
1020 /***********************************************************************
1021  *           ClipCursor16    (USER.16)
1022  */
1023 BOOL16 ClipCursor16( const RECT16 *rect )
1024 {
1025     if (!rect) SetRectEmpty32( &CURSOR_ClipRect );
1026     else CONV_RECT16TO32( rect, &CURSOR_ClipRect );
1027     return TRUE;
1028 }
1029
1030
1031 /***********************************************************************
1032  *           ClipCursor32    (USER32.52)
1033  */
1034 BOOL32 ClipCursor32( const RECT32 *rect )
1035 {
1036     if (!rect) SetRectEmpty32( &CURSOR_ClipRect );
1037     else CopyRect32( &CURSOR_ClipRect, rect );
1038     return TRUE;
1039 }
1040
1041
1042 /***********************************************************************
1043  *           GetCursorPos16    (USER.17)
1044  */
1045 void GetCursorPos16( POINT16 *pt )
1046 {
1047     Window root, child;
1048     int rootX, rootY, childX, childY;
1049     unsigned int mousebut;
1050
1051     if (!pt) return;
1052     if (!XQueryPointer( display, rootWindow, &root, &child,
1053                         &rootX, &rootY, &childX, &childY, &mousebut ))
1054         pt->x = pt->y = 0;
1055     else
1056     {
1057         pt->x = childX;
1058         pt->y = childY;
1059     }
1060     dprintf_cursor(stddeb, "GetCursorPos: ret=%d,%d\n", pt->x, pt->y );
1061 }
1062
1063
1064 /***********************************************************************
1065  *           GetCursorPos32    (USER32.228)
1066  */
1067 void GetCursorPos32( POINT32 *pt )
1068 {
1069     POINT16 pt16;
1070     GetCursorPos16( &pt16 );
1071     if (pt) CONV_POINT16TO32( &pt16, pt );
1072 }
1073
1074
1075 /***********************************************************************
1076  *           GetClipCursor16    (USER.309)
1077  */
1078 void GetClipCursor16( RECT16 *rect )
1079 {
1080     if (rect) CONV_RECT32TO16( &CURSOR_ClipRect, rect );
1081 }
1082
1083
1084 /***********************************************************************
1085  *           GetClipCursor32    (USER32.220)
1086  */
1087 void GetClipCursor32( RECT32 *rect )
1088 {
1089     if (rect) CopyRect32( rect, &CURSOR_ClipRect );
1090 }
1091
1092
1093 /**********************************************************************
1094  *          GetIconID    (USER.455)
1095  */
1096 WORD GetIconID( HGLOBAL16 hResource, DWORD resType )
1097 {
1098     CURSORICONDIR *lpDir = (CURSORICONDIR *)GlobalLock16(hResource);
1099 /* LockResource16(hResource); */
1100
1101     if (!lpDir || lpDir->idReserved ||
1102         ((lpDir->idType != 1) && (lpDir->idType != 2)))
1103     {
1104         dprintf_cursor(stddeb,"GetIconID: invalid resource directory\n");
1105         return 0;
1106     }
1107
1108     dprintf_cursor( stddeb, "GetIconID: hRes=%04x, entries=%i\n",
1109                     hResource, lpDir->idCount );
1110
1111     switch(resType)
1112     {
1113     case 1:  /* cursor */
1114         {
1115             CURSORDIRENTRY *entry = CURSORICON_FindBestCursor( lpDir,
1116                                     SYSMETRICS_CXCURSOR, SYSMETRICS_CYCURSOR );
1117             return entry ? entry->wResId : 0;
1118         }
1119     case 3:  /* icon */
1120         {
1121             ICONDIRENTRY * entry =  CURSORICON_FindBestIcon( lpDir,
1122                                     SYSMETRICS_CXICON, SYSMETRICS_CYICON,
1123                                     MIN( 16, COLOR_GetSystemPaletteSize() ) );
1124             return entry ? entry->wResId : 0;
1125         }
1126     }
1127     fprintf( stderr, "GetIconID: invalid res type %ld\n", resType );
1128     return 0;
1129 }
1130
1131
1132 /**********************************************************************
1133  *          LoadIconHandler    (USER.456)
1134  */
1135 HICON16 LoadIconHandler( HGLOBAL16 hResource, BOOL16 bNew )
1136 {
1137     dprintf_cursor(stddeb,"LoadIconHandler: hRes=%04x\n",hResource);
1138
1139     if( !bNew )
1140       {
1141         fprintf(stdnimp,"LoadIconHandler: 2.xx resources are not supported\n");
1142         return 0;
1143       }
1144     return CURSORICON_LoadHandler( hResource, 0, FALSE);
1145 }
1146
1147 /**********************************************************************
1148  *          GetIconInfo         (USER32.241)
1149  */
1150