/************************************************************
Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts,
and the Massachusetts Institute of Technology, Cambridge, Massachusetts.

                        All Rights Reserved

Permission to use, copy, modify, and distribute this software and its 
documentation for any purpose and without fee is hereby granted, 
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in 
supporting documentation, and that the names of Digital or MIT not be
used in advertising or publicity pertaining to distribution of the
software without specific, written prior permission.  

DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
SOFTWARE.

********************************************************/


/* $Header: events.c,v 1.76 87/06/24 14:48:52 swick Exp $ */

#include "X.h"
#include "misc.h"
#include "resource.h"
#define NEED←EVENTS
#define NEED←REPLIES
#include "Xproto.h"
#include "windowstr.h"
#include "inputstr.h"
#include "scrnintstr.h"
#include "cursorstr.h"

#include "dixstruct.h"
#include "opaque.h"

extern WindowRec WindowTable[];
extern int swappedClients[];
extern Bool IsParent();
extern void DeactivatePointerGrab();
extern void DeactivateKeyboardGrab();
extern void SetPointerStateMasks();
extern void SetKeyboardStateMasks();
extern int DeliverEventsToWindow();
extern Bool MatchingGrab();
extern void DoFocusEvents();


extern void (* EventSwapVector[128]) ();
extern void (* ReplySwapVector[256]) ();

#define NoSuchEvent 0x80000000	/* so doesn't match NoEventMask */
#define StructureAndSubMask ( StructureNotifyMask | SubstructureNotifyMask )
#define AllButtonsMask ( \
	Button1Mask | Button2Mask | Button3Mask | Button4Mask | Button5Mask )
#define MotionMask ( \
	PointerMotionMask | PointerMotionHintMask | Button1MotionMask | \
	Button2MotionMask | Button3MotionMask | Button4MotionMask | \
	Button5MotionMask | ButtonMotionMask )
#define PropagateMask ( \
	KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | \
	MotionMask )
#define AllModifiersMask ( \
	ShiftMask | LockMask | ControlMask | Mod1Mask | Mod2Mask | \
	Mod3Mask | Mod4Mask | Mod5Mask )
#define Motion←Filter(state) (PointerMotionMask | \
		(AllButtonsMask & state) | buttonMotionMask);


#define WID(w) ((w) ? ((w)->wid) : 0)

#define BitOn(ptr, bit) \
	((BYTE *) (ptr))[(bit)>>3] |= (1 << ((bit) & 7))
#define BitOff(ptr, bit) \
	((BYTE *) (ptr))[(bit)>>3] &= ~(1 << ((bit) & 7))
#define IsOn(ptr, bit) \
	(((BYTE *) (ptr))[(bit)>>3] & (1 << ((bit) & 7)))

extern debug←events;
extern InputInfo inputInfo;

extern KeySymsRec curKeySyms;

extern GrabRec keybdGrab;	/* used for active grabs */
extern GrabRec ptrGrab;

#define MAX←QUEUED←EVENTS 100
extern struct {
    unsigned int	num;
    QdEventRec		pending, free;	/* only forw, back used */
    DeviceIntPtr	replayDev;	/* kludgy rock to put flag for */
    WindowPtr		replayWin;	/*   ComputeFreezes            */
    Bool		playingEvents;
} syncEvents;

/*
 * 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.
 */
extern WindowPtr *spriteTrace;
#define ROOT spriteTrace[0]
extern int spriteTraceSize;
extern int spriteTraceGood;

extern WindowPtr *focusTrace;
extern int focusTraceSize;
extern int focusTraceGood;

extern CARD16 keyButtonState;
extern int buttonsDown;		/* number of buttons currently down */
extern Mask buttonMotionMask;

typedef struct {
    int		x, y;
} HotSpot;

extern  struct {
    CursorPtr	current;
    BoxRec	hotLimits;	/* logical constraints */
    BoxRec	physLimits;	/* of hot spot due to hardware limits */
    WindowPtr	win;
    HotSpot	hot;
} sprite;			/* info about the cursor sprite */

extern Bool lastWasMotion;

extern void DoEnterLeaveEvents();	/* merely forward declarations */
extern WindowPtr XYToWindow();
extern Bool CheckKeyboardGrabs();
extern void NormalKeyboardEvent();
extern int DeliverDeviceEvents();

extern ScreenPtr currentScreen;

extern CARD16 stateMasks[MAP←LENGTH];	/* only for default keyboard ? XXX */

extern int lastEventMask;

#define CantBeFiltered NoEventMask
extern int filters[128];
extern int PassiveClientGone();

void
InitPointerDeviceStruct(device, map, mapLength, motionProc, controlProc)
    DevicePtr device;
    BYTE *map;
    int mapLength;
    void (*controlProc)();
    int (*motionProc)();
{
    int i;
    DeviceIntPtr mouse = (DeviceIntPtr)device;

    mouse->grab = NullGrab;
    mouse->public.on = FALSE;
    mouse->u.ptr.mapLength = mapLength;
    mouse->u.ptr.map[0] = 0;
    for (i = 1; i <= mapLength; i++)
	mouse->u.ptr.map[i] = map[i];
    mouse->u.ptr.ctrl = defaultPointerControl;
    mouse->u.ptr.GetMotionProc = motionProc;
    mouse->u.ptr.CtrlProc = controlProc;
    mouse->u.ptr.autoReleaseGrab = FALSE;
    if (mouse == inputInfo.pointer)
	SetPointerStateMasks(mouse);
}

void
QueryMinMaxKeyCodes(minCode, maxCode)
    KeyCode *minCode, *maxCode;
{
    *minCode = curKeySyms.minKeyCode;
    *maxCode = curKeySyms.maxKeyCode;
}

