This patch implements a part of the XResource extension v1.2 (as specified in http://patchwork.freedesktop.org/patch/2720/ ). The request implemented is X_XResQueryClientIds.
This patch depends on the patch 9d0d0115eee6c3c8e5c8a39fc9ed63407d218e9b "dix: Add facilities for client ID tracking." that can be retrieved from git://gitorious.org/rjy-fdo/xserver.git . The patch is still against gitorious/xorg/xserver-xorg because that's my development environment, but it applies cleanly against meego-w40 as well. This latest version also adds Doxygen-formatted comments and takes a better notice of coding conventions (as in http://www.x.org/wiki/CodingStyle ). Signed-off-by: Erkki Seppälä <[email protected]> Reviewed-by: Rami Ylimäki <[email protected]> --- Xext/xres.c | 311 +++++++++++++++++++++++++++++++++++++++++++ include/protocol-versions.h | 2 +- 2 files changed, 312 insertions(+), 1 deletions(-) diff --git a/Xext/xres.c b/Xext/xres.c index 06639a2..ff7cf94 100644 --- a/Xext/xres.c +++ b/Xext/xres.c @@ -10,6 +10,7 @@ #include <string.h> #include <X11/X.h> #include <X11/Xproto.h> +#include <assert.h> #include "misc.h" #include "os.h" #include "dixstruct.h" @@ -22,6 +23,97 @@ #include "gcstruct.h" #include "modinit.h" #include "protocol-versions.h" +#include "client.h" +#include "list.h" +#include <string.h> + +/** @brief Holds fragments of responses for ConstructClientIds. + * + * note: there is no consideration for data alignment */ +typedef struct { + struct list l; + int bytes; + /* data follows */ +} FragmentList; + +/** @brief Holds structure for the generated response to + ProcXResQueryClientIds; used by ConstructClientId* -functions */ +typedef struct { + int numIds; + int resultBytes; + struct list response; + int sentClientMasks[MAXCLIENTS]; +} ConstructClientIdCtx; + +/** @brief Allocate and add a sequence of bytes at the end of a fragment list. + Call DestroyFragments to release the list. + + @param frags A pointer to head of an initialized linked list + @param bytes Number of bytes to allocate + @return Returns a pointer to the allocated non-zeroed region + that is to be filled by the caller. On error (out of memory) + returns NULL and makes no changes to the list. +*/ +static void * +AddFragment(struct list *frags, int bytes) +{ + FragmentList *f = malloc(sizeof(FragmentList) + bytes); + if (!f) { + return NULL; + } else { + f->bytes = bytes; + list_add(&f->l, frags->prev); + return (char*) f + sizeof(*f); + } +} + +/** @brief Sends all fragments in the list to the client. Does not + free anything. + + @param client The client to send the fragments to + @param frags The head of the list of fragments +*/ +static void +WriteFragmentsToClient(ClientPtr client, struct list *frags) +{ + FragmentList *it; + list_for_each_entry(it, frags, l) { + WriteToClient(client, it->bytes, (char*) it + sizeof(*it)); + } +} + +/** @brief Frees a list of fragments. Does not free() root node. + + @param frags The head of the list of fragments +*/ +static void +DestroyFragments(struct list *frags) +{ + FragmentList *it, *tmp; + list_for_each_entry_safe(it, tmp, frags, l) { + list_del(&it->l); + free(it); + } +} + +/** @brief Constructs a context record for ConstructClientId* functions + to use */ +static void +InitConstructClientIdCtx(ConstructClientIdCtx *ctx) +{ + ctx->numIds = 0; + ctx->resultBytes = 0; + list_init(&ctx->response); + memset(ctx->sentClientMasks, 0, sizeof(ctx->sentClientMasks)); +} + +/** @brief Destroys a context record, releases all memory (except the storage + for *ctx itself) */ +static void +DestroyConstructClientIdCtx(ConstructClientIdCtx *ctx) +{ + DestroyFragments(&ctx->response); +} static int ProcXResQueryVersion (ClientPtr client) @@ -298,6 +390,204 @@ ProcXResQueryClientPixmapBytes (ClientPtr client) return Success; } +/** @brief Finds out if a client's information need to be put into the + response; marks client having been handled, if that is the case. + + @param client The client to send information about + @param mask The request mask (0 to send everything, otherwise a + bitmask of X_XRes*Mask) + @param ctx The context record that tells which clients and id types + have been already handled + @param sendMask Which id type are we now considering. One of X_XRes*Mask. + + @return Returns TRUE if the client information needs to be on the + response, otherwise FALSE. +*/ +static Bool +WillConstructMask(ClientPtr client, CARD32 mask, + ConstructClientIdCtx *ctx, int sendMask) +{ + if ((!mask || (mask & sendMask)) + && !(ctx->sentClientMasks[client->index] & sendMask)) { + ctx->sentClientMasks[client->index] |= sendMask; + return TRUE; + } else { + return FALSE; + } +} + +/** @brief Constructs a response about a single client, based on a certain + client id spec + + @param sendClient Which client wishes to receive this answer. Used for + byte endianess. + @param client Which client are we considering. + @param mask The client id spec mask indicating which information + we want about this client. + @param ctx The context record containing the constructed response + and information on which clients and masks have been + already handled. + + @return Return TRUE if everything went OK, otherwise FALSE which indicates + a memory allocation problem. +*/ +static Bool +ConstructClientIdValue(ClientPtr sendClient, ClientPtr client, CARD32 mask, + ConstructClientIdCtx *ctx) +{ + xXResClientIdValue rep; + int n; + + rep.spec.client = client->clientAsMask; + if (client->swapped) { + swapl (&rep.spec.client, n); + } + + if (WillConstructMask(client, mask, ctx, X_XResClientXidMask)) { + void *ptr = AddFragment(&ctx->response, sizeof(rep)); + if (!ptr) { + return FALSE; + } + + rep.spec.mask = X_XResClientXidMask; + rep.length = 0; + if (sendClient->swapped) { + swapl (&rep.spec.mask, n); + /* swapl (&rep.length, n); - not required for rep.length = 0 */ + } + + memcpy(ptr, &rep, sizeof(rep)); + + ctx->resultBytes += sizeof(rep); + ++ctx->numIds; + } + if (WillConstructMask(client, mask, ctx, X_XResLocalClientPidMask)) { + pid_t pid = GetClientPid(client); + + if (pid != -1) { + void *ptr = AddFragment(&ctx->response, + sizeof(rep) + sizeof(CARD32)); + CARD32 *value = (void*) ((char*) ptr + sizeof(rep)); + + if (!ptr) { + return FALSE; + } + + rep.spec.mask = X_XResLocalClientPidMask; + rep.length = 4; + + if (sendClient->swapped) { + swapl (&rep.spec.mask, n); + swapl (&rep.length, n); + } + + if (sendClient->swapped) { + swapl (value, n); + } + memcpy(ptr, &rep, sizeof(rep)); + *value = pid; + + ctx->resultBytes += sizeof(rep) + sizeof(CARD32); + ++ctx->numIds; + } + } + + /* memory allocation errors earlier may return with FALSE */ + return TRUE; +} + +/** @brief Constructs a response about all clients, based on a client id specs + + @param client Which client which we are constructing the response for. + @param numSpecs Number of client id specs in specs + @param specs Client id specs + + @return Return Success if everything went OK, otherwise a Bad* (currently + BadAlloc or BadValue) +*/ +static int +ConstructClientIds(ClientPtr client, + int numSpecs, xXResClientIdSpec* specs, + ConstructClientIdCtx *ctx) +{ + int specIdx; + + for (specIdx = 0; specIdx < numSpecs; ++specIdx) { + if (specs[specIdx].client == 0) { + int c; + for (c = 0; c < currentMaxClients; ++c) { + if (clients[c]) { + if (!ConstructClientIdValue(client, clients[c], + specs[specIdx].mask, ctx)) { + return BadAlloc; + } + } + } + } else { + int clientID = CLIENT_ID(specs[specIdx].client); + + if ((clientID < currentMaxClients) && clients[clientID]) { + if (!ConstructClientIdValue(client, clients[clientID], + specs[specIdx].mask, ctx)) { + return BadAlloc; + } + } + } + } + + /* memory allocation errors earlier may return with BadAlloc */ + return Success; +} + +/** @brief Response to XResQueryClientIds request introduced in XResProto v1.2 + + @param client Which client which we are constructing the response for. + + @return Returns the value returned from ConstructClientIds with the same + semantics +*/ +static int +ProcXResQueryClientIds (ClientPtr client) +{ + REQUEST(xXResQueryClientIdsReq); + + xXResQueryClientIdsReply rep; + xXResClientIdSpec *specs = (void*) ((char*) stuff + sizeof(*stuff)); + int rc; + ConstructClientIdCtx ctx; + + InitConstructClientIdCtx(&ctx); + + REQUEST_AT_LEAST_SIZE(xXResQueryClientIdsReq); + REQUEST_FIXED_SIZE(xXResQueryClientIdsReq, + stuff->numSpecs * sizeof(specs[0])); + + rc = ConstructClientIds(client, stuff->numSpecs, specs, &ctx); + + if (rc == Success) { + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + + assert((ctx.resultBytes & 3) == 0); + rep.length = bytes_to_int32(ctx.resultBytes); + rep.numIds = ctx.numIds; + + if (client->swapped) { + int n; + swaps (&rep.sequenceNumber, n); + swapl (&rep.length, n); + swapl (&rep.numIds, n); + } + + WriteToClient(client,sizeof(rep),(char*)&rep); + WriteFragmentsToClient(client, &ctx.response); + } + + DestroyConstructClientIdCtx(&ctx); + + return rc; +} + static int ProcResDispatch (ClientPtr client) { @@ -311,6 +601,11 @@ ProcResDispatch (ClientPtr client) return ProcXResQueryClientResources(client); case X_XResQueryClientPixmapBytes: return ProcXResQueryClientPixmapBytes(client); + case X_XResQueryClientIds: + return ProcXResQueryClientIds(client); + case X_XResQueryResourceBytes: + /* not implemented yet */ + return BadRequest; default: break; } @@ -352,6 +647,17 @@ SProcXResQueryClientPixmapBytes (ClientPtr client) } static int +SProcXResQueryClientIds (ClientPtr client) +{ + REQUEST(xXResQueryClientIdsReq); + int n; + + REQUEST_AT_LEAST_SIZE (xXResQueryClientIdsReq); + swaps(&stuff->numSpecs,n); + return ProcXResQueryClientIds(client); +} + +static int SProcResDispatch (ClientPtr client) { REQUEST(xReq); @@ -368,6 +674,11 @@ SProcResDispatch (ClientPtr client) return SProcXResQueryClientResources(client); case X_XResQueryClientPixmapBytes: return SProcXResQueryClientPixmapBytes(client); + case X_XResQueryClientIds: + return SProcXResQueryClientIds(client); + case X_XResQueryResourceBytes: + /* not implemented yet */ + return BadRequest; default: break; } diff --git a/include/protocol-versions.h b/include/protocol-versions.h index c8c7f5f..a94ed17 100644 --- a/include/protocol-versions.h +++ b/include/protocol-versions.h @@ -139,7 +139,7 @@ /* Resource */ #define SERVER_XRES_MAJOR_VERSION 1 -#define SERVER_XRES_MINOR_VERSION 0 +#define SERVER_XRES_MINOR_VERSION 2 /* XvMC */ #define SERVER_XVMC_MAJOR_VERSION 1 -- 1.7.0.4 _______________________________________________ [email protected]: X.Org development Archives: http://lists.x.org/archives/xorg-devel Info: http://lists.x.org/mailman/listinfo/xorg-devel
