Site hosted by Angelfire.com: Build your free website today!

Hands-on Projects for the Linux Graphics Subsystem

New book from Christos Karayiannis

Available in Amazon Kindle format at:

amazon.com   amazon.co.uk   amazon.de   amazon.es   amazon.fr   amazon.it

X Events

The notion of the 'event' is central to the mechanism of the X Window System. X Client. At Events we read:

From a programmer's point of view, an event reports:

* Something that your program needs to know about, such as user input or information available from other clients.
* Something your program is doing that other clients need to know about, such as making text available for pasting to another client.
* Something the window manager needs to know, such as a request by your program for a change to the layout of the screen by mapping a window.

We have met for instance MapNotify at section 3.2.2.13. This is event type is described in MapNotify.

The example in this link describes a client that processes Expose events, KeyPress events and mouse button events. In the next text we will discuss the mouse events a by combining the section 3.2.5.1 and the section 5.1.4. Events are posted by the mouse and are processed by the X Server, which sends notification back to the clients. This is the second circle we examine after the X Client request and X Server request dispatching.

As seen in section 5.1.4 upon the pointer movement a MotionNotify event is prepared. The event is next queued via xf86PostButtonEvent(). This input event is processed then by ProcessInputEvents(), which as seen in section 3.2.5.1 resolves to a ProcessPointerEvent() call. This is implemented as:

 
void
#ifdef XKB
CoreProcessPointerEvent (register xEvent *xE, register DeviceIntPtr mouse, int count)
#else
ProcessPointerEvent (register xEvent *xE, register DeviceIntPtr mouse, int count)
#endif
{
    register GrabPtr	grab = mouse->grab;
    Bool                deactivateGrab = FALSE;
    register ButtonClassPtr butc = mouse->button;
#ifdef XKB
    XkbSrvInfoPtr xkbi= inputInfo.keyboard->key->xkbInfo;
#endif
#ifdef XEVIE
    if(xevieFlag && clients[xevieClientIndex] && !xeviegrabState &&
       (xevieMask & xevieFilters[xE->u.u.type])) {
      if(xevieEventSent)
        xevieEventSent = 0;
      else {
        xeviemouse = mouse;
        WriteToClient(clients[xevieClientIndex], sizeof(xEvent), (char *)xE);
        return;
      }
    }
#endif

    if (!syncEvents.playingEvents)
	NoticeTime(xE)
    XE_KBPTR.state = (butc->state | (
#ifdef XKB
			(noXkbExtension ?
				inputInfo.keyboard->key->state :
				xkbi->state.grab_mods)
#else
			inputInfo.keyboard->key->state
#endif
				    ));
    {
	NoticeTime(xE);
	if (DeviceEventCallback)
	{
	    DeviceEventInfoRec eventinfo;
	    /* see comment in EnqueueEvents regarding the next three lines */
	    if (xE->u.u.type == MotionNotify)
		XE_KBPTR.root =
		    WindowTable[sprite.hotPhys.pScreen->myNum]->drawable.id;
	    eventinfo.events = xE;
	    eventinfo.count = count;
	    CallCallbacks(&DeviceEventCallback, (pointer)&eventinfo);
	}
    }

    if (xE->u.u.type != MotionNotify)
    {
	register int  key;
	register BYTE *kptr;
	int           bit;

	XE_KBPTR.rootX = sprite.hot.x;
	XE_KBPTR.rootY = sprite.hot.y;

	key = xE->u.u.detail;
	kptr = &butc->down[key >> 3];
	bit = 1 << (key & 7);
	switch (xE->u.u.type)
	{
	case ButtonPress: 
	    mouse->valuator->motionHintWindow = NullWindow;
	    if (!(*kptr & bit))
		butc->buttonsDown++;
	    butc->motionMask = ButtonMotionMask;
	    *kptr |= bit;
#if !defined(XFree86Server) || !defined(XINPUT)
	    xE->u.u.detail = butc->map[key];
#endif
	    if (xE->u.u.detail == 0)
		return;
	    if (xE->u.u.detail <= 5)
		butc->state |= (Button1Mask >> 1) << xE->u.u.detail;
	    filters[MotionNotify] = Motion_Filter(butc);
	    if (!grab)
		if (CheckDeviceGrabs(mouse, xE, 0, count))
		    return;
	    break;
	case ButtonRelease: 
	    mouse->valuator->motionHintWindow = NullWindow;
	    if (*kptr & bit)
		--butc->buttonsDown;
	    if (!butc->buttonsDown)
		butc->motionMask = 0;
	    *kptr &= ~bit;
#if !defined(XFree86Server) || !defined(XINPUT)
	    xE->u.u.detail = butc->map[key];
#endif
	    if (xE->u.u.detail == 0)
		return;
	    if (xE->u.u.detail <= 5)
		butc->state &= ~((Button1Mask >> 1) << xE->u.u.detail);
	    filters[MotionNotify] = Motion_Filter(butc);
	    if (!butc->state && mouse->fromPassiveGrab)
		deactivateGrab = TRUE;
	    break;
	default: 
	    FatalError("bogus pointer event from ddx");
	}
    }

    else if (!CheckMotion(xE))
	return;
    if (grab)
	DeliverGrabbedEvent(xE, mouse, deactivateGrab, count);
    else
	DeliverDeviceEvents(sprite.win, xE, NullGrab, NullWindow,
			    mouse, count);
    if (deactivateGrab)
        (*mouse->DeactivateGrab)(mouse);
}