static void
SetKeySymsMap(pKeySyms)
    KeySymsPtr pKeySyms;
{
    int i, j;
    int rowDif = pKeySyms->minKeyCode - curKeySyms.minKeyCode;
           /* if keysym map size changes, grow map first */

    if (pKeySyms->mapWidth < curKeySyms.mapWidth)
    {
        for (i = pKeySyms->minKeyCode; i <= pKeySyms->maxKeyCode; i++)
	{
#define SI(r, c) (((r-pKeySyms->minKeyCode)*pKeySyms->mapWidth) + (c))
#define DI(r, c) (((r - curKeySyms.minKeyCode)*curKeySyms.mapWidth) + (c))
	    for (j = 0; j < pKeySyms->mapWidth; j++)
		curKeySyms.map[DI(i, j)] = pKeySyms->map[SI(i, j)];
	    for (j = pKeySyms->mapWidth; j < curKeySyms.mapWidth; j++)
		curKeySyms.map[DI(i, j)] = NoSymbol;
#undef SI
#undef DI
	}
	return;
    }
    else if (pKeySyms->mapWidth > curKeySyms.mapWidth)
    {
        KeySym *map;
	int bytes = sizeof(KeySym) * pKeySyms->mapWidth *
               (curKeySyms.maxKeyCode - curKeySyms.minKeyCode + 1);
        map = (KeySym *)Xalloc(bytes);
	bzero(map, bytes);
        if (curKeySyms.map)
	{
            for (i = 0; i <= curKeySyms.maxKeyCode-curKeySyms.minKeyCode; i++)
		bcopy(
		    &curKeySyms.map[i*curKeySyms.mapWidth],
		    &map[i*pKeySyms->mapWidth],
		    curKeySyms.mapWidth * sizeof(KeySym));
	    Xfree(curKeySyms.map);
	}
	curKeySyms.mapWidth = pKeySyms->mapWidth;
        curKeySyms.map = map;
    }
    bcopy(
	pKeySyms->map,
	&curKeySyms.map[rowDif],
	(pKeySyms->maxKeyCode - pKeySyms->minKeyCode + 1) *
	    (int)curKeySyms.mapWidth * sizeof(KeySym));
}


void 
InitKeyboardDeviceStruct(device, pKeySyms, pModifiers,
			      bellProc, controlProc)
    DevicePtr device;
    KeySymsPtr pKeySyms;
    ModifierMapPtr pModifiers;
    void (*bellProc)();
    void (*controlProc)();
{
#define SET←MOD(entry)  (keybd->u.keybd.modMap.entry = pModifiers->entry)

    DeviceIntPtr keybd = (DeviceIntPtr)device;

    keybd->grab = NullGrab;
    keybd->public.on = FALSE;

    keybd->u.keybd.ctrl = defaultKeyboardControl;
    keybd->u.keybd.BellProc = bellProc;
    keybd->u.keybd.CtrlProc = controlProc;
    keybd->u.keybd.focus.win = PointerRootWin;
    keybd->u.keybd.focus.revert = None;
    keybd->u.keybd.focus.time = currentTime;
    keybd->u.keybd.passiveGrab = FALSE;
    curKeySyms.minKeyCode = pKeySyms->minKeyCode;
    curKeySyms.maxKeyCode = pKeySyms->maxKeyCode;
    SET←MOD(lock);
    SET←MOD(shiftA);
    SET←MOD(shiftB);
    SET←MOD(controlA);
    SET←MOD(controlB);
    SET←MOD(mod1A);
    SET←MOD(mod1B);
    SET←MOD(mod2A);
    SET←MOD(mod2B);
    SET←MOD(mod3A);
    SET←MOD(mod3B);
    SET←MOD(mod4A);
    SET←MOD(mod4B);
    SET←MOD(mod5A);
    SET←MOD(mod5B);
    if (keybd == inputInfo.keyboard)
    {
	SetKeyboardStateMasks(keybd);
	SetKeySymsMap(pKeySyms);
	(*keybd->u.keybd.CtrlProc)(keybd, &keybd->u.keybd.ctrl);  
    }
#undef SET←MOD
}

void
InitOtherDeviceStruct(device, map, mapLength)
    DevicePtr device;
    BYTE *map;
    int mapLength;
{
    int i;
    DeviceIntPtr other = (DeviceIntPtr)device;

    other->grab = NullGrab;
    other->public.on = FALSE;
    other->u.other.mapLength = mapLength;
    other->u.other.map[0] =  0;
    for (i = 1; i <= mapLength; i++)
	other->u.other.map[i] = map[i];
    other->u.other.focus.win = NoneWin;
    other->u.other.focus.revert = None;
    other->u.other.focus.time = currentTime;
}

GrabPtr
SetDeviceGrab(device, grab)
    DevicePtr device;
    GrabPtr grab;
{
    register DeviceIntPtr dev = (DeviceIntPtr)device;
    GrabPtr oldGrab = dev->grab;
    dev->grab = grab; /* must not be deallocated */
    return oldGrab;
}

/*
 * Devices can't be resources since the bit patterns don't fit very well.
 * For one, where the client field would be, is random bits and the client
 * object might not be defined. For another, the "server" bit might be on.
 */

#ifdef INPUT←EXTENSION

DevicePtr
LookupInputDevice(deviceID)
    Device deviceID;
{
    int i;
    for (i = 0; i < inputInfo.numDevices; i++)
	if (inputInfo.devices[i]->public.deviceID == deviceID)
	    return &(inputInfo.devices[i]->public);
    return NullDevice;
}
#endif /* INTPUT←EXTENSION */

DevicePtr
LookupKeyboardDevice()
{
    return &inputInfo.keyboard->public;
}

DevicePtr
LookupPointerDevice()
{
    return &inputInfo.pointer->public;
}


