1 /**************************************************************
3 * Cursor support for Darwin X Server
5 * Three different cursor modes are possible:
6 * X (0) - tracking via Darwin kernel,
7 * display via X machine independent
8 * Kernel (1) - tracking and display via Darwin kernel
9 * (not currently supported)
10 * Hardware (2) - tracking and display via hardware
12 * The X software cursor uses the Darwin software cursor
13 * routines in IOFramebuffer.cpp to track the cursor, but
14 * displays the cursor image using the X machine
15 * independent display cursor routines in midispcur.c.
17 * The kernel cursor uses IOFramebuffer.cpp routines to
18 * track and display the cursor. This gives better
19 * performance as the display calls don't have to cross
20 * the kernel boundary. Unfortunately, this mode has
21 * synchronization issues with the user land X server
22 * and isn't currently used.
24 * Hardware cursor support lets the hardware handle these
27 * Kernel and hardware cursor mode only work for cursors
28 * up to a certain size, currently 16x16 pixels. If a
29 * bigger cursor is set, we fallback to X cursor mode.
32 * 1.0 by Torrey T. Lyons, October 30, 2000
34 **************************************************************/
36 * Copyright (c) 2001-2002 Torrey T. Lyons. All Rights Reserved.
38 * Permission is hereby granted, free of charge, to any person obtaining a
39 * copy of this software and associated documentation files (the "Software"),
40 * to deal in the Software without restriction, including without limitation
41 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
42 * and/or sell copies of the Software, and to permit persons to whom the
43 * Software is furnished to do so, subject to the following conditions:
45 * The above copyright notice and this permission notice shall be included in
46 * all copies or substantial portions of the Software.
48 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
49 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
50 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
51 * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
52 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
53 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
54 * DEALINGS IN THE SOFTWARE.
56 * Except as contained in this notice, the name(s) of the above copyright
57 * holders shall not be used in advertising or otherwise to promote the sale,
58 * use or other dealings in this Software without prior written authorization.
61 #if HAVE_XORG_CONFIG_H
62 #include <xorg-config.h>
64 #include "scrnintstr.h"
65 #include "cursorstr.h"
66 #include "mipointrst.h"
69 #include <IOKit/graphics/IOGraphicsLib.h>
70 #include <IOKit/hidsystem/IOHIDLib.h>
74 #define DUMP_DARWIN_CURSOR FALSE
76 #define CURSOR_PRIV(pScreen) \
77 ((XFIOKitCursorScreenPtr)pScreen->devPrivates[darwinCursorScreenIndex].ptr)
79 // The cursors format are documented in IOFramebufferShared.h.
80 #define RGBto34WithGamma(red, green, blue) \
82 | (((red) & 0xF) << 12) \
83 | (((green) & 0xF) << 8) \
84 | (((blue) & 0xF) << 4) )
85 #define RGBto38WithGamma(red, green, blue) \
87 | (((red) & 0xFF) << 16) \
88 | (((green) & 0xFF) << 8) \
90 #define HighBitOf32 0x80000000
95 RecolorCursorProcPtr RecolorCursor
;
96 InstallColormapProcPtr InstallColormap
;
97 QueryBestSizeProcPtr QueryBestSize
;
98 miPointerSpriteFuncPtr spriteFuncs
;
99 ColormapPtr pInstalledMap
;
100 } XFIOKitCursorScreenRec
, *XFIOKitCursorScreenPtr
;
102 static int darwinCursorScreenIndex
= -1;
103 static unsigned long darwinCursorGeneration
= 0;
106 ===========================================================================
108 Pointer sprite functions
110 ===========================================================================
114 Realizing the Darwin hardware cursor (ie. converting from the
115 X representation to the IOKit representation) is complicated
116 by the fact that we have three different potential cursor
117 formats to go to, one for each bit depth (8, 15, or 24).
118 The IOKit formats are documented in IOFramebufferShared.h.
119 X cursors are represented as two pieces, a source and a mask.
120 The mask is a bitmap indicating which parts of the cursor are
121 transparent and which parts are drawn. The source is a bitmap
122 indicating which parts of the non-transparent portion of the the
123 cursor should be painted in the foreground color and which should
124 be painted in the background color. The bitmaps are given in
125 32-bit format with least significant byte and bit first.
126 (This is opposite PowerPC Darwin.)
130 unsigned char image
[CURSORWIDTH
*CURSORHEIGHT
];
131 unsigned char mask
[CURSORWIDTH
*CURSORHEIGHT
];
132 } cursorPrivRec
, *cursorPrivPtr
;
135 * XFIOKitRealizeCursor8
136 * Convert the X cursor representation to an 8-bit depth
137 * format for Darwin. This function assumes the maximum cursor
138 * width is a multiple of 8.
141 XFIOKitRealizeCursor8(
145 cursorPrivPtr newCursor
;
146 unsigned char *newSourceP
, *newMaskP
;
147 CARD32
*oldSourceP
, *oldMaskP
;
148 xColorItem fgColor
, bgColor
;
149 int index
, x
, y
, rowPad
;
150 int cursorWidth
, cursorHeight
;
153 // check cursor size just to be sure
154 cursorWidth
= pCursor
->bits
->width
;
155 cursorHeight
= pCursor
->bits
->height
;
156 if (cursorHeight
> CURSORHEIGHT
|| cursorWidth
> CURSORWIDTH
)
159 // get cursor colors in colormap
160 index
= pScreen
->myNum
;
161 pmap
= miInstalledMaps
[index
];
162 if (!pmap
) return FALSE
;
164 fgColor
.red
= pCursor
->foreRed
;
165 fgColor
.green
= pCursor
->foreGreen
;
166 fgColor
.blue
= pCursor
->foreBlue
;
167 FakeAllocColor(pmap
, &fgColor
);
168 bgColor
.red
= pCursor
->backRed
;
169 bgColor
.green
= pCursor
->backGreen
;
170 bgColor
.blue
= pCursor
->backBlue
;
171 FakeAllocColor(pmap
, &bgColor
);
172 FakeFreeColor(pmap
, fgColor
.pixel
);
173 FakeFreeColor(pmap
, bgColor
.pixel
);
175 // allocate memory for new cursor image
176 newCursor
= xalloc( sizeof(cursorPrivRec
) );
179 memset( newCursor
->image
, pScreen
->blackPixel
, CURSORWIDTH
*CURSORHEIGHT
);
180 memset( newCursor
->mask
, 0, CURSORWIDTH
*CURSORHEIGHT
);
182 // convert to 8-bit Darwin cursor format
183 oldSourceP
= (CARD32
*) pCursor
->bits
->source
;
184 oldMaskP
= (CARD32
*) pCursor
->bits
->mask
;
185 newSourceP
= newCursor
->image
;
186 newMaskP
= newCursor
->mask
;
187 rowPad
= CURSORWIDTH
- cursorWidth
;
189 for (y
= 0; y
< cursorHeight
; y
++) {
190 for (x
= 0; x
< cursorWidth
; x
++) {
191 if (*oldSourceP
& (HighBitOf32
>> x
))
192 *newSourceP
= fgColor
.pixel
;
194 *newSourceP
= bgColor
.pixel
;
195 if (*oldMaskP
& (HighBitOf32
>> x
))
198 *newSourceP
= pScreen
->blackPixel
;
199 newSourceP
++; newMaskP
++;
201 oldSourceP
++; oldMaskP
++;
202 newSourceP
+= rowPad
; newMaskP
+= rowPad
;
206 pCursor
->devPriv
[pScreen
->myNum
] = (pointer
) newCursor
;
212 * XFIOKitRealizeCursor15
213 * Convert the X cursor representation to an 15-bit depth
217 XFIOKitRealizeCursor15(
221 unsigned short *newCursor
;
222 unsigned short fgPixel
, bgPixel
;
223 unsigned short *newSourceP
;
224 CARD32
*oldSourceP
, *oldMaskP
;
226 int cursorWidth
, cursorHeight
;
228 // check cursor size just to be sure
229 cursorWidth
= pCursor
->bits
->width
;
230 cursorHeight
= pCursor
->bits
->height
;
231 if (cursorHeight
> CURSORHEIGHT
|| cursorWidth
> CURSORWIDTH
)
234 // allocate memory for new cursor image
235 newCursor
= xalloc( CURSORWIDTH
*CURSORHEIGHT
*sizeof(short) );
238 memset( newCursor
, 0, CURSORWIDTH
*CURSORHEIGHT
*sizeof(short) );
240 // calculate pixel values
241 fgPixel
= RGBto34WithGamma( pCursor
->foreRed
, pCursor
->foreGreen
,
243 bgPixel
= RGBto34WithGamma( pCursor
->backRed
, pCursor
->backGreen
,
246 // convert to 15-bit Darwin cursor format
247 oldSourceP
= (CARD32
*) pCursor
->bits
->source
;
248 oldMaskP
= (CARD32
*) pCursor
->bits
->mask
;
249 newSourceP
= newCursor
;
250 rowPad
= CURSORWIDTH
- cursorWidth
;
252 for (y
= 0; y
< cursorHeight
; y
++) {
253 for (x
= 0; x
< cursorWidth
; x
++) {
254 if (*oldMaskP
& (HighBitOf32
>> x
)) {
255 if (*oldSourceP
& (HighBitOf32
>> x
))
256 *newSourceP
= fgPixel
;
258 *newSourceP
= bgPixel
;
264 oldSourceP
++; oldMaskP
++;
265 newSourceP
+= rowPad
;
268 #if DUMP_DARWIN_CURSOR
269 // Write out the cursor
270 ErrorF("Cursor: 0x%x\n", pCursor
);
271 ErrorF("Width = %i, Height = %i, RowPad = %i\n", cursorWidth
,
272 cursorHeight
, rowPad
);
273 for (y
= 0; y
< cursorHeight
; y
++) {
274 newSourceP
= newCursor
+ y
*CURSORWIDTH
;
275 for (x
= 0; x
< cursorWidth
; x
++) {
276 if (*newSourceP
== fgPixel
)
278 else if (*newSourceP
== bgPixel
)
289 pCursor
->devPriv
[pScreen
->myNum
] = (pointer
) newCursor
;
295 * XFIOKitRealizeCursor24
296 * Convert the X cursor representation to an 24-bit depth
297 * format for Darwin. This function assumes the maximum cursor
298 * width is a multiple of 8.
301 XFIOKitRealizeCursor24(
305 unsigned int *newCursor
;
306 unsigned int fgPixel
, bgPixel
;
307 unsigned int *newSourceP
;
308 CARD32
*oldSourceP
, *oldMaskP
;
310 int cursorWidth
, cursorHeight
;
312 // check cursor size just to be sure
313 cursorWidth
= pCursor
->bits
->width
;
314 cursorHeight
= pCursor
->bits
->height
;
315 if (cursorHeight
> CURSORHEIGHT
|| cursorWidth
> CURSORWIDTH
)
318 // allocate memory for new cursor image
319 newCursor
= xalloc( CURSORWIDTH
*CURSORHEIGHT
*sizeof(int) );
322 memset( newCursor
, 0, CURSORWIDTH
*CURSORHEIGHT
*sizeof(int) );
324 // calculate pixel values
325 fgPixel
= RGBto38WithGamma( pCursor
->foreRed
, pCursor
->foreGreen
,
327 bgPixel
= RGBto38WithGamma( pCursor
->backRed
, pCursor
->backGreen
,
330 // convert to 24-bit Darwin cursor format
331 oldSourceP
= (CARD32
*) pCursor
->bits
->source
;
332 oldMaskP
= (CARD32
*) pCursor
->bits
->mask
;
333 newSourceP
= newCursor
;
334 rowPad
= CURSORWIDTH
- cursorWidth
;
336 for (y
= 0; y
< cursorHeight
; y
++) {
337 for (x
= 0; x
< cursorWidth
; x
++) {
338 if (*oldMaskP
& (HighBitOf32
>> x
)) {
339 if (*oldSourceP
& (HighBitOf32
>> x
))
340 *newSourceP
= fgPixel
;
342 *newSourceP
= bgPixel
;
348 oldSourceP
++; oldMaskP
++;
349 newSourceP
+= rowPad
;
352 #if DUMP_DARWIN_CURSOR
353 // Write out the cursor
354 ErrorF("Cursor: 0x%x\n", pCursor
);
355 ErrorF("Width = %i, Height = %i, RowPad = %i\n", cursorWidth
,
356 cursorHeight
, rowPad
);
357 for (y
= 0; y
< cursorHeight
; y
++) {
358 newSourceP
= newCursor
+ y
*CURSORWIDTH
;
359 for (x
= 0; x
< cursorWidth
; x
++) {
360 if (*newSourceP
== fgPixel
)
362 else if (*newSourceP
== bgPixel
)
373 pCursor
->devPriv
[pScreen
->myNum
] = (pointer
) newCursor
;
379 * XFIOKitRealizeCursor
383 XFIOKitRealizeCursor(
388 XFIOKitCursorScreenPtr ScreenPriv
= CURSOR_PRIV(pScreen
);
389 DarwinFramebufferPtr dfb
= SCREEN_PRIV(pScreen
);
391 if ((pCursor
->bits
->height
> CURSORHEIGHT
) ||
392 (pCursor
->bits
->width
> CURSORWIDTH
) ||
393 // FIXME: this condition is not needed after kernel cursor works
394 !ScreenPriv
->canHWCursor
) {
395 result
= (*ScreenPriv
->spriteFuncs
->RealizeCursor
)(pScreen
, pCursor
);
396 } else if (dfb
->bitsPerPixel
== 8) {
397 result
= XFIOKitRealizeCursor8(pScreen
, pCursor
);
398 } else if (dfb
->bitsPerPixel
== 16) {
399 result
= XFIOKitRealizeCursor15(pScreen
, pCursor
);
401 result
= XFIOKitRealizeCursor24(pScreen
, pCursor
);
409 * XFIOKitUnrealizeCursor
413 XFIOKitUnrealizeCursor(
418 XFIOKitCursorScreenPtr ScreenPriv
= CURSOR_PRIV(pScreen
);
420 if ((pCursor
->bits
->height
> CURSORHEIGHT
) ||
421 (pCursor
->bits
->width
> CURSORWIDTH
) ||
422 // FIXME: this condition is not needed after kernel cursor works
423 !ScreenPriv
->canHWCursor
) {
424 result
= (*ScreenPriv
->spriteFuncs
->UnrealizeCursor
)(pScreen
, pCursor
);
426 xfree( pCursor
->devPriv
[pScreen
->myNum
] );
436 * Set the cursor sprite and position
437 * Use hardware cursor if possible
447 DarwinFramebufferPtr dfb
= SCREEN_PRIV(pScreen
);
448 XFIOKitScreenPtr iokitScreen
= XFIOKIT_SCREEN_PRIV(pScreen
);
449 StdFBShmem_t
*cshmem
= iokitScreen
->cursorShmem
;
450 XFIOKitCursorScreenPtr ScreenPriv
= CURSOR_PRIV(pScreen
);
452 // are we supposed to remove the cursor?
454 if (ScreenPriv
->cursorMode
== 0)
455 (*ScreenPriv
->spriteFuncs
->SetCursor
)(pScreen
, 0, x
, y
);
457 if (!cshmem
->cursorShow
) {
458 cshmem
->cursorShow
++;
459 if (cshmem
->hardwareCursorActive
) {
460 kr
= IOFBSetCursorVisible(iokitScreen
->fbService
, FALSE
);
468 // can we use the kernel or hardware cursor?
469 if ((pCursor
->bits
->height
<= CURSORHEIGHT
) &&
470 (pCursor
->bits
->width
<= CURSORWIDTH
) &&
471 // FIXME: condition not needed when kernel cursor works
472 ScreenPriv
->canHWCursor
) {
474 if (ScreenPriv
->cursorMode
== 0) // remove the X cursor
475 (*ScreenPriv
->spriteFuncs
->SetCursor
)(pScreen
, 0, x
, y
);
476 ScreenPriv
->cursorMode
= 1; // kernel cursor
478 // change the cursor image in shared memory
479 if (dfb
->bitsPerPixel
== 8) {
480 cursorPrivPtr newCursor
=
481 (cursorPrivPtr
) pCursor
->devPriv
[pScreen
->myNum
];
482 memcpy(cshmem
->cursor
.bw8
.image
[0], newCursor
->image
,
483 CURSORWIDTH
*CURSORHEIGHT
);
484 memcpy(cshmem
->cursor
.bw8
.mask
[0], newCursor
->mask
,
485 CURSORWIDTH
*CURSORHEIGHT
);
486 } else if (dfb
->bitsPerPixel
== 16) {
487 unsigned short *newCursor
=
488 (unsigned short *) pCursor
->devPriv
[pScreen
->myNum
];
489 memcpy(cshmem
->cursor
.rgb
.image
[0], newCursor
,
490 2*CURSORWIDTH
*CURSORHEIGHT
);
492 unsigned int *newCursor
=
493 (unsigned int *) pCursor
->devPriv
[pScreen
->myNum
];
494 memcpy(cshmem
->cursor
.rgb24
.image
[0], newCursor
,
495 4*CURSORWIDTH
*CURSORHEIGHT
);
498 // FIXME: We always use a full size cursor, even if the image
499 // is smaller because I couldn't get the padding to come out
501 cshmem
->cursorSize
[0].width
= CURSORWIDTH
;
502 cshmem
->cursorSize
[0].height
= CURSORHEIGHT
;
503 cshmem
->hotSpot
[0].x
= pCursor
->bits
->xhot
;
504 cshmem
->hotSpot
[0].y
= pCursor
->bits
->yhot
;
506 // try to use a hardware cursor
507 if (ScreenPriv
->canHWCursor
) {
508 kr
= IOFBSetNewCursor(iokitScreen
->fbService
, 0, 0, 0);
509 // FIXME: this is a fatal error without the kernel cursor
512 if (kr
!= KERN_SUCCESS
) {
513 ErrorF("Could not set new cursor with kernel return 0x%x.\n", kr
);
514 ScreenPriv
->canHWCursor
= FALSE
;
519 // make the new cursor visible
520 if (cshmem
->cursorShow
)
521 cshmem
->cursorShow
--;
523 if (!cshmem
->cursorShow
&& ScreenPriv
->canHWCursor
) {
524 kr
= IOFBSetCursorVisible(iokitScreen
->fbService
, TRUE
);
525 // FIXME: this is a fatal error without the kernel cursor
528 if (kr
!= KERN_SUCCESS
) {
529 ErrorF("Couldn't set hardware cursor visible with kernel return 0x%x.\n", kr
);
530 ScreenPriv
->canHWCursor
= FALSE
;
533 ScreenPriv
->cursorMode
= 2; // hardware cursor
539 // otherwise we use a software cursor
540 if (ScreenPriv
->cursorMode
) {
541 /* remove the kernel or hardware cursor */
542 XFIOKitSetCursor(pScreen
, 0, x
, y
);
545 ScreenPriv
->cursorMode
= 0;
546 (*ScreenPriv
->spriteFuncs
->SetCursor
)(pScreen
, pCursor
, x
, y
);
552 * Move the cursor. This is a noop for a kernel or hardware cursor.
560 XFIOKitCursorScreenPtr ScreenPriv
= CURSOR_PRIV(pScreen
);
562 // only the X cursor needs to be explicitly moved
563 if (!ScreenPriv
->cursorMode
)
564 (*ScreenPriv
->spriteFuncs
->MoveCursor
)(pScreen
, x
, y
);
567 static miPointerSpriteFuncRec darwinSpriteFuncsRec
= {
568 XFIOKitRealizeCursor
,
569 XFIOKitUnrealizeCursor
,
576 ===========================================================================
578 Pointer screen functions
580 ===========================================================================
584 * XFIOKitCursorOffScreen
586 static Bool
XFIOKitCursorOffScreen(ScreenPtr
*pScreen
, int *x
, int *y
)
594 static void XFIOKitCrossScreen(ScreenPtr pScreen
, Bool entering
)
601 * Change the cursor position without generating an event or motion history
611 kr
= IOHIDSetMouseLocation( xfIOKitInputConnect
, x
, y
);
612 if (kr
!= KERN_SUCCESS
) {
613 ErrorF("Could not set cursor position with kernel return 0x%x.\n", kr
);
615 miPointerWarpCursor(pScreen
, x
, y
);
618 static miPointerScreenFuncRec darwinScreenFuncsRec
= {
619 XFIOKitCursorOffScreen
,
628 ===========================================================================
630 Other screen functions
632 ===========================================================================
636 * XFIOKitCursorQueryBestSize
637 * Handle queries for best cursor size
640 XFIOKitCursorQueryBestSize(
642 unsigned short *width
,
643 unsigned short *height
,
646 XFIOKitCursorScreenPtr ScreenPriv
= CURSOR_PRIV(pScreen
);
648 if (class == CursorShape
) {
649 *width
= CURSORWIDTH
;
650 *height
= CURSORHEIGHT
;
652 (*ScreenPriv
->QueryBestSize
)(class, width
, height
, pScreen
);
658 * Initialize cursor support
664 XFIOKitScreenPtr iokitScreen
= XFIOKIT_SCREEN_PRIV(pScreen
);
665 XFIOKitCursorScreenPtr ScreenPriv
;
666 miPointerScreenPtr PointPriv
;
669 // start with no cursor displayed
670 if (!iokitScreen
->cursorShmem
->cursorShow
++) {
671 if (iokitScreen
->cursorShmem
->hardwareCursorActive
) {
672 kr
= IOFBSetCursorVisible(iokitScreen
->fbService
, FALSE
);
677 // initialize software cursor handling (always needed as backup)
678 if (!miDCInitialize(pScreen
, &darwinScreenFuncsRec
)) {
682 // allocate private storage for this screen's hardware cursor info
683 if (darwinCursorGeneration
!= serverGeneration
) {
684 if ((darwinCursorScreenIndex
= AllocateScreenPrivateIndex()) < 0)
686 darwinCursorGeneration
= serverGeneration
;
689 ScreenPriv
= xcalloc( 1, sizeof(XFIOKitCursorScreenRec
) );
690 if (!ScreenPriv
) return FALSE
;
692 pScreen
->devPrivates
[darwinCursorScreenIndex
].ptr
= (pointer
) ScreenPriv
;
694 // check if a hardware cursor is supported
695 if (!iokitScreen
->cursorShmem
->hardwareCursorCapable
) {
696 ScreenPriv
->canHWCursor
= FALSE
;
697 ErrorF("Hardware cursor not supported.\n");
699 // we need to make sure that the hardware cursor really works
700 ScreenPriv
->canHWCursor
= TRUE
;
701 kr
= IOFBSetNewCursor(iokitScreen
->fbService
, 0, 0, 0);
702 if (kr
!= KERN_SUCCESS
) {
703 ErrorF("Could not set hardware cursor with kernel return 0x%x.\n", kr
);
704 ScreenPriv
->canHWCursor
= FALSE
;
706 kr
= IOFBSetCursorVisible(iokitScreen
->fbService
, TRUE
);
707 if (kr
!= KERN_SUCCESS
) {
708 ErrorF("Couldn't set hardware cursor visible with kernel return 0x%x.\n", kr
);
709 ScreenPriv
->canHWCursor
= FALSE
;
711 IOFBSetCursorVisible(iokitScreen
->fbService
, FALSE
);
714 ScreenPriv
->cursorMode
= 0;
715 ScreenPriv
->pInstalledMap
= NULL
;
717 // override some screen procedures
718 ScreenPriv
->QueryBestSize
= pScreen
->QueryBestSize
;
719 pScreen
->QueryBestSize
= XFIOKitCursorQueryBestSize
;
720 // ScreenPriv->ConstrainCursor = pScreen->ConstrainCursor;
721 // pScreen->ConstrainCursor = XFIOKitConstrainCursor;
723 // initialize hardware cursor handling
724 PointPriv
= (miPointerScreenPtr
)
725 pScreen
->devPrivates
[miPointerScreenIndex
].ptr
;
727 ScreenPriv
->spriteFuncs
= PointPriv
->spriteFuncs
;
728 PointPriv
->spriteFuncs
= &darwinSpriteFuncsRec
;
730 /* Other routines that might be overridden */
732 CursorLimitsProcPtr CursorLimits;
733 RecolorCursorProcPtr RecolorCursor;