#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#include "windowstr.h"
#include <X11/extensions/ge.h>
#include "registry.h"
#include "geint.h"
#include "geext.h"
#define SERVER_GE_MAJOR 1
#define SERVER_GE_MINOR 0
#define rClient(obj) (clients[CLIENT_ID((obj)->resource)])
int GEEventBase;
int GEErrorBase;
static int GEClientPrivateKeyIndex;
DevPrivateKey GEClientPrivateKey = &GEClientPrivateKeyIndex;
int GEEventType;
int RT_GECLIENT = 0;
GEExtension GEExtensions[MAXEXTENSIONS];
static const int version_requests[] = {
X_GEQueryVersion,
X_GEQueryVersion,
};
static void SGEGenericEvent(xEvent* from, xEvent* to);
static void GERecalculateWinMask(WindowPtr pWin);
#define NUM_VERSION_REQUESTS (sizeof (version_requests) / sizeof (version_requests[0]))
static int
ProcGEQueryVersion(ClientPtr client)
{
int n;
GEClientInfoPtr pGEClient = GEGetClient(client);
xGEQueryVersionReply rep;
REQUEST(xGEQueryVersionReq);
REQUEST_SIZE_MATCH(xGEQueryVersionReq);
rep.repType = X_Reply;
rep.RepType = X_GEQueryVersion;
rep.length = 0;
rep.sequenceNumber = client->sequence;
rep.majorVersion = SERVER_GE_MAJOR;
rep.minorVersion = SERVER_GE_MINOR;
pGEClient->major_version = stuff->majorVersion;
pGEClient->minor_version = stuff->minorVersion;
if (client->swapped)
{
swaps(&rep.sequenceNumber, n);
swapl(&rep.length, n);
swaps(&rep.majorVersion, n);
swaps(&rep.minorVersion, n);
}
WriteToClient(client, sizeof(xGEQueryVersionReply), (char*)&rep);
return(client->noClientException);
}
int (*ProcGEVector[GENumberRequests])(ClientPtr) = {
ProcGEQueryVersion
};
static int
SProcGEQueryVersion(ClientPtr client)
{
int n;
REQUEST(xGEQueryVersionReq);
swaps(&stuff->length, n);
REQUEST_SIZE_MATCH(xGEQueryVersionReq);
swaps(&stuff->majorVersion, n);
swaps(&stuff->minorVersion, n);
return(*ProcGEVector[stuff->ReqType])(client);
}
int (*SProcGEVector[GENumberRequests])(ClientPtr) = {
SProcGEQueryVersion
};
static int
ProcGEDispatch(ClientPtr client)
{
GEClientInfoPtr pGEClient = GEGetClient(client);
REQUEST(xGEReq);
if (pGEClient->major_version >= NUM_VERSION_REQUESTS)
return BadRequest;
if (stuff->ReqType > version_requests[pGEClient->major_version])
return BadRequest;
return (ProcGEVector[stuff->ReqType])(client);
}
static int
SProcGEDispatch(ClientPtr client)
{
REQUEST(xGEReq);
if (stuff->ReqType >= GENumberRequests)
return BadRequest;
return (*SProcGEVector[stuff->ReqType])(client);
}
static void
GEClientCallback(CallbackListPtr *list,
pointer closure,
pointer data)
{
NewClientInfoRec *clientinfo = (NewClientInfoRec *) data;
ClientPtr pClient = clientinfo->client;
GEClientInfoPtr pGEClient = GEGetClient(pClient);
if (pGEClient == NULL)
{
pGEClient = xcalloc(1, sizeof(GEClientInfoRec));
dixSetPrivate(&pClient->devPrivates, GEClientPrivateKey, pGEClient);
}
pGEClient->major_version = 0;
pGEClient->minor_version = 0;
}
static void
GEResetProc(ExtensionEntry *extEntry)
{
DeleteCallback(&ClientStateCallback, GEClientCallback, 0);
EventSwapVector[GenericEvent] = NotImplemented;
GEEventBase = 0;
GEErrorBase = 0;
GEEventType = 0;
}
static void
SGEGenericEvent(xEvent* from, xEvent* to)
{
xGenericEvent* gefrom = (xGenericEvent*)from;
xGenericEvent* geto = (xGenericEvent*)to;
if (gefrom->extension > MAXEXTENSIONS)
{
ErrorF("GE: Invalid extension offset for event.\n");
return;
}
if (GEExtensions[gefrom->extension & 0x7F].evswap)
GEExtensions[gefrom->extension & 0x7F].evswap(gefrom, geto);
}
static int
GEClientGone(WindowPtr pWin, XID id)
{
GenericClientMasksPtr gclmask;
GenericMaskPtr gmask, prev = NULL;
if (!pWin || !pWin->optional)
return Success;
gclmask = pWin->optional->geMasks;
for (gmask = gclmask->geClients; gmask; gmask = gmask->next)
{
if (gmask->resource == id)
{
if (prev)
{
prev->next = gmask->next;
xfree(gmask);
} else {
gclmask->geClients = NULL;
CheckWindowOptionalNeed(pWin);
GERecalculateWinMask(pWin);
xfree(gmask);
}
return Success;
}
prev = gmask;
}
FatalError("Client not a GE client");
return BadImplementation;
}
void
GEExtensionInit(void)
{
ExtensionEntry *extEntry;
if(!AddCallback(&ClientStateCallback, GEClientCallback, 0))
{
FatalError("GEExtensionInit: register client callback failed.\n");
}
if((extEntry = AddExtension(GE_NAME,
GENumberEvents, GENumberErrors,
ProcGEDispatch, SProcGEDispatch,
GEResetProc, StandardMinorOpcode)) != 0)
{
GEEventBase = extEntry->eventBase;
GEErrorBase = extEntry->errorBase;
GEEventType = GEEventBase;
RT_GECLIENT = CreateNewResourceType((DeleteType)GEClientGone);
RegisterResourceName(RT_GECLIENT, "GECLIENT");
memset(GEExtensions, 0, sizeof(GEExtensions));
EventSwapVector[GenericEvent] = (EventSwapPtr) SGEGenericEvent;
} else {
FatalError("GEInit: AddExtensions failed.\n");
}
}
void
GERegisterExtension(int extension,
void (*ev_swap)(xGenericEvent* from, xGenericEvent* to),
void (*ev_fill)(xGenericEvent* ev, DeviceIntPtr pDev,
WindowPtr pWin, GrabPtr pGrab))
{
if ((extension & 0x7F) >= MAXEXTENSIONS)
FatalError("GE: extension > MAXEXTENSIONS. This should not happen.\n");
GEExtensions[extension & 0x7f].evswap = ev_swap;
GEExtensions[extension & 0x7f].evfill = ev_fill;
}
void
GEInitEvent(xGenericEvent* ev, int extension)
{
ev->type = GenericEvent;
ev->extension = extension;
ev->length = 0;
}
static void
GERecalculateWinMask(WindowPtr pWin)
{
int i;
GenericMaskPtr it;
GenericClientMasksPtr evmasks;
if (!pWin->optional)
return;
evmasks = pWin->optional->geMasks;
for (i = 0; i < MAXEXTENSIONS; i++)
{
evmasks->eventMasks[i] = 0;
}
it = pWin->optional->geMasks->geClients;
while(it)
{
for (i = 0; i < MAXEXTENSIONS; i++)
{
evmasks->eventMasks[i] |= it->eventMask[i];
}
it = it->next;
}
}
void
GEWindowSetMask(ClientPtr pClient, DeviceIntPtr pDev,
WindowPtr pWin, int extension, Mask mask)
{
GenericMaskPtr cli;
extension = (extension & 0x7F);
if (extension > MAXEXTENSIONS)
{
ErrorF("Invalid extension number.\n");
return;
}
if (!pWin->optional && !MakeWindowOptional(pWin))
{
ErrorF("GE: Could not make window optional.\n");
return;
}
if (mask)
{
GenericClientMasksPtr evmasks = pWin->optional->geMasks;
cli = evmasks->geClients;
while(cli)
{
if (rClient(cli) == pClient && cli->dev == pDev)
break;
cli = cli->next;
}
if (!cli)
{
cli = (GenericMaskPtr)xcalloc(1, sizeof(GenericMaskRec));
if (!cli)
{
ErrorF("GE: Insufficient memory to alloc client.\n");
return;
}
cli->next = evmasks->geClients;
cli->resource = FakeClientID(pClient->index);
cli->dev = pDev;
evmasks->geClients = cli;
AddResource(cli->resource, RT_GECLIENT, (pointer)pWin);
}
cli->eventMask[extension] = mask;
} else
{
cli = pWin->optional->geMasks->geClients;
if (rClient(cli) == pClient && cli->dev == pDev)
{
pWin->optional->geMasks->geClients = cli->next;
xfree(cli);
} else
{
GenericMaskPtr prev = cli;
cli = cli->next;
while(cli)
{
if (rClient(cli) == pClient && cli->dev == pDev)
{
prev->next = cli->next;
xfree(cli);
break;
}
prev = cli;
cli = cli->next;
}
}
if (!cli)
return;
}
GERecalculateWinMask(pWin);
}
BOOL
GEDeviceMaskIsSet(WindowPtr pWin, DeviceIntPtr pDev,
int extension, Mask mask)
{
GenericMaskPtr gemask;
if (!pWin->optional || !pWin->optional->geMasks)
return FALSE;
extension &= 0x7F;
if (!pWin->optional->geMasks->eventMasks[extension] & mask)
return FALSE;
gemask = pWin->optional->geMasks->geClients;
while(gemask)
{
if ((!gemask->dev || gemask->dev == pDev) &&
(gemask->eventMask[extension] & mask))
return TRUE;
gemask = gemask->next;
}
return FALSE;
}