static int
SendMappingNotify(request, firstKeyCode, count)
    BYTE request, firstKeyCode, count;
{
    int i;
    xEvent event;

    event.u.u.type = MappingNotify;
    event.u.mappingNotify.request = request;
    if (request == MappingKeyboard)
    {
        event.u.mappingNotify.firstKeyCode = firstKeyCode;
        event.u.mappingNotify.count = count;
    }
    /* 0 is the server client */
    for (i=1; i<currentMaxClients; i++)
        if (! clients[i]->clientGone)
            WriteEventToClient(clients[i], 1, (pointer)&event);
}

/*
 * n-sqared algorithm. n < 255 and don't want to copy the whole thing and
 * sort it to do the checking. How often is it called? Just being lazy?
 */
static Bool
BadDeviceMap(buff, length, low, high)
    BYTE *buff;
    int length;
    unsigned low, high;
{
    int     i, j;

    for (i = 0; i < length; i++)
	if (buff[i])		       /* only check non-zero elements */
	{
	    if ((low > buff[i]) || (high < buff[i]))
		return TRUE;
	    for (j = i + 1; j < length; j++)
		if (buff[i] == buff[j])
		    return TRUE;
	}
    return FALSE;
}

int 
ProcSetModifierMapping(client)
    ClientPtr client;
{
#define LEGAL←MOD(mod) \
    if (modMap.mod != NoSymbol)\
    {\
        if (!LegalModifier(modMap.mod))\
        {\
            rep.success = MappingFailed;\
	    goto WriteMappingReply;\
	}\
	if ((inputInfo.keyboard->u.keybd.modMap.mod != modMap.mod) &&\
		IsOn(inputInfo.keyboard->down, modMap.mod))\
        {\
            rep.success = MappingBusy;\
	    goto WriteMappingReply;\
	}\
    }\

    xSetModifierMappingReply rep;
    REQUEST(xSetModifierMappingReq);
    ModifierMapRec modMap;
    
    REQUEST←SIZE←MATCH(xSetModifierMappingReq);

    modMap.lock = stuff->lock;
    modMap.shiftA = stuff->shiftA;
    modMap.shiftB = stuff->shiftB;
    modMap.controlA = stuff->controlA;
    modMap.controlB = stuff->controlB;
    modMap.mod1A = stuff->mod1A;
    modMap.mod1B = stuff->mod1B;
    modMap.mod2A = stuff->mod2A;
    modMap.mod2B = stuff->mod2B;
    modMap.mod3A = stuff->mod3A;
    modMap.mod3B = stuff->mod3B;
    modMap.mod4A = stuff->mod4A;
    modMap.mod4B = stuff->mod4B;
    modMap.mod5A = stuff->mod5A;
    modMap.mod5B = stuff->mod5B;

    if (BadDeviceMap ((BYTE *)&modMap, 15, curKeySyms.minKeyCode, 
		      curKeySyms.maxKeyCode))
        return BadValue;    

    rep.type = X←Reply;
    rep.length = 0;
    rep.sequenceNumber = client->sequence;
    rep.success = MappingSuccess;

    LEGAL←MOD(lock); 
    LEGAL←MOD(shiftA);
    LEGAL←MOD(shiftB);
    LEGAL←MOD(controlA);
    LEGAL←MOD(controlB);
    LEGAL←MOD(mod1A);
    LEGAL←MOD(mod1B);
    LEGAL←MOD(mod2A);
    LEGAL←MOD(mod2B);
    LEGAL←MOD(mod3A);
    LEGAL←MOD(mod3B);
    LEGAL←MOD(mod4A);
    LEGAL←MOD(mod4B);
    LEGAL←MOD(mod5A);
    LEGAL←MOD(mod5B);

WriteMappingReply:
    WriteReplyToClient(client, sizeof(xSetModifierMappingReply), &rep);

    if (rep.success == MappingSuccess)
    {
	inputInfo.keyboard->u.keybd.modMap = modMap;
	SetKeyboardStateMasks(inputInfo.keyboard);
        SendMappingNotify(MappingModifier, 0, 0);
    }
    return(client->noClientException);
#undef LEGAL←MOD
}

int
ProcGetModifierMapping(client)
    ClientPtr client;
{
    xGetModifierMappingReply rep;
    REQUEST(xReq);

    REQUEST←SIZE←MATCH(xReq);
    rep.type = X←Reply;
    rep.length = 0;
    rep.sequenceNumber = client->sequence;
    rep.lock = inputInfo.keyboard->u.keybd.modMap.lock;
    rep.shiftA = inputInfo.keyboard->u.keybd.modMap.shiftA;
    rep.shiftB = inputInfo.keyboard->u.keybd.modMap.shiftB;
    rep.controlA = inputInfo.keyboard->u.keybd.modMap.controlA;
    rep.controlB = inputInfo.keyboard->u.keybd.modMap.controlB;
    rep.mod1A = inputInfo.keyboard->u.keybd.modMap.mod1A;
    rep.mod1B = inputInfo.keyboard->u.keybd.modMap.mod1B;
    rep.mod2A = inputInfo.keyboard->u.keybd.modMap.mod2A;
    rep.mod2B = inputInfo.keyboard->u.keybd.modMap.mod2B;
    rep.mod3A = inputInfo.keyboard->u.keybd.modMap.mod3A;
    rep.mod3B = inputInfo.keyboard->u.keybd.modMap.mod3B;
    rep.mod4A = inputInfo.keyboard->u.keybd.modMap.mod4A;
    rep.mod4B = inputInfo.keyboard->u.keybd.modMap.mod4B;
    rep.mod5A = inputInfo.keyboard->u.keybd.modMap.mod5A;
    rep.mod5B = inputInfo.keyboard->u.keybd.modMap.mod5B;

    WriteReplyToClient(client, sizeof(xGetModifierMappingReply), &rep);

    return client->noClientException;
}

