/* $XConsortium: lbxdix.c /main/28 1996/12/26 11:58:11 rws $ */ /* * Copyright 1993 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. * */ /* various bits of DIX-level mangling */ #include #include #define NEED_REPLIES #define NEED_EVENTS #include "X.h" #include "Xproto.h" #include "misc.h" #include "os.h" #include "dixstruct.h" #include "resource.h" #include "inputstr.h" #include "servermd.h" #include "dixfontstr.h" #include "gcstruct.h" #include "scrnintstr.h" #include "windowstr.h" #include "propertyst.h" #define _XLBX_SERVER_ #include "lbxstr.h" #include "lbxserve.h" #include "lbxtags.h" #include "lbxdata.h" #include "Xfuncproto.h" extern void CopySwap32Write(); extern int (*ProcVector[256]) (); extern int (*SwappedProcVector[256]) (); extern void (*ReplySwapVector[256]) (); extern void LbxWriteSConnSetupPrefix(); int lbx_font_private; void LbxDixInit() { TagInit(); lbx_font_private = AllocateFontPrivateIndex(); } /* ARGSUSED */ void LbxAllowMotion(client, num) ClientPtr client; int num; { LbxProxyPtr proxy = LbxProxy(client); proxy->motion_allowed_events += num; } extern WindowPtr *WindowTable; extern xConnSetupPrefix connSetupPrefix; extern char *ConnectionInfo; extern int connBlockScreenStart; int LbxSendConnSetup(client, reason) ClientPtr client; char *reason; { int dlength; int i, ndex, lim, wndex; CARD32 dataBuf[16]; xLbxConnSetupPrefix csp; NewClientInfoRec nci; LbxProxyPtr proxy = LbxProxy(client); if (reason) { SendConnSetup(client, reason); LbxForceOutput(proxy); /* expedient to avoid another state variable */ return (client->noClientException); } IncrementClientCount(); client->requestVector = client->swapped ? SwappedProcVector : ProcVector; client->sequence = 0; dataBuf[0] = client->clientAsMask; csp.success = TRUE; csp.majorVersion = connSetupPrefix.majorVersion; csp.minorVersion = connSetupPrefix.minorVersion; csp.tag = 0; #ifdef XAPPGROUP if (!client->appgroup) { #endif csp.changeType = 1; /* LbxNormalDeltas */ csp.length = 2 + /* tag + resource-id-base */ screenInfo.numScreens; /* input-mask per screen */ wndex = 0; ndex = 1; lim = screenInfo.numScreens; #ifdef XAPPGROUP } else { csp.changeType = 2; /* LbxAppGroupDeltas */ csp.length = 7 + /* tag, res-id-base, root, visual, colormap, b&w-pix */ 1 + screenInfo.numScreens - screenInfo.numVideoScreens; XagGetDeltaInfo (client, &dataBuf[1]); for (i = 0; i < MAXSCREENS; i++) { if ((CARD32) WindowTable[i]->drawable.id == dataBuf[1]) { dataBuf[6] = WindowTable[i]->eventMask | wOtherEventMasks(WindowTable[i]); break; } } wndex = screenInfo.numVideoScreens; ndex = 7; lim = screenInfo.numScreens - screenInfo.numVideoScreens; } #endif for (i = 0; i < lim; i++, ndex++, wndex++) { dataBuf[ndex] = WindowTable[wndex]->eventMask | wOtherEventMasks(WindowTable[wndex]); } dlength = (csp.length - 1) << 2; if (LbxProxyClient(proxy)->swapped) { swaps(&csp.length, i); } if (client->swapped) { LbxWriteSConnSetupPrefix(client, &csp); SwapLongs(dataBuf, (1 + screenInfo.numScreens)); WriteToClient(client, dlength, (pointer) dataBuf); } else { WriteToClient(client, sizeof(xLbxConnSetupPrefix), (char *) &csp); WriteToClient(client, dlength, (pointer) dataBuf); } LbxForceOutput(proxy); /* expedient to avoid another state variable */ client->clientState = ClientStateRunning; if (ClientStateCallback) { if (LbxProxyClient(proxy)->swapped != client->swapped) { swaps(&csp.length, i); } nci.client = client; nci.prefix = (xConnSetupPrefix*) &csp; nci.setup = (xConnSetup *) ConnectionInfo; CallCallbacks(&ClientStateCallback, (pointer) &nci); } return client->noClientException; } extern InputInfo inputInfo; static XID modifier_map_tag; int LbxGetModifierMapping(client) ClientPtr client; { TagData td; pointer tagdata; xLbxGetModifierMappingReply rep; register KeyClassPtr keyc = inputInfo.keyboard->key; int dlength = keyc->maxKeysPerModifier << 3; Bool tag_known = FALSE, send_data; int n; if (!modifier_map_tag) { tagdata = (pointer) keyc->modifierKeyMap; TagSaveTag(LbxTagTypeModmap, dlength, tagdata, &modifier_map_tag); } else { td = TagGetTag(modifier_map_tag); tagdata = td->tdata; tag_known = TagProxyMarked(modifier_map_tag, LbxProxyID(client)); } if (modifier_map_tag) TagMarkProxy(modifier_map_tag, LbxProxyID(client)); send_data = (!modifier_map_tag || !tag_known); rep.type = X_Reply; rep.keyspermod = keyc->maxKeysPerModifier; rep.sequenceNumber = client->sequence; rep.tag = modifier_map_tag; rep.pad0 = rep.pad1 = rep.pad2 = rep.pad3 = rep.pad4 = 0; if (send_data) rep.length = dlength >> 2; else rep.length = 0; if (client->swapped) { swaps(&rep.sequenceNumber, n); swapl(&rep.length, n); swapl(&rep.tag, n); } WriteToClient(client, sizeof(xLbxGetModifierMappingReply), (char *)&rep); if (send_data) WriteToClient(client, dlength, (char *) tagdata); return client->noClientException; } void LbxFlushModifierMapTag() { if (modifier_map_tag) TagDeleteTag(modifier_map_tag); } static XID keyboard_map_tag; int LbxGetKeyboardMapping(client) ClientPtr client; { TagData td; pointer tagdata; xLbxGetKeyboardMappingReply rep; REQUEST(xLbxGetKeyboardMappingReq); KeySymsPtr curKeySyms = &inputInfo.keyboard->key->curKeySyms; int dlength; Bool tag_known = FALSE, send_data; int n; REQUEST_SIZE_MATCH(xLbxGetKeyboardMappingReq); if ((stuff->firstKeyCode < curKeySyms->minKeyCode) || (stuff->firstKeyCode > curKeySyms->maxKeyCode)) { client->errorValue = stuff->firstKeyCode; return BadValue; } if (stuff->firstKeyCode + stuff->count > curKeySyms->maxKeyCode + 1) { client->errorValue = stuff->count; return BadValue; } rep.type = X_Reply; rep.sequenceNumber = client->sequence; rep.keysperkeycode = curKeySyms->mapWidth; /* length is a count of 4 byte quantities and KeySyms are 4 bytes */ if (!keyboard_map_tag) { tagdata = (pointer) &curKeySyms->map[(stuff->firstKeyCode - curKeySyms->minKeyCode) * curKeySyms->mapWidth]; dlength = (curKeySyms->mapWidth * stuff->count); TagSaveTag(LbxTagTypeKeymap, dlength, tagdata, &keyboard_map_tag); } else { td = TagGetTag(keyboard_map_tag); tagdata = td->tdata; tag_known = TagProxyMarked(keyboard_map_tag, LbxProxyID(client)); } if (keyboard_map_tag) TagMarkProxy(keyboard_map_tag, LbxProxyID(client)); send_data = (!keyboard_map_tag || !tag_known); rep.type = X_Reply; rep.keysperkeycode = curKeySyms->mapWidth; rep.sequenceNumber = client->sequence; rep.tag = keyboard_map_tag; rep.pad0 = rep.pad1 = rep.pad2 = rep.pad3 = rep.pad4 = 0; if (send_data) rep.length = (curKeySyms->mapWidth * stuff->count); else rep.length = 0; if (client->swapped) { swaps(&rep.sequenceNumber, n); swapl(&rep.length, n); swapl(&rep.tag, n); } WriteToClient(client, sizeof(xLbxGetKeyboardMappingReply), (char *)&rep); if (send_data) { client->pSwapReplyFunc = CopySwap32Write; WriteSwappedDataToClient(client, curKeySyms->mapWidth * stuff->count * sizeof(KeySym), &curKeySyms->map[(stuff->firstKeyCode - curKeySyms->minKeyCode) * curKeySyms->mapWidth]); } return client->noClientException; } void LbxFlushKeyboardMapTag() { if (keyboard_map_tag) TagDeleteTag(keyboard_map_tag); } /* counts number of bits needed to hold value */ static int _bitsize(val) int val; { int bits = 1; /* always need one for sign bit */ if (val == 0) return (bits); if (val < 0) { val = -val; } while (val) { bits++; val >>= 1; } return bits; } /* * squashes the font (if possible), returning the new length and * a pointer to the new data (which has been allocated). if it can't * squish, it just returns a 0 and the data is sent in raw form. */ int _lbx_fi_junklen = sizeof(BYTE) * 2 + sizeof(CARD16) + sizeof(CARD32); static int squish_font_info(qfr, rlen, sqrep) xQueryFontReply *qfr; int rlen; xLbxFontInfo **sqrep; { int len, hlen; xLbxFontInfo *new; xCharInfo *minb, *maxb, *ci, bbox; int i; char *t; xLbxCharInfo *chars; int num_chars; num_chars = qfr->nCharInfos; if (num_chars == 0) return 0; minb = &qfr->minBounds; maxb = &qfr->maxBounds; /* * first do the quick check -- if the attribute fields aren't all the * same, punt */ if (minb->attributes != maxb->attributes) return 0; #define compute(field) \ bbox.field = max(_bitsize(minb->field), _bitsize(maxb->field)) compute(characterWidth); compute(leftSideBearing); compute(rightSideBearing); compute(ascent); compute(descent); #undef compute /* make sure it fits */ if (!((bbox.characterWidth <= LBX_WIDTH_BITS) && (bbox.leftSideBearing <= LBX_LEFT_BITS) && (bbox.rightSideBearing <= LBX_RIGHT_BITS) && (bbox.ascent <= LBX_ASCENT_BITS) && (bbox.descent <= LBX_DESCENT_BITS))) { return 0; } hlen = sizeof(xLbxFontInfo) + qfr->nFontProps * sizeof(xFontProp); len = hlen + (num_chars * sizeof(xLbxCharInfo)); new = (xLbxFontInfo *) xalloc(len); if (!new) return 0; /* gross hack to avoid copying all the fields */ t = (char *) qfr; t += _lbx_fi_junklen; /* copy all but the char infos */ memcpy((char *) new, (char *) t, hlen); t = (char *) new; t += hlen; chars = (xLbxCharInfo *) t; t = (char *) qfr; t += sizeof(xQueryFontReply) + qfr->nFontProps * sizeof(xFontProp); ci = (xCharInfo *) t; /* now copy & pack the charinfos */ for (i = 0; i < num_chars; i++, chars++, ci++) { chars->metrics = 0; chars->metrics |= (LBX_MASK_BITS(ci->characterWidth, LBX_WIDTH_BITS) << LBX_WIDTH_SHIFT); chars->metrics |= (LBX_MASK_BITS(ci->leftSideBearing, LBX_LEFT_BITS) << LBX_LEFT_SHIFT); chars->metrics |= (LBX_MASK_BITS(ci->rightSideBearing, LBX_RIGHT_BITS) << LBX_RIGHT_SHIFT); chars->metrics |= (LBX_MASK_BITS(ci->ascent, LBX_ASCENT_BITS) << LBX_ASCENT_SHIFT); chars->metrics |= (LBX_MASK_BITS(ci->descent, LBX_DESCENT_BITS) << LBX_DESCENT_SHIFT); } *sqrep = new; return len; } int LbxQueryFont(client) ClientPtr client; { xQueryFontReply *reply; xLbxQueryFontReply lbxrep; FontPtr pFont; register GC *pGC; Bool send_data = FALSE; Bool free_data = FALSE; int rlength = 0; FontTagInfoPtr ftip; int sqlen = 0; xLbxFontInfo *sqrep, *sreply = NULL; REQUEST(xLbxQueryFontReq); REQUEST_SIZE_MATCH(xLbxQueryFontReq); client->errorValue = stuff->fid; /* EITHER font or gc */ pFont = (FontPtr) SecurityLookupIDByType(client, stuff->fid, RT_FONT, SecurityReadAccess); if (!pFont) { /* can't use VERIFY_GC because it might return BadGC */ pGC = (GC *) SecurityLookupIDByType(client, stuff->fid, RT_GC, SecurityReadAccess); if (!pGC || !pGC->font) { /* catch a non-existent builtin font */ client->errorValue = stuff->fid; return (BadFont); /* procotol spec says only error is BadFont */ } pFont = pGC->font; } /* get tag (if any) */ ftip = (FontTagInfoPtr) FontGetPrivate(pFont, lbx_font_private); if (!ftip) { xCharInfo *pmax = FONTINKMAX(pFont); xCharInfo *pmin = FONTINKMIN(pFont); int nprotoxcistructs; nprotoxcistructs = ( pmax->rightSideBearing == pmin->rightSideBearing && pmax->leftSideBearing == pmin->leftSideBearing && pmax->descent == pmin->descent && pmax->ascent == pmin->ascent && pmax->characterWidth == pmin->characterWidth) ? 0 : N2dChars(pFont); rlength = sizeof(xQueryFontReply) + FONTINFONPROPS(FONTCHARSET(pFont)) * sizeof(xFontProp) + nprotoxcistructs * sizeof(xCharInfo); reply = (xQueryFontReply *) xalloc(rlength); if (!reply) { return (BadAlloc); } free_data = TRUE; send_data = TRUE; QueryFont(pFont, reply, nprotoxcistructs); sqlen = squish_font_info(reply, rlength, &sqrep); if (!sqlen) { /* if it failed to squish, send it raw */ char *t; lbxrep.compression = 0; sqlen = rlength - _lbx_fi_junklen; t = (char *) reply; sqrep = (xLbxFontInfo *) (t + _lbx_fi_junklen); } else { lbxrep.compression = 1; xfree(reply); /* no longer needed */ } } else { /* just get data from tag */ sqrep = ftip->fontinfo; sqlen = ftip->size; lbxrep.compression = ftip->compression; } if (!ftip) { /* data allocation is done when font is first queried */ ftip = (FontTagInfoPtr) xalloc(sizeof(FontTagInfoRec)); if (ftip && TagSaveTag(LbxTagTypeFont, sqlen, (pointer) ftip, &ftip->tid)) { FontSetPrivate(pFont, lbx_font_private, (pointer) ftip); ftip->pfont = pFont; ftip->size = sqlen; ftip->fontinfo = sqrep; ftip->compression = lbxrep.compression; free_data = FALSE; } else { xfree(ftip); } } if (ftip) { if (!TagProxyMarked(ftip->tid, LbxProxyID(client))) send_data = TRUE; TagMarkProxy(ftip->tid, LbxProxyID(client)); lbxrep.tag = ftip->tid; } else { lbxrep.tag = 0; send_data = TRUE; } lbxrep.type = X_Reply; lbxrep.sequenceNumber = client->sequence; lbxrep.pad0 = lbxrep.pad1 = lbxrep.pad2 = lbxrep.pad3 = lbxrep.pad4 = 0; if (send_data) lbxrep.length = sqlen >> 2; else lbxrep.length = 0; if (client->swapped) { int n; swaps(&lbxrep.sequenceNumber, n); swapl(&lbxrep.length, n); swapl(&lbxrep.tag, n); sreply = (xLbxFontInfo *) ALLOCATE_LOCAL(sqlen); if (!sreply) return BadAlloc; memcpy((char *) sreply, (char *) sqrep, sqlen); LbxSwapFontInfo(sreply, lbxrep.compression); sqrep = sreply; } WriteToClient(client, sizeof(xLbxQueryFontReply), (char *) &lbxrep); if (send_data) WriteToClient(client, sqlen, (char *)sqrep); if (free_data) xfree(sqrep); if (sreply) DEALLOCATE_LOCAL(sreply); return (client->noClientException); } void LbxFreeFontTag(pfont) FontPtr pfont; { FontTagInfoPtr ftip; ftip = (FontTagInfoPtr) FontGetPrivate(pfont, lbx_font_private); if (ftip) TagDeleteTag(ftip->tid); } LbxInvalidateTag(client, tag) ClientPtr client; XID tag; { TagClearProxy(tag, LbxProxyID(client)); return client->noClientException; } void LbxSendInvalidateTag(client, tag, tagtype) ClientPtr client; XID tag; int tagtype; { xLbxInvalidateTagEvent ev; int n; ev.type = LbxEventCode; ev.lbxType = LbxInvalidateTagEvent; ev.sequenceNumber = client->sequence; ev.tag = tag; ev.tagType = tagtype; ev.pad1 = ev.pad2 = ev.pad3 = ev.pad4 = ev.pad5 = 0; if (client->swapped) { swaps(&ev.sequenceNumber, n); swapl(&ev.tag, n); swapl(&ev.tagType, n); } DBG(DBG_CLIENT, (stderr, "Invalidating tag %d\n", tag)); WriteToClient(client, sizeof(xLbxInvalidateTagEvent), (char *) &ev); LbxForceOutput(LbxProxy(client)); } static void LbxSendSendTagData(pid, tag, tagtype) int pid; XID tag; int tagtype; { xLbxSendTagDataEvent ev; int n; LbxProxyPtr proxy; ClientPtr client; LbxClientPtr lbxcp; proxy = LbxPidToProxy(pid); lbxcp = proxy->lbxClients[0]; if (lbxcp && (client = lbxcp->client)) { ev.type = LbxEventCode; ev.lbxType = LbxSendTagDataEvent; ev.sequenceNumber = client->sequence; ev.tag = tag; ev.tagType = tagtype; ev.pad1 = ev.pad2 = ev.pad3 = ev.pad4 = ev.pad5 = 0; if (client->swapped) { swaps(&ev.sequenceNumber, n); swapl(&ev.tag, n); swapl(&ev.tagType, n); } DBG(DBG_CLIENT, (stderr, "Requesting tag %d\n", tag)); WriteToClient(client, sizeof(xLbxSendTagDataEvent), (char *) &ev); LbxForceOutput(proxy); } } /* * keep track of clients stalled waiting for tags to come back from * a proxy. since multiple clinets can be waiting for the same tag, * we have to keep a list of all of them. */ typedef struct _sendtagq { XID tag; int num_stalled; ClientPtr *stalled_clients; struct _sendtagq *next; } SendTagQRec, *SendTagQPtr; static SendTagQPtr queried_tags = NULL; #define LbxSendTagFailed -1 #define LbxSendTagSendIt 0 #define LbxSendTagAlreadySent 1 static Bool LbxQueueSendTag(client, tag) ClientPtr client; XID tag; { SendTagQPtr stqp, *prev, new; ClientPtr *newlist; /* see if we're asking for one already in the pipeline */ for (prev = &queried_tags; stqp = *prev; prev = &stqp->next) { if (stqp->tag == tag) { /* add new client to list */ newlist = (ClientPtr *) xrealloc(stqp->stalled_clients, (sizeof(ClientPtr) * (stqp->num_stalled + 1))); if (!newlist) return LbxSendTagFailed; newlist[stqp->num_stalled++] = client; stqp->stalled_clients = newlist; DBG(DBG_CLIENT, (stderr, "Additional client requesting tag %d\n", tag)); return LbxSendTagAlreadySent; } } /* make new one */ new = (SendTagQPtr) xalloc(sizeof(SendTagQRec)); newlist = (ClientPtr *) xalloc(sizeof(ClientPtr)); if (!new || !newlist) { xfree(new); xfree(newlist); return LbxSendTagFailed; } *newlist = client; new->stalled_clients = newlist; new->num_stalled = 1; new->tag = tag; new->next = NULL; /* stick on end of list */ *prev = new; return LbxSendTagSendIt; } SendTagQPtr LbxFindQTag(tag) XID tag; { SendTagQPtr stqp; for (stqp = queried_tags; stqp; stqp = stqp->next) { if (stqp->tag == tag) return stqp; } return NULL; } static void LbxFreeQTag(stqp) SendTagQPtr stqp; { xfree(stqp->stalled_clients); xfree(stqp); } static void LbxRemoveQTag(tag) XID tag; { SendTagQPtr stqp, *prev; for (prev = &queried_tags; stqp = *prev; prev = &stqp->next) { if (stqp->tag == tag) { *prev = stqp->next; LbxFreeQTag(stqp); return; } } } Bool LbxFlushQTag(tag) XID tag; { SendTagQPtr stqp; ClientPtr *cp; stqp = LbxFindQTag(tag); if (!stqp) return FALSE; for (cp = stqp->stalled_clients; --stqp->num_stalled >= 0; cp++) AttendClient(*cp); LbxRemoveQTag(tag); return TRUE; } void ProcessQTagZombies() { SendTagQPtr stqp; ClientPtr *out, *in; int i; for (stqp = queried_tags; stqp; stqp = stqp->next) { out = stqp->stalled_clients; for (in = out, i = stqp->num_stalled; --i >= 0; in++) { if ((*in)->clientGone) --stqp->num_stalled; else *out++ = *in; } } } /* * server sends this */ void LbxQueryTagData(client, owner_pid, tag, tagtype) ClientPtr client; int owner_pid; XID tag; int tagtype; { /* save the info and the client being stalled */ if (LbxQueueSendTag(client, tag) == LbxSendTagSendIt) LbxSendSendTagData(owner_pid, tag, tagtype); } /* * server recieves this */ int LbxTagData(client, tag, len, data) ClientPtr client; XID tag; unsigned long len; pointer data; { TagData td; PropertyPtr pProp; td = TagGetTag(tag); if (!td || td->data_type != LbxTagTypeProperty) return Success; if (!td->global) { /* somebody changed contents while we were querying */ TagDeleteTag(tag); return Success; } LbxFlushQTag(tag); pProp = (PropertyPtr) td->tdata; if (pProp->tag_id != tag || pProp->owner_pid != LbxProxyID(client)) return Success; pProp->owner_pid = 0; if (len != td->size) pProp->size = len / (pProp->format >> 3); pProp->data = xrealloc(pProp->data, len); if (!pProp->data) { pProp->size = 0; return Success; } if (client->swapped) { switch (pProp->format) { case 32: SwapLongs((CARD32 *) data, len >> 2); break; case 16: SwapShorts((short *) data, len >> 1); break; default: break; } } memmove((char *) pProp->data, (char *) data, len); return Success; } /* when server resets, need to reset global tags */ void LbxResetTags() { SendTagQPtr stqp; modifier_map_tag = 0; keyboard_map_tag = 0; /* clean out any pending tag requests */ while (stqp = queried_tags) { queried_tags = stqp->next; LbxFreeQTag(stqp); } }