CheckMotion() checks the mouse motion by comparing the rootX and rootY position the mouse posted (as seen in section 5.1.4) with the x and y coordination of the sprite:
	if ((sprite.hotPhys.x != XE_KBPTR.rootX) ||
	    (sprite.hotPhys.y != XE_KBPTR.rootY))
	{
	    (*sprite.hotPhys.pScreen->SetCursorPosition)(

If there is motion the sprite position is updated. miPointerSetCursorPosition() is used as the pScreen->SetCursorPosition routine which calls miPointerUpdate(), this miSpriteMoveCursor(), this miSpriteSetCursor(), this miDCMoveCursor(), the latter finally composes the screen with the cursor on the right position.

The events are then delivered to the clients either by DeliverDeviceEvents() or DeliverGrabbedEvent() (it resolves to DeliverDeviceEvents). DeliverDeviceEvents() calls DeliverEventsToWindow(), which calls TryClientEvents() to send the event to the client that is the window owner. This follows a WriteEventsToClient() and then a WriteToClient() call.

CheckMotion is implemented as:

 
static Bool
CheckMotion(xEvent *xE)
{
    WindowPtr prevSpriteWin = sprite.win;

#ifdef PANORAMIX
    if(!noPanoramiXExtension)
	return XineramaCheckMotion(xE);
#endif

    if (xE && !syncEvents.playingEvents)
    {
	if (sprite.hot.pScreen != sprite.hotPhys.pScreen)
	{
	    sprite.hot.pScreen = sprite.hotPhys.pScreen;
	    ROOT = WindowTable[sprite.hot.pScreen->myNum];
	}
	sprite.hot.x = XE_KBPTR.rootX;
	sprite.hot.y = XE_KBPTR.rootY;
	if (sprite.hot.x < sprite.physLimits.x1)
	    sprite.hot.x = sprite.physLimits.x1;
	else if (sprite.hot.x >= sprite.physLimits.x2)
	    sprite.hot.x = sprite.physLimits.x2 - 1;
	if (sprite.hot.y < sprite.physLimits.y1)
	    sprite.hot.y = sprite.physLimits.y1;
	else if (sprite.hot.y >= sprite.physLimits.y2)
	    sprite.hot.y = sprite.physLimits.y2 - 1;
#ifdef SHAPE
	if (sprite.hotShape)
	    ConfineToShape(sprite.hotShape, &sprite.hot.x, &sprite.hot.y);
#endif
#ifdef XEVIE
        xeviehot.x = sprite.hot.x;
        xeviehot.y = sprite.hot.y;
#endif
	sprite.hotPhys = sprite.hot;
	if ((sprite.hotPhys.x != XE_KBPTR.rootX) ||
	    (sprite.hotPhys.y != XE_KBPTR.rootY))
	{
	    (*sprite.hotPhys.pScreen->SetCursorPosition)(
		sprite.hotPhys.pScreen,
		sprite.hotPhys.x, sprite.hotPhys.y, FALSE);
	}

	XE_KBPTR.rootX = sprite.hot.x;
	XE_KBPTR.rootY = sprite.hot.y;
    }

sprite is the cursor sprite, defined in the same file as:

 
static  struct {
    CursorPtr	current;
    BoxRec	hotLimits;	/* logical constraints of hot spot */
    Bool	confined;	/* confined to screen */
#if defined(SHAPE) || defined(PANORAMIX)
    RegionPtr	hotShape;	/* additional logical shape constraint */
#endif
    BoxRec	physLimits;	/* physical constraints of hot spot */
    WindowPtr	win;		/* window of logical position */
    HotSpot	hot;		/* logical pointer position */
    HotSpot	hotPhys;	/* physical pointer position */

#ifdef PANORAMIX
    ScreenPtr	screen;		/* all others are in Screen 0 coordinates */
    RegionRec   Reg1;	        /* Region 1 for confining motion */
    RegionRec   Reg2;		/* Region 2 for confining virtual motion */
    WindowPtr   windows[MAXSCREENS];
    WindowPtr	confineWin;	/* confine window */ 
#endif
} sprite;			/* info about the cursor sprite */

Also the following are also defined:

 
/*
 * The window trace information is used to avoid having to compute all the
 * windows between the root and the current pointer window each time a button
 * or key goes down. The grabs on each of those windows must be checked.
 */
static WindowPtr *spriteTrace = (WindowPtr *)NULL;
#define ROOT spriteTrace[0]


#define XE_KBPTR (xE->u.keyButtonPointer)

Where is *sprite.hotPhys.pScreen->SetCursorPosition function found?

The software cursor initialization takes place in MGAScreenInit():

MGAScreenInit(), discussed in section 3.2.2.11 calls miDCInitialize() as:

    /* Initialize software cursor.
	Must precede creation of the default colormap */
    miDCInitialize(pScreen, xf86GetPointerScreenFuncs());

miDCInitialize() calls miSpriteInitialize() as:

    if (!miSpriteInitialize (pScreen, &miDCFuncs, screenFuncs))

screenFuncs were previously obtained from xf86GetPointerScreenFuncs(), as a miDCInitialize() argument. It returns xf86PointerScreenFuncs.

Next miSpriteInitialize() calls miPointerInitialize() as:

    if (!miPointerInitialize (pScreen, &miSpritePointerFuncs, screenFuncs,TRUE))

miPointerInitialize() is implemented as:

Bool
miPointerInitialize (pScreen, spriteFuncs, screenFuncs, waitForUpdate)
    ScreenPtr		    pScreen;
    miPointerSpriteFuncPtr  spriteFuncs;
    miPointerScreenFuncPtr  screenFuncs;
    Bool		    waitForUpdate;
{
    miPointerScreenPtr	pScreenPriv;

    if (miPointerGeneration != serverGeneration)
    {
	miPointerScreenIndex = AllocateScreenPrivateIndex();
	if (miPointerScreenIndex < 0)
	    return FALSE;
	miPointerGeneration = serverGeneration;
    }
    pScreenPriv = (miPointerScreenPtr) xalloc (sizeof (miPointerScreenRec));
    if (!pScreenPriv)
	return FALSE;
    pScreenPriv->spriteFuncs = spriteFuncs;
    pScreenPriv->screenFuncs = screenFuncs;
    /*
     * check for uninitialized methods
     */
    if (!screenFuncs->EnqueueEvent)
	screenFuncs->EnqueueEvent = mieqEnqueue;
    if (!screenFuncs->NewEventScreen)
	screenFuncs->NewEventScreen = mieqSwitchScreen;
    pScreenPriv->waitForUpdate = waitForUpdate;
    pScreenPriv->showTransparent = FALSE;
    pScreenPriv->CloseScreen = pScreen->CloseScreen;
    pScreen->CloseScreen = miPointerCloseScreen;
    pScreen->devPrivates[miPointerScreenIndex].ptr = (pointer) pScreenPriv;
    /*
     * set up screen cursor method table
     */
    pScreen->ConstrainCursor = miPointerConstrainCursor;
    pScreen->CursorLimits = miPointerCursorLimits;
    pScreen->DisplayCursor = miPointerDisplayCursor;
    pScreen->RealizeCursor = miPointerRealizeCursor;
    pScreen->UnrealizeCursor = miPointerUnrealizeCursor;
    pScreen->SetCursorPosition = miPointerSetCursorPosition;
    pScreen->RecolorCursor = miRecolorCursor;
    pScreen->PointerNonInterestBox = miPointerPointerNonInterestBox;
    /*
     * set up the pointer object
     */
    miPointer.pScreen = NULL;
    miPointer.pSpriteScreen = NULL;
    miPointer.pCursor = NULL;
    miPointer.pSpriteCursor = NULL;
    miPointer.limits.x1 = 0;
    miPointer.limits.x2 = 32767;
    miPointer.limits.y1 = 0;
    miPointer.limits.y2 = 32767;
    miPointer.confined = FALSE;
    miPointer.x = 0;
    miPointer.y = 0;
    miPointer.history_start = miPointer.history_end = 0;
    return TRUE;
}

miPointerInitialize() sets SetCursorPosition to miPointerSetCursorPosition().

miPointerSetCursorPosition() is implemented as:

static Bool
miPointerSetCursorPosition(pScreen, x, y, generateEvent)
    ScreenPtr pScreen;
    int       x, y;
    Bool      generateEvent;
{
    SetupScreen (pScreen);

    GenerateEvent = generateEvent;
    /* device dependent - must pend signal and call miPointerWarpCursor */
    (*pScreenPriv->screenFuncs->WarpCursor) (pScreen, x, y);
    if (!generateEvent)
	miPointerUpdate();
    return TRUE;
}

miPointerUpdate() is implemented as:

    
/*
 * miPointerUpdate
 *
 * Syncronize the sprite with the cursor - called from ProcessInputEvents
 */

void
miPointerUpdate ()
{
    ScreenPtr		pScreen;
    miPointerScreenPtr	pScreenPriv;
    CursorPtr		pCursor;
    int			x, y, devx, devy;

    pScreen = miPointer.pScreen;
    x = miPointer.x;
    y = miPointer.y;
    devx = miPointer.devx;
    devy = miPointer.devy;
    if (!pScreen)
	return;
    pScreenPriv = GetScreenPrivate (pScreen);
    /*
     * if the cursor has switched screens, disable the sprite
     * on the old screen
     */
    if (pScreen != miPointer.pSpriteScreen)
    {
	if (miPointer.pSpriteScreen)
	{
	    miPointerScreenPtr  pOldPriv;
    	
	    pOldPriv = GetScreenPrivate (miPointer.pSpriteScreen);
	    if (miPointer.pCursor)
	    {
	    	(*pOldPriv->spriteFuncs->SetCursor)
			    	(miPointer.pSpriteScreen, NullCursor, 0, 0);
	    }
	    (*pOldPriv->screenFuncs->CrossScreen) (miPointer.pSpriteScreen, FALSE);
	}
	(*pScreenPriv->screenFuncs->CrossScreen) (pScreen, TRUE);
	(*pScreenPriv->spriteFuncs->SetCursor)
				(pScreen, miPointer.pCursor, x, y);
	miPointer.devx = x;
	miPointer.devy = y;
	miPointer.pSpriteCursor = miPointer.pCursor;
	miPointer.pSpriteScreen = pScreen;
    }
    /*
     * if the cursor has changed, display the new one
     */
    else if (miPointer.pCursor != miPointer.pSpriteCursor)
    {
	pCursor = miPointer.pCursor;
	if (pCursor->bits->emptyMask && !pScreenPriv->showTransparent)
	    pCursor = NullCursor;
	(*pScreenPriv->spriteFuncs->SetCursor) (pScreen, pCursor, x, y);

	miPointer.devx = x;
	miPointer.devy = y;
	miPointer.pSpriteCursor = miPointer.pCursor;
    }
    else if (x != devx || y != devy)
    {
	miPointer.devx = x;
	miPointer.devy = y;
	if(!miPointer.pCursor->bits->emptyMask)
	    (*pScreenPriv->spriteFuncs->MoveCursor) (pScreen, x, y);
    }
}

At miPointerInitialize as second argument (spriteFuncs) it was passed miSpritePointerFuncs, defined as:

   
_X_EXPORT miPointerSpriteFuncRec miSpritePointerFuncs = {
    miSpriteRealizeCursor,
    miSpriteUnrealizeCursor,
    miSpriteSetCursor,
    miSpriteMoveCursor,
};

MoveCursor becomes therefore miSpriteMoveCursor(), implemented as:

   
static void
miSpriteMoveCursor (pScreen, x, y)
    ScreenPtr	pScreen;
    int		x, y;
{
    miSpriteScreenPtr	pScreenPriv;

    pScreenPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr;
    miSpriteSetCursor (pScreen, pScreenPriv->pCursor, x, y);
}

pScreenPriv, a pointer to the screen privates is obtained and then its cursor field is passed as argument to miSpriteSetCursor().

miSpriteSetCursor() is implemented as:

   
static void
miSpriteSetCursor (pScreen, pCursor, x, y)
    ScreenPtr	pScreen;
    CursorPtr	pCursor;
    int		x;
    int		y;
{
    miSpriteScreenPtr	pScreenPriv;

    pScreenPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr;
    if (!pCursor)
    {
    	pScreenPriv->shouldBeUp = FALSE;
    	if (pScreenPriv->isUp)
	    miSpriteRemoveCursor (pScreen);
	pScreenPriv->pCursor = 0;
	return;
    }
    pScreenPriv->shouldBeUp = TRUE;
    if (pScreenPriv->x == x &&
	pScreenPriv->y == y &&
	pScreenPriv->pCursor == pCursor &&
	!pScreenPriv->checkPixels)
    {
	return;
    }
    pScreenPriv->x = x;
    pScreenPriv->y = y;
    pScreenPriv->pCacheWin = NullWindow;

    if (pScreenPriv->checkPixels || pScreenPriv->pCursor != pCursor)
    {
	pScreenPriv->pCursor = pCursor;
	miSpriteFindColors (pScreen);
    }
    if (pScreenPriv->isUp) {
	int	sx, sy;
	/*
	 * check to see if the old saved region
	 * encloses the new sprite, in which case we use
	 * the flicker-free MoveCursor primitive.
	 */
	sx = pScreenPriv->x - (int)pCursor->bits->xhot;
	sy = pScreenPriv->y - (int)pCursor->bits->yhot;
	if (sx + (int) pCursor->bits->width >= pScreenPriv->saved.x1 &&
	    sx < pScreenPriv->saved.x2 &&
	    sy + (int) pCursor->bits->height >= pScreenPriv->saved.y1 &&
	    sy < pScreenPriv->saved.y2 &&
	    (int) pCursor->bits->width + (2 * SPRITE_PAD) ==
		pScreenPriv->saved.x2 - pScreenPriv->saved.x1 &&
	    (int) pCursor->bits->height + (2 * SPRITE_PAD) ==
		pScreenPriv->saved.y2 - pScreenPriv->saved.y1
	    )
	{
	    DamageDrawInternal (pScreen, TRUE);
	    miSpriteIsUpFALSE (pScreen, pScreenPriv);
	    if (!(sx >= pScreenPriv->saved.x1 &&
	      	  sx + (int)pCursor->bits->width < pScreenPriv->saved.x2 &&
	      	  sy >= pScreenPriv->saved.y1 &&
	      	  sy + (int)pCursor->bits->height < pScreenPriv->saved.y2))
	    {
		int oldx1, oldy1, dx, dy;

		oldx1 = pScreenPriv->saved.x1;
		oldy1 = pScreenPriv->saved.y1;
		dx = oldx1 - (sx - SPRITE_PAD);
		dy = oldy1 - (sy - SPRITE_PAD);
		pScreenPriv->saved.x1 -= dx;
		pScreenPriv->saved.y1 -= dy;
		pScreenPriv->saved.x2 -= dx;
		pScreenPriv->saved.y2 -= dy;
		(void) (*pScreenPriv->funcs->ChangeSave) (pScreen,
				pScreenPriv->saved.x1,
 				pScreenPriv->saved.y1,
				pScreenPriv->saved.x2 - pScreenPriv->saved.x1,
				pScreenPriv->saved.y2 - pScreenPriv->saved.y1,
				dx, dy);
	    }

	    (void) (*pScreenPriv->funcs->MoveCursor) (pScreen, pCursor,
				  pScreenPriv->saved.x1,
 				  pScreenPriv->saved.y1,
				  pScreenPriv->saved.x2 - pScreenPriv->saved.x1,
				  pScreenPriv->saved.y2 - pScreenPriv->saved.y1,
				  sx - pScreenPriv->saved.x1,
				  sy - pScreenPriv->saved.y1,
				  pScreenPriv->colors[SOURCE_COLOR].pixel,
				  pScreenPriv->colors[MASK_COLOR].pixel);
	    miSpriteIsUpTRUE (pScreen, pScreenPriv);
	    DamageDrawInternal (pScreen, FALSE);
	}
	else
	{
	    SPRITE_DEBUG (("SetCursor remove\n"));
	    miSpriteRemoveCursor (pScreen);
	}
    }
    if (!pScreenPriv->isUp && pScreenPriv->pCursor)
    {
	SPRITE_DEBUG (("SetCursor restore\n"));
	miSpriteRestoreCursor (pScreen);
    }
}

Which is the pScreenPriv->funcs->MoveCursor function?

pScreenPriv is of type miSpriteScreenPtr:

    CursorPtr	    pCursor;
    int		    x;			/* cursor hotspot */
    int		    y;
    BoxRec	    saved;		/* saved area from the screen */
    Bool	    isUp;		/* cursor in frame buffer */
    Bool	    shouldBeUp;		/* cursor should be displayed */
    WindowPtr	    pCacheWin;		/* window the cursor last seen in */
    Bool	    isInCacheWin;
    Bool	    checkPixels;	/* check colormap collision */
    xColorItem	    colors[2];
    ColormapPtr	    pInstalledMap;
    ColormapPtr	    pColormap;
    VisualPtr	    pVisual;
    miSpriteCursorFuncPtr    funcs;

    DamagePtr	    pDamage;		/* damage tracking structure */
} miSpriteScreenRec, *miSpriteScreenPtr;
The pScreenPriv funcs field is set in miSpriteInitialize() as:
    pScreenPriv->funcs = cursorFuncs;
where cursorFuncs is the second argument of miSpriteInitialize() prototype:
miSpriteInitialize (pScreen, cursorFuncs, screenFuncs)
miSpriteInitialize() was called as:
  if (!miSpriteInitialize (pScreen, &miDCFuncs, screenFuncs))
Therefore the cursorFuncs is miDCFuncs, defined as:
static miSpriteCursorFuncRec miDCFuncs = {
    miDCRealizeCursor,
    miDCUnrealizeCursor,
    miDCPutUpCursor,
    miDCSaveUnderCursor,
    miDCRestoreUnderCursor,
    miDCMoveCursor,
    miDCChangeSave,
};
miDCMoveCursor is implemented in midispcur.c:


static Bool
miDCMoveCursor (pScreen, pCursor, x, y, w, h, dx, dy, source, mask)
    ScreenPtr	    pScreen;
    CursorPtr	    pCursor;
    int		    x, y, w, h, dx, dy;
    unsigned long   source, mask;
{
    miDCCursorPtr   pPriv;
    miDCScreenPtr   pScreenPriv;
    int		    status;
    WindowPtr	    pWin;
    GCPtr	    pGC;
    XID		    gcval = FALSE;
    PixmapPtr	    pTemp;

    pPriv = (miDCCursorPtr) pCursor->bits->devPriv[pScreen->myNum];
    if (!pPriv)
    {
	pPriv = miDCRealize(pScreen, pCursor);
	if (!pPriv)
	    return FALSE;
    }
    pScreenPriv = (miDCScreenPtr) pScreen->devPrivates[miDCScreenIndex].ptr;
    pWin = WindowTable[pScreen->myNum];
    pTemp = pScreenPriv->pTemp;
    if (!pTemp ||
	pTemp->drawable.width != pScreenPriv->pSave->drawable.width ||
	pTemp->drawable.height != pScreenPriv->pSave->drawable.height)
    {
	if (pTemp)
	    (*pScreen->DestroyPixmap) (pTemp);
#ifdef ARGB_CURSOR
	if (pScreenPriv->pTempPicture)
	{
	    FreePicture (pScreenPriv->pTempPicture, 0);
	    pScreenPriv->pTempPicture = 0;
	}
#endif
	pScreenPriv->pTemp = pTemp = (*pScreen->CreatePixmap)
	    (pScreen, w, h, pScreenPriv->pSave->drawable.depth);
	if (!pTemp)
	    return FALSE;
    }
    if (!pScreenPriv->pMoveGC)
    {
	pScreenPriv->pMoveGC = CreateGC ((DrawablePtr)pTemp,
	    GCGraphicsExposures, &gcval, &status);
	if (!pScreenPriv->pMoveGC)
	    return FALSE;
    }
    /*
     * copy the saved area to a temporary pixmap
     */
    pGC = pScreenPriv->pMoveGC;
    if (pGC->serialNumber != pTemp->drawable.serialNumber)
	ValidateGC ((DrawablePtr) pTemp, pGC);
    (*pGC->ops->CopyArea)((DrawablePtr)pScreenPriv->pSave,
			  (DrawablePtr)pTemp, pGC, 0, 0, w, h, 0, 0);
    
    /*
     * draw the cursor in the temporary pixmap
     */
#ifdef ARGB_CURSOR
    if (pPriv->pPicture)
    {
	if (!EnsurePicture(pScreenPriv->pTempPicture, &pTemp->drawable, pWin))
	    return FALSE;
	CompositePicture (PictOpOver,
			  pPriv->pPicture,
			  NULL,
			  pScreenPriv->pTempPicture,
			  0, 0, 0, 0, 
			  dx, dy, 
			  pCursor->bits->width,
			  pCursor->bits->height);
    }
    else
#endif
    {
	if (!pScreenPriv->pPixSourceGC)
	{
	    pScreenPriv->pPixSourceGC = CreateGC ((DrawablePtr)pTemp,
		GCGraphicsExposures, &gcval, &status);
	    if (!pScreenPriv->pPixSourceGC)
		return FALSE;
	}
	if (!pScreenPriv->pPixMaskGC)
	{
	    pScreenPriv->pPixMaskGC = CreateGC ((DrawablePtr)pTemp,
		GCGraphicsExposures, &gcval, &status);
	    if (!pScreenPriv->pPixMaskGC)
		return FALSE;
	}
	miDCPutBits ((DrawablePtr)pTemp, pPriv,
		     pScreenPriv->pPixSourceGC, pScreenPriv->pPixMaskGC,
		     dx, dy, pCursor->bits->width, pCursor->bits->height,
		     source, mask);
    }

    /*
     * copy the temporary pixmap onto the screen
     */

    if (!EnsureGC(pScreenPriv->pRestoreGC, pWin))
	return FALSE;
    pGC = pScreenPriv->pRestoreGC;
    if (pWin->drawable.serialNumber != pGC->serialNumber)
	ValidateGC ((DrawablePtr) pWin, pGC);

    (*pGC->ops->CopyArea) ((DrawablePtr) pTemp, (DrawablePtr) pWin,
			    pGC,
			    0, 0, w, h, x, y);
    return TRUE;
}

miSpriteCursorFuncRec is defined in misprite.h as:

typedef struct {
    Bool	(*RealizeCursor)(
		ScreenPtr /*pScreen*/,
		CursorPtr /*pCursor*/
);
    Bool	(*UnrealizeCursor)(
		ScreenPtr /*pScreen*/,
		CursorPtr /*pCursor*/
);
    Bool	(*PutUpCursor)(
		ScreenPtr /*pScreen*/,
		CursorPtr /*pCursor*/,
		int /*x*/,
		int /*y*/,
		unsigned long /*source*/,
		unsigned long /*mask*/
);
    Bool	(*SaveUnderCursor)(
		ScreenPtr /*pScreen*/,
		int /*x*/,
		int /*y*/,
		int /*w*/,
		int /*h*/
);
    Bool	(*RestoreUnderCursor)(
		ScreenPtr /*pScreen*/,
		int /*x*/,
		int /*y*/,
		int /*w*/,
		int /*h*/
);
    Bool	(*MoveCursor)(
		ScreenPtr /*pScreen*/,
		CursorPtr /*pCursor*/,
		int /*x*/,
		int /*y*/,
		int /*w*/,
		int /*h*/,
		int /*dx*/,
		int /*dy*/,
		unsigned long /*source*/,
		unsigned long /*mask*/
);
    Bool	(*ChangeSave)(
		ScreenPtr /*pScreen*/,
		int /*x*/,
		int /*y*/,
		int /*w*/,
		int /*h*/,
		int /*dx*/,
		int /*dy*/
);

} miSpriteCursorFuncRec, *miSpriteCursorFuncPtr;

After the software cursor initialization the hardware cursor initialization takes place in MGAScreenInit():

    /* Initialize HW cursor layer.
	Must follow software cursor initialization*/
    if (pMga->HWCursor) {
	if(!MGAHWCursorInit(pScreen))
	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
		"Hardware cursor initialization failed\n");
    }

MGAHWCursorInit() calls xf86InitCursor() as:

    return(xf86InitCursor(pScreen, infoPtr));
xf86InitCursor() is implemented as:

Bool
xf86InitCursor(
   ScreenPtr pScreen,
   xf86CursorInfoPtr infoPtr
)
{
    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
    xf86CursorScreenPtr ScreenPriv;
    miPointerScreenPtr PointPriv;

    if (xf86CursorGeneration != serverGeneration) {
	if ((xf86CursorScreenIndex = AllocateScreenPrivateIndex()) < 0)
	    return FALSE;
	xf86CursorGeneration = serverGeneration;
    }

    if (!xf86InitHardwareCursor(pScreen, infoPtr))
	return FALSE;

    ScreenPriv = xcalloc(1, sizeof(xf86CursorScreenRec));
    if (!ScreenPriv)
	return FALSE;

    pScreen->devPrivates[xf86CursorScreenIndex].ptr = ScreenPriv;

    ScreenPriv->SWCursor = TRUE;
    ScreenPriv->isUp = FALSE;
    ScreenPriv->CurrentCursor = NULL;
    ScreenPriv->CursorInfoPtr = infoPtr;
    ScreenPriv->PalettedCursor = FALSE;
    ScreenPriv->pInstalledMap = NULL;

    ScreenPriv->CloseScreen = pScreen->CloseScreen;
    pScreen->CloseScreen = xf86CursorCloseScreen;
    ScreenPriv->QueryBestSize = pScreen->QueryBestSize;
    pScreen->QueryBestSize = xf86CursorQueryBestSize;
    ScreenPriv->RecolorCursor = pScreen->RecolorCursor;
    pScreen->RecolorCursor = xf86CursorRecolorCursor;

    if ((infoPtr->pScrn->bitsPerPixel == 8) &&
	!(infoPtr->Flags & HARDWARE_CURSOR_TRUECOLOR_AT_8BPP)) {
	ScreenPriv->InstallColormap = pScreen->InstallColormap;
	pScreen->InstallColormap = xf86CursorInstallColormap;
	ScreenPriv->PalettedCursor = TRUE;
    }

    PointPriv = pScreen->devPrivates[miPointerScreenIndex].ptr;

    ScreenPriv->showTransparent = PointPriv->showTransparent;
    if (infoPtr->Flags & HARDWARE_CURSOR_SHOW_TRANSPARENT)
	PointPriv->showTransparent = TRUE;
    else
	PointPriv->showTransparent = FALSE;
    ScreenPriv->spriteFuncs = PointPriv->spriteFuncs;
    PointPriv->spriteFuncs = &xf86CursorSpriteFuncs;

    ScreenPriv->SwitchMode = pScrn->SwitchMode;
    ScreenPriv->EnterVT = pScrn->EnterVT;
    ScreenPriv->LeaveVT = pScrn->LeaveVT;
    ScreenPriv->SetDGAMode = pScrn->SetDGAMode;
    
    ScreenPriv->ForceHWCursorCount = 0;
    ScreenPriv->HWCursorForced = FALSE;

    if (pScrn->SwitchMode)
	pScrn->SwitchMode = xf86CursorSwitchMode;
    pScrn->EnterVT = xf86CursorEnterVT;
    pScrn->LeaveVT = xf86CursorLeaveVT;
    pScrn->SetDGAMode = xf86CursorSetDGAMode;

    return TRUE;
}

In xf86InitCursor() PointPriv->spriteFuncs is set to the xf86CursorSpriteFuncs address:

    PointPriv->spriteFuncs = &xf86CursorSpriteFuncs;
where xf86CursorSpriteFuncs is defined as:

static miPointerSpriteFuncRec xf86CursorSpriteFuncs = {
   xf86CursorRealizeCursor,
   xf86CursorUnrealizeCursor,
   xf86CursorSetCursor,
   xf86CursorMoveCursor
};

Notice that PointPriv is of type miPointerScreenPtr, which is defined as:
typedef struct {
    miPointerSpriteFuncPtr  spriteFuncs;	/* sprite-specific methods */
    miPointerScreenFuncPtr  screenFuncs;	/* screen-specific methods */
    CloseScreenProcPtr	    CloseScreen;
    Bool		    waitForUpdate;	/* don't move cursor in SIGIO */
    Bool		    showTransparent;	/* show empty cursors */
} miPointerScreenRec, *miPointerScreenPtr;
and miPointerScreenFuncPtr is defined as:
typedef struct _miPointerScreenFuncRec {
    Bool	(*CursorOffScreen)(
                    ScreenPtr* /* ppScr */,
                    int*  /* px */,
                    int*  /* py */
                    );
    void	(*CrossScreen)(
                    ScreenPtr /* pScr */,
                    int  /* entering */
                    );
    void	(*WarpCursor)(
                    ScreenPtr /* pScr */,
                    int  /* x */,
                    int  /* y */
                    );
    void	(*EnqueueEvent)(
                    xEventPtr /* event */
                    );
    void	(*NewEventScreen)(
                    ScreenPtr /* pScr */,
		    Bool /* fromDIX */
                    );
} miPointerScreenFuncRec, *miPointerScreenFuncPtr;

REFERENCES

Events
The Keyboard and Pointer
Events

For the Hardware cursors - Software cursors:

Strategies for Porting the X v11 Sample Server
Cursor Notes
Definition of the Porting Layer
X Server Device Developer's Guide