int
ProcChangeKeyboardMapping(client)
    ClientPtr client;
{
    REQUEST(xChangeKeyboardMappingReq);
    int len;
    int count;
    KeySymsRec keysyms;

    REQUEST←AT←LEAST←SIZE(xChangeKeyboardMappingReq);

    len = stuff->length - (sizeof(xChangeKeyboardMappingReq) >> 2);  
    if (len % stuff->keySymsPerKeyCode != 0)
            return BadLength;
    if ((stuff->firstKeyCode < curKeySyms.minKeyCode) ||
	(stuff->firstKeyCode + len > curKeySyms.maxKeyCode) ||
        (stuff->keySymsPerKeyCode == 0))
            return BadValue;
    count = len / stuff->keySymsPerKeyCode;
    keysyms.minKeyCode = stuff->firstKeyCode;
    keysyms.maxKeyCode = stuff->firstKeyCode + count;
    keysyms.mapWidth = stuff->keySymsPerKeyCode;
    keysyms.map = (KeySym *)&stuff[1];
    SetKeySymsMap(&keysyms);
    SendMappingNotify(MappingKeyboard, stuff->firstKeyCode, (BYTE) count);
    return client->noClientException;

}

int
ProcSetPointerMapping(client)
    ClientPtr client;
{
    REQUEST(xSetPointerMappingReq);
    BYTE *map;
    xSetPointerMappingReply rep;
    register int i;

    REQUEST←AT←LEAST←SIZE(xSetPointerMappingReq);
    if (stuff->length != (sizeof(xSetPointerMappingReq) + stuff->nElts + 3)>>2)
	return BadLength;
    rep.type = X←Reply;
    rep.length = 0;
    rep.sequenceNumber = client->sequence;
    rep.success = MappingSuccess;
    map = (BYTE *)&stuff[1];
    if (stuff->nElts != inputInfo.pointer->u.ptr.mapLength)
	return BadValue;
    if (BadDeviceMap(&map[0], (int)stuff->nElts, 1, 255))
	return BadValue;
    for (i=0; i < stuff->nElts; i++)
	if ((inputInfo.pointer->u.ptr.map[i + 1] != map[i]) &&
		IsOn(inputInfo.pointer->down, i + 1))
	{
    	    rep.success = MappingBusy;
	    WriteReplyToClient(client, sizeof(xSetPointerMappingReply), &rep);
            return Success;
	}
    for (i = 0; i < stuff->nElts; i++)
	inputInfo.pointer->u.ptr.map[i + 1] = map[i];
    SetPointerStateMasks((DevicePtr)inputInfo.pointer);	   
    WriteReplyToClient(client, sizeof(xSetPointerMappingReply), &rep);
    SendMappingNotify(MappingPointer, 0, 0);
    return Success;
}

int
ProcGetKeyboardMapping(client)
    ClientPtr client;
{
    xGetKeyboardMappingReply rep;
    REQUEST(xGetKeyboardMappingReq);

    REQUEST←SIZE←MATCH(xGetKeyboardMappingReq);

    if ((stuff->firstKeyCode < curKeySyms.minKeyCode) ||
        (stuff->firstKeyCode > curKeySyms.maxKeyCode) ||
	(stuff->firstKeyCode + stuff->count > curKeySyms.maxKeyCode + 1))
        return BadValue;

    rep.type = X←Reply;
    rep.sequenceNumber = client->sequence;
    rep.keySymsPerKeyCode = curKeySyms.mapWidth;
/* length is a count of 4 byte quantities and KeySyms are 4 bytes */
    rep.length = (curKeySyms.mapWidth * stuff->count);
    WriteReplyToClient(client, sizeof(xGetKeyboardMappingReply), &rep);

    WriteReplyToClient(
	client,
	curKeySyms.mapWidth * stuff->count * sizeof(KeySym),
	&curKeySyms.map[stuff->firstKeyCode - curKeySyms.minKeyCode]);

    return client->noClientException;
}

int
ProcGetPointerMapping(client)
    ClientPtr client;
{
    xGetPointerMappingReply rep;
    REQUEST(xReq);

    REQUEST←SIZE←MATCH(xReq);
    rep.type = X←Reply;
    rep.sequenceNumber = client->sequence;
    rep.nElts = inputInfo.pointer->u.ptr.mapLength;
    rep.length = (rep.nElts + (4-1))/4;
    WriteReplyToClient(client, sizeof(xGetPointerMappingReply), &rep);
    WriteReplyToClient(client, rep.nElts, &inputInfo.pointer->u.ptr.map[1]);
    return Success;    
}

int
Ones(mask)                /* HACKMEM 169 */
    Mask mask;
{
    register int y;

    y = (mask >> 1) &033333333333;
    y = mask - y - ((y >>1) & 033333333333);
    return (((y + (y >> 3)) & 030707070707) % 077);
}

void
NoteLedState(keybd, led, on)
    DeviceIntPtr keybd;
    int		led;
    Bool	on;
{
    KeybdCtrl *ctrl = &keybd->u.keybd.ctrl;
    if (on)
	ctrl->leds |= (1 << (led - 1));
    else
	ctrl->leds &= ~(1 << (led - 1)); /* assumes 32-bit longs XXX */
}

