xenocara/app/lbxproxy/di/lbxfuncs.c
2006-11-26 14:07:37 +00:00

1447 lines
37 KiB
C

/* $Xorg: lbxfuncs.c,v 1.3 2000/08/17 19:53:55 cpqbld Exp $ */
/*
* Copyright 1994 Network Computing Devices, Inc.
* Copyright 1996 X Consortium, Inc.
*
* Permission to use, copy, modify, distribute, and sell this software and
* its documentation for any purpose is hereby granted without fee, 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 name Network Computing Devices, Inc. not be
* used in advertising or publicity pertaining to distribution of this
* software without specific, written prior permission.
*
* THIS SOFTWARE IS PROVIDED `AS-IS'. NETWORK COMPUTING DEVICES, INC.,
* DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING WITHOUT
* LIMITATION ALL IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE, OR NONINFRINGEMENT. IN NO EVENT SHALL NETWORK
* COMPUTING DEVICES, INC., BE LIABLE FOR ANY DAMAGES WHATSOEVER, INCLUDING
* SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES, INCLUDING LOSS OF USE, DATA,
* OR PROFITS, EVEN IF ADVISED OF THE POSSIBILITY THEREOF, AND REGARDLESS OF
* WHETHER IN AN ACTION IN CONTRACT, TORT OR NEGLIGENCE, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
/* $XFree86: xc/programs/lbxproxy/di/lbxfuncs.c,v 1.6tsi Exp $ */
/*
* top level LBX request & reply handling
*/
/*
* requests copy out interesting stuff and then swap so original data
* is left alone as much as possible. note that the length field
* is *not* swapped
*
* replied data is copied yet again before swapping because the data
* may be stored as a tag result and we don't want to change that.
*/
#include <stdio.h>
#include "assert.h"
#include "lbx.h"
#include "atomcache.h"
#include "util.h"
#include "init.h"
#include "tags.h"
#include "resource.h"
#include "wire.h"
#include "swap.h"
#include "reqtype.h"
#include "lbxext.h"
#include "proxyopts.h"
#ifdef DEBUG
extern int lbxDebug;
#endif
static Bool intern_atom_reply();
static Bool get_atom_name_reply();
static Bool get_mod_map_reply();
static Bool get_key_map_reply();
static Bool sync_reply();
static Bool get_queryfont_reply();
static Bool GetWinAttrAndGeomReply();
#define reply_length(cp,rep) ((rep)->type==X_Reply ? \
32 + (HostUnswapLong((cp),(rep)->length) << 2) \
: 32)
char protocolMode = PROTOCOL_FULL;
/* ARGSUSED */
static void
get_connection_info(client, cs, cs_len, change_type, changes, changes_len)
ClientPtr client;
xConnSetup *cs;
int cs_len;
int change_type;
CARD32 *changes;
int changes_len;
{
xWindowRoot *root;
xDepth *depth;
xVisualType *vis;
char *dp = (char *) cs;
int i,
j,
k;
static int pad[4] = {0, 3, 2, 1};
if (!changes)
return;
cs->ridBase = changes[0];
dp += sizeof(xConnSetup);
/* skip vendor string & pixmap formats */
dp += cs->nbytesVendor + pad[cs->nbytesVendor & 3];
for (i = 0; i < cs->numFormats; i++) {
if (((xPixmapFormat *)dp)->depth == 1)
client->ZbitsPerPixel1 = ((xPixmapFormat *)dp)->bitsPerPixel;
dp += sizeof(xPixmapFormat);
}
/* process screens */
root = (xWindowRoot *) dp;
if (change_type == 2) {
if (changes[2])
root->rootVisualID = (VisualID) changes[2];
if (changes[3]) {
root->defaultColormap = (Colormap) changes[3];
root->whitePixel = changes[4];
root->blackPixel = changes[5];
}
}
client->rootWindow = root->windowId;
for (i = 0; i < cs->numRoots; i++) {
if (change_type != 2) {
root->currentInputMask = changes[i + 1];
} else {
root->currentInputMask = changes[i + 6];
}
dp += sizeof(xWindowRoot);
for (j = 0; j < root->nDepths; j++) {
depth = (xDepth *) dp;
dp += sizeof(xDepth);
for (k = 0; k < depth->nVisuals; k++) {
vis = (xVisualType *) dp;
CreateVisual(depth->depth, vis);
dp += (sizeof(xVisualType));
vis = (xVisualType *) dp;
}
}
if (!LookupIDByType(client, root->defaultColormap, RT_COLORMAP))
CreateColormap(client,
root->defaultColormap, root->rootVisualID);
}
}
static void
send_setup_reply(ClientPtr client, Bool success, int majorVer, int minorVer,
void *cs, int cs_len)
{
xConnSetupPrefix reply;
reply.success = success;
if (!success) {
reply.lengthReason = strlen((char *)cs);
cs_len = reply.lengthReason + 3;
}
reply.majorVersion = majorVer;
reply.minorVersion = minorVer;
reply.length = cs_len >> 2;
if (client->swapped)
WriteSConnSetupPrefix(client, &reply);
else
(void)WriteToClient(client, sizeof(xConnSetupPrefix), (char *) &reply);
if (success && client->swapped)
WriteSConnectionInfo(client, (unsigned long)(reply.length << 2), cs);
else
(void)WriteToClient(client, (int)(reply.length << 2), cs);
}
static void
finish_setup_reply(client, cs, cs_len, change_type, changes, changes_len, majorVer, minorVer)
ClientPtr client;
xConnSetup *cs;
int cs_len;
int change_type;
CARD32* changes;
int changes_len;
int majorVer,
minorVer;
{
get_connection_info(client, cs, cs_len, change_type, changes, changes_len);
client->minKeyCode = cs->minKeyCode;
client->maxKeyCode = cs->maxKeyCode;
client->imageByteOrder = cs->imageByteOrder;
client->bitmapBitOrder = cs->bitmapBitOrder;
client->bitmapScanlineUnit = cs->bitmapScanlineUnit;
client->bitmapScanlinePad = cs->bitmapScanlinePad;
client->ridBase = cs->ridBase;
client->ridMask = cs->ridMask;
FinishInitClientResources (client, cs->ridBase, cs->ridMask);
send_setup_reply(client, TRUE, majorVer, minorVer, cs, cs_len);
}
/*
* ConnectionSetup data can come from three places: 1) a fully qualified
* connection-setup in the reply, 2) from the tag store, and 3) built
* from the Display* returned by the call the proxy made to XOpenDisplay.
*/
static void
get_setup_reply(client, data, len)
ClientPtr client;
char *data;
int len;
{
register xLbxConnSetupPrefix *rep;
TagData td;
xConnSetup *tag_data;
Bool free_td = FALSE;
CARD32* changes = NULL;
int changes_len = 0;
rep = (xLbxConnSetupPrefix *) data;
if (client->swapped) {
data = (char *)ALLOCATE_LOCAL(len);
memcpy(data, (char *)rep, len);
rep = (xLbxConnSetupPrefix *) data;
SwapLbxConnSetupPrefix(rep);
}
switch (rep->changeType) {
default:
case 0: /* full ConnectionSetup, possibly with tag */
#ifdef LBX_STATS
getsetup_full++;
#endif
tag_data = (xConnSetup *) &rep[1];
if (rep->tag != 0) {
if (!TagStoreData(client->server, client->server->global_cache,
rep->tag, rep->length,
LbxTagTypeConnInfo, tag_data)) {
/* tell server we lost it */
SendInvalidateTag(client, rep->tag);
}
}
len = rep->length << 2;
break;
case 1: /* LbxNormalDeltas */
case 2: /* LbxEmbeddedAppGroup */
changes = (CARD32*) &rep[1];
changes_len = rep->length - 1;
if (client->swapped)
SwapLongs(changes, changes_len);
if (rep->tag != 0) {
td = TagGetTag(client->server, client->server->global_cache,
rep->tag);
if (!td) {
fprintf(stderr, "no data for setup tag 0x%lx\n",
(long)rep->tag);
send_setup_reply(client, FALSE, 0, 0, "bad tag data from server", 0);
if (client->swapped)
DEALLOCATE_LOCAL(data);
return;
}
#ifdef LBX_STATS
getsetup_tag++;
tag_bytes_unsent += td->size - len;
#endif
tag_data = td->tdata;
len = td->size;
} else {
DisplayGetConnSetup (client->server->dpy, &tag_data, &len,
rep->changeType, changes, changes_len);
free_td = TRUE;
}
break;
}
finish_setup_reply(client, tag_data, len,
rep->changeType, changes, changes_len,
(int) rep->majorVersion, (int) rep->minorVersion);
if (free_td) xfree (tag_data);
if (client->swapped)
DEALLOCATE_LOCAL(data);
}
int
ProcLBXInternAtom(client)
ClientPtr client;
{
REQUEST(xInternAtomReq);
char *s;
Atom atom,
a = None;
xInternAtomReply reply;
ReplyStuffPtr nr;
char n;
CARD16 nbytes;
nbytes = stuff->nbytes;
if (client->swapped) {
swaps(&nbytes, n);
}
if (nbytes > MAX_ATOM_LENGTH)
return ProcStandardRequest(client);
s = (char *)stuff + sizeof(xInternAtomReq);
atom = LbxMakeAtom(client->server, s, nbytes, a, FALSE);
if (atom != None) {
reply.type = X_Reply;
reply.length = 0;
reply.sequenceNumber = LBXSequenceNumber(client);
reply.atom = atom;
if (client->swapped)
SwapInternAtomReply(&reply);
if (LBXCacheSafe(client)) {
FinishLBXRequest(client, REQ_YANK);
WriteToClient(client, sizeof(xInternAtomReply), &reply);
} else { /* store for later */
if (!LBXCanDelayReply(client))
SendLbxSync(client);
FinishLBXRequest(client, REQ_YANKLATE);
SaveReplyData(client, (xReply *) & reply, 0, NULL);
}
#ifdef LBX_STATS
intern_good++;
#endif
return Success;
} else if (nbytes < MAX_ATOM_LENGTH) {
nr = NewReply(client, X_InternAtom, 0, intern_atom_reply);
if (!nr)
return ProcStandardRequest(client);
strncpy(nr->request_info.xintern.str, s, nbytes);
nr->request_info.xintern.str[nbytes] = '\0';
nr->request_info.xintern.len = nbytes;
#ifdef LBX_STATS
intern_miss++;
#endif
return ProcStandardRequest(client);
}
return 0; /* ?!?!? */
}
static Bool
intern_atom_reply(client, nr, data)
ClientPtr client;
ReplyStuffPtr nr;
char *data;
{
Atom atom;
char *str;
xInternAtomReply *reply;
int len;
char n;
reply = (xInternAtomReply *) data;
str = nr->request_info.xintern.str;
len = nr->request_info.xintern.len;
atom = reply->atom;
if (client->swapped) {
swapl(&atom, n);
}
if (atom != None)
/* make sure it gets stuffed in the DB */
(void) LbxMakeAtom(client->server, str, len, atom, TRUE);
return TRUE;
}
int
ProcLBXGetAtomName(client)
ClientPtr client;
{
REQUEST(xResourceReq);
char *str;
xGetAtomNameReply reply;
int len;
ReplyStuffPtr nr;
char n;
Atom id;
id = stuff->id;
if (client->swapped) {
swapl(&id, n);
}
str = NameForAtom(client->server, id);
if (str) { /* found the value */
len = strlen(str);
reply.type = X_Reply;
reply.length = (len + 3) >> 2;
reply.sequenceNumber = LBXSequenceNumber(client);
reply.nameLength = len;
if (client->swapped)
SwapGetAtomNameReply(&reply);
if (LBXCacheSafe(client)) {
FinishLBXRequest(client, REQ_YANK);
WriteToClient(client, sizeof(xGetAtomNameReply), &reply);
WriteToClient(client, len, str);
} else {
if (!LBXCanDelayReply(client))
SendLbxSync(client);
FinishLBXRequest(client, REQ_YANKLATE);
SaveReplyData(client, (xReply *) & reply, len, str);
}
#ifdef LBX_STATS
getatom_good++;
#endif
return Success;
} else {
nr = NewReply(client, X_GetAtomName, 0, get_atom_name_reply);
if (!nr)
return ProcStandardRequest(client);
nr->request_info.xgetatom.atom = id;
#ifdef LBX_STATS
getatom_miss++;
#endif
return ProcStandardRequest(client);
}
}
static Bool
get_atom_name_reply(client, nr, data)
ClientPtr client;
ReplyStuffPtr nr;
char *data;
{
Atom atom;
char *s;
xGetAtomNameReply *reply;
CARD16 len;
char n;
reply = (xGetAtomNameReply *) data;
len = reply->nameLength;
if (client->swapped) {
swaps(&len, n);
}
if (len > MAX_ATOM_LENGTH)
return FALSE;
s = data + sizeof(xGetAtomNameReply);
atom = nr->request_info.xgetatom.atom;
/* make sure it gets stuffed in the DB */
if (atom)
(void) LbxMakeAtom(client->server, s, (unsigned) len, atom, TRUE);
return TRUE;
}
/*
* Send an LbxSync request to the server. After the SyncReply comes
* back, the proxy will flush any replies it saved for the client.
*/
void
SendLbxSync (client)
ClientPtr client;
{
xLbxSyncReq req;
ReplyStuffPtr nr;
#ifdef SEQ_DEBUG
fprintf(stderr, "sending LbxSync, seq 0x%x\n", LBXSequenceNumber(client) - 1);
#endif
ForceSequenceUpdate(client);
nr = NewReply(client, client->server->lbxReq, X_LbxSync, sync_reply);
--nr->sequenceNumber; /* executed BEFORE the real request */
req.reqType = client->server->lbxReq;
req.lbxReqType = X_LbxSync;
req.length = sz_xLbxSyncReq >> 2;
WriteReqToServer (client, sz_xLbxSyncReq, (char *) &req, TRUE);
}
/* ARGSUSED */
static Bool
sync_reply(client, nr, data)
ClientPtr client;
ReplyStuffPtr nr;
char *data;
{
/* do nothing; just here to catch and discard the reply */
return TRUE;
}
void
WriteError(client, majorCode, minorCode, resId, errorCode)
ClientPtr client;
unsigned int majorCode;
unsigned int minorCode;
XID resId;
int errorCode;
{
xError rep;
int n;
rep.type = X_Error;
rep.sequenceNumber = LBXSequenceNumber(client);
rep.errorCode = errorCode;
rep.majorCode = majorCode;
rep.minorCode = minorCode;
rep.resourceID = resId;
if (client->swapped) {
swaps(&rep.sequenceNumber, n);
swaps(&rep.minorCode, n);
swaps(&rep.resourceID, n);
}
WriteToClient(client, sizeof(rep), (char *)&rep);
}
int
ProcLBXGetModifierMapping(client)
ClientPtr client;
{
ReplyStuffPtr nr;
nr = NewReply(client, client->server->lbxReq, X_LbxGetModifierMapping,
get_mod_map_reply);
if (!nr)
return ProcStandardRequest(client);
FinishLBXRequest(client, REQ_PASSTHROUGH);
SendGetModifierMapping(client);
return Success;
}
/*ARGSUSED*/
static Bool
get_mod_map_reply(client, nr, data)
ClientPtr client;
ReplyStuffPtr nr;
char *data;
{
xLbxGetModifierMappingReply *rep;
int len;
pointer tag_data;
CARD32 tag;
char n;
xGetModifierMappingReply reply;
rep = (xLbxGetModifierMappingReply *) data;
tag = rep->tag;
if (client->swapped) {
swapl(&tag, n);
}
len = rep->keyspermod << 3;
if (rep->tag) {
if (rep->length) { /* first time, set tag */
#ifdef LBX_STATS
getmodmap_full++;
#endif
tag_data = (pointer) &rep[1];
if (!TagStoreData(client->server, client->server->global_cache,
tag, len,
LbxTagTypeModmap, tag_data)) {
/* tell server we lost it */
SendInvalidateTag(client, tag);
}
} else {
tag_data = TagGetData(client->server, client->server->global_cache,
tag);
if (!tag_data) {
fprintf(stderr, "no data for mod map tag 0x%lx\n", (long)tag);
WriteError(client, X_GetModifierMapping, 0, 0, BadAlloc);
return TRUE;
}
#ifdef LBX_STATS
getmodmap_tag++;
tag_bytes_unsent += (rep->keyspermod << 3);
#endif
}
} else {
#ifdef LBX_STATS
getmodmap_full++;
#endif
/* server didn't send us a tag for some reason -- just pass on data */
tag_data = (pointer) &rep[1];
}
reply.type = X_Reply;
reply.numKeyPerModifier = rep->keyspermod;
reply.sequenceNumber = rep->sequenceNumber;
reply.length = len >> 2;
if (client->swapped)
SwapModmapReply(&reply);
WriteToClient(client, sizeof(xGetModifierMappingReply), &reply);
WriteToClient(client, len, tag_data);
return TRUE;
}
int
ProcLBXGetKeyboardMapping(client)
ClientPtr client;
{
REQUEST(xGetKeyboardMappingReq);
ReplyStuffPtr nr;
nr = NewReply(client, client->server->lbxReq, X_LbxGetKeyboardMapping,
get_key_map_reply);
if (!nr)
return ProcStandardRequest(client);
nr->request_info.lbxgetkeymap.count = stuff->count;
nr->request_info.lbxgetkeymap.first = stuff->firstKeyCode;
FinishLBXRequest(client, REQ_PASSTHROUGH);
SendGetKeyboardMapping(client);
return Success;
}
/*
* always ask for the whole map from server, and send requested subset to
* client
*/
static Bool
get_key_map_reply(client, nr, data)
ClientPtr client;
ReplyStuffPtr nr;
char *data;
{
xLbxGetKeyboardMappingReply *rep;
int len;
pointer tag_data;
CARD32 tag;
char n;
xGetKeyboardMappingReply reply;
char *sdata;
rep = (xLbxGetKeyboardMappingReply *) data;
tag = rep->tag;
if (client->swapped) {
swapl(&tag, n);
}
if (tag) {
if (rep->length) { /* first time, set tag */
#ifdef LBX_STATS
getkeymap_full++;
#endif
tag_data = (pointer) &rep[1];
len = rep->keysperkeycode *
(LBXMaxKeyCode(client) - LBXMinKeyCode(client) + 1) * 4;
/* data always swapped, because reswapped when written */
if (client->swapped)
SwapLongs((CARD32 *) tag_data, len / 4);
if (!TagStoreData(client->server, client->server->global_cache,
tag, len,
LbxTagTypeKeymap, tag_data)) {
/* tell server we lost it */
SendInvalidateTag(client, tag);
}
} else {
tag_data = TagGetData(client->server,
client->server->global_cache, tag);
if (!tag_data) {
fprintf(stderr, "no data for key map tag 0x%lx\n", (long)tag);
WriteError(client, X_GetKeyboardMapping, 0, 0, BadAlloc);
return TRUE;
}
#ifdef LBX_STATS
getkeymap_tag++;
tag_bytes_unsent += (rep->keysperkeycode *
(LBXMaxKeyCode(client) - LBXMinKeyCode(client) + 1) * 4);
#endif
}
} else {
#ifdef LBX_STATS
getkeymap_full++;
#endif
/* server didn't send us a tag for some reason -- just pass on data */
tag_data = (pointer) &rep[1];
/* data always swapped, because reswapped when written */
if (client->swapped) {
len = rep->keysperkeycode *
(LBXMaxKeyCode(client) - LBXMinKeyCode(client) + 1) * 4;
SwapLongs((CARD32 *) tag_data, len / 4);
}
}
len = (rep->keysperkeycode * nr->request_info.lbxgetkeymap.count) << 2;
reply.type = X_Reply;
reply.keySymsPerKeyCode = rep->keysperkeycode;
reply.sequenceNumber = rep->sequenceNumber;
reply.length = len >> 2;
tag_data = (char *)tag_data + (rep->keysperkeycode *
(nr->request_info.lbxgetkeymap.first -
LBXMinKeyCode(client)));
if (client->swapped) {
SwapKeymapReply(&reply);
/* have to copy data because we could be handed the tag storage */
sdata = (char *) ALLOCATE_LOCAL(len);
if (sdata) {
memcpy(sdata, tag_data, len);
SwapLongs((CARD32 *) sdata, len / 4);
}
} else
sdata = tag_data;
WriteToClient(client, sizeof(xGetKeyboardMappingReply), &reply);
WriteToClient(client, len, sdata);
if (sdata != tag_data)
DEALLOCATE_LOCAL(sdata);
return TRUE;
}
int
ProcLBXQueryFont(client)
ClientPtr client;
{
REQUEST(xResourceReq);
ReplyStuffPtr nr;
Font fid;
char n;
fid = stuff->id;
if (client->swapped) {
swapl(&fid, n);
}
nr = NewReply(client, client->server->lbxReq, X_LbxQueryFont,
get_queryfont_reply);
if (!nr)
return ProcStandardRequest(client);
FinishLBXRequest(client, REQ_PASSTHROUGH);
SendQueryFont(client, fid);
return Success;
}
static INT16
unpack_val(val, mask, sft, bts)
CARD32 val;
CARD32 mask;
int sft,
bts;
{
CARD16 utmp;
INT16 sval;
/* get the proper value */
utmp = (val & mask) >> sft;
/* push the sign bit to the right spot */
utmp <<= (16 - bts);
/* cast it so sign bit takes effect */
sval = (INT16) utmp;
/* shift back down */
sval >>= (16 - bts);
return sval;
}
/*ARGSUSED*/
static int
UnsquishFontInfo(int compression, xLbxFontInfo *fdata, int dlen, pointer *qfr)
{
int len,
hlen,
junklen = sizeof(BYTE) * 2 + sizeof(CARD16) + sizeof(CARD32);
char *t;
int nchars;
int i;
xCharInfo *maxb;
xQueryFontReply *new;
xLbxCharInfo *lci;
xCharInfo *ci;
CARD16 attrs;
maxb = &fdata->maxBounds;
nchars = fdata->nCharInfos;
hlen = sizeof(xQueryFontReply) + fdata->nFontProps * sizeof(xFontProp);
len = hlen + nchars * sizeof(xCharInfo);
new = (xQueryFontReply *) xalloc(len);
*qfr = (pointer) new;
if (!new) /* XXX bad stuff... */
return 0;
/* copy the header & props parts */
t = (char *) new;
t += junklen;
if (compression) {
memcpy((char *) t, (char *) fdata, hlen - junklen);
} else {
memcpy((char *) t, (char *) fdata, len - junklen);
return len;
}
attrs = maxb->attributes;
t = (char *) fdata;
t += hlen - junklen;
lci = (xLbxCharInfo *) t;
t = (char *) new;
t += hlen;
ci = (xCharInfo *) t;
/* now expand the chars */
for (i = 0; i < nchars; i++, lci++, ci++) {
if (lci->metrics == 0) {
/* empty char */
ci->characterWidth = ci->leftSideBearing = ci->rightSideBearing =
ci->ascent = ci->descent = ci->attributes = 0;
} else {
ci->characterWidth =
unpack_val(lci->metrics, LBX_WIDTH_MASK,
LBX_WIDTH_SHIFT, LBX_WIDTH_BITS);
ci->leftSideBearing = unpack_val(lci->metrics, LBX_LEFT_MASK,
LBX_LEFT_SHIFT, LBX_LEFT_BITS);
ci->rightSideBearing = unpack_val(lci->metrics, LBX_RIGHT_MASK,
LBX_RIGHT_SHIFT, LBX_RIGHT_BITS);
ci->ascent = unpack_val(lci->metrics, LBX_ASCENT_MASK,
LBX_ASCENT_SHIFT, LBX_ASCENT_BITS);
ci->descent = unpack_val(lci->metrics, LBX_DESCENT_MASK,
LBX_DESCENT_SHIFT, LBX_DESCENT_BITS);
ci->attributes = attrs;
}
}
return len;
}
/*ARGSUSED*/
static Bool
get_queryfont_reply(client, nr, data)
ClientPtr client;
ReplyStuffPtr nr;
char *data;
{
xLbxQueryFontReply *rep;
int len,
sqlen;
pointer tag_data,
sqtag_data;
TagData td;
CARD32 tag;
char n;
xQueryFontReply *reply;
rep = (xLbxQueryFontReply *) data;
tag = rep->tag;
if (client->swapped) {
swapl(&tag, n);
}
if (tag) {
if (rep->length) { /* first time, set tag */
#ifdef LBX_STATS
queryfont_full++;
#endif
sqtag_data = (pointer) &rep[1];
sqlen = rep->length << 2;
if (client->swapped)
LbxSwapFontInfo(sqtag_data, rep->compression);
/*
* store squished version of data
*/
if (!TagStoreData(client->server, client->server->global_cache,
tag, sqlen,
LbxTagTypeFont, sqtag_data)) {
/* tell server we lost it */
SendInvalidateTag(client, tag);
}
len = UnsquishFontInfo(rep->compression, sqtag_data, sqlen,
&tag_data);
} else {
td = TagGetTag(client->server, client->server->global_cache, tag);
if (!td) {
fprintf(stderr, "no data for font tag 0x%lx\n", (long)tag);
WriteError(client, X_QueryFont, 0, 0, BadAlloc);
return TRUE;
}
sqlen = td->size;
sqtag_data = td->tdata;
len = UnsquishFontInfo(rep->compression, sqtag_data, sqlen,
&tag_data);
#ifdef LBX_STATS
queryfont_tag++;
tag_bytes_unsent += len;
#endif
}
} else {
#ifdef LBX_STATS
queryfont_full++;
#endif
/* server didn't send us a tag for some reason -- just pass on data */
sqtag_data = (pointer) &rep[1];
if (client->swapped)
LbxSwapFontInfo(sqtag_data, FALSE);
sqlen = rep->length << 2;
len = UnsquishFontInfo(rep->compression, sqtag_data, sqlen, &tag_data);
}
reply = (xQueryFontReply *) ALLOCATE_LOCAL(len);
if (reply) {
memcpy((char *) reply, (char *) tag_data, len);
/* patch up certain fields */
reply->type = X_Reply;
reply->sequenceNumber = rep->sequenceNumber;
reply->length = (len - sizeof(xGenericReply)) >> 2;
len -= sizeof(xQueryFontReply);
if (client->swapped)
SwapFont(reply, TRUE);
WriteToClient(client, sizeof(xQueryFontReply), reply);
WriteToClient(client, len, reply + 1);
DEALLOCATE_LOCAL(reply);
}
xfree(tag_data); /* free unsquished version */
return TRUE;
}
int
ProcLBXGetWindowAttributes(client)
ClientPtr client;
{
REQUEST(xResourceReq);
xLbxGetWinAttrAndGeomReq newreq;
XServerPtr server = client->server;
ReplyStuffPtr nr;
/*
* GetWindowAttributes is always followed by GetGeometry.
* At this point, if lbxproxy requests the window attributes
* *AND* the geometry in one request, we are guaranteed to be
* able to short circuit the GetGeometry that follows.
*/
nr = NewReply(client, client->server->lbxReq, X_LbxGetWinAttrAndGeom,
GetWinAttrAndGeomReply);
if (!nr)
return ProcStandardRequest(client);
/*
* R6 Xlib will not wait for the GetWindowAttributes reply before
* sending the GetGeometry. As a result, when lbxproxy gets the
* GetGeometry we must defer short circuting until lbxproxy receives
* the LbxGetWinAttrAndGeomReply.
*/
nr->request_info.lbxWinGeom.got_geom_request = FALSE;
nr->request_info.lbxWinGeom.got_geom_reply = FALSE;
FinishLBXRequest(client, REQ_PASSTHROUGH);
newreq.reqType = server->lbxReq;
newreq.lbxReqType = X_LbxGetWinAttrAndGeom;
newreq.length = sz_xLbxGetWinAttrAndGeomReq >> 2;
newreq.id = stuff->id;
WriteReqToServer (client, sz_xLbxGetWinAttrAndGeomReq, (char *) &newreq, TRUE);
return Success;
}
static Bool
GetWinAttrAndGeomReply (client, nr, data)
ClientPtr client;
ReplyStuffPtr nr;
char *data;
{
xLbxGetWinAttrAndGeomReply *lbxrep;
xGetWindowAttributesReply reply;
char n;
/*
* We got the window attributes and geometry. Write the
* WindowAttributes reply now.
*/
lbxrep = (xLbxGetWinAttrAndGeomReply *) data;
reply.type = X_Reply;
reply.sequenceNumber = lbxrep->sequenceNumber;
reply.length = (sizeof(xGetWindowAttributesReply) -
sizeof(xGenericReply)) >> 2;
reply.backingStore = lbxrep->backingStore;
reply.visualID = lbxrep->visualID;
#if defined(__cplusplus) || defined(c_plusplus)
reply.c_class = lbxrep->c_class;
#else
reply.class = lbxrep->class;
#endif
reply.bitGravity = lbxrep->bitGravity;
reply.winGravity = lbxrep->winGravity;
reply.backingBitPlanes = lbxrep->backingBitPlanes;
reply.backingPixel = lbxrep->backingPixel;
reply.saveUnder = lbxrep->saveUnder;
reply.mapInstalled = lbxrep->mapInstalled;
reply.mapState = lbxrep->mapState;
reply.override = lbxrep->override;
reply.colormap = lbxrep->colormap;
reply.allEventMasks = lbxrep->allEventMasks;
reply.yourEventMask = lbxrep->yourEventMask;
reply.doNotPropagateMask = lbxrep->doNotPropagateMask;
if (client->swapped) {
swaps (&reply.sequenceNumber, n);
swapl (&reply.length, n);
}
WriteToClient(client, sizeof(xGetWindowAttributesReply), &reply);
if (nr->request_info.lbxWinGeom.got_geom_request)
{
/*
* We can write the GetGeometry reply now too.
*/
xGetGeometryReply geomReply;
geomReply.type = X_Reply;
geomReply.sequenceNumber = lbxrep->sequenceNumber + 1;
geomReply.length = 0;
geomReply.depth = lbxrep->depth;
geomReply.root = lbxrep->root;
geomReply.x = lbxrep->x;
geomReply.y = lbxrep->y;
geomReply.width = lbxrep->width;
geomReply.height = lbxrep->height;
geomReply.borderWidth = lbxrep->borderWidth;
if (client->swapped) {
swaps (&geomReply.sequenceNumber, n);
}
WriteToClient(client, sizeof(xGetGeometryReply), &geomReply);
LBXLastResponse(client) = lbxrep->sequenceNumber + 1;
return TRUE; /* remove matching reply record */
}
else
{
/*
* We didn't get the GetGeometry request yet, so we
* stash away the geometry.
*/
nr->request_info.lbxWinGeom.got_geom_reply = TRUE;
nr->request_info.lbxWinGeom.depth = lbxrep->depth;
nr->request_info.lbxWinGeom.root = lbxrep->root;
nr->request_info.lbxWinGeom.x = lbxrep->x;
nr->request_info.lbxWinGeom.y = lbxrep->y;
nr->request_info.lbxWinGeom.width = lbxrep->width;
nr->request_info.lbxWinGeom.height = lbxrep->height;
nr->request_info.lbxWinGeom.borderWidth = lbxrep->borderWidth;
return FALSE; /* don't remove matching reply record */
}
}
int
ProcLBXGetGeometry(client)
ClientPtr client;
{
/* REQUEST(xResourceReq); */
xGetGeometryReply reply;
ReplyStuffPtr nr;
char n;
/*
* If the previous request was GetWindowAttributes, then lbxproxy
* requested the window attributes *AND* the geometry in one request.
* That means we can short circuit this GetGeometry!
*/
nr = GetMatchingReply (client, LBXSequenceNumber(client) - 1, FALSE);
if (!nr || nr->major != client->server->lbxReq ||
nr->minor != X_LbxGetWinAttrAndGeom)
{
/*
* This GetGeometry was not preceded by a GetWindowAttributes,
* so we can't short circuit. Send the normal GetGeometry request.
*/
return ProcStandardRequest(client);
}
if (nr->request_info.lbxWinGeom.got_geom_reply)
{
/*
* We already have the geom information, so we
* can write the reply now.
*/
reply.type = X_Reply;
reply.sequenceNumber = LBXSequenceNumber(client);
reply.length = 0;
reply.depth = nr->request_info.lbxWinGeom.depth;
reply.root = nr->request_info.lbxWinGeom.root;
reply.x = nr->request_info.lbxWinGeom.x;
reply.y = nr->request_info.lbxWinGeom.y;
reply.width = nr->request_info.lbxWinGeom.width;
reply.height = nr->request_info.lbxWinGeom.height;
reply.borderWidth = nr->request_info.lbxWinGeom.borderWidth;
if (client->swapped) {
swaps (&reply.sequenceNumber, n);
}
FinishLBXRequest(client, REQ_YANK);
WriteToClient(client, sizeof(xGetGeometryReply), &reply);
RemoveReply (client, nr);
}
else
{
/*
* We must wait for the geom information before
* writing the GetGeometry reply.
*/
nr->request_info.lbxWinGeom.got_geom_request = TRUE;
FinishLBXRequest(client, REQ_YANKLATE);
}
return Success;
}
/* We're just looking for signs of the window manager here */
int
ProcLBXChangeWindowAttributes(client)
ClientPtr client;
{
REQUEST(xChangeWindowAttributesReq);
Window win;
CARD32 mask;
char n;
win = stuff->window;
mask = stuff->valueMask;
if (client->swapped) {
swapl(&win, n);
swapl(&mask, n);
}
if (mask == CWEventMask && win == LBXRootWindow(client)) {
mask = *(CARD32 *)&stuff[1];
if (client->swapped) {
swapl(&mask, n);
}
if (mask & SubstructureRedirectMask)
client->server->wm_running = TRUE;
}
return ProcStandardRequest(client);
}
void
FinishLBXRequest(client, yank)
ClientPtr client;
int yank;
{
REQUEST(xReq);
char n;
if (yank != REQ_PASSTHROUGH) {
LBXLastForReply(client) = LBXSequenceNumber(client);
LBXLastForResponse(client) = LBXSequenceNumber(client);
if (yank == REQ_YANK || yank == REQ_REPLACE)
LBXLastResponse(client) = LBXSequenceNumber(client);
} else {
switch (GeneratesReplies(client, stuff)) {
case REQ_TYPE_YES:
LBXLastForReply(client) = LBXSequenceNumber(client);
LBXLastForResponse(client) = LBXSequenceNumber(client);
break;
case REQ_TYPE_MAYBE:
LBXLastForResponse(client) = LBXSequenceNumber(client);
break;
case REQ_TYPE_NO:
if (protocolMode != PROTOCOL_POOR &&
GeneratesEvents(client, stuff))
LBXLastForResponse(client) = LBXSequenceNumber(client);
break;
}
}
switch (protocolMode) {
case PROTOCOL_FULL:
LBXCacheSafe(client) = (LBXSequenceNumber(client) ==
LBXLastResponse(client));
LBXCanDelayReply(client) = (LBXSequenceNumber(client) ==
LBXLastForReply(client));
break;
default:
LBXCacheSafe(client) = (LBXLastForResponse(client) <=
LBXLastResponse(client));
LBXCanDelayReply(client) = (LBXLastForResponse(client) <=
LBXLastForReply(client));
break;
}
#ifdef SEQ_DEBUG
fprintf(stderr,
"finished req %d, seq 0x%x, yank %d cache %d delay %d reply 0x%x response 0x%x\n",
stuff->reqType, LBXSequenceNumber(client), yank,
LBXCacheSafe(client), LBXCanDelayReply(client),
LBXLastForReply(client), LBXLastForResponse(client));
#endif
if (yank == REQ_YANK || yank == REQ_YANKLATE) {
LBXSequenceLost(client)++;
LBXYanked(client)++;
DBG(DBG_CLIENT, (stderr, "short-circuited client %d req %d\n",
client->index, stuff->reqType));
}
/* make sure server's sequence number is accurate */
if (yank != REQ_YANK && yank != REQ_YANKLATE && LBXSequenceLost(client))
BumpSequence(client);
/* put request length in proxy byte order */
if (client->swapped) {
swaps(&stuff->length, n);
}
}
/*
* need to rewrite error codes for requests we've replaced.
*
* QueryFont regularly hits this in normal operation
*/
static int
patchup_error(client, err, nr)
ClientPtr client;
xError *err;
ReplyStuffPtr nr;
{
int retval = 1;
CARD16 minor_code;
char n;
minor_code = err->minorCode;
if (client->swapped) {
swaps(&minor_code, n);
}
switch (minor_code) {
case X_LbxGetModifierMapping:
minor_code = X_GetModifierMapping;
break;
case X_LbxGetKeyboardMapping:
minor_code = X_GetKeyboardMapping;
break;
case X_LbxGetProperty:
minor_code = X_GetProperty;
break;
case X_LbxQueryFont:
minor_code = X_QueryFont;
break;
case X_LbxGetWinAttrAndGeom:
minor_code = X_GetWindowAttributes;
if (nr->request_info.lbxWinGeom.got_geom_request) {
err->majorCode = minor_code;
err->minorCode = 0;
if (client->swapped) {
swaps(&err->sequenceNumber, n);
}
WriteToClient (client, sizeof(xError), (char *)err);
if (client->swapped) {
swaps(&err->sequenceNumber, n);
}
err->sequenceNumber++;
LBXLastResponse(client) = err->sequenceNumber;
minor_code = X_GetGeometry;
}
break;
default:
retval = 0; /* error caused by some LBX req that shouldn't
* have an error, so eat it */
break;
}
err->majorCode = minor_code; /* err->majorCode is CARD8, don't swap */
err->minorCode = 0;
return retval;
}
static Bool
error_matches(client, nr, err)
ClientPtr client;
ReplyStuffPtr nr;
xError *err;
{
CARD16 mc;
char n;
mc = err->minorCode;
if (client->swapped) {
swaps(&mc, n);
}
return (err->majorCode == nr->major && mc == nr->minor);
}
/*
* returns TRUE if data (possibly modified) is to be sent on to client,
* FALSE if data is replaced
*/
static Bool
HandleReply(client, data, len)
ClientPtr client;
char *data;
int len;
{
xGenericReply *reply;
xError *err;
ReplyStuffPtr nr;
Bool ret = TRUE;
char n;
reply = (xGenericReply *) data;
if (client->awaitingSetup) {
xConnSetupPrefix *prefix = (xConnSetupPrefix *) reply;
AttendClient(client);
if (prefix->success) {
get_setup_reply(client, (char *) reply, len);
return FALSE;
}
return TRUE;
}
if (client->swapped && reply->type != KeymapNotify) {
swaps(&reply->sequenceNumber, n);
}
if (reply->type != KeymapNotify &&
reply->sequenceNumber < LBXLastResponse(client)) {
/* spontaneous events, and events in PROTOCOL_POOR mode,
* may have sequence numbers that are earlier
* than short-circuited replies and errors */
if (reply->type > X_Reply)
reply->sequenceNumber = LBXLastResponse(client);
}
if (reply->type != KeymapNotify &&
reply->sequenceNumber > LBXSequenceNumber(client))
{
#ifdef SEQ_DEBUG
fprintf(stderr, "lbxproxy: reply seq #0x%x > internal seq 0x%x\n",
reply->sequenceNumber, LBXSequenceNumber(client));
#endif
reply->sequenceNumber = LBXSequenceNumber(client);
}
if (reply->type != X_Reply) { /* event or error */
/* clear out pending replies that resulted in errors */
if (reply->type == X_Error) {
LBXLastResponse(client) = reply->sequenceNumber;
err = (xError *) reply;
nr = GetMatchingReply(client, reply->sequenceNumber, TRUE);
if (nr && error_matches(client, nr, err)) {
if (err->majorCode == client->server->lbxReq) {
int eret;
if ((eret = patchup_error(client, err, nr)) < 0) {
CloseDownClient(client);
return FALSE;
} else if (eret == 0) {
/* error for proxy -- eat it */
ret = FALSE;
}
} else {
/* error in core X or other extension */
HandleExtensionError(client, err, nr);
}
}
if (nr)
RemoveReply(client, nr);
} else if (reply->type >= 64)
HandleExtensionEvent(client, (xEvent *)reply);
if (client->swapped && reply->type != KeymapNotify) {
swaps(&reply->sequenceNumber, n);
}
return ret;
}
LBXLastResponse(client) = reply->sequenceNumber;
nr = GetMatchingReply(client, reply->sequenceNumber, TRUE);
if (nr) {
if (nr->major == client->server->lbxReq)
ret = FALSE;
if ((*nr->reply_func)(client, nr, (char *)reply))
RemoveReply(client, nr);
}
if (client->swapped) { /* put seq & length back */
swaps(&reply->sequenceNumber, n);
swapl(&reply->length, n);
}
return ret;
}
void
DoLBXReply(client, data, len)
ClientPtr client;
char *data;
int len;
{
if (HandleReply(client, data, len))
WriteToClient (client, len, data);
FlushDelayedReplies (client);
switch (protocolMode) {
case PROTOCOL_FULL:
LBXCacheSafe(client) = (LBXSequenceNumber(client) ==
LBXLastResponse(client));
break;
default:
LBXCacheSafe(client) = (LBXLastForResponse(client) <=
LBXLastResponse(client));
break;
}
#ifdef SEQ_DEBUG
fprintf(stderr, "finished reply 0x%x, cache %d\n",
((xGenericReply *)data)->sequenceNumber, LBXCacheSafe(client));
#endif
}