2 * Cursor and icon support
4 * Copyright 1995 Alexandre Julliard
10 * http://www.microsoft.com/win32dev/ui/icons.htm
12 * Cursors and icons are stored in a global heap block, with the
15 * CURSORICONINFO info;
19 * The bits structures are in the format of a device-dependent bitmap.
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 :-(
33 #include "cursoricon.h"
34 #include "sysmetrics.h"
40 extern UINT16 COLOR_GetSystemPaletteSize();
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 */
47 /**********************************************************************
48 * CURSORICON_FindBestIcon
50 * Find the icon closest to the requested size and number of colors.
52 static ICONDIRENTRY *CURSORICON_FindBestIcon( CURSORICONDIR *dir, int width,
53 int height, int colors )
55 int i, maxcolors, maxwidth, maxheight;
56 ICONDIRENTRY *entry, *bestEntry = NULL;
60 fprintf( stderr, "Icon: empty directory!\n" );
63 if (dir->idCount == 1) return &dir->idEntries[0].icon; /* No choice... */
65 /* First find the exact size with less colors */
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))
73 maxcolors = entry->bColorCount;
75 if (bestEntry) return bestEntry;
77 /* First find the exact size with more colors */
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))
85 maxcolors = entry->bColorCount;
87 if (bestEntry) return bestEntry;
89 /* Now find a smaller one with less colors */
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))
98 maxwidth = entry->bWidth;
99 maxheight = entry->bHeight;
100 maxcolors = entry->bColorCount;
102 if (bestEntry) return bestEntry;
104 /* Now find a smaller one with more colors */
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))
114 maxwidth = entry->bWidth;
115 maxheight = entry->bHeight;
116 maxcolors = entry->bColorCount;
118 if (bestEntry) return bestEntry;
120 /* Now find a larger one with less colors */
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))
129 maxwidth = entry->bWidth;
130 maxheight = entry->bHeight;
131 maxcolors = entry->bColorCount;
133 if (bestEntry) return bestEntry;
135 /* Now find a larger one with more colors */
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))
143 maxwidth = entry->bWidth;
144 maxheight = entry->bHeight;
145 maxcolors = entry->bColorCount;
152 /**********************************************************************
153 * CURSORICON_FindBestCursor
155 * Find the cursor closest to the requested size.
157 static CURSORDIRENTRY *CURSORICON_FindBestCursor( CURSORICONDIR *dir,
158 int width, int height )
160 int i, maxwidth, maxheight;
161 CURSORDIRENTRY *entry, *bestEntry = NULL;
163 if (dir->idCount < 1)
165 fprintf( stderr, "Cursor: empty directory!\n" );
168 if (dir->idCount == 1) return &dir->idEntries[0].cursor; /* No choice... */
170 /* First find the largest one smaller than or equal to the requested size*/
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))
178 maxwidth = entry->wWidth;
179 maxheight = entry->wHeight;
181 if (bestEntry) return bestEntry;
183 /* Now find the smallest one larger than the requested size */
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))
190 maxwidth = entry->wWidth;
191 maxheight = entry->wHeight;
198 /**********************************************************************
199 * CURSORICON_LoadDirEntry
201 * Load the icon/cursor directory for a given resource name and find the
202 * best matching entry.
204 static BOOL32 CURSORICON_LoadDirEntry( HINSTANCE32 hInstance, SEGPTR name,
205 INT32 width, INT32 height,
206 INT32 colors, BOOL32 fCursor,
207 CURSORICONDIRENTRY *dirEntry )
212 CURSORICONDIRENTRY *entry = NULL;
214 if (!(hRsrc = FindResource16( hInstance, name,
215 fCursor ? RT_GROUP_CURSOR : RT_GROUP_ICON )))
217 if (!(hMem = LoadResource16( hInstance, hRsrc ))) return FALSE;
218 if ((dir = (CURSORICONDIR *)LockResource16( hMem )))
221 entry = (CURSORICONDIRENTRY *)CURSORICON_FindBestCursor( dir,
224 entry = (CURSORICONDIRENTRY *)CURSORICON_FindBestIcon( dir,
225 width, height, colors );
226 if (entry) *dirEntry = *entry;
228 FreeResource16( hMem );
229 return (entry != NULL);
233 /**********************************************************************
234 * CURSORICON_LoadHandler
236 * Create a cursor or icon from a resource.
238 HGLOBAL16 CURSORICON_LoadHandler( HGLOBAL16 handle, HINSTANCE16 hInstance,
241 static char* __loadhandlerStr = "CURSORICON_LoadHandler";
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;
251 if (fCursor) /* If cursor, get the hotspot */
253 POINT16 *pt = (POINT16 *)LockResource16( handle );
255 bmi = (BITMAPINFO *)(pt + 1);
257 else bmi = (BITMAPINFO *)LockResource16( handle );
259 /* Check bitmap header */
261 if ( (bmi->bmiHeader.biSize != sizeof(BITMAPCOREHEADER)) &&
262 (bmi->bmiHeader.biSize != sizeof(BITMAPINFOHEADER) ||
263 bmi->bmiHeader.biCompression != BI_RGB) )
265 fprintf(stderr,"%s: invalid bitmap header.\n", __loadhandlerStr);
269 if( (hdc = GetDC32( 0 )) )
272 INT32 size = DIB_BitmapInfoSize( bmi, DIB_RGB_COLORS );
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:
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
285 if( (pInfo = (BITMAPINFO *)HeapAlloc( GetProcessHeap(), 0,
286 MAX(size, sizeof(BITMAPINFOHEADER) + 2*sizeof(RGBQUAD)))) )
288 memcpy( pInfo, bmi, size );
289 pInfo->bmiHeader.biHeight /= 2;
291 /* Create the XOR bitmap */
293 hXorBits = CreateDIBitmap32( hdc, &pInfo->bmiHeader, CBM_INIT,
294 (char*)bmi + size, pInfo, DIB_RGB_COLORS );
297 char* bits = (char *)bmi + size + bmi->bmiHeader.biHeight *
298 DIB_GetDIBWidthBytes(bmi->bmiHeader.biWidth,
299 bmi->bmiHeader.biBitCount) / 2;
301 pInfo->bmiHeader.biBitCount = 1;
302 if (pInfo->bmiHeader.biSize == sizeof(BITMAPINFOHEADER))
304 RGBQUAD *rgb = pInfo->bmiColors;
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;
313 RGBTRIPLE *rgb = (RGBTRIPLE *)(((BITMAPCOREHEADER *)pInfo) + 1);
315 rgb[0].rgbtBlue = rgb[0].rgbtGreen = rgb[0].rgbtRed = 0x00;
316 rgb[1].rgbtBlue = rgb[1].rgbtGreen = rgb[1].rgbtRed = 0xff;
319 /* Create the AND bitmap */
321 hAndBits = CreateDIBitmap32( hdc, &pInfo->bmiHeader, CBM_INIT,
322 bits, pInfo, DIB_RGB_COLORS );
323 if( !hAndBits ) DeleteObject32( hXorBits );
325 HeapFree( GetProcessHeap(), 0, pInfo );
327 ReleaseDC32( 0, hdc );
330 if( !hXorBits || !hAndBits )
332 fprintf(stderr,"%s: unable to create a bitmap.\n", __loadhandlerStr );
336 /* Now create the CURSORICONINFO structure */
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;
343 if (!(handle = GlobalAlloc16( GMEM_MOVEABLE,
344 sizeof(CURSORICONINFO) + sizeXor + sizeAnd)))
346 DeleteObject32( hXorBits );
347 DeleteObject32( hAndBits );
351 /* Make it owned by the module */
352 if (hInstance) FarSetOwner( handle, GetExePtr(hInstance) );
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;
363 /* Transfer the bitmap bits to the CURSORICONINFO structure */
365 GetBitmapBits32( hAndBits, sizeAnd, (char *)(info + 1) );
366 GetBitmapBits32( hXorBits, sizeXor, (char *)(info + 1) + sizeAnd );
367 DeleteObject32( hXorBits );
368 DeleteObject32( hAndBits );
369 GlobalUnlock16( handle );
373 /**********************************************************************
376 * Load a cursor or icon.
378 static HGLOBAL16 CURSORICON_Load( HINSTANCE16 hInstance, SEGPTR name,
379 INT32 width, INT32 height, INT32 colors,
382 HGLOBAL16 handle, hRet;
384 CURSORICONDIRENTRY dirEntry;
386 if (!hInstance) /* OEM cursor/icon */
388 if (HIWORD(name)) /* Check for '#xxx' name */
390 char *ptr = PTR_SEG_TO_LIN( name );
391 if (ptr[0] != '#') return 0;
392 if (!(name = (SEGPTR)atoi( ptr + 1 ))) return 0;
394 return OBM_LoadCursorIcon( LOWORD(name), fCursor );
397 /* Find the best entry in the directory */
399 if (!CURSORICON_LoadDirEntry( hInstance, name, width, height,
400 colors, fCursor, &dirEntry )) return 0;
402 /* Load the resource */
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;
409 hRet = CURSORICON_LoadHandler( handle, hInstance, fCursor );
410 FreeResource16(handle);
415 /***********************************************************************
418 * Make a copy of a cursor or icon.
420 static HGLOBAL16 CURSORICON_Copy( HINSTANCE16 hInstance, HGLOBAL16 handle )
422 char *ptrOld, *ptrNew;
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 );
438 /***********************************************************************
439 * CURSORICON_IconToCursor
441 * Converts bitmap to mono and truncates if icon is too large
443 HCURSOR16 CURSORICON_IconToCursor(HICON16 hIcon, BOOL32 bSemiTransparent)
446 CURSORICONINFO *ptr = NULL;
447 HTASK16 hTask = GetCurrentTask();
448 TDB* pTask = (TDB *)GlobalLock16(hTask);
451 if (!(ptr = (CURSORICONINFO*)GlobalLock16( hIcon ))) return FALSE;
452 if (ptr->bPlanes * ptr->bBitsPerPixel == 1)
453 hRet = CURSORICON_Copy( pTask->hInstance, hIcon );
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);
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 */
476 x = (ptr->nWidth > 32) ? 32 : ptr->nWidth;
477 y = (ptr->nHeight > 32) ? 32 : ptr->nHeight;
479 for( iy = 0; iy < y; iy++ )
481 val = BITMAP_WIDTH_BYTES( ptr->nWidth, 1 );
482 memcpy( pAndBits + iy * 4,
483 (BYTE *)(ptr + 1) + iy * val, (val>4) ? 4 : val);
486 for( ix = 0; ix < x; ix++ )
488 if( bSemiTransparent && ((ix+shift)%2) )
490 pbc = pAndBits + iy * 4 + ix/8;
491 *pbc |= 0x80 >> (ix%8);
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 )
503 *pbc |= 0x80 >> (ix%8);
507 psPtr += ptr->nWidthBytes;
510 hRet = CreateCursorIconIndirect( pTask->hInstance , &cI, pAndBits, pXorBits);
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) );
522 /***********************************************************************
523 * LoadCursor16 (USER.173)
525 HCURSOR16 LoadCursor16( HINSTANCE16 hInstance, SEGPTR name )
528 dprintf_cursor( stddeb, "LoadCursor16: %04x '%s'\n",
529 hInstance, (char *)PTR_SEG_TO_LIN( name ) );
531 dprintf_cursor( stddeb, "LoadCursor16: %04x %04x\n",
532 hInstance, LOWORD(name) );
534 return CURSORICON_Load( hInstance, name,
535 SYSMETRICS_CXCURSOR, SYSMETRICS_CYCURSOR, 1, TRUE);
539 /***********************************************************************
540 * LoadIcon16 (USER.174)
542 HICON16 LoadIcon16( HINSTANCE16 hInstance, SEGPTR name )
545 dprintf_icon( stddeb, "LoadIcon: %04x '%s'\n",
546 hInstance, (char *)PTR_SEG_TO_LIN( name ) );
548 dprintf_icon( stddeb, "LoadIcon: %04x %04x\n",
549 hInstance, LOWORD(name) );
551 return CURSORICON_Load( hInstance, name,
552 SYSMETRICS_CXICON, SYSMETRICS_CYICON,
553 MIN( 16, COLOR_GetSystemPaletteSize() ), FALSE );
557 /***********************************************************************
558 * CreateCursor16 (USER.406)
560 HCURSOR16 CreateCursor16(HINSTANCE16 hInstance, INT16 xHotSpot, INT16 yHotSpot,
561 INT16 nWidth, INT16 nHeight,
562 LPCVOID lpANDbits, LPCVOID lpXORbits )
564 CURSORICONINFO info = { { xHotSpot, yHotSpot }, nWidth, nHeight, 0, 1, 1 };
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 );
572 /***********************************************************************
573 * CreateCursor32 (USER32.66)
575 HCURSOR32 CreateCursor32(HINSTANCE32 hInstance, INT32 xHotSpot, INT32 yHotSpot,
576 INT32 nWidth, INT32 nHeight,
577 LPCVOID lpANDbits, LPCVOID lpXORbits )
579 CURSORICONINFO info = { { xHotSpot, yHotSpot }, nWidth, nHeight, 0, 1, 1 };
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 );
587 /***********************************************************************
588 * CreateIcon16 (USER.407)
590 HICON16 CreateIcon16( HINSTANCE16 hInstance, INT16 nWidth, INT16 nHeight,
591 BYTE bPlanes, BYTE bBitsPixel,
592 LPCVOID lpANDbits, LPCVOID lpXORbits )
594 CURSORICONINFO info = { { 0, 0 }, nWidth, nHeight, 0, bPlanes, bBitsPixel};
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 );
602 /***********************************************************************
603 * CreateIcon32 (USER32.74)
605 HICON32 CreateIcon32( HINSTANCE32 hInstance, INT32 nWidth, INT32 nHeight,
606 BYTE bPlanes, BYTE bBitsPixel,
607 LPCVOID lpANDbits, LPCVOID lpXORbits )
609 CURSORICONINFO info = { { 0, 0 }, nWidth, nHeight, 0, bPlanes, bBitsPixel};
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 );
617 /***********************************************************************
618 * CreateCursorIconIndirect (USER.408)
620 HGLOBAL16 CreateCursorIconIndirect(HINSTANCE16 hInstance, CURSORICONINFO *info,
621 LPCVOID lpANDbits, LPCVOID lpXORbits )
625 int sizeAnd, sizeXor;
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)))
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 );
644 /***********************************************************************
645 * CopyIcon16 (USER.368)
647 HICON16 CopyIcon16( HINSTANCE16 hInstance, HICON16 hIcon )
649 dprintf_icon( stddeb, "CopyIcon16: %04x %04x\n", hInstance, hIcon );
650 return CURSORICON_Copy( hInstance, hIcon );
654 /***********************************************************************
655 * CopyIcon32 (USER32.59)
657 HICON32 CopyIcon32( HICON32 hIcon )
659 dprintf_icon( stddeb, "CopyIcon32: %04x\n", hIcon );
660 return CURSORICON_Copy( 0, hIcon );
664 /***********************************************************************
665 * CopyCursor16 (USER.369)
667 HCURSOR16 CopyCursor16( HINSTANCE16 hInstance, HCURSOR16 hCursor )
669 dprintf_cursor( stddeb, "CopyCursor16: %04x %04x\n", hInstance, hCursor );
670 return CURSORICON_Copy( hInstance, hCursor );
674 /***********************************************************************
675 * DestroyIcon16 (USER.457)
677 BOOL16 DestroyIcon16( HICON16 hIcon )
679 return DestroyIcon32( hIcon );
683 /***********************************************************************
684 * DestroyIcon32 (USER32.132)
686 BOOL32 DestroyIcon32( HICON32 hIcon )
688 dprintf_icon( stddeb, "DestroyIcon: %04x\n", hIcon );
689 /* FIXME: should check for OEM icon here */
690 return (GlobalFree16( hIcon ) == 0);
694 /***********************************************************************
695 * DestroyCursor16 (USER.458)
697 BOOL16 DestroyCursor16( HCURSOR16 hCursor )
699 return DestroyCursor32( hCursor );
703 /***********************************************************************
704 * DestroyCursor32 (USER32.131)
706 BOOL32 DestroyCursor32( HCURSOR32 hCursor )
708 dprintf_cursor( stddeb, "DestroyCursor: %04x\n", hCursor );
709 /* FIXME: should check for OEM cursor here */
710 return (GlobalFree16( hCursor ) != 0);
714 /***********************************************************************
715 * DrawIcon16 (USER.84)
717 BOOL16 DrawIcon16( HDC16 hdc, INT16 x, INT16 y, HICON16 hIcon )
719 return DrawIcon32( hdc, x, y, hIcon );
723 /***********************************************************************
724 * DrawIcon32 (USER32.158)
726 BOOL32 DrawIcon32( HDC32 hdc, INT32 x, INT32 y, HICON32 hIcon )
730 HBITMAP32 hXorBits, hAndBits;
731 COLORREF oldFg, oldBg;
733 if (!(ptr = (CURSORICONINFO *)GlobalLock16( hIcon ))) return FALSE;
734 if (!(hMemDC = CreateCompatibleDC32( hdc ))) return FALSE;
735 hAndBits = CreateBitmap32( ptr->nWidth, ptr->nHeight, 1, 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) );
743 if (hXorBits && hAndBits)
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 );
751 DeleteDC32( hMemDC );
752 if (hXorBits) DeleteObject32( hXorBits );
753 if (hAndBits) DeleteObject32( hAndBits );
754 GlobalUnlock16( hIcon );
755 SetTextColor32( hdc, oldFg );
756 SetBkColor32( hdc, oldBg );
761 /***********************************************************************
762 * DumpIcon (USER.459)
764 DWORD DumpIcon( SEGPTR pInfo, WORD *lpLen,
765 SEGPTR *lpXorBits, SEGPTR *lpAndBits )
767 CURSORICONINFO *info = PTR_SEG_TO_LIN( pInfo );
768 int sizeAnd, sizeXor;
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 );
780 /***********************************************************************
781 * CURSORICON_SetCursor
783 * Change the X cursor. Helper function for SetCursor() and ShowCursor().
785 static BOOL32 CURSORICON_SetCursor( HCURSOR16 hCursor )
787 Pixmap pixmapBits, pixmapMask, pixmapAll;
789 Cursor cursor = None;
791 if (!hCursor) /* Create an empty cursor */
793 static const char data[] = { 0 };
795 bg.red = bg.green = bg.blue = 0x0000;
796 pixmapBits = XCreateBitmapFromData( display, rootWindow, data, 1, 1 );
799 cursor = XCreatePixmapCursor( display, pixmapBits, pixmapBits,
801 XFreePixmap( display, pixmapBits );
804 else /* Create the X cursor from the bits */
809 if (!(ptr = (CURSORICONINFO*)GlobalLock16( hCursor ))) return FALSE;
810 if (ptr->bPlanes * ptr->bBitsPerPixel != 1)
812 fprintf( stderr, "Cursor %04x has more than 1 bpp!\n", hCursor );
816 /* Create a pixmap and transfer all the bits to it */
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
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);
830 extern void _XInitImageFuncPtrs( XImage* );
831 image->byte_order = MSBFirst;
832 image->bitmap_bit_order = MSBFirst;
833 image->bitmap_unit = 16;
834 _XInitImageFuncPtrs(image);
836 CallTo32_LargeStack( XPutImage, 10,
837 display, pixmapAll, BITMAP_monoGC, image,
838 0, 0, 0, 0, ptr->nWidth, ptr->nHeight*2 );
840 XDestroyImage( image );
843 /* Now create the 2 pixmaps for bits and mask */
845 pixmapBits = XCreatePixmap( display, rootWindow,
846 ptr->nWidth, ptr->nHeight, 1 );
847 pixmapMask = XCreatePixmap( display, rootWindow,
848 ptr->nWidth, ptr->nHeight, 1 );
850 /* Make sure everything went OK so far */
852 if (pixmapBits && pixmapMask && pixmapAll)
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
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
869 * Bits = 'Xor' and not 'And'
870 * Mask = 'Xor' or not 'And'
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
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 );
893 /* Now free everything */
895 if (pixmapAll) XFreePixmap( display, pixmapAll );
896 if (pixmapBits) XFreePixmap( display, pixmapBits );
897 if (pixmapMask) XFreePixmap( display, pixmapMask );
898 GlobalUnlock16( hCursor );
901 if (cursor == None) return FALSE;
902 if (CURSORICON_XCursor != None) XFreeCursor( display, CURSORICON_XCursor );
903 CURSORICON_XCursor = cursor;
905 if (rootWindow != DefaultRootWindow(display))
907 /* Set the cursor on the desktop window */
908 XDefineCursor( display, rootWindow, cursor );
912 /* Set the same cursor for all top-level windows */
913 HWND32 hwnd = GetWindow32( GetDesktopWindow32(), GW_CHILD );
916 Window win = WIN_GetXWindow( hwnd );
917 if (win) XDefineCursor( display, win, cursor );
918 hwnd = GetWindow32( hwnd, GW_HWNDNEXT );
925 /***********************************************************************
926 * SetCursor16 (USER.69)
928 HCURSOR16 SetCursor16( HCURSOR16 hCursor )
930 return (HCURSOR16)SetCursor32( hCursor );
934 /***********************************************************************
935 * SetCursor32 (USER32.471)
937 HCURSOR32 SetCursor32( HCURSOR32 hCursor )
939 HCURSOR32 hOldCursor;
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 );
951 /***********************************************************************
952 * SetCursorPos16 (USER.70)
954 void SetCursorPos16( INT16 x, INT16 y )
956 SetCursorPos32( x, y );
960 /***********************************************************************
961 * SetCursorPos32 (USER32.473)
963 BOOL32 SetCursorPos32( INT32 x, INT32 y )
965 dprintf_cursor( stddeb, "SetCursorPos: x=%d y=%d\n", x, y );
966 XWarpPointer( display, rootWindow, rootWindow, 0, 0, 0, 0, x, y );
971 /***********************************************************************
972 * ShowCursor16 (USER.71)
974 INT16 ShowCursor16( BOOL16 bShow )
976 return ShowCursor32( bShow );
980 /***********************************************************************
981 * ShowCursor32 (USER32.529)
983 INT32 ShowCursor32( BOOL32 bShow )
985 dprintf_cursor( stddeb, "ShowCursor: %d, count=%d\n",
986 bShow, CURSOR_ShowCount );
990 if (++CURSOR_ShowCount == 0)
991 CURSORICON_SetCursor( hActiveCursor ); /* Show it */
995 if (--CURSOR_ShowCount == -1)
996 CURSORICON_SetCursor( 0 ); /* Hide it */
998 return CURSOR_ShowCount;
1002 /***********************************************************************
1003 * GetCursor16 (USER.247)
1005 HCURSOR16 GetCursor16(void)
1007 return hActiveCursor;
1011 /***********************************************************************
1012 * GetCursor32 (USER32.226)
1014 HCURSOR32 GetCursor32(void)
1016 return hActiveCursor;
1020 /***********************************************************************
1021 * ClipCursor16 (USER.16)
1023 BOOL16 ClipCursor16( const RECT16 *rect )
1025 if (!rect) SetRectEmpty32( &CURSOR_ClipRect );
1026 else CONV_RECT16TO32( rect, &CURSOR_ClipRect );
1031 /***********************************************************************
1032 * ClipCursor32 (USER32.52)
1034 BOOL32 ClipCursor32( const RECT32 *rect )
1036 if (!rect) SetRectEmpty32( &CURSOR_ClipRect );
1037 else CopyRect32( &CURSOR_ClipRect, rect );
1042 /***********************************************************************
1043 * GetCursorPos16 (USER.17)
1045 void GetCursorPos16( POINT16 *pt )
1048 int rootX, rootY, childX, childY;
1049 unsigned int mousebut;
1052 if (!XQueryPointer( display, rootWindow, &root, &child,
1053 &rootX, &rootY, &childX, &childY, &mousebut ))
1060 dprintf_cursor(stddeb, "GetCursorPos: ret=%d,%d\n", pt->x, pt->y );
1064 /***********************************************************************
1065 * GetCursorPos32 (USER32.228)
1067 void GetCursorPos32( POINT32 *pt )
1070 GetCursorPos16( &pt16 );
1071 if (pt) CONV_POINT16TO32( &pt16, pt );
1075 /***********************************************************************
1076 * GetClipCursor16 (USER.309)
1078 void GetClipCursor16( RECT16 *rect )
1080 if (rect) CONV_RECT32TO16( &CURSOR_ClipRect, rect );
1084 /***********************************************************************
1085 * GetClipCursor32 (USER32.220)
1087 void GetClipCursor32( RECT32 *rect )
1089 if (rect) CopyRect32( rect, &CURSOR_ClipRect );
1093 /**********************************************************************
1094 * GetIconID (USER.455)
1096 WORD GetIconID( HGLOBAL16 hResource, DWORD resType )
1098 CURSORICONDIR *lpDir = (CURSORICONDIR *)GlobalLock16(hResource);
1099 /* LockResource16(hResource); */
1101 if (!lpDir || lpDir->idReserved ||
1102 ((lpDir->idType != 1) && (lpDir->idType != 2)))
1104 dprintf_cursor(stddeb,"GetIconID: invalid resource directory\n");
1108 dprintf_cursor( stddeb, "GetIconID: hRes=%04x, entries=%i\n",
1109 hResource, lpDir->idCount );
1113 case 1: /* cursor */
1115 CURSORDIRENTRY *entry = CURSORICON_FindBestCursor( lpDir,
1116 SYSMETRICS_CXCURSOR, SYSMETRICS_CYCURSOR );
1117 return entry ? entry->wResId : 0;
1121 ICONDIRENTRY * entry = CURSORICON_FindBestIcon( lpDir,
1122 SYSMETRICS_CXICON, SYSMETRICS_CYICON,
1123 MIN( 16, COLOR_GetSystemPaletteSize() ) );
1124 return entry ? entry->wResId : 0;
1127 fprintf( stderr, "GetIconID: invalid res type %ld\n", resType );
1132 /**********************************************************************
1133 * LoadIconHandler (USER.456)
1135 HICON16 LoadIconHandler( HGLOBAL16 hResource, BOOL16 bNew )
1137 dprintf_cursor(stddeb,"LoadIconHandler: hRes=%04x\n",hResource);
1141 fprintf(stdnimp,"LoadIconHandler: 2.xx resources are not supported\n");
1144 return CURSORICON_LoadHandler( hResource, 0, FALSE);
1147 /**********************************************************************
1148 * GetIconInfo (USER32.241)