int
ProcChangeKeyboardControl (client)
    ClientPtr client;
{
#define DO←ALL    0xffffffff
    KeybdCtrl ctrl;
    DeviceIntPtr keybd = inputInfo.keyboard;
    long *vlist;
    int t;
    int led = DO←ALL;
    int key = DO←ALL;
    REQUEST(xChangeKeyboardControlReq);

    REQUEST←AT←LEAST←SIZE(xChangeKeyboardControlReq);
    if (stuff->length !=(sizeof(xChangeKeyboardControlReq)>>2) + Ones(stuff->mask))
	return BadLength;
    vlist = (long *)&stuff[1];		/* first word of values */
    ctrl = keybd->u.keybd.ctrl;
    if (stuff->mask & KBKeyClickPercent)
    {
	t = (INT8)*vlist;
	vlist++;
	if (t == -1)
	    t = defaultKeyboardControl.click;
	else if (t < 0 || t > 100)
	    return BadValue;
	ctrl.click = t;
    }
    if (stuff->mask & KBBellPercent)
    {
	t = (INT8)*vlist;
	vlist++;
	if (t == -1)
	    t = defaultKeyboardControl.bell;
	else if (t < 0 || t > 100)
	    return BadValue;
	ctrl.bell = t;
    }
    if (stuff->mask & KBBellPitch)
    {
	t = (INT16)*vlist;
	vlist++;
	if (t == -1)
	    t = defaultKeyboardControl.bell←pitch;
	else if (t < 0)
	    return BadValue;
	ctrl.bell←pitch = t;
    }
    if (stuff->mask & KBBellDuration)
    {
	t = (INT16)*vlist;
	vlist++;
	if (t == -1)
	    t = defaultKeyboardControl.bell←duration;
	else if (t < 0)
	    return BadValue;
	ctrl.bell←duration = t;
    }
    if (stuff->mask & KBLed)
    {
	led = (CARD8)*vlist;
	vlist++;
	if (led < 1 || led > 32)
	    return BadValue;
	if (!(stuff->mask & KBLedMode))
	    return BadMatch;
    }
    if (stuff->mask & KBLedMode)
    {
	t = (CARD8)*vlist;
	vlist++;
	if (t == LedModeOff)
	{
	    if (led == DO←ALL)
		ctrl.leds = 0x0;
	    else
		ctrl.leds &= ~(1 << (led - 1)); /* assumes 32-bit longs XXX */
	}
	else if (t == LedModeOn)
	{
	    if (led == DO←ALL)
		ctrl.leds = DO←ALL;
	    else
		ctrl.leds |= (1 << (led - 1));
	}
	else
	    return BadValue;
    }
    if (stuff->mask & KBKey)
    {
	key = (KeyCode)*vlist;
	vlist++;
	if (key < 8 || key > 255)
	    return BadValue;
	if (!(stuff->mask & KBAutoRepeatMode))
	    return BadMatch;
    }
    if (stuff->mask & KBAutoRepeatMode)
    {
	int index = (key >> 3);
	int mask = (1 << (key & 7));
	t = (CARD8)*vlist;
	vlist++;
	if (t == AutoRepeatModeOff)
	{
	    if (key == DO←ALL)
		ctrl.autoRepeat = FALSE;
	    else
		ctrl.autoRepeats[index] &= ~mask;
	}
	else if (t == AutoRepeatModeOn)
	{
	    if (key == DO←ALL)
		ctrl.autoRepeat = TRUE;
	    else
		ctrl.autoRepeats[index] |= mask;
	}
	else if (t == AutoRepeatModeDefault)
	{
	    if (key == DO←ALL)
		ctrl.autoRepeat = defaultKeyboardControl.autoRepeat;
	    else
		ctrl.autoRepeats[index] &= ~mask;
		ctrl.autoRepeats[index] =
			(ctrl.autoRepeats[index] & ~mask) |
			(defaultKeyboardControl.autoRepeats[index] & mask);
	}
	else
	    return BadValue;
    }
    keybd->u.keybd.ctrl = ctrl;
    (*keybd->u.keybd.CtrlProc)(keybd, &keybd->u.keybd.ctrl);
    return Success;
#undef DO←ALL
} 

int
ProcGetKeyboardControl (client)
    ClientPtr client;
{
    int i;
    DeviceIntPtr keybd = inputInfo.keyboard;
    xGetKeyboardControlReply rep;
    REQUEST(xReq);

    REQUEST←SIZE←MATCH(xReq);
    rep.type = X←Reply;
    rep.length = 5;
    rep.sequenceNumber = client->sequence;
    rep.globalAutoRepeat = keybd->u.keybd.ctrl.autoRepeat;
    rep.keyClickPercent = keybd->u.keybd.ctrl.click;
    rep.bellPercent = keybd->u.keybd.ctrl.bell;
    rep.bellPitch = keybd->u.keybd.ctrl.bell←pitch;
    rep.bellDuration = keybd->u.keybd.ctrl.bell←duration;
    rep.ledMask = keybd->u.keybd.ctrl.leds;
    for (i = 0; i < 32; i++)
	rep.map[i] = keybd->u.keybd.ctrl.autoRepeats[i];
    WriteReplyToClient(client, sizeof(xGetKeyboardControlReply), &rep);
    return Success;
} 

int
ProcBell(client)
    ClientPtr client;
{
    register DeviceIntPtr keybd = inputInfo.keyboard;
    REQUEST(xBellReq);
    REQUEST←SIZE←MATCH(xBellReq);
    if (stuff->percent < -100 || stuff->percent > 100)
	return BadValue;
    (*keybd->u.keybd.BellProc)(
	min(100, max(0, stuff->percent + keybd->u.keybd.ctrl.bell)),
	keybd);
    return Success;
} 

int
ProcChangePointerControl(client)
    ClientPtr client;
{
    DeviceIntPtr mouse = inputInfo.pointer;
    PtrCtrl ctrl;		/* might get BadValue part way through */
    REQUEST(xChangePointerControlReq);

    REQUEST←SIZE←MATCH(xChangePointerControlReq);
    ctrl = mouse->u.ptr.ctrl;
    if (stuff->doAccel)
    {
	if (stuff->accelNum == -1)
	    ctrl.num = defaultPointerControl.num;
	else if (stuff->accelNum < 0)
	{
	    client->errorValue = stuff->accelNum;
	    return BadValue;
	}
	else ctrl.num = stuff->accelNum;
	if (stuff->accelDenum == -1)
	    ctrl.den = defaultPointerControl.den;
	else if (stuff->accelDenum <= 0)
	{
	    client->errorValue = stuff->accelDenum;
	    return BadValue;
	}
	else ctrl.den = stuff->accelDenum;
    }
    if (stuff->doThresh)
    {
	if (stuff->threshold == -1)
	    ctrl.threshold = defaultPointerControl.threshold;
	else if (stuff->threshold <= 0)
	{
	    client->errorValue = stuff->threshold;
	    return BadValue;
	}
	else ctrl.threshold = stuff->threshold;
    }
    mouse->u.ptr.ctrl = ctrl;
    (*mouse->u.ptr.CtrlProc)(mouse, &mouse->u.ptr.ctrl);
    return Success;
} 

