Implemented first part of XResource extension v1.2: X_XResQueryClientIds
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 feature introduced by
1e933665be
"dix: Add facilities for
client ID tracking." .
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ä <erkki.seppala@vincit.fi>
This commit is contained in:
parent
80fefc42f5
commit
96864bfa95
317
Xext/xres.c
317
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,98 @@
|
|||
#include "gcstruct.h"
|
||||
#include "modinit.h"
|
||||
#include "protocol-versions.h"
|
||||
#include "client.h"
|
||||
#include "list.h"
|
||||
#include "misc.h"
|
||||
#include <string.h>
|
||||
|
||||
/** @brief Holds fragments of responses for ConstructClientIds.
|
||||
*
|
||||
* note: there is no consideration for data alignment */
|
||||
typedef struct {
|
||||
struct xorg_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 xorg_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 xorg_list *frags, int bytes)
|
||||
{
|
||||
FragmentList *f = malloc(sizeof(FragmentList) + bytes);
|
||||
if (!f) {
|
||||
return NULL;
|
||||
} else {
|
||||
f->bytes = bytes;
|
||||
xorg_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 xorg_list *frags)
|
||||
{
|
||||
FragmentList *it;
|
||||
xorg_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 xorg_list *frags)
|
||||
{
|
||||
FragmentList *it, *tmp;
|
||||
xorg_list_for_each_entry_safe(it, tmp, frags, l) {
|
||||
xorg_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;
|
||||
xorg_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)
|
||||
|
@ -288,6 +381,202 @@ 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;
|
||||
|
||||
rep.spec.client = client->clientAsMask;
|
||||
if (client->swapped) {
|
||||
swapl (&rep.spec.client);
|
||||
}
|
||||
|
||||
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);
|
||||
/* 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);
|
||||
swapl (&rep.length);
|
||||
}
|
||||
|
||||
if (sendClient->swapped) {
|
||||
swapl (value);
|
||||
}
|
||||
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) {
|
||||
swaps (&rep.sequenceNumber);
|
||||
swapl (&rep.length);
|
||||
swapl (&rep.numIds);
|
||||
}
|
||||
|
||||
WriteToClient(client,sizeof(rep),(char*)&rep);
|
||||
WriteFragmentsToClient(client, &ctx.response);
|
||||
}
|
||||
|
||||
DestroyConstructClientIdCtx(&ctx);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int
|
||||
ProcResDispatch(ClientPtr client)
|
||||
{
|
||||
|
@ -301,8 +590,12 @@ ProcResDispatch(ClientPtr client)
|
|||
return ProcXResQueryClientResources(client);
|
||||
case X_XResQueryClientPixmapBytes:
|
||||
return ProcXResQueryClientPixmapBytes(client);
|
||||
default:
|
||||
break;
|
||||
case X_XResQueryClientIds:
|
||||
return ProcXResQueryClientIds(client);
|
||||
case X_XResQueryResourceBytes:
|
||||
/* not implemented yet */
|
||||
return BadRequest;
|
||||
default: break;
|
||||
}
|
||||
|
||||
return BadRequest;
|
||||
|
@ -335,7 +628,17 @@ SProcXResQueryClientPixmapBytes(ClientPtr client)
|
|||
}
|
||||
|
||||
static int
|
||||
SProcResDispatch(ClientPtr client)
|
||||
SProcXResQueryClientIds (ClientPtr client)
|
||||
{
|
||||
REQUEST(xXResQueryClientIdsReq);
|
||||
|
||||
REQUEST_AT_LEAST_SIZE (xXResQueryClientIdsReq);
|
||||
swapl(&stuff->numSpecs);
|
||||
return ProcXResQueryClientIds(client);
|
||||
}
|
||||
|
||||
static int
|
||||
SProcResDispatch (ClientPtr client)
|
||||
{
|
||||
REQUEST(xReq);
|
||||
swaps(&stuff->length);
|
||||
|
@ -349,8 +652,12 @@ SProcResDispatch(ClientPtr client)
|
|||
return SProcXResQueryClientResources(client);
|
||||
case X_XResQueryClientPixmapBytes:
|
||||
return SProcXResQueryClientPixmapBytes(client);
|
||||
default:
|
||||
break;
|
||||
case X_XResQueryClientIds:
|
||||
return SProcXResQueryClientIds(client);
|
||||
case X_XResQueryResourceBytes:
|
||||
/* not implemented yet */
|
||||
return BadRequest;
|
||||
default: break;
|
||||
}
|
||||
|
||||
return BadRequest;
|
||||
|
|
|
@ -135,7 +135,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
|
||||
|
|
Loading…
Reference in New Issue
Block a user