2 * Cursor and icon support
4 * Copyright 1995 Alexandre Julliard
10 * Cursors and icons are stored in a global heap block, with the
13 * CURSORICONINFO info;
17 * The bits structures are in the format of a device-dependent bitmap.
19 * This layout is very sub-optimal, as the bitmap bits are stored in
20 * the X client instead of in the server like other bitmaps; however,
21 * some programs (notably Paint Brush) expect to be able to manipulate
22 * the bits directly :-(
30 #include "cursoricon.h"
31 #include "sysmetrics.h"
39 Cursor CURSORICON_XCursor
= None
; /* Current X cursor */
40 static HCURSOR hActiveCursor
= 0; /* Active cursor */
41 static int CURSOR_ShowCount
= 0; /* Cursor display count */
42 static RECT CURSOR_ClipRect
; /* Cursor clipping rect */
44 /**********************************************************************
45 * CURSORICON_FindBestIcon
47 * Find the icon closest to the requested size and number of colors.
49 static ICONDIRENTRY
*CURSORICON_FindBestIcon( CURSORICONDIR
*dir
, int width
,
50 int height
, int colors
)
52 int i
, maxcolors
, maxwidth
, maxheight
;
53 ICONDIRENTRY
*entry
, *bestEntry
= NULL
;
57 fprintf( stderr
, "Icon: empty directory!\n" );
60 if (dir
->idCount
== 1) return &dir
->idEntries
[0].icon
; /* No choice... */
62 /* First find the exact size with less colors */
65 for (i
= 0, entry
= &dir
->idEntries
[0].icon
; i
< dir
->idCount
; i
++,entry
++)
66 if ((entry
->bWidth
== width
) && (entry
->bHeight
== height
) &&
67 (entry
->bColorCount
<= colors
) && (entry
->bColorCount
> maxcolors
))
70 maxcolors
= entry
->bColorCount
;
72 if (bestEntry
) return bestEntry
;
74 /* First find the exact size with more colors */
77 for (i
= 0, entry
= &dir
->idEntries
[0].icon
; i
< dir
->idCount
; i
++,entry
++)
78 if ((entry
->bWidth
== width
) && (entry
->bHeight
== height
) &&
79 (entry
->bColorCount
> colors
) && (entry
->bColorCount
<= maxcolors
))
82 maxcolors
= entry
->bColorCount
;
84 if (bestEntry
) return bestEntry
;
86 /* Now find a smaller one with less colors */
88 maxcolors
= maxwidth
= maxheight
= 0;
89 for (i
= 0, entry
= &dir
->idEntries
[0].icon
; i
< dir
->idCount
; i
++,entry
++)
90 if ((entry
->bWidth
<= width
) && (entry
->bHeight
<= height
) &&
91 (entry
->bWidth
>= maxwidth
) && (entry
->bHeight
>= maxheight
) &&
92 (entry
->bColorCount
<= colors
) && (entry
->bColorCount
> maxcolors
))
95 maxwidth
= entry
->bWidth
;
96 maxheight
= entry
->bHeight
;
97 maxcolors
= entry
->bColorCount
;
99 if (bestEntry
) return bestEntry
;
101 /* Now find a smaller one with more colors */
104 maxwidth
= maxheight
= 0;
105 for (i
= 0, entry
= &dir
->idEntries
[0].icon
; i
< dir
->idCount
; i
++,entry
++)
106 if ((entry
->bWidth
<= width
) && (entry
->bHeight
<= height
) &&
107 (entry
->bWidth
>= maxwidth
) && (entry
->bHeight
>= maxheight
) &&
108 (entry
->bColorCount
> colors
) && (entry
->bColorCount
<= maxcolors
))
111 maxwidth
= entry
->bWidth
;
112 maxheight
= entry
->bHeight
;
113 maxcolors
= entry
->bColorCount
;
115 if (bestEntry
) return bestEntry
;
117 /* Now find a larger one with less colors */
120 maxwidth
= maxheight
= 255;
121 for (i
= 0, entry
= &dir
->idEntries
[0].icon
; i
< dir
->idCount
; i
++,entry
++)
122 if ((entry
->bWidth
<= maxwidth
) && (entry
->bHeight
<= maxheight
) &&
123 (entry
->bColorCount
<= colors
) && (entry
->bColorCount
> maxcolors
))
126 maxwidth
= entry
->bWidth
;
127 maxheight
= entry
->bHeight
;
128 maxcolors
= entry
->bColorCount
;
130 if (bestEntry
) return bestEntry
;
132 /* Now find a larger one with more colors */
134 maxcolors
= maxwidth
= maxheight
= 255;
135 for (i
= 0, entry
= &dir
->idEntries
[0].icon
; i
< dir
->idCount
; i
++,entry
++)
136 if ((entry
->bWidth
<= maxwidth
) && (entry
->bHeight
<= maxheight
) &&
137 (entry
->bColorCount
> colors
) && (entry
->bColorCount
<= maxcolors
))
140 maxwidth
= entry
->bWidth
;
141 maxheight
= entry
->bHeight
;
142 maxcolors
= entry
->bColorCount
;
149 /**********************************************************************
150 * CURSORICON_FindBestCursor
152 * Find the cursor closest to the requested size.
154 static CURSORDIRENTRY
*CURSORICON_FindBestCursor( CURSORICONDIR
*dir
,
155 int width
, int height
)
157 int i
, maxwidth
, maxheight
;
158 CURSORDIRENTRY
*entry
, *bestEntry
= NULL
;
160 if (dir
->idCount
< 1)
162 fprintf( stderr
, "Cursor: empty directory!\n" );
165 if (dir
->idCount
== 1) return &dir
->idEntries
[0].cursor
; /* No choice... */
167 /* First find the largest one smaller than or equal to the requested size*/
169 maxwidth
= maxheight
= 0;
170 for(i
= 0,entry
= &dir
->idEntries
[0].cursor
; i
< dir
->idCount
; i
++,entry
++)
171 if ((entry
->wWidth
<= width
) && (entry
->wHeight
<= height
) &&
172 (entry
->wWidth
> maxwidth
) && (entry
->wHeight
> maxheight
))
175 maxwidth
= entry
->wWidth
;
176 maxheight
= entry
->wHeight
;
178 if (bestEntry
) return bestEntry
;
180 /* Now find the smallest one larger than the requested size */
182 maxwidth
= maxheight
= 255;
183 for(i
= 0,entry
= &dir
->idEntries
[0].cursor
; i
< dir
->idCount
; i
++,entry
++)
184 if ((entry
->wWidth
< maxwidth
) && (entry
->wHeight
< maxheight
))
187 maxwidth
= entry
->wWidth
;
188 maxheight
= entry
->wHeight
;
195 /**********************************************************************
196 * CURSORICON_LoadDirEntry
198 * Load the icon/cursor directory for a given resource name and find the
199 * best matching entry.
201 static BOOL
CURSORICON_LoadDirEntry(HANDLE hInstance
, SEGPTR name
,
202 int width
, int height
, int colors
,
203 BOOL fCursor
, CURSORICONDIRENTRY
*dirEntry
)
208 CURSORICONDIRENTRY
*entry
= NULL
;
210 if (!(hRsrc
= FindResource( hInstance
, name
,
211 fCursor
? RT_GROUP_CURSOR
: RT_GROUP_ICON
)))
213 if (!(hMem
= LoadResource( hInstance
, hRsrc
))) return FALSE
;
214 if ((dir
= (CURSORICONDIR
*)LockResource( hMem
)))
217 entry
= (CURSORICONDIRENTRY
*)CURSORICON_FindBestCursor( dir
,
220 entry
= (CURSORICONDIRENTRY
*)CURSORICON_FindBestIcon( dir
,
221 width
, height
, colors
);
222 if (entry
) *dirEntry
= *entry
;
224 FreeResource( hMem
);
225 return (entry
!= NULL
);
229 /**********************************************************************
230 * CURSORICON_LoadHandler
232 * Create a cursor or icon from a resource.
234 static HANDLE
CURSORICON_LoadHandler( HANDLE handle
, HINSTANCE hInstance
,
237 HANDLE hAndBits
, hXorBits
;
239 int size
, sizeAnd
, sizeXor
;
240 POINT hotspot
= { 0 ,0 };
241 BITMAPOBJ
*bmpXor
, *bmpAnd
;
242 BITMAPINFO
*bmi
, *pInfo
;
243 CURSORICONINFO
*info
;
246 if (fCursor
) /* If cursor, get the hotspot */
248 POINT
*pt
= (POINT
*)LockResource( handle
);
250 bmi
= (BITMAPINFO
*)(pt
+ 1);
252 else bmi
= (BITMAPINFO
*)LockResource( handle
);
254 /* Create a copy of the bitmap header */
256 size
= DIB_BitmapInfoSize( bmi
, DIB_RGB_COLORS
);
257 /* Make sure we have room for the monochrome bitmap later on */
258 size
= MAX( size
, sizeof(BITMAPINFOHEADER
) + 2*sizeof(RGBQUAD
) );
259 pInfo
= (BITMAPINFO
*)xmalloc( size
);
260 memcpy( pInfo
, bmi
, size
);
262 if (pInfo
->bmiHeader
.biSize
== sizeof(BITMAPINFOHEADER
))
264 if (pInfo
->bmiHeader
.biCompression
!= BI_RGB
)
266 fprintf(stderr
,"Unknown size for compressed icon bitmap.\n");
270 pInfo
->bmiHeader
.biHeight
/= 2;
272 else if (pInfo
->bmiHeader
.biSize
== sizeof(BITMAPCOREHEADER
))
274 BITMAPCOREHEADER
*core
= (BITMAPCOREHEADER
*)pInfo
;
279 fprintf( stderr
, "CURSORICON_Load: Unknown bitmap length %ld!\n",
280 pInfo
->bmiHeader
.biSize
);
285 /* Create the XOR bitmap */
287 if (!(hdc
= GetDC( 0 )))
293 hXorBits
= CreateDIBitmap( hdc
, &pInfo
->bmiHeader
, CBM_INIT
,
294 (char*)bmi
+ size
, pInfo
, DIB_RGB_COLORS
);
296 /* Fix the bitmap header to load the monochrome mask */
298 if (pInfo
->bmiHeader
.biSize
== sizeof(BITMAPINFOHEADER
))
300 BITMAPINFOHEADER
*bih
= &pInfo
->bmiHeader
;
301 RGBQUAD
*rgb
= pInfo
->bmiColors
;
302 bits
= (char *)bmi
+ size
+
303 DIB_GetImageWidthBytes(bih
->biWidth
,bih
->biBitCount
)*bih
->biHeight
;
305 bih
->biClrUsed
= bih
->biClrImportant
= 2;
306 rgb
[0].rgbBlue
= rgb
[0].rgbGreen
= rgb
[0].rgbRed
= 0x00;
307 rgb
[1].rgbBlue
= rgb
[1].rgbGreen
= rgb
[1].rgbRed
= 0xff;
308 rgb
[0].rgbReserved
= rgb
[1].rgbReserved
= 0;
312 BITMAPCOREHEADER
*bch
= (BITMAPCOREHEADER
*)pInfo
;
313 RGBTRIPLE
*rgb
= (RGBTRIPLE
*)(bch
+ 1);
314 bits
= (char *)bmi
+ size
+
315 DIB_GetImageWidthBytes(bch
->bcWidth
,bch
->bcBitCount
)*bch
->bcHeight
;
317 rgb
[0].rgbtBlue
= rgb
[0].rgbtGreen
= rgb
[0].rgbtRed
= 0x00;
318 rgb
[1].rgbtBlue
= rgb
[1].rgbtGreen
= rgb
[1].rgbtRed
= 0xff;
321 /* Create the AND bitmap */
323 hAndBits
= CreateDIBitmap( hdc
, &pInfo
->bmiHeader
, CBM_INIT
,
324 bits
, pInfo
, DIB_RGB_COLORS
);
327 /* Now create the CURSORICONINFO structure */
329 bmpXor
= (BITMAPOBJ
*) GDI_GetObjPtr( hXorBits
, BITMAP_MAGIC
);
330 bmpAnd
= (BITMAPOBJ
*) GDI_GetObjPtr( hAndBits
, BITMAP_MAGIC
);
331 sizeXor
= bmpXor
->bitmap
.bmHeight
* bmpXor
->bitmap
.bmWidthBytes
;
332 sizeAnd
= bmpAnd
->bitmap
.bmHeight
* bmpAnd
->bitmap
.bmWidthBytes
;
334 if (!(handle
= GlobalAlloc( GMEM_MOVEABLE
,
335 sizeof(CURSORICONINFO
) + sizeXor
+ sizeAnd
)))
337 DeleteObject( hXorBits
);
338 DeleteObject( hAndBits
);
342 /* Make it owned by the module */
343 if (hInstance
) FarSetOwner( handle
, (WORD
)(DWORD
)GetExePtr(hInstance
) );
345 info
= (CURSORICONINFO
*)GlobalLock( handle
);
346 info
->ptHotSpot
.x
= hotspot
.x
;
347 info
->ptHotSpot
.y
= hotspot
.y
;
348 info
->nWidth
= bmpXor
->bitmap
.bmWidth
;
349 info
->nHeight
= bmpXor
->bitmap
.bmHeight
;
350 info
->nWidthBytes
= bmpXor
->bitmap
.bmWidthBytes
;
351 info
->bPlanes
= bmpXor
->bitmap
.bmPlanes
;
352 info
->bBitsPerPixel
= bmpXor
->bitmap
.bmBitsPixel
;
354 /* Transfer the bitmap bits to the CURSORICONINFO structure */
356 GetBitmapBits( hAndBits
, sizeAnd
, (char *)(info
+ 1) );
357 GetBitmapBits( hXorBits
, sizeXor
, (char *)(info
+ 1) + sizeAnd
);
358 DeleteObject( hXorBits
);
359 DeleteObject( hAndBits
);
360 GlobalUnlock( handle
);
364 /**********************************************************************
367 * Load a cursor or icon.
369 static HANDLE
CURSORICON_Load( HANDLE hInstance
, SEGPTR name
, int width
,
370 int height
, int colors
, BOOL fCursor
)
374 CURSORICONDIRENTRY dirEntry
;
376 if (!hInstance
) /* OEM cursor/icon */
378 if (HIWORD(name
)) /* Check for '#xxx' name */
380 char *ptr
= PTR_SEG_TO_LIN( name
);
381 if (ptr
[0] != '#') return 0;
382 if (!(name
= (SEGPTR
)atoi( ptr
+ 1 ))) return 0;
384 return OBM_LoadCursorIcon( LOWORD(name
), fCursor
);
387 /* Find the best entry in the directory */
389 if (!CURSORICON_LoadDirEntry( hInstance
, name
, width
, height
,
390 colors
, fCursor
, &dirEntry
)) return 0;
392 /* Load the resource */
394 if (!(hRsrc
= FindResource( hInstance
,
395 MAKEINTRESOURCE( dirEntry
.icon
.wResId
),
396 fCursor
? RT_CURSOR
: RT_ICON
))) return 0;
397 if (!(handle
= LoadResource( hInstance
, hRsrc
))) return 0;
399 hRet
= CURSORICON_LoadHandler( handle
, hInstance
, fCursor
);
400 FreeResource(handle
);
405 /***********************************************************************
408 * Make a copy of a cursor or icon.
410 static HANDLE
CURSORICON_Copy( HANDLE hInstance
, HANDLE handle
)
412 char *ptrOld
, *ptrNew
;
416 if (!(ptrOld
= (char *)GlobalLock( handle
))) return 0;
417 if (!(hInstance
= GetExePtr( hInstance
))) return 0;
418 size
= GlobalSize( handle
);
419 hNew
= GlobalAlloc( GMEM_MOVEABLE
, size
);
420 FarSetOwner( hNew
, (WORD
)(DWORD
)hInstance
);
421 ptrNew
= (char *)GlobalLock( hNew
);
422 memcpy( ptrNew
, ptrOld
, size
);
423 GlobalUnlock( handle
);
424 GlobalUnlock( hNew
);
428 /***********************************************************************
429 * CURSORICON_IconToCursor
431 * Should convert bitmap to mono and truncate if too large
432 * FIXME: if icon is passed returns a copy of OCR_DRAGOBJECT cursor
433 * but should actually convert icon to cursor.
435 HCURSOR
CURSORICON_IconToCursor(HICON hIcon
)
437 CURSORICONINFO
*ptr
= NULL
;
440 if (!(ptr
= (CURSORICONINFO
*)GlobalLock( hIcon
))) return FALSE
;
441 if (ptr
->bPlanes
* ptr
->bBitsPerPixel
== 1)
443 return hIcon
; /* assuming it's a cursor */
449 HTASK hTask
= GetCurrentTask();
450 TDB
* pTask
= (TDB
*)GlobalLock(hTask
);
454 fprintf( stdnimp
, "IconToCursor: Icons are not supported, returning default!\n");
455 return CURSORICON_Copy( pTask
->hInstance
,
456 CURSORICON_Load(0,MAKEINTRESOURCE(OCR_DRAGOBJECT
),
457 SYSMETRICS_CXCURSOR
, SYSMETRICS_CYCURSOR
, 1, TRUE
) );
463 /***********************************************************************
464 * LoadCursor (USER.173)
466 HCURSOR
LoadCursor( HANDLE hInstance
, SEGPTR name
)
469 dprintf_cursor( stddeb
, "LoadCursor: "NPFMT
" '%s'\n",
470 hInstance
, (char *)PTR_SEG_TO_LIN( name
) );
472 dprintf_cursor( stddeb
, "LoadCursor: "NPFMT
" %04x\n",
473 hInstance
, LOWORD(name
) );
475 return CURSORICON_Load( hInstance
, name
,
476 SYSMETRICS_CXCURSOR
, SYSMETRICS_CYCURSOR
, 1, TRUE
);
480 /***********************************************************************
481 * LoadIcon (USER.174)
483 HICON
LoadIcon( HANDLE hInstance
, SEGPTR name
)
486 dprintf_icon( stddeb
, "LoadIcon: "NPFMT
" '%s'\n",
487 hInstance
, (char *)PTR_SEG_TO_LIN( name
) );
489 dprintf_icon( stddeb
, "LoadIcon: "NPFMT
" %04x\n",
490 hInstance
, LOWORD(name
) );
492 return CURSORICON_Load( hInstance
, name
,
493 SYSMETRICS_CXICON
, SYSMETRICS_CYICON
,
494 MIN( 16, 1 << screenDepth
), FALSE
);
498 /***********************************************************************
499 * CreateCursor (USER.406)
501 HCURSOR
CreateCursor( HINSTANCE hInstance
, INT xHotSpot
, INT yHotSpot
,
502 INT nWidth
, INT nHeight
,
503 const BYTE
*lpANDbits
, const BYTE
*lpXORbits
)
505 CURSORICONINFO info
= { { xHotSpot
, yHotSpot
}, nWidth
, nHeight
, 0, 1, 1 };
507 dprintf_cursor( stddeb
, "CreateCursor: %dx%d spot=%d,%d xor=%p and=%p\n",
508 nWidth
, nHeight
, xHotSpot
, yHotSpot
, lpXORbits
, lpANDbits
);
509 return CreateCursorIconIndirect( hInstance
, &info
, lpANDbits
, lpXORbits
);
513 /***********************************************************************
514 * CreateIcon (USER.407)
516 HICON
CreateIcon( HINSTANCE hInstance
, INT nWidth
, INT nHeight
, BYTE bPlanes
,
517 BYTE bBitsPixel
, const BYTE
* lpANDbits
, const BYTE
* lpXORbits
)
519 CURSORICONINFO info
= { { 0, 0 }, nWidth
, nHeight
, 0, bPlanes
, bBitsPixel
};
521 dprintf_icon( stddeb
, "CreateIcon: %dx%dx%d, xor=%p, and=%p\n",
522 nWidth
, nHeight
, bPlanes
* bBitsPixel
, lpXORbits
, lpANDbits
);
523 return CreateCursorIconIndirect( hInstance
, &info
, lpANDbits
, lpXORbits
);
527 /***********************************************************************
528 * CreateCursorIconIndirect (USER.408)
530 HANDLE
CreateCursorIconIndirect( HANDLE hInstance
, CURSORICONINFO
*info
,
531 const BYTE
*lpANDbits
, const BYTE
*lpXORbits
)
535 int sizeAnd
, sizeXor
;
537 hInstance
= GetExePtr( hInstance
); /* Make it a module handle */
538 if (!hInstance
|| !lpXORbits
|| !lpANDbits
|| info
->bPlanes
!= 1) return 0;
539 info
->nWidthBytes
= (info
->nWidth
* info
->bBitsPerPixel
+ 15) / 16 * 2;
540 sizeXor
= info
->nHeight
* info
->nWidthBytes
;
541 sizeAnd
= info
->nHeight
* ((info
->nWidth
+ 15) / 16 * 2);
542 if (!(handle
= DirectResAlloc(hInstance
, 0x10,
543 sizeof(CURSORICONINFO
) + sizeXor
+ sizeAnd
)))
545 ptr
= (char *)GlobalLock( handle
);
546 memcpy( ptr
, info
, sizeof(*info
) );
547 memcpy( ptr
+ sizeof(CURSORICONINFO
), lpANDbits
, sizeAnd
);
548 memcpy( ptr
+ sizeof(CURSORICONINFO
) + sizeAnd
, lpXORbits
, sizeXor
);
549 GlobalUnlock( handle
);
554 /***********************************************************************
555 * CopyIcon (USER.368)
558 HICON
CopyIcon( HICON hIcon
)
560 dprintf_icon( stddeb
, "CopyIcon: "NPFMT
"\n", hIcon
);
561 return CURSORICON_Copy( 0, hIcon
);
564 HICON
CopyIcon( HANDLE hInstance
, HICON hIcon
)
566 dprintf_icon( stddeb
, "CopyIcon: "NPFMT
" "NPFMT
"\n", hInstance
, hIcon
);
567 return CURSORICON_Copy( hInstance
, hIcon
);
572 /***********************************************************************
573 * CopyCursor (USER.369)
576 HCURSOR
CopyCursor( HCURSOR hCursor
)
578 dprintf_cursor( stddeb
, "CopyCursor: "NPFMT
"\n", hCursor
);
579 return CURSORICON_Copy( 0, hCursor
);
582 HCURSOR
CopyCursor( HANDLE hInstance
, HCURSOR hCursor
)
584 dprintf_cursor( stddeb
, "CopyCursor: "NPFMT
" "NPFMT
"\n", hInstance
, hCursor
);
585 return CURSORICON_Copy( hInstance
, hCursor
);
590 /***********************************************************************
591 * DestroyIcon (USER.457)
593 BOOL
DestroyIcon( HICON hIcon
)
595 dprintf_icon( stddeb
, "DestroyIcon: "NPFMT
"\n", hIcon
);
596 /* FIXME: should check for OEM icon here */
597 return (GlobalFree( hIcon
) != 0);
601 /***********************************************************************
602 * DestroyCursor (USER.458)
604 BOOL
DestroyCursor( HCURSOR hCursor
)
606 dprintf_cursor( stddeb
, "DestroyCursor: "NPFMT
"\n", hCursor
);
607 /* FIXME: should check for OEM cursor here */
608 return (GlobalFree( hCursor
) != 0);
612 /***********************************************************************
615 BOOL
DrawIcon( HDC hdc
, INT x
, INT y
, HICON hIcon
)
619 HBITMAP hXorBits
, hAndBits
;
620 COLORREF oldFg
, oldBg
;
622 if (!(ptr
= (CURSORICONINFO
*)GlobalLock( hIcon
))) return FALSE
;
623 if (!(hMemDC
= CreateCompatibleDC( hdc
))) return FALSE
;
624 hAndBits
= CreateBitmap( ptr
->nWidth
, ptr
->nHeight
, 1, 1, (char *)(ptr
+1));
625 hXorBits
= CreateBitmap( ptr
->nWidth
, ptr
->nHeight
, ptr
->bPlanes
,
626 ptr
->bBitsPerPixel
, (char *)(ptr
+ 1)
627 + ptr
->nHeight
* ((ptr
->nWidth
+ 15) / 16 * 2) );
628 oldFg
= SetTextColor( hdc
, RGB(0,0,0) );
629 oldBg
= SetBkColor( hdc
, RGB(255,255,255) );
631 if (hXorBits
&& hAndBits
)
633 HBITMAP hBitTemp
= SelectObject( hMemDC
, hAndBits
);
634 BitBlt( hdc
, x
, y
, ptr
->nWidth
, ptr
->nHeight
, hMemDC
, 0, 0, SRCAND
);
635 SelectObject( hMemDC
, hXorBits
);
636 BitBlt( hdc
, x
, y
, ptr
->nWidth
, ptr
->nHeight
, hMemDC
, 0, 0, SRCINVERT
);
637 SelectObject( hMemDC
, hBitTemp
);
640 if (hXorBits
) DeleteObject( hXorBits
);
641 if (hAndBits
) DeleteObject( hAndBits
);
642 GlobalUnlock( hIcon
);
643 SetTextColor( hdc
, oldFg
);
644 SetBkColor( hdc
, oldBg
);
649 /***********************************************************************
650 * DumpIcon (USER.459)
652 DWORD
DumpIcon( SEGPTR pInfo
, WORD
*lpLen
,
653 SEGPTR
*lpXorBits
, SEGPTR
*lpAndBits
)
655 CURSORICONINFO
*info
= PTR_SEG_TO_LIN( pInfo
);
656 int sizeAnd
, sizeXor
;
659 sizeXor
= info
->nHeight
* info
->nWidthBytes
;
660 sizeAnd
= info
->nHeight
* ((info
->nWidth
+ 15) / 16 * 2);
661 if (lpAndBits
) *lpAndBits
= pInfo
+ sizeof(CURSORICONINFO
);
662 if (lpXorBits
) *lpXorBits
= pInfo
+ sizeof(CURSORICONINFO
) + sizeAnd
;
663 if (lpLen
) *lpLen
= sizeof(CURSORICONINFO
) + sizeAnd
+ sizeXor
;
664 return MAKELONG( sizeXor
, sizeXor
);
668 /***********************************************************************
669 * CURSORICON_SetCursor
671 * Change the X cursor. Helper function for SetCursor() and ShowCursor().
673 static BOOL
CURSORICON_SetCursor( HCURSOR hCursor
)
675 Pixmap pixmapBits
, pixmapMask
, pixmapAll
;
677 Cursor cursor
= None
;
679 if (!hCursor
) /* Create an empty cursor */
681 static const char data
[] = { 0 };
683 bg
.red
= bg
.green
= bg
.blue
= 0x0000;
684 pixmapBits
= XCreateBitmapFromData( display
, rootWindow
, data
, 1, 1 );
687 cursor
= XCreatePixmapCursor( display
, pixmapBits
, pixmapBits
,
689 XFreePixmap( display
, pixmapBits
);
692 else /* Create the X cursor from the bits */
697 if (!(ptr
= (CURSORICONINFO
*)GlobalLock( hCursor
))) return FALSE
;
698 if (ptr
->bPlanes
* ptr
->bBitsPerPixel
!= 1)
700 fprintf( stderr
, "Cursor "NPFMT
" has more than 1 bpp!\n", hCursor
);
704 /* Create a pixmap and transfer all the bits to it */
706 pixmapAll
= XCreatePixmap( display
, rootWindow
,
707 ptr
->nWidth
, ptr
->nHeight
* 2, 1 );
708 image
= XCreateImage( display
, DefaultVisualOfScreen(screen
),
709 1, ZPixmap
, 0, (char *)(ptr
+ 1), ptr
->nWidth
,
710 ptr
->nHeight
* 2, 16, ptr
->nWidthBytes
);
713 extern void _XInitImageFuncPtrs( XImage
* );
714 image
->byte_order
= MSBFirst
;
715 image
->bitmap_bit_order
= MSBFirst
;
716 image
->bitmap_unit
= 16;
717 _XInitImageFuncPtrs(image
);
719 CallTo32_LargeStack( XPutImage
, 10,
720 display
, pixmapAll
, BITMAP_monoGC
, image
,
721 0, 0, 0, 0, ptr
->nWidth
, ptr
->nHeight
*2 );
723 XDestroyImage( image
);
726 /* Now create the 2 pixmaps for bits and mask */
728 pixmapBits
= XCreatePixmap( display
, rootWindow
,
729 ptr
->nWidth
, ptr
->nHeight
, 1 );
730 pixmapMask
= XCreatePixmap( display
, rootWindow
,
731 ptr
->nWidth
, ptr
->nHeight
, 1 );
733 /* Make sure everything went OK so far */
735 if (pixmapBits
&& pixmapMask
&& pixmapAll
)
737 /* We have to do some magic here, as cursors are not fully
738 * compatible between Windows and X11. Under X11, there
739 * are only 3 possible color cursor: black, white and
740 * masked. So we map the 4th Windows color (invert the
741 * bits on the screen) to black. This require some boolean
745 * Xor And Result | Bits Mask Result
746 * 0 0 black | 0 1 background
747 * 0 1 no change | X 0 no change
748 * 1 0 white | 1 1 foreground
749 * 1 1 inverted | 0 1 background
752 * Bits = 'Xor' and not 'And'
753 * Mask = 'Xor' or not 'And'
755 * FIXME: apparently some servers do support 'inverted' color.
756 * I don't know if it's correct per the X spec, but maybe
757 * we ought to take advantage of it. -- AJ
759 XCopyArea( display
, pixmapAll
, pixmapBits
, BITMAP_monoGC
,
760 0, 0, ptr
->nWidth
, ptr
->nHeight
, 0, 0 );
761 XCopyArea( display
, pixmapAll
, pixmapMask
, BITMAP_monoGC
,
762 0, 0, ptr
->nWidth
, ptr
->nHeight
, 0, 0 );
763 XSetFunction( display
, BITMAP_monoGC
, GXandReverse
);
764 XCopyArea( display
, pixmapAll
, pixmapBits
, BITMAP_monoGC
,
765 0, ptr
->nHeight
, ptr
->nWidth
, ptr
->nHeight
, 0, 0 );
766 XSetFunction( display
, BITMAP_monoGC
, GXorReverse
);
767 XCopyArea( display
, pixmapAll
, pixmapMask
, BITMAP_monoGC
,
768 0, ptr
->nHeight
, ptr
->nWidth
, ptr
->nHeight
, 0, 0 );
769 XSetFunction( display
, BITMAP_monoGC
, GXcopy
);
770 fg
.red
= fg
.green
= fg
.blue
= 0xffff;
771 bg
.red
= bg
.green
= bg
.blue
= 0x0000;
772 cursor
= XCreatePixmapCursor( display
, pixmapBits
, pixmapMask
,
773 &fg
, &bg
, ptr
->ptHotSpot
.x
, ptr
->ptHotSpot
.y
);
776 /* Now free everything */
778 if (pixmapAll
) XFreePixmap( display
, pixmapAll
);
779 if (pixmapBits
) XFreePixmap( display
, pixmapBits
);
780 if (pixmapMask
) XFreePixmap( display
, pixmapMask
);
781 GlobalUnlock( hCursor
);
784 if (cursor
== None
) return FALSE
;
785 if (CURSORICON_XCursor
!= None
) XFreeCursor( display
, CURSORICON_XCursor
);
786 CURSORICON_XCursor
= cursor
;
788 if (rootWindow
!= DefaultRootWindow(display
))
790 /* Set the cursor on the desktop window */
791 XDefineCursor( display
, rootWindow
, cursor
);
795 /* Set the same cursor for all top-level windows */
796 HWND hwnd
= GetWindow( GetDesktopWindow(), GW_CHILD
);
799 Window win
= WIN_GetXWindow( hwnd
);
800 if (win
) XDefineCursor( display
, win
, cursor
);
801 hwnd
= GetWindow( hwnd
, GW_HWNDNEXT
);
808 /***********************************************************************
809 * SetCursor (USER.69)
811 HCURSOR
SetCursor( HCURSOR hCursor
)
815 if (hCursor
== hActiveCursor
) return hActiveCursor
; /* No change */
816 dprintf_cursor( stddeb
, "SetCursor: "NPFMT
"\n", hCursor
);
817 hOldCursor
= hActiveCursor
;
818 hActiveCursor
= hCursor
;
819 /* Change the cursor shape only if it is visible */
820 if (CURSOR_ShowCount
>= 0) CURSORICON_SetCursor( hActiveCursor
);
825 /***********************************************************************
826 * SetCursorPos (USER.70)
828 void SetCursorPos( short x
, short y
)
830 dprintf_cursor( stddeb
, "SetCursorPos: x=%d y=%d\n", x
, y
);
831 XWarpPointer( display
, rootWindow
, rootWindow
, 0, 0, 0, 0, x
, y
);
835 /***********************************************************************
836 * ShowCursor (USER.71)
838 int ShowCursor( BOOL bShow
)
840 dprintf_cursor( stddeb
, "ShowCursor: %d, count=%d\n",
841 bShow
, CURSOR_ShowCount
);
845 if (++CURSOR_ShowCount
== 0)
846 CURSORICON_SetCursor( hActiveCursor
); /* Show it */
850 if (--CURSOR_ShowCount
== -1)
851 CURSORICON_SetCursor( 0 ); /* Hide it */
853 return CURSOR_ShowCount
;
857 /***********************************************************************
858 * GetCursor (USER.247)
860 HCURSOR
GetCursor(void)
862 return hActiveCursor
;
866 /***********************************************************************
867 * ClipCursor (USER.16)
869 BOOL
ClipCursor( RECT
*rect
)
871 if (!rect
) SetRectEmpty( &CURSOR_ClipRect
);
872 else CopyRect( &CURSOR_ClipRect
, rect
);
877 /***********************************************************************
878 * GetCursorPos (USER.17)
880 void GetCursorPos( POINT
*pt
)
883 int rootX
, rootY
, childX
, childY
;
884 unsigned int mousebut
;
887 if (!XQueryPointer( display
, rootWindow
, &root
, &child
,
888 &rootX
, &rootY
, &childX
, &childY
, &mousebut
))
892 pt
->x
= rootX
+ desktopX
;
893 pt
->y
= rootY
+ desktopY
;
895 dprintf_cursor(stddeb
, "GetCursorPos: ret=%ld,%ld\n", (LONG
)pt
->x
,
900 /***********************************************************************
901 * GetClipCursor (USER.309)
903 void GetClipCursor( RECT
*rect
)
905 if (rect
) CopyRect( rect
, &CURSOR_ClipRect
);
909 /**********************************************************************
910 * GetIconID (USER.455)
912 WORD
GetIconID( HANDLE hResource
, DWORD resType
)
914 CURSORICONDIR
*lpDir
= LockResource(hResource
);
916 if (!lpDir
|| lpDir
->idReserved
||
917 ((lpDir
->idType
!= 1) && (lpDir
->idType
!= 2)))
919 dprintf_cursor(stddeb
,"GetIconID: invalid resource directory\n");
923 dprintf_cursor( stddeb
, "GetIconID: hRes="NPFMT
", entries=%i\n",
924 hResource
, lpDir
->idCount
);
930 CURSORDIRENTRY
*entry
= CURSORICON_FindBestCursor( lpDir
,
931 SYSMETRICS_CXCURSOR
, SYSMETRICS_CYCURSOR
);
932 return entry
? entry
->wResId
: 0;
936 ICONDIRENTRY
*entry
= CURSORICON_FindBestIcon( lpDir
,
937 SYSMETRICS_CXICON
, SYSMETRICS_CYICON
,
938 MIN( 16, 1 << screenDepth
) );
939 return entry
? entry
->wResId
: 0;
942 fprintf( stderr
, "GetIconID: invalid res type %ld\n", resType
);
947 /**********************************************************************
948 * LoadIconHandler (USER.456)
950 HICON
LoadIconHandler( HANDLE hResource
, BOOL bNew
)
952 dprintf_cursor(stddeb
,"LoadIconHandler: hRes="NPFMT
"\n",hResource
);
956 fprintf(stdnimp
,"LoadIconHandler: 2.xx resources are not supported\n");
959 return CURSORICON_LoadHandler( hResource
, 0, FALSE
);