int
ProcGetPointerControl(client)
    ClientPtr client;
{
    register DeviceIntPtr mouse = inputInfo.pointer;
    REQUEST(xReq);
    xGetPointerControlReply rep;

    REQUEST←SIZE←MATCH(xReq);
    rep.type = X←Reply;
    rep.length = 0;
    rep.sequenceNumber = client->sequence;
    rep.threshold = mouse->u.ptr.ctrl.threshold;
    rep.accelNumerator = mouse->u.ptr.ctrl.num;
    rep.accelDenominator = mouse->u.ptr.ctrl.den;
    WriteReplyToClient(client, sizeof(xGenericReply), &rep);
    return Success;
}

int
ProcGetMotionEvents(client)
    ClientPtr client;
{
    WindowPtr pWin;
    xTimecoord * coords;
    xGetMotionEventsReply rep;
    int     i, count, xmin, xmax, ymin, ymax;
    DeviceIntPtr mouse = inputInfo.pointer;
    TimeStamp start, stop;
    REQUEST(xGetMotionEventsReq);

    REQUEST←SIZE←MATCH(xGetMotionEventsReq);
    pWin = (WindowPtr) LookupID(stuff->window, RT←WINDOW, RC←CORE);
    if (!pWin)
    {
	client->errorValue = stuff->window;
	return BadWindow;
    }
    lastWasMotion = FALSE;
    rep.type = X←Reply;
    rep.sequenceNumber = client->sequence;
    rep.nEvents = 0;
    start = ClientTimeToServerTime(stuff->start);
    stop = ClientTimeToServerTime(stuff->stop);
    if (CompareTimeStamps(start, stop) == LATER)
        return Success;
    if (CompareTimeStamps(start, currentTime) == LATER)
        return Success;
    if (CompareTimeStamps(stop, currentTime) == LATER)
        stop = currentTime;
    if (inputInfo.numMotionEvents)
    {
	coords = (xTimecoord *) Xalloc(
		inputInfo.numMotionEvents * sizeof(xTimecoord));
	count = (*mouse->u.ptr.GetMotionProc) (
		mouse, coords, start.milliseconds, stop.milliseconds);
	xmin = pWin->absCorner.x - pWin->borderWidth;
	xmax =
	    pWin->absCorner.x + pWin->clientWinSize.width + pWin->borderWidth;
	ymin = pWin->absCorner.y - pWin->borderWidth;
	ymax =
	    pWin->absCorner.y + pWin->clientWinSize.height + pWin->borderWidth;
	for (i = 0; i < count; i++)
	    if ((xmin <= coords[i].x) && (coords[i].x < xmax) &&
		    (ymin <= coords[i].y) && (coords[i].y < ymax))
	    {
		coords[rep.nEvents].x = coords[i].x - pWin->absCorner.x;
		coords[rep.nEvents].y = coords[i].y - pWin->absCorner.y;
		rep.nEvents++;
	    }
    }
    rep.length = rep.nEvents * sizeof(xTimecoord) / 4;
    WriteReplyToClient(client, sizeof(xGetMotionEventsReply), &rep);
    if (inputInfo.numMotionEvents)
    {
	WriteReplyToClient( client, (int)rep.nEvents * sizeof(xTimecoord), coords);
	Xfree(coords);
    }
    return Success;
}

int
ProcQueryPointer(client)
    ClientPtr client;
{
    xQueryPointerReply rep;
    WindowPtr pWin, t;
    REQUEST(xResourceReq);

    REQUEST←SIZE←MATCH(xResourceReq);
    pWin = (WindowPtr)LookupID(stuff->id, RT←WINDOW, RC←CORE);
    if (!pWin)
    {
	client->errorValue = stuff->id;
	return BadWindow;
    }
    lastWasMotion = FALSE;
    rep.type = X←Reply;
    rep.sequenceNumber = client->sequence;
    rep.sameScreen = xTrue;		/* XXX */
    rep.mask = keyButtonState;
    rep.length = 0;
    rep.root = (ROOT)->wid;
    rep.rootX = sprite.hot.x;
    rep.rootY = sprite.hot.y;
    rep.winX = sprite.hot.x - pWin->absCorner.x;
    rep.winY = sprite.hot.y - pWin->absCorner.y;
    rep.child = None;
    for (t = sprite.win; t; t = t->parent)
	if (t->parent == pWin)
	{
	    rep.child = t->wid;
	    break;
	}
    WriteReplyToClient(client, sizeof(xQueryPointerReply), &rep);

    return(Success);    
}

int
ProcQueryKeymap(client)
    ClientPtr client;
{
    xQueryKeymapReply rep;
    int i;

    rep.type = X←Reply;
    rep.sequenceNumber = client->sequence;
    rep.length = 2;
    for (i = 0; i<32; i++)
	rep.map[i] = inputInfo.keyboard->down[i];
    WriteReplyToClient(client, sizeof(xQueryKeymapReply), &rep);
    return Success;
}

