#define NEED_REPLIES
#define NEED_EVENTS
#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#include <X11/X.h>
#include <X11/Xproto.h>
#include "misc.h"
#include "dixstruct.h"
#include "extnsionst.h"
#include "colormapst.h"
#include "scrnintstr.h"
#include "servermd.h"
#define _XEVIE_SERVER_
#include <X11/extensions/Xeviestr.h>
#include <X11/Xfuncproto.h>
#include "input.h"
#include "inputstr.h"
#include "windowstr.h"
#include "cursorstr.h"
#include <xkbsrv.h>
#include "../os/osdep.h"
#define NoSuchEvent 0x80000000
#ifdef XKB
extern Bool noXkbExtension;
#endif
extern int xeviegrabState;
static int ProcDispatch (register ClientPtr client), SProcDispatch (register ClientPtr client);
static void ResetProc (ExtensionEntry *extEntry);
static unsigned char ReqCode = 0;
static int ErrorBase;
int xevieFlag = 0;
int xevieClientIndex = 0;
DeviceIntPtr xeviekb = NULL;
DeviceIntPtr xeviemouse = NULL;
Mask xevieMask = 0;
int xevieEventSent = 0;
int xevieKBEventSent = 0;
static unsigned int xevieServerGeneration;
static int xevieDevicePrivateIndex;
static Bool xevieModifiersOn = FALSE;
#define XEVIEINFO(dev) ((xevieDeviceInfoPtr)dev->devPrivates[xevieDevicePrivateIndex].ptr)
Mask xevieFilters[128] =
{
NoSuchEvent,
NoSuchEvent,
KeyPressMask,
KeyReleaseMask,
ButtonPressMask,
ButtonReleaseMask,
PointerMotionMask
};
typedef struct {
ProcessInputProc processInputProc;
ProcessInputProc realInputProc;
DeviceUnwrapProc unwrapProc;
} xevieDeviceInfoRec, *xevieDeviceInfoPtr;
typedef struct {
CARD32 time;
KeyClassPtr keyc;
} xevieKeycQueueRec, *xevieKeycQueuePtr;
#define KEYC_QUEUE_SIZE 100
static xevieKeycQueueRec keycq[KEYC_QUEUE_SIZE] = {{0, NULL}};
static int keycqHead = 0, keycqTail = 0;
static int ProcDispatch (ClientPtr), SProcDispatch (ClientPtr);
static void ResetProc (ExtensionEntry*);
static int ErrorBase;
static Bool XevieStart(void);
static void XevieEnd(int clientIndex);
static void XevieClientStateCallback(CallbackListPtr *pcbl, pointer nulldata,
pointer calldata);
static void XevieServerGrabStateCallback(CallbackListPtr *pcbl,
pointer nulldata,
pointer calldata);
static Bool XevieAdd(DeviceIntPtr device, pointer data);
static void XevieWrap(DeviceIntPtr device, ProcessInputProc proc);
static Bool XevieRemove(DeviceIntPtr device, pointer data);
static void doSendEvent(xEvent *xE, DeviceIntPtr device);
static void XeviePointerProcessInputProc(xEvent *xE, DeviceIntPtr dev,
int count);
static void XevieKbdProcessInputProc(xEvent *xE, DeviceIntPtr dev, int count);
void
XevieExtensionInit (void)
{
ExtensionEntry* extEntry;
if (serverGeneration != xevieServerGeneration) {
if ((xevieDevicePrivateIndex = AllocateDevicePrivateIndex()) == -1)
return;
xevieServerGeneration = serverGeneration;
}
if (!AddCallback(&ServerGrabCallback,XevieServerGrabStateCallback,NULL))
return;
if ((extEntry = AddExtension (XEVIENAME,
0,
XevieNumberErrors,
ProcDispatch,
SProcDispatch,
ResetProc,
StandardMinorOpcode))) {
ReqCode = (unsigned char)extEntry->base;
ErrorBase = extEntry->errorBase;
}
}
static
void ResetProc (ExtensionEntry *extEntry)
{
}
static
int ProcQueryVersion (register ClientPtr client)
{
xXevieQueryVersionReply rep;
REQUEST_SIZE_MATCH (xXevieQueryVersionReq);
rep.type = X_Reply;
rep.length = 0;
rep.sequence_number = client->sequence;
rep.server_major_version = XEVIE_MAJOR_VERSION;
rep.server_minor_version = XEVIE_MINOR_VERSION;
WriteToClient (client, sizeof (xXevieQueryVersionReply), (char *)&rep);
return client->noClientException;
}
static
int ProcStart (register ClientPtr client)
{
xXevieStartReply rep;
REQUEST_SIZE_MATCH (xXevieStartReq);
rep.pad1 = 0;
if(!xevieFlag){
if (AddCallback(&ClientStateCallback,XevieClientStateCallback,NULL)) {
xevieFlag = 1;
rep.pad1 = 1;
xevieClientIndex = client->index;
if(!keycq[0].time ) {
int i;
for(i=0; i<KEYC_QUEUE_SIZE; i++) {
keycq[i].keyc = xalloc(sizeof(KeyClassRec));
keycq[i].keyc->xkbInfo = xalloc(sizeof(XkbSrvInfoRec));
}
}
} else
return BadAlloc;
} else
return BadAccess;
#ifdef XKB
if (!noXkbExtension) {
if (!XevieStart()) {
DeleteCallback(&ClientStateCallback,XevieClientStateCallback,NULL);
return BadAlloc;
}
}
#endif
xevieModifiersOn = FALSE;
rep.type = X_Reply;
rep.sequence_number = client->sequence;
WriteToClient (client, sizeof (xXevieStartReply), (char *)&rep);
return client->noClientException;
}
static
int ProcEnd (register ClientPtr client)
{
xXevieEndReply rep;
if (xevieFlag) {
if (client->index != xevieClientIndex)
return BadAccess;
DeleteCallback(&ClientStateCallback,XevieClientStateCallback,NULL);
XevieEnd(xevieClientIndex);
}
rep.type = X_Reply;
rep.sequence_number = client->sequence;
WriteToClient (client, sizeof (xXevieEndReply), (char *)&rep);
return client->noClientException;
}
static
int ProcSend (register ClientPtr client)
{
REQUEST (xXevieSendReq);
xXevieSendReply rep;
xEvent *xE;
static unsigned char lastDetail = 0, lastType = 0;
if (client->index != xevieClientIndex)
return BadAccess;
xE = (xEvent *)&stuff->event;
rep.type = X_Reply;
rep.sequence_number = client->sequence;
WriteToClient (client, sizeof (xXevieSendReply), (char *)&rep);
switch(xE->u.u.type) {
case KeyPress:
case KeyRelease:
xevieKBEventSent = 1;
#ifdef XKB
if(!noXkbExtension)
doSendEvent(xE, inputInfo.keyboard);
else
#endif
CoreProcessKeyboardEvent (xE, xeviekb, 1);
break;
case ButtonPress:
case ButtonRelease:
case MotionNotify:
xevieEventSent = 1;
#ifdef XKB
if(!noXkbExtension)
doSendEvent(xE, inputInfo.pointer);
else
#endif
CoreProcessPointerEvent(xE, xeviemouse, 1);
break;
default:
break;
}
lastType = xE->u.u.type;
lastDetail = xE->u.u.detail;
return client->noClientException;
}
static
int ProcSelectInput (register ClientPtr client)
{
REQUEST (xXevieSelectInputReq);
xXevieSelectInputReply rep;
if (client->index != xevieClientIndex)
return BadAccess;
xevieMask = (long)stuff->event_mask;
rep.type = X_Reply;
rep.sequence_number = client->sequence;
WriteToClient (client, sizeof (xXevieSelectInputReply), (char *)&rep);
return client->noClientException;
}
static
int ProcDispatch (register ClientPtr client)
{
REQUEST (xReq);
switch (stuff->data)
{
case X_XevieQueryVersion:
return ProcQueryVersion (client);
case X_XevieStart:
return ProcStart (client);
case X_XevieEnd:
return ProcEnd (client);
case X_XevieSend:
return ProcSend (client);
case X_XevieSelectInput:
return ProcSelectInput(client);
default:
return BadRequest;
}
}
static
int SProcQueryVersion (register ClientPtr client)
{
register int n;
REQUEST(xXevieQueryVersionReq);
swaps(&stuff->length, n);
return ProcQueryVersion(client);
}
static
int SProcStart (ClientPtr client)
{
register int n;
REQUEST (xXevieStartReq);
swaps (&stuff->length, n);
swapl (&stuff->screen, n);
REQUEST_AT_LEAST_SIZE (xXevieStartReq);
return ProcStart (client);
}
static
int SProcEnd (ClientPtr client)
{
register int n;
REQUEST (xXevieEndReq);
swaps (&stuff->length, n);
REQUEST_AT_LEAST_SIZE (xXevieEndReq);
swapl(&stuff->cmap, n);
return ProcEnd (client);
}
static
int SProcSend (ClientPtr client)
{
register int n;
REQUEST (xXevieSendReq);
swaps (&stuff->length, n);
REQUEST_AT_LEAST_SIZE (xXevieSendReq);
swapl(&stuff->event, n);
return ProcSend (client);
}
static
int SProcSelectInput (ClientPtr client)
{
register int n;
REQUEST (xXevieSelectInputReq);
swaps (&stuff->length, n);
REQUEST_AT_LEAST_SIZE (xXevieSendReq);
swapl(&stuff->event_mask, n);
return ProcSelectInput (client);
}
static
int SProcDispatch (register ClientPtr client)
{
REQUEST(xReq);
switch (stuff->data)
{
case X_XevieQueryVersion:
return SProcQueryVersion (client);
case X_XevieStart:
return SProcStart (client);
case X_XevieEnd:
return SProcEnd (client);
case X_XevieSend:
return SProcSend (client);
case X_XevieSelectInput:
return SProcSelectInput(client);
default:
return BadRequest;
}
}
#define WRAP_INPUTPROC(dev,store,inputProc) \
store->processInputProc = dev->public.processInputProc; \
dev->public.processInputProc = inputProc; \
store->realInputProc = dev->public.realInputProc; \
dev->public.realInputProc = inputProc;
#define COND_WRAP_INPUTPROC(dev,store,inputProc) \
if (dev->public.processInputProc == dev->public.realInputProc) \
dev->public.processInputProc = inputProc; \
store->processInputProc = \
store->realInputProc = dev->public.realInputProc; \
dev->public.realInputProc = inputProc;
#define UNWRAP_INPUTPROC(dev,restore) \
dev->public.processInputProc = restore->processInputProc; \
dev->public.realInputProc = restore->realInputProc;
#define UNWRAP_INPUTPROC(dev,restore) \
dev->public.processInputProc = restore->processInputProc; \
dev->public.realInputProc = restore->realInputProc;
#define XEVIE_EVENT(xE) \
(xevieFlag \
&& !xeviegrabState \
&& clients[xevieClientIndex] \
&& (xevieMask & xevieFilters[xE->u.u.type]))
static void
sendEvent(ClientPtr pClient, xEvent *xE)
{
if(pClient->swapped) {
xEvent eventTo;
(*EventSwapVector[xE->u.u.type & 0177]) (xE, &eventTo);
(void)WriteToClient(pClient, sizeof(xEvent), (char *)&eventTo);
} else {
(void)WriteToClient(pClient, sizeof(xEvent), (char *) xE);
}
}
static void
XevieKbdProcessInputProc(xEvent *xE, DeviceIntPtr dev, int count)
{
int key, bit;
BYTE *kptr;
ProcessInputProc tmp;
KeyClassPtr keyc = dev->key;
xevieDeviceInfoPtr xeviep = XEVIEINFO(dev);
if(XEVIE_EVENT(xE)) {
key = xE->u.u.detail;
kptr = &keyc->down[key >> 3];
bit = 1 << (key & 7);
if (dev->key->modifierMap[xE->u.u.detail])
xevieModifiersOn = TRUE;
xE->u.keyButtonPointer.event = xeviewin->drawable.id;
xE->u.keyButtonPointer.root = GetCurrentRootWindow()->drawable.id;
xE->u.keyButtonPointer.child = (xeviewin->firstChild)
? xeviewin->firstChild->drawable.id:0;
xE->u.keyButtonPointer.rootX = xeviehot.x;
xE->u.keyButtonPointer.rootY = xeviehot.y;
xE->u.keyButtonPointer.state = keyc->state | inputInfo.pointer->button->state;
xE->u.u.sequenceNumber = clients[xevieClientIndex]->sequence;
#ifdef XKB
if(!noXkbExtension) {
switch(xE->u.u.type) {
case KeyPress: *kptr |= bit; break;
case KeyRelease: *kptr &= ~bit; break;
}
}
#endif
keycq[keycqHead].time = xE->u.keyButtonPointer.time;
memcpy(keycq[keycqHead].keyc, keyc, sizeof(KeyClassRec) - sizeof(KeyClassPtr));
memcpy(keycq[keycqHead].keyc->xkbInfo, keyc->xkbInfo, sizeof(XkbSrvInfoRec));
if(++keycqHead >=KEYC_QUEUE_SIZE)
keycqHead = 0;
sendEvent(clients[xevieClientIndex], xE);
return;
}
tmp = dev->public.realInputProc;
UNWRAP_INPUTPROC(dev,xeviep);
dev->public.processInputProc(xE,dev,count);
COND_WRAP_INPUTPROC(dev,xeviep,tmp);
}
static void
XeviePointerProcessInputProc(xEvent *xE, DeviceIntPtr dev, int count)
{
xevieDeviceInfoPtr xeviep = XEVIEINFO(dev);
ProcessInputProc tmp;
if (XEVIE_EVENT(xE)) {
xE->u.u.sequenceNumber = clients[xevieClientIndex]->sequence;
sendEvent(clients[xevieClientIndex], xE);
return;
}
tmp = dev->public.realInputProc;
UNWRAP_INPUTPROC(dev,xeviep);
dev->public.processInputProc(xE,dev,count);
COND_WRAP_INPUTPROC(dev,xeviep,tmp);
}
static Bool
XevieStart(void)
{
ProcessInputProc prp;
prp = XevieKbdProcessInputProc;
if (!XevieAdd(inputInfo.keyboard,&prp))
return FALSE;
prp = XeviePointerProcessInputProc;
if (!XevieAdd(inputInfo.pointer,&prp))
return FALSE;
return TRUE;
}
static void
XevieEnd(int clientIndex)
{
if (!clientIndex || clientIndex == xevieClientIndex) {
#ifdef XKB
if(!noXkbExtension) {
XevieRemove(inputInfo.keyboard,NULL);
inputInfo.keyboard->public.processInputProc = CoreProcessKeyboardEvent;
inputInfo.keyboard->public.realInputProc = CoreProcessKeyboardEvent;
XkbSetExtension(inputInfo.keyboard,ProcessKeyboardEvent);
XevieRemove(inputInfo.pointer,NULL);
inputInfo.pointer->public.processInputProc = CoreProcessPointerEvent;
inputInfo.pointer->public.realInputProc = CoreProcessPointerEvent;
XkbSetExtension(inputInfo.pointer,ProcessPointerEvent);
}
#endif
xevieFlag = 0;
xevieClientIndex = 0;
DeleteCallback (&ClientStateCallback, XevieClientStateCallback, NULL);
}
}
static void
XevieClientStateCallback(CallbackListPtr *pcbl, pointer nulldata,
pointer calldata)
{
NewClientInfoRec *pci = (NewClientInfoRec *)calldata;
ClientPtr client = pci->client;
if (client->clientState == ClientStateGone
|| client->clientState == ClientStateRetained)
XevieEnd(client->index);
}
static void
XevieServerGrabStateCallback(CallbackListPtr *pcbl, pointer nulldata,
pointer calldata)
{
ServerGrabInfoRec *grbinfo = (ServerGrabInfoRec *)calldata;
if (grbinfo->grabstate == SERVER_GRABBED)
xeviegrabState = TRUE;
else
xeviegrabState = FALSE;
}
#define UNWRAP_UNWRAPPROC(device,proc_store) \
device->unwrapProc = proc_store;
#define WRAP_UNWRAPPROC(device,proc_store,proc) \
proc_store = device->unwrapProc; \
device->unwrapProc = proc;
static void
xevieUnwrapProc(DeviceIntPtr device, DeviceHandleProc proc, pointer data)
{
xevieDeviceInfoPtr xeviep = XEVIEINFO(device);
ProcessInputProc tmp = device->public.processInputProc;
UNWRAP_INPUTPROC(device,xeviep);
UNWRAP_UNWRAPPROC(device,xeviep->unwrapProc);
proc(device,data);
WRAP_INPUTPROC(device,xeviep,tmp);
WRAP_UNWRAPPROC(device,xeviep->unwrapProc,xevieUnwrapProc);
}
static Bool
XevieUnwrapAdd(DeviceIntPtr device, void* data)
{
if (device->unwrapProc)
device->unwrapProc(device,XevieUnwrapAdd,data);
else {
ProcessInputProc *ptr = data;
XevieWrap(device,*ptr);
}
return TRUE;
}
static Bool
XevieAdd(DeviceIntPtr device, void* data)
{
xevieDeviceInfoPtr xeviep;
if (!AllocateDevicePrivate(device, xevieDevicePrivateIndex))
return FALSE;
xeviep = xalloc (sizeof (xevieDeviceInfoRec));
if (!xeviep)
return FALSE;
device->devPrivates[xevieDevicePrivateIndex].ptr = xeviep;
XevieUnwrapAdd(device, data);
return TRUE;
}
static Bool
XevieRemove(DeviceIntPtr device,pointer data)
{
xevieDeviceInfoPtr xeviep = XEVIEINFO(device);
if (!xeviep) return TRUE;
UNWRAP_INPUTPROC(device,xeviep);
UNWRAP_UNWRAPPROC(device,xeviep->unwrapProc);
xfree(xeviep);
device->devPrivates[xevieDevicePrivateIndex].ptr = NULL;
return TRUE;
}
static void
XevieWrap(DeviceIntPtr device, ProcessInputProc proc)
{
xevieDeviceInfoPtr xeviep = XEVIEINFO(device);
WRAP_INPUTPROC(device,xeviep,proc);
WRAP_UNWRAPPROC(device,xeviep->unwrapProc,xevieUnwrapProc);
}
static void
doSendEvent(xEvent *xE, DeviceIntPtr dev)
{
xevieDeviceInfoPtr xeviep = XEVIEINFO(dev);
ProcessInputProc tmp = dev->public.realInputProc;
if (((xE->u.u.type==KeyPress)||(xE->u.u.type==KeyRelease))
&& !xevieModifiersOn) {
KeyClassPtr keyc = dev->key;
CARD8 realModes = dev->key->modifierMap[xE->u.u.detail];
int notFound = 0;
if(keycq[keycqTail].time != xE->u.keyButtonPointer.time) {
while(keycq[keycqTail].time != xE->u.keyButtonPointer.time) {
if(++keycqTail >= KEYC_QUEUE_SIZE)
keycqTail = 0;
if(keycqTail == keycqHead) {
notFound = 1;
break;
}
}
}
if(!notFound) {
dev->key = keycq[keycqTail].keyc;
if(++keycqTail >= KEYC_QUEUE_SIZE)
keycqTail = 0;
}
dev->key->modifierMap[xE->u.u.detail] = 0;
if(dev->key->xkbInfo->repeatKey != 0 && xE->u.u.type != KeyPress)
XkbLastRepeatEvent= (pointer)xE;
UNWRAP_INPUTPROC(dev,xeviep);
dev->public.processInputProc(xE,dev,1);
COND_WRAP_INPUTPROC(dev,xeviep,tmp);
XkbLastRepeatEvent= NULL;
dev->key->modifierMap[xE->u.u.detail] = realModes;
dev->key = keyc;
if(notFound) {
DeleteCallback(&ClientStateCallback,XevieClientStateCallback,NULL);
XevieEnd(xevieClientIndex);
ErrorF("Error: Xevie keyc queue size is not enough, disable Xevie\n");
}
} else {
UNWRAP_INPUTPROC(dev,xeviep);
dev->public.processInputProc(xE,dev,1);
COND_WRAP_INPUTPROC(dev,xeviep,tmp);
}
}