int
ProcSendEvent(client)
    ClientPtr client;
{
    WindowPtr pWin;
    WindowPtr effectiveFocus = NullWindow; /* only set if dest==InputFocus */
    REQUEST(xSendEventReq);

    REQUEST←SIZE←MATCH(xSendEventReq);
    if (stuff->destination == PointerWindow)
	pWin = sprite.win;
    else if (stuff->destination == InputFocus)
    {
	WindowPtr inputFocus = inputInfo.keyboard->u.keybd.focus.win;
	if ((inputFocus == NoneWin) || (inputFocus == PointerRootWin))
	    return Success;
	if (IsParent(inputFocus, sprite.win))
	{
	    effectiveFocus = inputFocus;
	    pWin = sprite.win;
	}
	else
	    effectiveFocus = pWin = inputFocus;
    }
    else
	pWin = (WindowPtr)LookupID(stuff->destination, RT←WINDOW, RC←CORE);
    if (!pWin)
    {
	client->errorValue = stuff->destination;
	return BadWindow;
    }
    stuff->event.u.u.type |= 0x80;
    if (stuff->propagate)
    {
	for (;pWin; pWin = pWin->parent)
	{
	    if (DeliverEventsToWindow(
			pWin, &stuff->event, 1, stuff->eventMask, NullGrab))
		return Success;
	    if (pWin == effectiveFocus)
		return Success;
	    stuff->eventMask &= ~pWin->dontPropagateMask;
	}
    }
    else
	DeliverEventsToWindow(
	    pWin, &stuff->event, 1, stuff->eventMask, NullGrab);
    return Success;
}

int
ProcUngrabKey(client)
    ClientPtr client;
{
    REQUEST(xUngrabKeyReq);
    WindowPtr pWin;
    GrabPtr grab;

    REQUEST←SIZE←MATCH(xUngrabKeyReq);
    pWin = (WindowPtr) LookupID(stuff->grabWindow, RT←WINDOW, RC←CORE);
    if (!pWin)
    {
	client->errorValue = stuff->grabWindow;
	return BadWindow;
    }
    for (grab = PASSIVEGRABS(pWin); grab; grab = grab->next)
    {
	if (MatchingGrab(
	    (int)stuff->key, (int)stuff->modifiers, inputInfo.keyboard, grab, TRUE))
	{
	    if (client == grab->client)
		FreeResource(grab->resource, RC←NONE);
		/*
		 * Might need to unlink multiple requests, the keys might
		 * be put on individually, but taken off with an AnyMumble.
		 */
	}
    }
    return(Success);
}

int
ProcGrabKey(client)
    ClientPtr client;
{
    WindowPtr pWin;
    REQUEST(xGrabKeyReq);
    GrabPtr grab;
    Bool useOld = FALSE;

    REQUEST←SIZE←MATCH(xGrabKeyReq);
    if ((stuff->key > curKeySyms.maxKeyCode) || (stuff->key < curKeySyms.minKeyCode))
        return BadValue;
    pWin = (WindowPtr)LookupID(stuff->grabWindow, RT←WINDOW, RC←CORE);
    client->errorValue = stuff->grabWindow;
    if (!pWin)
    {
	client->errorValue = stuff->grabWindow;
	return BadWindow;
    }
    for (grab = PASSIVEGRABS(pWin); grab; grab = grab->next)
    {
	if (MatchingGrab(
	    (int)stuff->key, (int)stuff->modifiers, inputInfo.keyboard, grab, TRUE))
	{
	    if (client == grab->client)
	    {
		useOld = TRUE;
		break;
	    }
	    else
		return BadAccess;
	}
    }
    if (!useOld)
    {
	grab = (GrabPtr)Xalloc(sizeof(GrabRec));
	grab->next = PASSIVEGRABS(pWin);
	grab->resource = FakeClientID((int)client->index);
	pWin->passiveGrabs = (pointer)grab;
	AddResource(grab->resource, RT←FAKE, (pointer)pWin, PassiveClientGone, RC←CORE);
    }
    grab->client = client;
    grab->device = inputInfo.keyboard;
    grab->window = pWin;
    grab->eventMask = KeyPressMask | KeyReleaseMask;
    grab->ownerEvents = stuff->ownerEvents;
    grab->keyboardMode = stuff->keyboardMode;
    grab->pointerMode = stuff->pointerMode;
    grab->modifiers = stuff->modifiers;
    grab->u.keybd.key = stuff->key;
    return(Success);
}

int
ProcGrabButton(client)
    ClientPtr client;
{
    WindowPtr pWin, confineTo;
    REQUEST(xGrabButtonReq);
    GrabPtr grab;
    Bool useOld = FALSE;
    CursorPtr cursor;

    REQUEST←SIZE←MATCH(xGrabButtonReq);
    if ((stuff->pointerMode != GrabModeSync) && 
	(stuff->pointerMode != GrabModeAsync) && 
	(stuff->keyboardMode != GrabModeSync) && 
	(stuff->keyboardMode != GrabModeAsync))
        return BadValue;

    pWin = (WindowPtr) LookupID(stuff->grabWindow, RT←WINDOW, RC←CORE);
    if (!pWin)
    {
	client->errorValue = stuff->grabWindow;
	return BadWindow;
    }
    if (stuff->confineTo == None)
	confineTo = NullWindow;
    else
    {
	confineTo = (WindowPtr)LookupID(stuff->confineTo, RT←WINDOW, RC←CORE);
	if (!confineTo)
	{
	    client->errorValue = stuff->confineTo;
	    return BadWindow;
	}
    }
    if (stuff->cursor == None)
	cursor = NullCursor;
    else
    {
	cursor = (CursorPtr)LookupID(stuff->cursor, RT←CURSOR, RC←CORE);
	if (!cursor)
	{
	    client->errorValue = stuff->cursor;
	    return BadCursor;
	}
    }
    for (grab = PASSIVEGRABS(pWin); grab; grab = grab->next)
    {
	if (MatchingGrab(
	    (int)stuff->button, (int)stuff->modifiers, inputInfo.pointer, grab, FALSE))
	{
	    if (client == grab->client)
	    {
		useOld = TRUE;
		break;
	    }
	    else
		return BadAccess;
	}
    }
    if (!useOld)
    {
	grab = (GrabPtr)Xalloc(sizeof(GrabRec));
	grab->next = PASSIVEGRABS(pWin);
	grab->resource = FakeClientID((int)client->index);
	pWin->passiveGrabs = (pointer)grab;
	AddResource(grab->resource, RT←FAKE, (pointer)pWin, PassiveClientGone, RC←CORE);
    }
    grab->client = client;
    grab->device = inputInfo.pointer;
    grab->window = pWin;
    grab->eventMask = stuff->eventMask | ButtonPress | ButtonRelease;
    grab->ownerEvents = stuff->ownerEvents;
    grab->keyboardMode = stuff->keyboardMode;
    grab->pointerMode = stuff->pointerMode;
    grab->modifiers = stuff->modifiers;
    grab->u.ptr.button = stuff->button;
    grab->u.ptr.confineTo = confineTo;
    grab->u.ptr.cursor = cursor;
    return(Success);
}

int
ProcUngrabButton(client)
    ClientPtr client;
{
    REQUEST(xUngrabButtonReq);
    WindowPtr pWin;
    GrabPtr grab;

    REQUEST←SIZE←MATCH(xUngrabButtonReq);
    pWin = (WindowPtr) LookupID(stuff->grabWindow, RT←WINDOW, RC←CORE);
    if (!pWin)
    {
	client->errorValue = stuff->grabWindow;
	return BadWindow;
    }
    for (grab = PASSIVEGRABS(pWin); grab; grab = grab->next)
    {
	if (MatchingGrab(
	    (int)stuff->button, (int)stuff->modifiers, inputInfo.pointer, grab, FALSE))
	{
	    if (client == grab->client)
		FreeResource(grab->resource, RC←NONE);
		/*
		 * Might need to unlink multiple requests, the buttons might
		 * be put on individually, but taken off with an AnyMumble.
		 */
	}
    }
    return(Success);
}

void
DeleteWindowFromAnyEvents(pWin, freeResources)
    WindowPtr		pWin;
    Bool		freeResources;
{
    WindowPtr		parent;
    FocusPtr		focus = &inputInfo.keyboard->u.keybd.focus;
    DeviceIntPtr	mouse = inputInfo.pointer;
    OtherClientsPtr	oc;
    GrabPtr		passive;

    if (pWin == focus->win)
    {
	switch (focus->revert)
	{
	    case RevertToNone:
		DoFocusEvents(pWin, NoneWin, NotifyNormal);
		focus->win = NoneWin;
	    case RevertToParent:
		for (
		    parent = pWin->parent; 
		    !parent->realized; 
		    parent = parent->parent);
		DoFocusEvents(pWin, parent, NotifyNormal);
		focus->win = parent;
		focus->revert = RevertToNone;
	    case RevertToPointerRoot:
		DoFocusEvents(pWin, PointerRootWin, NotifyNormal);
		focus->win = PointerRootWin;
	}
    }
    if ((mouse->grab) && (mouse->grab->window == pWin))
	DeactivatePointerGrab(mouse);
    if ((inputInfo.keyboard->grab) &&
	(inputInfo.keyboard->grab->window == pWin))
	DeactivateKeyboardGrab(inputInfo.keyboard);
    if (freeResources)
    {
	while (oc = OTHERCLIENTS(pWin))
	    FreeResource(oc->resource, RC←NONE);
	while (passive = PASSIVEGRABS(pWin))
	    FreeResource(passive->resource, RC←NONE);
     }
}

Mask
EventMaskForClient(win, client, allMask)
    WindowPtr		win;
    ClientPtr		client;
    Mask		*allMask;
{
    OtherClientsPtr	other;
    Mask		him;
    if (win->client == client)
	him = win->eventMask;
    *allMask = win->eventMask;
    for (other = OTHERCLIENTS(win); other; other = other->next)
    {
	if (other->client == client)
	    him = other->mask;
	*allMask |= other->mask;
    }
    return him;
}


int
ProcRecolorCursor(client)
    ClientPtr client;
{
    CursorPtr pCursor;
    int		nscr;
    ScreenPtr	pscr;
    REQUEST(xRecolorCursorReq);

    REQUEST←SIZE←MATCH(xRecolorCursorReq);
    pCursor = (CursorPtr)LookupID(stuff->cursor, RT←CURSOR, RC←CORE);
    if ( !pCursor) 
    {
	client->errorValue = stuff->cursor;
	return (BadCursor);
    }

    pCursor->foreRed = stuff->foreRed;
    pCursor->foreGreen = stuff->foreGreen;
    pCursor->foreBlue = stuff->foreBlue;

    pCursor->backRed = stuff->backRed;
    pCursor->backGreen = stuff->backGreen;
    pCursor->backBlue = stuff->backBlue;

    for ( nscr=0, pscr=screenInfo.screen;
	  nscr<screenInfo.numScreens;
	  nscr++, pscr++)
    {
	( *pscr->RecolorCursor)(pscr, pCursor,
		(pCursor == sprite.current) && (pscr == currentScreen));
    }
    return (Success);
}

void
WriteEventToClient(pClient, count, pbuf)
    ClientPtr	pClient;
    int		count;
    char	*pbuf;
{
    if(pClient->swapped)
    {
    int iEvent;
      for(iEvent = 0; iEvent < count; iEvent++)
      (*EventSwapVector[(((xEvent *)pbuf) + iEvent)->u.u.type])
		(pClient, sizeof(xEvent), (xEvent *)pbuf);
    }
    else
    {
	WriteToClient(pClient, count * sizeof(xEvent), pbuf);
    }
}