xres.c revision 6e78d31f
105b261ecSmrg/*
205b261ecSmrg   Copyright (c) 2002  XFree86 Inc
305b261ecSmrg*/
405b261ecSmrg
505b261ecSmrg#ifdef HAVE_DIX_CONFIG_H
605b261ecSmrg#include <dix-config.h>
705b261ecSmrg#endif
805b261ecSmrg
905b261ecSmrg#include <stdio.h>
1005b261ecSmrg#include <string.h>
1105b261ecSmrg#include <X11/X.h>
1205b261ecSmrg#include <X11/Xproto.h>
1335c4bbdfSmrg#include <assert.h>
1405b261ecSmrg#include "misc.h"
1505b261ecSmrg#include "os.h"
1605b261ecSmrg#include "dixstruct.h"
1705b261ecSmrg#include "extnsionst.h"
1805b261ecSmrg#include "swaprep.h"
194642e01fSmrg#include "registry.h"
2005b261ecSmrg#include <X11/extensions/XResproto.h>
2105b261ecSmrg#include "pixmapstr.h"
2205b261ecSmrg#include "windowstr.h"
2305b261ecSmrg#include "gcstruct.h"
2435c4bbdfSmrg#include "extinit.h"
256747b715Smrg#include "protocol-versions.h"
2635c4bbdfSmrg#include "client.h"
2735c4bbdfSmrg#include "list.h"
2835c4bbdfSmrg#include "misc.h"
2935c4bbdfSmrg#include <string.h>
3035c4bbdfSmrg#include "hashtable.h"
3135c4bbdfSmrg#include "picturestr.h"
3235c4bbdfSmrg
3335c4bbdfSmrg#ifdef COMPOSITE
3435c4bbdfSmrg#include "compint.h"
3535c4bbdfSmrg#endif
3635c4bbdfSmrg
3735c4bbdfSmrg/** @brief Holds fragments of responses for ConstructClientIds.
3835c4bbdfSmrg *
3935c4bbdfSmrg *  note: there is no consideration for data alignment */
4035c4bbdfSmrgtypedef struct {
4135c4bbdfSmrg    struct xorg_list l;
4235c4bbdfSmrg    int   bytes;
4335c4bbdfSmrg    /* data follows */
4435c4bbdfSmrg} FragmentList;
4535c4bbdfSmrg
4635c4bbdfSmrg#define FRAGMENT_DATA(ptr) ((void*) ((char*) (ptr) + sizeof(FragmentList)))
4735c4bbdfSmrg
4835c4bbdfSmrg/** @brief Holds structure for the generated response to
4935c4bbdfSmrg           ProcXResQueryClientIds; used by ConstructClientId* -functions */
5035c4bbdfSmrgtypedef struct {
5135c4bbdfSmrg    int           numIds;
5235c4bbdfSmrg    int           resultBytes;
5335c4bbdfSmrg    struct xorg_list   response;
5435c4bbdfSmrg    int           sentClientMasks[MAXCLIENTS];
5535c4bbdfSmrg} ConstructClientIdCtx;
5635c4bbdfSmrg
5735c4bbdfSmrg/** @brief Holds the structure for information required to
5835c4bbdfSmrg           generate the response to XResQueryResourceBytes. In addition
5935c4bbdfSmrg           to response it contains information on the query as well,
6035c4bbdfSmrg           as well as some volatile information required by a few
6135c4bbdfSmrg           functions that cannot take that information directly
6235c4bbdfSmrg           via a parameter, as they are called via already-existing
6335c4bbdfSmrg           higher order functions. */
6435c4bbdfSmrgtypedef struct {
6535c4bbdfSmrg    ClientPtr     sendClient;
6635c4bbdfSmrg    int           numSizes;
6735c4bbdfSmrg    int           resultBytes;
6835c4bbdfSmrg    struct xorg_list response;
6935c4bbdfSmrg    int           status;
7035c4bbdfSmrg    long          numSpecs;
7135c4bbdfSmrg    xXResResourceIdSpec *specs;
7235c4bbdfSmrg    HashTable     visitedResources;
7335c4bbdfSmrg
7435c4bbdfSmrg    /* Used by AddSubResourceSizeSpec when AddResourceSizeValue is
7535c4bbdfSmrg       handling crossreferences */
7635c4bbdfSmrg    HashTable     visitedSubResources;
7735c4bbdfSmrg
7835c4bbdfSmrg    /* used when ConstructResourceBytesCtx is passed to
7935c4bbdfSmrg       AddResourceSizeValue2 via FindClientResourcesByType */
8035c4bbdfSmrg    RESTYPE       resType;
8135c4bbdfSmrg
8235c4bbdfSmrg    /* used when ConstructResourceBytesCtx is passed to
8335c4bbdfSmrg       AddResourceSizeValueByResource from ConstructResourceBytesByResource */
8435c4bbdfSmrg    xXResResourceIdSpec       *curSpec;
8535c4bbdfSmrg
8635c4bbdfSmrg    /** Used when iterating through a single resource's subresources
8735c4bbdfSmrg
8835c4bbdfSmrg        @see AddSubResourceSizeSpec */
8935c4bbdfSmrg    xXResResourceSizeValue    *sizeValue;
9035c4bbdfSmrg} ConstructResourceBytesCtx;
9135c4bbdfSmrg
9235c4bbdfSmrg/** @brief Allocate and add a sequence of bytes at the end of a fragment list.
9335c4bbdfSmrg           Call DestroyFragments to release the list.
9435c4bbdfSmrg
9535c4bbdfSmrg    @param frags A pointer to head of an initialized linked list
9635c4bbdfSmrg    @param bytes Number of bytes to allocate
9735c4bbdfSmrg    @return Returns a pointer to the allocated non-zeroed region
9835c4bbdfSmrg            that is to be filled by the caller. On error (out of memory)
9935c4bbdfSmrg            returns NULL and makes no changes to the list.
10035c4bbdfSmrg*/
10135c4bbdfSmrgstatic void *
10235c4bbdfSmrgAddFragment(struct xorg_list *frags, int bytes)
10335c4bbdfSmrg{
10435c4bbdfSmrg    FragmentList *f = malloc(sizeof(FragmentList) + bytes);
10535c4bbdfSmrg    if (!f) {
10635c4bbdfSmrg        return NULL;
10735c4bbdfSmrg    } else {
10835c4bbdfSmrg        f->bytes = bytes;
10935c4bbdfSmrg        xorg_list_add(&f->l, frags->prev);
11035c4bbdfSmrg        return (char*) f + sizeof(*f);
11135c4bbdfSmrg    }
11235c4bbdfSmrg}
11335c4bbdfSmrg
11435c4bbdfSmrg/** @brief Sends all fragments in the list to the client. Does not
11535c4bbdfSmrg           free anything.
11635c4bbdfSmrg
11735c4bbdfSmrg    @param client The client to send the fragments to
11835c4bbdfSmrg    @param frags The head of the list of fragments
11935c4bbdfSmrg*/
12035c4bbdfSmrgstatic void
12135c4bbdfSmrgWriteFragmentsToClient(ClientPtr client, struct xorg_list *frags)
12235c4bbdfSmrg{
12335c4bbdfSmrg    FragmentList *it;
12435c4bbdfSmrg    xorg_list_for_each_entry(it, frags, l) {
12535c4bbdfSmrg        WriteToClient(client, it->bytes, (char*) it + sizeof(*it));
12635c4bbdfSmrg    }
12735c4bbdfSmrg}
12835c4bbdfSmrg
12935c4bbdfSmrg/** @brief Frees a list of fragments. Does not free() root node.
13035c4bbdfSmrg
13135c4bbdfSmrg    @param frags The head of the list of fragments
13235c4bbdfSmrg*/
13335c4bbdfSmrgstatic void
13435c4bbdfSmrgDestroyFragments(struct xorg_list *frags)
13535c4bbdfSmrg{
13635c4bbdfSmrg    FragmentList *it, *tmp;
13735c4bbdfSmrg    xorg_list_for_each_entry_safe(it, tmp, frags, l) {
13835c4bbdfSmrg        xorg_list_del(&it->l);
13935c4bbdfSmrg        free(it);
14035c4bbdfSmrg    }
14135c4bbdfSmrg}
14235c4bbdfSmrg
14335c4bbdfSmrg/** @brief Constructs a context record for ConstructClientId* functions
14435c4bbdfSmrg           to use */
14535c4bbdfSmrgstatic void
14635c4bbdfSmrgInitConstructClientIdCtx(ConstructClientIdCtx *ctx)
14735c4bbdfSmrg{
14835c4bbdfSmrg    ctx->numIds = 0;
14935c4bbdfSmrg    ctx->resultBytes = 0;
15035c4bbdfSmrg    xorg_list_init(&ctx->response);
15135c4bbdfSmrg    memset(ctx->sentClientMasks, 0, sizeof(ctx->sentClientMasks));
15235c4bbdfSmrg}
15335c4bbdfSmrg
15435c4bbdfSmrg/** @brief Destroys a context record, releases all memory (except the storage
15535c4bbdfSmrg           for *ctx itself) */
15635c4bbdfSmrgstatic void
15735c4bbdfSmrgDestroyConstructClientIdCtx(ConstructClientIdCtx *ctx)
15835c4bbdfSmrg{
15935c4bbdfSmrg    DestroyFragments(&ctx->response);
16035c4bbdfSmrg}
16135c4bbdfSmrg
16235c4bbdfSmrgstatic Bool
16335c4bbdfSmrgInitConstructResourceBytesCtx(ConstructResourceBytesCtx *ctx,
16435c4bbdfSmrg                              ClientPtr                  sendClient,
16535c4bbdfSmrg                              long                       numSpecs,
16635c4bbdfSmrg                              xXResResourceIdSpec       *specs)
16735c4bbdfSmrg{
16835c4bbdfSmrg    ctx->sendClient = sendClient;
16935c4bbdfSmrg    ctx->numSizes = 0;
17035c4bbdfSmrg    ctx->resultBytes = 0;
17135c4bbdfSmrg    xorg_list_init(&ctx->response);
17235c4bbdfSmrg    ctx->status = Success;
17335c4bbdfSmrg    ctx->numSpecs = numSpecs;
17435c4bbdfSmrg    ctx->specs = specs;
17535c4bbdfSmrg    ctx->visitedResources = ht_create(sizeof(XID), 0,
17635c4bbdfSmrg                                      ht_resourceid_hash, ht_resourceid_compare,
17735c4bbdfSmrg                                      NULL);
17835c4bbdfSmrg
17935c4bbdfSmrg    if (!ctx->visitedResources) {
18035c4bbdfSmrg        return FALSE;
18135c4bbdfSmrg    } else {
18235c4bbdfSmrg        return TRUE;
18335c4bbdfSmrg    }
18435c4bbdfSmrg}
18535c4bbdfSmrg
18635c4bbdfSmrgstatic void
18735c4bbdfSmrgDestroyConstructResourceBytesCtx(ConstructResourceBytesCtx *ctx)
18835c4bbdfSmrg{
18935c4bbdfSmrg    DestroyFragments(&ctx->response);
19035c4bbdfSmrg    ht_destroy(ctx->visitedResources);
19135c4bbdfSmrg}
19205b261ecSmrg
19305b261ecSmrgstatic int
19435c4bbdfSmrgProcXResQueryVersion(ClientPtr client)
19535c4bbdfSmrg{
19635c4bbdfSmrg    xXResQueryVersionReply rep = {
19735c4bbdfSmrg        .type = X_Reply,
19835c4bbdfSmrg        .sequenceNumber = client->sequence,
19935c4bbdfSmrg        .length = 0,
20035c4bbdfSmrg        .server_major = SERVER_XRES_MAJOR_VERSION,
20135c4bbdfSmrg        .server_minor = SERVER_XRES_MINOR_VERSION
20235c4bbdfSmrg    };
20335c4bbdfSmrg
20435c4bbdfSmrg    REQUEST_SIZE_MATCH(xXResQueryVersionReq);
20535c4bbdfSmrg
20635c4bbdfSmrg    if (client->swapped) {
20735c4bbdfSmrg        swaps(&rep.sequenceNumber);
20835c4bbdfSmrg        swapl(&rep.length);
20935c4bbdfSmrg        swaps(&rep.server_major);
21035c4bbdfSmrg        swaps(&rep.server_minor);
21135c4bbdfSmrg    }
21235c4bbdfSmrg    WriteToClient(client, sizeof(xXResQueryVersionReply), &rep);
2136747b715Smrg    return Success;
21405b261ecSmrg}
21505b261ecSmrg
21605b261ecSmrgstatic int
21735c4bbdfSmrgProcXResQueryClients(ClientPtr client)
21805b261ecSmrg{
21905b261ecSmrg    /* REQUEST(xXResQueryClientsReq); */
22005b261ecSmrg    xXResQueryClientsReply rep;
22105b261ecSmrg    int *current_clients;
22205b261ecSmrg    int i, num_clients;
22305b261ecSmrg
22405b261ecSmrg    REQUEST_SIZE_MATCH(xXResQueryClientsReq);
22505b261ecSmrg
22635c4bbdfSmrg    current_clients = xallocarray(currentMaxClients, sizeof(int));
22705b261ecSmrg
22805b261ecSmrg    num_clients = 0;
22935c4bbdfSmrg    for (i = 0; i < currentMaxClients; i++) {
23035c4bbdfSmrg        if (clients[i]) {
23135c4bbdfSmrg            current_clients[num_clients] = i;
23235c4bbdfSmrg            num_clients++;
23335c4bbdfSmrg        }
23405b261ecSmrg    }
23505b261ecSmrg
23635c4bbdfSmrg    rep = (xXResQueryClientsReply) {
23735c4bbdfSmrg        .type = X_Reply,
23835c4bbdfSmrg        .sequenceNumber = client->sequence,
23935c4bbdfSmrg        .length = bytes_to_int32(num_clients * sz_xXResClient),
24035c4bbdfSmrg        .num_clients = num_clients
24135c4bbdfSmrg    };
24205b261ecSmrg    if (client->swapped) {
24335c4bbdfSmrg        swaps(&rep.sequenceNumber);
24435c4bbdfSmrg        swapl(&rep.length);
24535c4bbdfSmrg        swapl(&rep.num_clients);
24635c4bbdfSmrg    }
24735c4bbdfSmrg    WriteToClient(client, sizeof(xXResQueryClientsReply), &rep);
24835c4bbdfSmrg
24935c4bbdfSmrg    if (num_clients) {
25005b261ecSmrg        xXResClient scratch;
25105b261ecSmrg
25235c4bbdfSmrg        for (i = 0; i < num_clients; i++) {
25305b261ecSmrg            scratch.resource_base = clients[current_clients[i]]->clientAsMask;
25405b261ecSmrg            scratch.resource_mask = RESOURCE_ID_MASK;
25535c4bbdfSmrg
25635c4bbdfSmrg            if (client->swapped) {
25735c4bbdfSmrg                swapl(&scratch.resource_base);
25835c4bbdfSmrg                swapl(&scratch.resource_mask);
25905b261ecSmrg            }
26035c4bbdfSmrg            WriteToClient(client, sz_xXResClient, &scratch);
26105b261ecSmrg        }
26205b261ecSmrg    }
26305b261ecSmrg
2646747b715Smrg    free(current_clients);
26505b261ecSmrg
2666747b715Smrg    return Success;
26705b261ecSmrg}
26805b261ecSmrg
26905b261ecSmrgstatic void
27035c4bbdfSmrgResFindAllRes(void *value, XID id, RESTYPE type, void *cdata)
27105b261ecSmrg{
27235c4bbdfSmrg    int *counts = (int *) cdata;
27305b261ecSmrg
27405b261ecSmrg    counts[(type & TypeMask) - 1]++;
27505b261ecSmrg}
27605b261ecSmrg
27705b261ecSmrgstatic int
27835c4bbdfSmrgProcXResQueryClientResources(ClientPtr client)
27905b261ecSmrg{
28005b261ecSmrg    REQUEST(xXResQueryClientResourcesReq);
28105b261ecSmrg    xXResQueryClientResourcesReply rep;
28205b261ecSmrg    int i, clientID, num_types;
28305b261ecSmrg    int *counts;
28405b261ecSmrg
28505b261ecSmrg    REQUEST_SIZE_MATCH(xXResQueryClientResourcesReq);
28605b261ecSmrg
28705b261ecSmrg    clientID = CLIENT_ID(stuff->xid);
28805b261ecSmrg
28935c4bbdfSmrg    if ((clientID >= currentMaxClients) || !clients[clientID]) {
29005b261ecSmrg        client->errorValue = stuff->xid;
29105b261ecSmrg        return BadValue;
29205b261ecSmrg    }
29305b261ecSmrg
2946747b715Smrg    counts = calloc(lastResourceType + 1, sizeof(int));
29505b261ecSmrg
29605b261ecSmrg    FindAllClientResources(clients[clientID], ResFindAllRes, counts);
29705b261ecSmrg
29805b261ecSmrg    num_types = 0;
29905b261ecSmrg
30035c4bbdfSmrg    for (i = 0; i <= lastResourceType; i++) {
30135c4bbdfSmrg        if (counts[i])
30235c4bbdfSmrg            num_types++;
30305b261ecSmrg    }
30405b261ecSmrg
30535c4bbdfSmrg    rep = (xXResQueryClientResourcesReply) {
30635c4bbdfSmrg        .type = X_Reply,
30735c4bbdfSmrg        .sequenceNumber = client->sequence,
30835c4bbdfSmrg        .length = bytes_to_int32(num_types * sz_xXResType),
30935c4bbdfSmrg        .num_types = num_types
31035c4bbdfSmrg    };
31105b261ecSmrg    if (client->swapped) {
31235c4bbdfSmrg        swaps(&rep.sequenceNumber);
31335c4bbdfSmrg        swapl(&rep.length);
31435c4bbdfSmrg        swapl(&rep.num_types);
31535c4bbdfSmrg    }
31605b261ecSmrg
31735c4bbdfSmrg    WriteToClient(client, sizeof(xXResQueryClientResourcesReply), &rep);
31805b261ecSmrg
31935c4bbdfSmrg    if (num_types) {
32005b261ecSmrg        xXResType scratch;
32135c4bbdfSmrg        const char *name;
32205b261ecSmrg
32335c4bbdfSmrg        for (i = 0; i < lastResourceType; i++) {
32435c4bbdfSmrg            if (!counts[i])
32535c4bbdfSmrg                continue;
32605b261ecSmrg
32735c4bbdfSmrg            name = LookupResourceName(i + 1);
3284642e01fSmrg            if (strcmp(name, XREGISTRY_UNKNOWN))
32935c4bbdfSmrg                scratch.resource_type = MakeAtom(name, strlen(name), TRUE);
33035c4bbdfSmrg            else {
33105b261ecSmrg                char buf[40];
33235c4bbdfSmrg
33305b261ecSmrg                snprintf(buf, sizeof(buf), "Unregistered resource %i", i + 1);
33435c4bbdfSmrg                scratch.resource_type = MakeAtom(buf, strlen(buf), TRUE);
33505b261ecSmrg            }
33605b261ecSmrg
33705b261ecSmrg            scratch.count = counts[i];
33805b261ecSmrg
33935c4bbdfSmrg            if (client->swapped) {
34035c4bbdfSmrg                swapl(&scratch.resource_type);
34135c4bbdfSmrg                swapl(&scratch.count);
34205b261ecSmrg            }
34335c4bbdfSmrg            WriteToClient(client, sz_xXResType, &scratch);
34405b261ecSmrg        }
34505b261ecSmrg    }
34605b261ecSmrg
3476747b715Smrg    free(counts);
34835c4bbdfSmrg
3496747b715Smrg    return Success;
35005b261ecSmrg}
35105b261ecSmrg
35205b261ecSmrgstatic unsigned long
35335c4bbdfSmrgResGetApproxPixmapBytes(PixmapPtr pix)
35405b261ecSmrg{
35535c4bbdfSmrg    unsigned long nPixels;
35635c4bbdfSmrg    float bytesPerPixel;
35705b261ecSmrg
35835c4bbdfSmrg    bytesPerPixel = (float)pix->drawable.bitsPerPixel / 8.0;
35935c4bbdfSmrg    nPixels = pix->drawable.width * pix->drawable.height;
36005b261ecSmrg
36135c4bbdfSmrg    /* Divide by refcnt as pixmap could be shared between clients,
36235c4bbdfSmrg     * so total pixmap mem is shared between these.
36335c4bbdfSmrg     */
36435c4bbdfSmrg    return (nPixels * bytesPerPixel) / pix->refcnt;
36505b261ecSmrg}
36605b261ecSmrg
36735c4bbdfSmrgstatic void
36835c4bbdfSmrgResFindResourcePixmaps(void *value, XID id, RESTYPE type, void *cdata)
36905b261ecSmrg{
37035c4bbdfSmrg    SizeType sizeFunc = GetResourceTypeSizeFunc(type);
37135c4bbdfSmrg    ResourceSizeRec size = { 0, 0, 0 };
37235c4bbdfSmrg    unsigned long *bytes = cdata;
37305b261ecSmrg
37435c4bbdfSmrg    sizeFunc(value, id, &size);
37535c4bbdfSmrg    *bytes += size.pixmapRefSize;
37605b261ecSmrg}
37705b261ecSmrg
37805b261ecSmrgstatic void
37935c4bbdfSmrgResFindPixmaps(void *value, XID id, void *cdata)
38005b261ecSmrg{
38135c4bbdfSmrg    unsigned long *bytes = (unsigned long *) cdata;
38235c4bbdfSmrg    PixmapPtr pix = (PixmapPtr) value;
38305b261ecSmrg
38435c4bbdfSmrg    *bytes += ResGetApproxPixmapBytes(pix);
38535c4bbdfSmrg}
38605b261ecSmrg
38735c4bbdfSmrgstatic void
38835c4bbdfSmrgResFindWindowPixmaps(void *value, XID id, void *cdata)
38935c4bbdfSmrg{
39035c4bbdfSmrg    unsigned long *bytes = (unsigned long *) cdata;
39135c4bbdfSmrg    WindowPtr pWin = (WindowPtr) value;
39235c4bbdfSmrg
39335c4bbdfSmrg    if (pWin->backgroundState == BackgroundPixmap)
39435c4bbdfSmrg        *bytes += ResGetApproxPixmapBytes(pWin->background.pixmap);
39535c4bbdfSmrg
39635c4bbdfSmrg    if (pWin->border.pixmap != NULL && !pWin->borderIsPixel)
39735c4bbdfSmrg        *bytes += ResGetApproxPixmapBytes(pWin->border.pixmap);
39805b261ecSmrg}
39905b261ecSmrg
40005b261ecSmrgstatic void
40135c4bbdfSmrgResFindGCPixmaps(void *value, XID id, void *cdata)
40205b261ecSmrg{
40335c4bbdfSmrg    unsigned long *bytes = (unsigned long *) cdata;
40435c4bbdfSmrg    GCPtr pGC = (GCPtr) value;
40505b261ecSmrg
40635c4bbdfSmrg    if (pGC->stipple != NULL)
40735c4bbdfSmrg        *bytes += ResGetApproxPixmapBytes(pGC->stipple);
40805b261ecSmrg
40935c4bbdfSmrg    if (pGC->tile.pixmap != NULL && !pGC->tileIsPixel)
41035c4bbdfSmrg        *bytes += ResGetApproxPixmapBytes(pGC->tile.pixmap);
41135c4bbdfSmrg}
41235c4bbdfSmrg
41335c4bbdfSmrg#ifdef RENDER
41435c4bbdfSmrgstatic void
41535c4bbdfSmrgResFindPicturePixmaps(void *value, XID id, void *cdata)
41635c4bbdfSmrg{
41735c4bbdfSmrg    ResFindResourcePixmaps(value, id, PictureType, cdata);
41835c4bbdfSmrg}
41935c4bbdfSmrg#endif
42035c4bbdfSmrg
42135c4bbdfSmrg#ifdef COMPOSITE
42235c4bbdfSmrgstatic void
42335c4bbdfSmrgResFindCompositeClientWindowPixmaps (void *value, XID id, void *cdata)
42435c4bbdfSmrg{
42535c4bbdfSmrg    ResFindResourcePixmaps(value, id, CompositeClientWindowType, cdata);
42605b261ecSmrg}
42735c4bbdfSmrg#endif
42805b261ecSmrg
42905b261ecSmrgstatic int
43035c4bbdfSmrgProcXResQueryClientPixmapBytes(ClientPtr client)
43105b261ecSmrg{
43205b261ecSmrg    REQUEST(xXResQueryClientPixmapBytesReq);
43305b261ecSmrg    xXResQueryClientPixmapBytesReply rep;
43405b261ecSmrg    int clientID;
43505b261ecSmrg    unsigned long bytes;
43605b261ecSmrg
43705b261ecSmrg    REQUEST_SIZE_MATCH(xXResQueryClientPixmapBytesReq);
43805b261ecSmrg
43905b261ecSmrg    clientID = CLIENT_ID(stuff->xid);
44005b261ecSmrg
44135c4bbdfSmrg    if ((clientID >= currentMaxClients) || !clients[clientID]) {
44205b261ecSmrg        client->errorValue = stuff->xid;
44305b261ecSmrg        return BadValue;
44405b261ecSmrg    }
44505b261ecSmrg
44605b261ecSmrg    bytes = 0;
44705b261ecSmrg
44835c4bbdfSmrg    FindClientResourcesByType(clients[clientID], RT_PIXMAP, ResFindPixmaps,
44935c4bbdfSmrg                              (void *) (&bytes));
45005b261ecSmrg
45135c4bbdfSmrg    /*
45235c4bbdfSmrg     * Make sure win background pixmaps also held to account.
45305b261ecSmrg     */
45435c4bbdfSmrg    FindClientResourcesByType(clients[clientID], RT_WINDOW,
45535c4bbdfSmrg                              ResFindWindowPixmaps, (void *) (&bytes));
45605b261ecSmrg
45735c4bbdfSmrg    /*
45805b261ecSmrg     * GC Tile & Stipple pixmaps too.
45935c4bbdfSmrg     */
46035c4bbdfSmrg    FindClientResourcesByType(clients[clientID], RT_GC,
46135c4bbdfSmrg                              ResFindGCPixmaps, (void *) (&bytes));
46235c4bbdfSmrg
46335c4bbdfSmrg#ifdef RENDER
46435c4bbdfSmrg    /* Render extension picture pixmaps. */
46535c4bbdfSmrg    FindClientResourcesByType(clients[clientID], PictureType,
46635c4bbdfSmrg                              ResFindPicturePixmaps,
46735c4bbdfSmrg                              (void *)(&bytes));
46835c4bbdfSmrg#endif
46905b261ecSmrg
47005b261ecSmrg#ifdef COMPOSITE
47135c4bbdfSmrg    /* Composite extension client window pixmaps. */
47235c4bbdfSmrg    FindClientResourcesByType(clients[clientID], CompositeClientWindowType,
47335c4bbdfSmrg                              ResFindCompositeClientWindowPixmaps,
47435c4bbdfSmrg                              (void *)(&bytes));
47505b261ecSmrg#endif
47605b261ecSmrg
47735c4bbdfSmrg    rep = (xXResQueryClientPixmapBytesReply) {
47835c4bbdfSmrg        .type = X_Reply,
47935c4bbdfSmrg        .sequenceNumber = client->sequence,
48035c4bbdfSmrg        .length = 0,
48135c4bbdfSmrg        .bytes = bytes,
48205b261ecSmrg#ifdef _XSERVER64
48335c4bbdfSmrg        .bytes_overflow = bytes >> 32
48405b261ecSmrg#else
48535c4bbdfSmrg        .bytes_overflow = 0
48605b261ecSmrg#endif
48735c4bbdfSmrg    };
48805b261ecSmrg    if (client->swapped) {
48935c4bbdfSmrg        swaps(&rep.sequenceNumber);
49035c4bbdfSmrg        swapl(&rep.length);
49135c4bbdfSmrg        swapl(&rep.bytes);
49235c4bbdfSmrg        swapl(&rep.bytes_overflow);
49305b261ecSmrg    }
49435c4bbdfSmrg    WriteToClient(client, sizeof(xXResQueryClientPixmapBytesReply), &rep);
49505b261ecSmrg
4966747b715Smrg    return Success;
49705b261ecSmrg}
49805b261ecSmrg
49935c4bbdfSmrg/** @brief Finds out if a client's information need to be put into the
50035c4bbdfSmrg    response; marks client having been handled, if that is the case.
50135c4bbdfSmrg
50235c4bbdfSmrg    @param client   The client to send information about
50335c4bbdfSmrg    @param mask     The request mask (0 to send everything, otherwise a
50435c4bbdfSmrg                    bitmask of X_XRes*Mask)
50535c4bbdfSmrg    @param ctx      The context record that tells which clients and id types
50635c4bbdfSmrg                    have been already handled
50735c4bbdfSmrg    @param sendMask Which id type are we now considering. One of X_XRes*Mask.
50835c4bbdfSmrg
50935c4bbdfSmrg    @return Returns TRUE if the client information needs to be on the
51035c4bbdfSmrg            response, otherwise FALSE.
51135c4bbdfSmrg*/
51235c4bbdfSmrgstatic Bool
51335c4bbdfSmrgWillConstructMask(ClientPtr client, CARD32 mask,
51435c4bbdfSmrg                  ConstructClientIdCtx *ctx, int sendMask)
51535c4bbdfSmrg{
51635c4bbdfSmrg    if ((!mask || (mask & sendMask))
51735c4bbdfSmrg        && !(ctx->sentClientMasks[client->index] & sendMask)) {
51835c4bbdfSmrg        ctx->sentClientMasks[client->index] |= sendMask;
51935c4bbdfSmrg        return TRUE;
52035c4bbdfSmrg    } else {
52135c4bbdfSmrg        return FALSE;
52235c4bbdfSmrg    }
52335c4bbdfSmrg}
52435c4bbdfSmrg
52535c4bbdfSmrg/** @brief Constructs a response about a single client, based on a certain
52635c4bbdfSmrg           client id spec
52735c4bbdfSmrg
52835c4bbdfSmrg    @param sendClient Which client wishes to receive this answer. Used for
52935c4bbdfSmrg                      byte endianess.
53035c4bbdfSmrg    @param client     Which client are we considering.
53135c4bbdfSmrg    @param mask       The client id spec mask indicating which information
53235c4bbdfSmrg                      we want about this client.
53335c4bbdfSmrg    @param ctx        The context record containing the constructed response
53435c4bbdfSmrg                      and information on which clients and masks have been
53535c4bbdfSmrg                      already handled.
53635c4bbdfSmrg
53735c4bbdfSmrg    @return Return TRUE if everything went OK, otherwise FALSE which indicates
53835c4bbdfSmrg            a memory allocation problem.
53935c4bbdfSmrg*/
54035c4bbdfSmrgstatic Bool
54135c4bbdfSmrgConstructClientIdValue(ClientPtr sendClient, ClientPtr client, CARD32 mask,
54235c4bbdfSmrg                       ConstructClientIdCtx *ctx)
54335c4bbdfSmrg{
54435c4bbdfSmrg    xXResClientIdValue rep;
54535c4bbdfSmrg
54635c4bbdfSmrg    rep.spec.client = client->clientAsMask;
54735c4bbdfSmrg    if (client->swapped) {
54835c4bbdfSmrg        swapl (&rep.spec.client);
54935c4bbdfSmrg    }
55035c4bbdfSmrg
55135c4bbdfSmrg    if (WillConstructMask(client, mask, ctx, X_XResClientXIDMask)) {
55235c4bbdfSmrg        void *ptr = AddFragment(&ctx->response, sizeof(rep));
55335c4bbdfSmrg        if (!ptr) {
55435c4bbdfSmrg            return FALSE;
55535c4bbdfSmrg        }
55635c4bbdfSmrg
55735c4bbdfSmrg        rep.spec.mask = X_XResClientXIDMask;
55835c4bbdfSmrg        rep.length = 0;
55935c4bbdfSmrg        if (sendClient->swapped) {
56035c4bbdfSmrg            swapl (&rep.spec.mask);
56135c4bbdfSmrg            /* swapl (&rep.length, n); - not required for rep.length = 0 */
56235c4bbdfSmrg        }
56335c4bbdfSmrg
56435c4bbdfSmrg        memcpy(ptr, &rep, sizeof(rep));
56535c4bbdfSmrg
56635c4bbdfSmrg        ctx->resultBytes += sizeof(rep);
56735c4bbdfSmrg        ++ctx->numIds;
56835c4bbdfSmrg    }
56935c4bbdfSmrg    if (WillConstructMask(client, mask, ctx, X_XResLocalClientPIDMask)) {
57035c4bbdfSmrg        pid_t pid = GetClientPid(client);
57135c4bbdfSmrg
57235c4bbdfSmrg        if (pid != -1) {
57335c4bbdfSmrg            void *ptr = AddFragment(&ctx->response,
57435c4bbdfSmrg                                    sizeof(rep) + sizeof(CARD32));
57535c4bbdfSmrg            CARD32 *value = (void*) ((char*) ptr + sizeof(rep));
57635c4bbdfSmrg
57735c4bbdfSmrg            if (!ptr) {
57835c4bbdfSmrg                return FALSE;
57935c4bbdfSmrg            }
58035c4bbdfSmrg
58135c4bbdfSmrg            rep.spec.mask = X_XResLocalClientPIDMask;
58235c4bbdfSmrg            rep.length = 4;
58335c4bbdfSmrg
58435c4bbdfSmrg            if (sendClient->swapped) {
58535c4bbdfSmrg                swapl (&rep.spec.mask);
58635c4bbdfSmrg                swapl (&rep.length);
58735c4bbdfSmrg            }
58835c4bbdfSmrg
58935c4bbdfSmrg            if (sendClient->swapped) {
59035c4bbdfSmrg                swapl (value);
59135c4bbdfSmrg            }
59235c4bbdfSmrg            memcpy(ptr, &rep, sizeof(rep));
59335c4bbdfSmrg            *value = pid;
59435c4bbdfSmrg
59535c4bbdfSmrg            ctx->resultBytes += sizeof(rep) + sizeof(CARD32);
59635c4bbdfSmrg            ++ctx->numIds;
59735c4bbdfSmrg        }
59835c4bbdfSmrg    }
59935c4bbdfSmrg
60035c4bbdfSmrg    /* memory allocation errors earlier may return with FALSE */
60135c4bbdfSmrg    return TRUE;
60235c4bbdfSmrg}
60335c4bbdfSmrg
60435c4bbdfSmrg/** @brief Constructs a response about all clients, based on a client id specs
60535c4bbdfSmrg
60635c4bbdfSmrg    @param client   Which client which we are constructing the response for.
60735c4bbdfSmrg    @param numSpecs Number of client id specs in specs
60835c4bbdfSmrg    @param specs    Client id specs
60935c4bbdfSmrg
61035c4bbdfSmrg    @return Return Success if everything went OK, otherwise a Bad* (currently
61135c4bbdfSmrg            BadAlloc or BadValue)
61235c4bbdfSmrg*/
61335c4bbdfSmrgstatic int
61435c4bbdfSmrgConstructClientIds(ClientPtr client,
61535c4bbdfSmrg                   int numSpecs, xXResClientIdSpec* specs,
61635c4bbdfSmrg                   ConstructClientIdCtx *ctx)
61735c4bbdfSmrg{
61835c4bbdfSmrg    int specIdx;
61935c4bbdfSmrg
62035c4bbdfSmrg    for (specIdx = 0; specIdx < numSpecs; ++specIdx) {
62135c4bbdfSmrg        if (specs[specIdx].client == 0) {
62235c4bbdfSmrg            int c;
62335c4bbdfSmrg            for (c = 0; c < currentMaxClients; ++c) {
62435c4bbdfSmrg                if (clients[c]) {
62535c4bbdfSmrg                    if (!ConstructClientIdValue(client, clients[c],
62635c4bbdfSmrg                                                specs[specIdx].mask, ctx)) {
62735c4bbdfSmrg                        return BadAlloc;
62835c4bbdfSmrg                    }
62935c4bbdfSmrg                }
63035c4bbdfSmrg            }
63135c4bbdfSmrg        } else {
63235c4bbdfSmrg            int clientID = CLIENT_ID(specs[specIdx].client);
63335c4bbdfSmrg
63435c4bbdfSmrg            if ((clientID < currentMaxClients) && clients[clientID]) {
63535c4bbdfSmrg                if (!ConstructClientIdValue(client, clients[clientID],
63635c4bbdfSmrg                                            specs[specIdx].mask, ctx)) {
63735c4bbdfSmrg                    return BadAlloc;
63835c4bbdfSmrg                }
63935c4bbdfSmrg            }
64035c4bbdfSmrg        }
64135c4bbdfSmrg    }
64235c4bbdfSmrg
64335c4bbdfSmrg    /* memory allocation errors earlier may return with BadAlloc */
64435c4bbdfSmrg    return Success;
64535c4bbdfSmrg}
64635c4bbdfSmrg
64735c4bbdfSmrg/** @brief Response to XResQueryClientIds request introduced in XResProto v1.2
64835c4bbdfSmrg
64935c4bbdfSmrg    @param client Which client which we are constructing the response for.
65035c4bbdfSmrg
65135c4bbdfSmrg    @return Returns the value returned from ConstructClientIds with the same
65235c4bbdfSmrg            semantics
65335c4bbdfSmrg*/
65435c4bbdfSmrgstatic int
65535c4bbdfSmrgProcXResQueryClientIds (ClientPtr client)
65635c4bbdfSmrg{
65735c4bbdfSmrg    REQUEST(xXResQueryClientIdsReq);
65835c4bbdfSmrg
65935c4bbdfSmrg    xXResClientIdSpec        *specs = (void*) ((char*) stuff + sizeof(*stuff));
66035c4bbdfSmrg    int                       rc;
66135c4bbdfSmrg    ConstructClientIdCtx      ctx;
66235c4bbdfSmrg
66335c4bbdfSmrg    InitConstructClientIdCtx(&ctx);
66435c4bbdfSmrg
66535c4bbdfSmrg    REQUEST_AT_LEAST_SIZE(xXResQueryClientIdsReq);
66635c4bbdfSmrg    REQUEST_FIXED_SIZE(xXResQueryClientIdsReq,
66735c4bbdfSmrg                       stuff->numSpecs * sizeof(specs[0]));
66835c4bbdfSmrg
66935c4bbdfSmrg    rc = ConstructClientIds(client, stuff->numSpecs, specs, &ctx);
67035c4bbdfSmrg
67135c4bbdfSmrg    if (rc == Success) {
67235c4bbdfSmrg        xXResQueryClientIdsReply  rep = {
67335c4bbdfSmrg            .type = X_Reply,
67435c4bbdfSmrg            .sequenceNumber = client->sequence,
67535c4bbdfSmrg            .length = bytes_to_int32(ctx.resultBytes),
67635c4bbdfSmrg            .numIds = ctx.numIds
67735c4bbdfSmrg        };
67835c4bbdfSmrg
67935c4bbdfSmrg        assert((ctx.resultBytes & 3) == 0);
68035c4bbdfSmrg
68135c4bbdfSmrg        if (client->swapped) {
68235c4bbdfSmrg            swaps (&rep.sequenceNumber);
68335c4bbdfSmrg            swapl (&rep.length);
68435c4bbdfSmrg            swapl (&rep.numIds);
68535c4bbdfSmrg        }
68635c4bbdfSmrg
68735c4bbdfSmrg        WriteToClient(client, sizeof(rep), &rep);
68835c4bbdfSmrg        WriteFragmentsToClient(client, &ctx.response);
68935c4bbdfSmrg    }
69035c4bbdfSmrg
69135c4bbdfSmrg    DestroyConstructClientIdCtx(&ctx);
69235c4bbdfSmrg
69335c4bbdfSmrg    return rc;
69435c4bbdfSmrg}
69535c4bbdfSmrg
69635c4bbdfSmrg/** @brief Swaps xXResResourceIdSpec endianess */
69735c4bbdfSmrgstatic void
69835c4bbdfSmrgSwapXResResourceIdSpec(xXResResourceIdSpec *spec)
69935c4bbdfSmrg{
70035c4bbdfSmrg    swapl(&spec->resource);
70135c4bbdfSmrg    swapl(&spec->type);
70235c4bbdfSmrg}
70335c4bbdfSmrg
70435c4bbdfSmrg/** @brief Swaps xXResResourceSizeSpec endianess */
70535c4bbdfSmrgstatic void
70635c4bbdfSmrgSwapXResResourceSizeSpec(xXResResourceSizeSpec *size)
70735c4bbdfSmrg{
70835c4bbdfSmrg    SwapXResResourceIdSpec(&size->spec);
70935c4bbdfSmrg    swapl(&size->bytes);
71035c4bbdfSmrg    swapl(&size->refCount);
71135c4bbdfSmrg    swapl(&size->useCount);
71235c4bbdfSmrg}
71335c4bbdfSmrg
71435c4bbdfSmrg/** @brief Swaps xXResResourceSizeValue endianess */
71535c4bbdfSmrgstatic void
71635c4bbdfSmrgSwapXResResourceSizeValue(xXResResourceSizeValue *rep)
71735c4bbdfSmrg{
71835c4bbdfSmrg    SwapXResResourceSizeSpec(&rep->size);
71935c4bbdfSmrg    swapl(&rep->numCrossReferences);
72035c4bbdfSmrg}
72135c4bbdfSmrg
72235c4bbdfSmrg/** @brief Swaps the response bytes */
72335c4bbdfSmrgstatic void
72435c4bbdfSmrgSwapXResQueryResourceBytes(struct xorg_list *response)
72535c4bbdfSmrg{
72635c4bbdfSmrg    struct xorg_list *it = response->next;
72735c4bbdfSmrg    int c;
72835c4bbdfSmrg
72935c4bbdfSmrg    while (it != response) {
73035c4bbdfSmrg        xXResResourceSizeValue *value = FRAGMENT_DATA(it);
73135c4bbdfSmrg        it = it->next;
73235c4bbdfSmrg        for (c = 0; c < value->numCrossReferences; ++c) {
73335c4bbdfSmrg            xXResResourceSizeSpec *spec = FRAGMENT_DATA(it);
73435c4bbdfSmrg            SwapXResResourceSizeSpec(spec);
73535c4bbdfSmrg            it = it->next;
73635c4bbdfSmrg        }
73735c4bbdfSmrg        SwapXResResourceSizeValue(value);
73835c4bbdfSmrg    }
73935c4bbdfSmrg}
74035c4bbdfSmrg
74135c4bbdfSmrg/** @brief Adds xXResResourceSizeSpec describing a resource's size into
74235c4bbdfSmrg           the buffer contained in the context. The resource is considered
74335c4bbdfSmrg           to be a subresource.
74435c4bbdfSmrg
74535c4bbdfSmrg   @see AddResourceSizeValue
74635c4bbdfSmrg
74735c4bbdfSmrg   @param[in] value     The X resource object on which to add information
74835c4bbdfSmrg                        about to the buffer
74935c4bbdfSmrg   @param[in] id        The ID of the X resource
75035c4bbdfSmrg   @param[in] type      The type of the X resource
75135c4bbdfSmrg   @param[in/out] cdata The context object of type ConstructResourceBytesCtx.
75235c4bbdfSmrg                        Void pointer type is used here to satisfy the type
75335c4bbdfSmrg                        FindRes
75435c4bbdfSmrg*/
75535c4bbdfSmrgstatic void
75635c4bbdfSmrgAddSubResourceSizeSpec(void *value,
75735c4bbdfSmrg                       XID id,
75835c4bbdfSmrg                       RESTYPE type,
75935c4bbdfSmrg                       void *cdata)
76035c4bbdfSmrg{
76135c4bbdfSmrg    ConstructResourceBytesCtx *ctx = cdata;
76235c4bbdfSmrg
76335c4bbdfSmrg    if (ctx->status == Success) {
76435c4bbdfSmrg        xXResResourceSizeSpec **prevCrossRef =
76535c4bbdfSmrg          ht_find(ctx->visitedSubResources, &value);
76635c4bbdfSmrg        if (!prevCrossRef) {
76735c4bbdfSmrg            Bool ok = TRUE;
76835c4bbdfSmrg            xXResResourceSizeSpec *crossRef =
76935c4bbdfSmrg                AddFragment(&ctx->response, sizeof(xXResResourceSizeSpec));
77035c4bbdfSmrg            ok = ok && crossRef != NULL;
77135c4bbdfSmrg            if (ok) {
77235c4bbdfSmrg                xXResResourceSizeSpec **p;
77335c4bbdfSmrg                p = ht_add(ctx->visitedSubResources, &value);
77435c4bbdfSmrg                if (!p) {
77535c4bbdfSmrg                    ok = FALSE;
77635c4bbdfSmrg                } else {
77735c4bbdfSmrg                    *p = crossRef;
77835c4bbdfSmrg                }
77935c4bbdfSmrg            }
78035c4bbdfSmrg            if (!ok) {
78135c4bbdfSmrg                ctx->status = BadAlloc;
78235c4bbdfSmrg            } else {
78335c4bbdfSmrg                SizeType sizeFunc = GetResourceTypeSizeFunc(type);
78435c4bbdfSmrg                ResourceSizeRec size = { 0, 0, 0 };
78535c4bbdfSmrg                sizeFunc(value, id, &size);
78635c4bbdfSmrg
78735c4bbdfSmrg                crossRef->spec.resource = id;
78835c4bbdfSmrg                crossRef->spec.type = type;
78935c4bbdfSmrg                crossRef->bytes = size.resourceSize;
79035c4bbdfSmrg                crossRef->refCount = size.refCnt;
79135c4bbdfSmrg                crossRef->useCount = 1;
79235c4bbdfSmrg
79335c4bbdfSmrg                ++ctx->sizeValue->numCrossReferences;
79435c4bbdfSmrg
79535c4bbdfSmrg                ctx->resultBytes += sizeof(*crossRef);
79635c4bbdfSmrg            }
79735c4bbdfSmrg        } else {
79835c4bbdfSmrg            /* if we have visited the subresource earlier (from current parent
79935c4bbdfSmrg               resource), just increase its use count by one */
80035c4bbdfSmrg            ++(*prevCrossRef)->useCount;
80135c4bbdfSmrg        }
80235c4bbdfSmrg    }
80335c4bbdfSmrg}
80435c4bbdfSmrg
80535c4bbdfSmrg/** @brief Adds xXResResourceSizeValue describing a resource's size into
80635c4bbdfSmrg           the buffer contained in the context. In addition, the
80735c4bbdfSmrg           subresources are iterated and added as xXResResourceSizeSpec's
80835c4bbdfSmrg           by using AddSubResourceSizeSpec
80935c4bbdfSmrg
81035c4bbdfSmrg   @see AddSubResourceSizeSpec
81135c4bbdfSmrg
81235c4bbdfSmrg   @param[in] value     The X resource object on which to add information
81335c4bbdfSmrg                        about to the buffer
81435c4bbdfSmrg   @param[in] id        The ID of the X resource
81535c4bbdfSmrg   @param[in] type      The type of the X resource
81635c4bbdfSmrg   @param[in/out] cdata The context object of type ConstructResourceBytesCtx.
81735c4bbdfSmrg                        Void pointer type is used here to satisfy the type
81835c4bbdfSmrg                        FindRes
81935c4bbdfSmrg*/
82035c4bbdfSmrgstatic void
82135c4bbdfSmrgAddResourceSizeValue(void *ptr, XID id, RESTYPE type, void *cdata)
82235c4bbdfSmrg{
82335c4bbdfSmrg    ConstructResourceBytesCtx *ctx = cdata;
82435c4bbdfSmrg    if (ctx->status == Success &&
82535c4bbdfSmrg        !ht_find(ctx->visitedResources, &id)) {
82635c4bbdfSmrg        Bool ok = TRUE;
82735c4bbdfSmrg        HashTable ht;
82835c4bbdfSmrg        HtGenericHashSetupRec htSetup = {
82935c4bbdfSmrg            .keySize = sizeof(void*)
83035c4bbdfSmrg        };
83135c4bbdfSmrg
83235c4bbdfSmrg        /* it doesn't matter that we don't undo the work done here
83335c4bbdfSmrg         * immediately. All but ht_init will be undone at the end
83435c4bbdfSmrg         * of the request and there can happen no failure after
83535c4bbdfSmrg         * ht_init, so we don't need to clean it up here in any
83635c4bbdfSmrg         * special way */
83735c4bbdfSmrg
83835c4bbdfSmrg        xXResResourceSizeValue *value =
83935c4bbdfSmrg            AddFragment(&ctx->response, sizeof(xXResResourceSizeValue));
84035c4bbdfSmrg        if (!value) {
84135c4bbdfSmrg            ok = FALSE;
84235c4bbdfSmrg        }
84335c4bbdfSmrg        ok = ok && ht_add(ctx->visitedResources, &id);
84435c4bbdfSmrg        if (ok) {
84535c4bbdfSmrg            ht = ht_create(htSetup.keySize,
84635c4bbdfSmrg                           sizeof(xXResResourceSizeSpec*),
84735c4bbdfSmrg                           ht_generic_hash, ht_generic_compare,
84835c4bbdfSmrg                           &htSetup);
84935c4bbdfSmrg            ok = ok && ht;
85035c4bbdfSmrg        }
85135c4bbdfSmrg
85235c4bbdfSmrg        if (!ok) {
85335c4bbdfSmrg            ctx->status = BadAlloc;
85435c4bbdfSmrg        } else {
85535c4bbdfSmrg            SizeType sizeFunc = GetResourceTypeSizeFunc(type);
85635c4bbdfSmrg            ResourceSizeRec size = { 0, 0, 0 };
85735c4bbdfSmrg
85835c4bbdfSmrg            sizeFunc(ptr, id, &size);
85935c4bbdfSmrg
86035c4bbdfSmrg            value->size.spec.resource = id;
86135c4bbdfSmrg            value->size.spec.type = type;
86235c4bbdfSmrg            value->size.bytes = size.resourceSize;
86335c4bbdfSmrg            value->size.refCount = size.refCnt;
86435c4bbdfSmrg            value->size.useCount = 1;
86535c4bbdfSmrg            value->numCrossReferences = 0;
86635c4bbdfSmrg
86735c4bbdfSmrg            ctx->sizeValue = value;
86835c4bbdfSmrg            ctx->visitedSubResources = ht;
86935c4bbdfSmrg            FindSubResources(ptr, type, AddSubResourceSizeSpec, ctx);
87035c4bbdfSmrg            ctx->visitedSubResources = NULL;
87135c4bbdfSmrg            ctx->sizeValue = NULL;
87235c4bbdfSmrg
87335c4bbdfSmrg            ctx->resultBytes += sizeof(*value);
87435c4bbdfSmrg            ++ctx->numSizes;
87535c4bbdfSmrg
87635c4bbdfSmrg            ht_destroy(ht);
87735c4bbdfSmrg        }
87835c4bbdfSmrg    }
87935c4bbdfSmrg}
88035c4bbdfSmrg
88135c4bbdfSmrg/** @brief A variant of AddResourceSizeValue that passes the resource type
88235c4bbdfSmrg           through the context object to satisfy the type FindResType
88335c4bbdfSmrg
88435c4bbdfSmrg   @see AddResourceSizeValue
88535c4bbdfSmrg
88635c4bbdfSmrg   @param[in] ptr        The resource
88735c4bbdfSmrg   @param[in] id         The resource ID
88835c4bbdfSmrg   @param[in/out] cdata  The context object that contains the resource type
88935c4bbdfSmrg*/
89035c4bbdfSmrgstatic void
89135c4bbdfSmrgAddResourceSizeValueWithResType(void *ptr, XID id, void *cdata)
89235c4bbdfSmrg{
89335c4bbdfSmrg    ConstructResourceBytesCtx *ctx = cdata;
89435c4bbdfSmrg    AddResourceSizeValue(ptr, id, ctx->resType, cdata);
89535c4bbdfSmrg}
89635c4bbdfSmrg
89735c4bbdfSmrg/** @brief Adds the information of a resource into the buffer if it matches
89835c4bbdfSmrg           the match condition.
89935c4bbdfSmrg
90035c4bbdfSmrg   @see AddResourceSizeValue
90135c4bbdfSmrg
90235c4bbdfSmrg   @param[in] ptr        The resource
90335c4bbdfSmrg   @param[in] id         The resource ID
90435c4bbdfSmrg   @param[in] type       The resource type
90535c4bbdfSmrg   @param[in/out] cdata  The context object as a void pointer to satisfy the
90635c4bbdfSmrg                         type FindAllRes
90735c4bbdfSmrg*/
90835c4bbdfSmrgstatic void
90935c4bbdfSmrgAddResourceSizeValueByResource(void *ptr, XID id, RESTYPE type, void *cdata)
91035c4bbdfSmrg{
91135c4bbdfSmrg    ConstructResourceBytesCtx *ctx = cdata;
91235c4bbdfSmrg    xXResResourceIdSpec *spec = ctx->curSpec;
91335c4bbdfSmrg
91435c4bbdfSmrg    if ((!spec->type || spec->type == type) &&
91535c4bbdfSmrg        (!spec->resource || spec->resource == id)) {
91635c4bbdfSmrg        AddResourceSizeValue(ptr, id, type, ctx);
91735c4bbdfSmrg    }
91835c4bbdfSmrg}
91935c4bbdfSmrg
92035c4bbdfSmrg/** @brief Add all resources of the client into the result buffer
92135c4bbdfSmrg           disregarding all those specifications that specify the
92235c4bbdfSmrg           resource by its ID. Those are handled by
92335c4bbdfSmrg           ConstructResourceBytesByResource
92435c4bbdfSmrg
92535c4bbdfSmrg   @see ConstructResourceBytesByResource
92635c4bbdfSmrg
92735c4bbdfSmrg   @param[in] aboutClient  Which client is being considered
92835c4bbdfSmrg   @param[in/out] ctx      The context that contains the resource id
92935c4bbdfSmrg                           specifications as well as the result buffer
93035c4bbdfSmrg*/
93135c4bbdfSmrgstatic void
93235c4bbdfSmrgConstructClientResourceBytes(ClientPtr aboutClient,
93335c4bbdfSmrg                             ConstructResourceBytesCtx *ctx)
93435c4bbdfSmrg{
93535c4bbdfSmrg    int specIdx;
93635c4bbdfSmrg    for (specIdx = 0; specIdx < ctx->numSpecs; ++specIdx) {
93735c4bbdfSmrg        xXResResourceIdSpec* spec = ctx->specs + specIdx;
93835c4bbdfSmrg        if (spec->resource) {
93935c4bbdfSmrg            /* these specs are handled elsewhere */
94035c4bbdfSmrg        } else if (spec->type) {
94135c4bbdfSmrg            ctx->resType = spec->type;
94235c4bbdfSmrg            FindClientResourcesByType(aboutClient, spec->type,
94335c4bbdfSmrg                                      AddResourceSizeValueWithResType, ctx);
94435c4bbdfSmrg        } else {
94535c4bbdfSmrg            FindAllClientResources(aboutClient, AddResourceSizeValue, ctx);
94635c4bbdfSmrg        }
94735c4bbdfSmrg    }
94835c4bbdfSmrg}
94935c4bbdfSmrg
95035c4bbdfSmrg/** @brief Add the sizes of all such resources that can are specified by
95135c4bbdfSmrg           their ID in the resource id specification. The scan can
95235c4bbdfSmrg           by limited to a client with the aboutClient parameter
95335c4bbdfSmrg
95435c4bbdfSmrg   @see ConstructResourceBytesByResource
95535c4bbdfSmrg
95635c4bbdfSmrg   @param[in] aboutClient  Which client is being considered. This may be None
95735c4bbdfSmrg                           to mean all clients.
95835c4bbdfSmrg   @param[in/out] ctx      The context that contains the resource id
95935c4bbdfSmrg                           specifications as well as the result buffer. In
96035c4bbdfSmrg                           addition this function uses the curSpec field to
96135c4bbdfSmrg                           keep a pointer to the current resource id
96235c4bbdfSmrg                           specification in it, which can be used by
96335c4bbdfSmrg                           AddResourceSizeValueByResource .
96435c4bbdfSmrg*/
96535c4bbdfSmrgstatic void
96635c4bbdfSmrgConstructResourceBytesByResource(XID aboutClient, ConstructResourceBytesCtx *ctx)
96735c4bbdfSmrg{
96835c4bbdfSmrg    int specIdx;
96935c4bbdfSmrg    for (specIdx = 0; specIdx < ctx->numSpecs; ++specIdx) {
97035c4bbdfSmrg        xXResResourceIdSpec *spec = ctx->specs + specIdx;
97135c4bbdfSmrg        if (spec->resource) {
97235c4bbdfSmrg            int cid = CLIENT_ID(spec->resource);
97335c4bbdfSmrg            if (cid < currentMaxClients &&
97435c4bbdfSmrg                (aboutClient == None || cid == aboutClient)) {
97535c4bbdfSmrg                ClientPtr client = clients[cid];
97635c4bbdfSmrg                if (client) {
97735c4bbdfSmrg                    ctx->curSpec = spec;
97835c4bbdfSmrg                    FindAllClientResources(client,
97935c4bbdfSmrg                                           AddResourceSizeValueByResource,
98035c4bbdfSmrg                                           ctx);
98135c4bbdfSmrg                }
98235c4bbdfSmrg            }
98335c4bbdfSmrg        }
98435c4bbdfSmrg    }
98535c4bbdfSmrg}
98635c4bbdfSmrg
98735c4bbdfSmrg/** @brief Build the resource size response for the given client
98835c4bbdfSmrg           (or all if not specified) per the parameters set up
98935c4bbdfSmrg           in the context object.
99035c4bbdfSmrg
99135c4bbdfSmrg  @param[in] aboutClient  Which client to consider or None for all clients
99235c4bbdfSmrg  @param[in/out] ctx      The context object that contains the request as well
99335c4bbdfSmrg                          as the response buffer.
99435c4bbdfSmrg*/
99505b261ecSmrgstatic int
99635c4bbdfSmrgConstructResourceBytes(XID aboutClient,
99735c4bbdfSmrg                       ConstructResourceBytesCtx *ctx)
99835c4bbdfSmrg{
99935c4bbdfSmrg    if (aboutClient) {
100035c4bbdfSmrg        int clientIdx = CLIENT_ID(aboutClient);
100135c4bbdfSmrg        ClientPtr client = NullClient;
100235c4bbdfSmrg
100335c4bbdfSmrg        if ((clientIdx >= currentMaxClients) || !clients[clientIdx]) {
100435c4bbdfSmrg            ctx->sendClient->errorValue = aboutClient;
100535c4bbdfSmrg            return BadValue;
100635c4bbdfSmrg        }
100735c4bbdfSmrg
100835c4bbdfSmrg        client = clients[clientIdx];
100935c4bbdfSmrg
101035c4bbdfSmrg        ConstructClientResourceBytes(client, ctx);
101135c4bbdfSmrg        ConstructResourceBytesByResource(aboutClient, ctx);
101235c4bbdfSmrg    } else {
101335c4bbdfSmrg        int clientIdx;
101435c4bbdfSmrg
101535c4bbdfSmrg        ConstructClientResourceBytes(NULL, ctx);
101635c4bbdfSmrg
101735c4bbdfSmrg        for (clientIdx = 0; clientIdx < currentMaxClients; ++clientIdx) {
101835c4bbdfSmrg            ClientPtr client = clients[clientIdx];
101935c4bbdfSmrg
102035c4bbdfSmrg            if (client) {
102135c4bbdfSmrg                ConstructClientResourceBytes(client, ctx);
102235c4bbdfSmrg            }
102335c4bbdfSmrg        }
102435c4bbdfSmrg
102535c4bbdfSmrg        ConstructResourceBytesByResource(None, ctx);
102635c4bbdfSmrg    }
102735c4bbdfSmrg
102835c4bbdfSmrg
102935c4bbdfSmrg    return ctx->status;
103035c4bbdfSmrg}
103135c4bbdfSmrg
103235c4bbdfSmrg/** @brief Implements the XResQueryResourceBytes of XResProto v1.2 */
103335c4bbdfSmrgstatic int
103435c4bbdfSmrgProcXResQueryResourceBytes (ClientPtr client)
103535c4bbdfSmrg{
103635c4bbdfSmrg    REQUEST(xXResQueryResourceBytesReq);
103735c4bbdfSmrg
103835c4bbdfSmrg    int                          rc;
103935c4bbdfSmrg    ConstructResourceBytesCtx    ctx;
104035c4bbdfSmrg
104135c4bbdfSmrg    REQUEST_AT_LEAST_SIZE(xXResQueryResourceBytesReq);
10426e78d31fSmrg    if (stuff->numSpecs > UINT32_MAX / sizeof(ctx.specs[0]))
10436e78d31fSmrg        return BadLength;
104435c4bbdfSmrg    REQUEST_FIXED_SIZE(xXResQueryResourceBytesReq,
104535c4bbdfSmrg                       stuff->numSpecs * sizeof(ctx.specs[0]));
104635c4bbdfSmrg
104735c4bbdfSmrg    if (!InitConstructResourceBytesCtx(&ctx, client,
104835c4bbdfSmrg                                       stuff->numSpecs,
104935c4bbdfSmrg                                       (void*) ((char*) stuff +
105035c4bbdfSmrg                                                sz_xXResQueryResourceBytesReq))) {
105135c4bbdfSmrg        return BadAlloc;
105235c4bbdfSmrg    }
105335c4bbdfSmrg
105435c4bbdfSmrg    rc = ConstructResourceBytes(stuff->client, &ctx);
105535c4bbdfSmrg
105635c4bbdfSmrg    if (rc == Success) {
105735c4bbdfSmrg        xXResQueryResourceBytesReply rep = {
105835c4bbdfSmrg            .type = X_Reply,
105935c4bbdfSmrg            .sequenceNumber = client->sequence,
106035c4bbdfSmrg            .length = bytes_to_int32(ctx.resultBytes),
106135c4bbdfSmrg            .numSizes = ctx.numSizes
106235c4bbdfSmrg        };
106335c4bbdfSmrg
106435c4bbdfSmrg        if (client->swapped) {
106535c4bbdfSmrg            swaps (&rep.sequenceNumber);
106635c4bbdfSmrg            swapl (&rep.length);
106735c4bbdfSmrg            swapl (&rep.numSizes);
106835c4bbdfSmrg
106935c4bbdfSmrg            SwapXResQueryResourceBytes(&ctx.response);
107035c4bbdfSmrg        }
107135c4bbdfSmrg
107235c4bbdfSmrg        WriteToClient(client, sizeof(rep), &rep);
107335c4bbdfSmrg        WriteFragmentsToClient(client, &ctx.response);
107435c4bbdfSmrg    }
107535c4bbdfSmrg
107635c4bbdfSmrg    DestroyConstructResourceBytesCtx(&ctx);
107735c4bbdfSmrg
107835c4bbdfSmrg    return rc;
107935c4bbdfSmrg}
108035c4bbdfSmrg
108135c4bbdfSmrgstatic int
108235c4bbdfSmrgProcResDispatch(ClientPtr client)
108305b261ecSmrg{
108405b261ecSmrg    REQUEST(xReq);
108505b261ecSmrg    switch (stuff->data) {
108605b261ecSmrg    case X_XResQueryVersion:
108705b261ecSmrg        return ProcXResQueryVersion(client);
108805b261ecSmrg    case X_XResQueryClients:
108905b261ecSmrg        return ProcXResQueryClients(client);
109005b261ecSmrg    case X_XResQueryClientResources:
109105b261ecSmrg        return ProcXResQueryClientResources(client);
109205b261ecSmrg    case X_XResQueryClientPixmapBytes:
109305b261ecSmrg        return ProcXResQueryClientPixmapBytes(client);
109435c4bbdfSmrg    case X_XResQueryClientIds:
109535c4bbdfSmrg        return ProcXResQueryClientIds(client);
109635c4bbdfSmrg    case X_XResQueryResourceBytes:
109735c4bbdfSmrg        return ProcXResQueryResourceBytes(client);
109805b261ecSmrg    default: break;
109905b261ecSmrg    }
110005b261ecSmrg
110105b261ecSmrg    return BadRequest;
110205b261ecSmrg}
110305b261ecSmrg
110405b261ecSmrgstatic int
110535c4bbdfSmrgSProcXResQueryVersion(ClientPtr client)
110605b261ecSmrg{
110735c4bbdfSmrg    REQUEST_SIZE_MATCH(xXResQueryVersionReq);
110805b261ecSmrg    return ProcXResQueryVersion(client);
110905b261ecSmrg}
111005b261ecSmrg
111105b261ecSmrgstatic int
111235c4bbdfSmrgSProcXResQueryClientResources(ClientPtr client)
111305b261ecSmrg{
111405b261ecSmrg    REQUEST(xXResQueryClientResourcesReq);
111535c4bbdfSmrg    REQUEST_SIZE_MATCH(xXResQueryClientResourcesReq);
111635c4bbdfSmrg    swapl(&stuff->xid);
111705b261ecSmrg    return ProcXResQueryClientResources(client);
111805b261ecSmrg}
111905b261ecSmrg
112005b261ecSmrgstatic int
112135c4bbdfSmrgSProcXResQueryClientPixmapBytes(ClientPtr client)
112205b261ecSmrg{
112305b261ecSmrg    REQUEST(xXResQueryClientPixmapBytesReq);
112435c4bbdfSmrg    REQUEST_SIZE_MATCH(xXResQueryClientPixmapBytesReq);
112535c4bbdfSmrg    swapl(&stuff->xid);
112605b261ecSmrg    return ProcXResQueryClientPixmapBytes(client);
112705b261ecSmrg}
112805b261ecSmrg
112935c4bbdfSmrgstatic int
113035c4bbdfSmrgSProcXResQueryClientIds (ClientPtr client)
113135c4bbdfSmrg{
113235c4bbdfSmrg    REQUEST(xXResQueryClientIdsReq);
113335c4bbdfSmrg
113435c4bbdfSmrg    REQUEST_AT_LEAST_SIZE (xXResQueryClientIdsReq);
113535c4bbdfSmrg    swapl(&stuff->numSpecs);
113635c4bbdfSmrg    return ProcXResQueryClientIds(client);
113735c4bbdfSmrg}
113835c4bbdfSmrg
113935c4bbdfSmrg/** @brief Implements the XResQueryResourceBytes of XResProto v1.2.
114035c4bbdfSmrg    This variant byteswaps request contents before issuing the
114135c4bbdfSmrg    rest of the work to ProcXResQueryResourceBytes */
114235c4bbdfSmrgstatic int
114335c4bbdfSmrgSProcXResQueryResourceBytes (ClientPtr client)
114435c4bbdfSmrg{
114535c4bbdfSmrg    REQUEST(xXResQueryResourceBytesReq);
114635c4bbdfSmrg    int c;
114735c4bbdfSmrg    xXResResourceIdSpec *specs = (void*) ((char*) stuff + sizeof(*stuff));
114835c4bbdfSmrg
114935c4bbdfSmrg    REQUEST_AT_LEAST_SIZE(xXResQueryResourceBytesReq);
11506e78d31fSmrg    swapl(&stuff->numSpecs);
115135c4bbdfSmrg    REQUEST_FIXED_SIZE(xXResQueryResourceBytesReq,
115235c4bbdfSmrg                       stuff->numSpecs * sizeof(specs[0]));
115335c4bbdfSmrg
115435c4bbdfSmrg    for (c = 0; c < stuff->numSpecs; ++c) {
115535c4bbdfSmrg        SwapXResResourceIdSpec(specs + c);
115635c4bbdfSmrg    }
115735c4bbdfSmrg
115835c4bbdfSmrg    return ProcXResQueryResourceBytes(client);
115935c4bbdfSmrg}
116035c4bbdfSmrg
116105b261ecSmrgstatic int
116205b261ecSmrgSProcResDispatch (ClientPtr client)
116305b261ecSmrg{
116405b261ecSmrg    REQUEST(xReq);
116535c4bbdfSmrg    swaps(&stuff->length);
116605b261ecSmrg
116705b261ecSmrg    switch (stuff->data) {
116805b261ecSmrg    case X_XResQueryVersion:
116905b261ecSmrg        return SProcXResQueryVersion(client);
117035c4bbdfSmrg    case X_XResQueryClients:   /* nothing to swap */
117105b261ecSmrg        return ProcXResQueryClients(client);
117205b261ecSmrg    case X_XResQueryClientResources:
117305b261ecSmrg        return SProcXResQueryClientResources(client);
117405b261ecSmrg    case X_XResQueryClientPixmapBytes:
117505b261ecSmrg        return SProcXResQueryClientPixmapBytes(client);
117635c4bbdfSmrg    case X_XResQueryClientIds:
117735c4bbdfSmrg        return SProcXResQueryClientIds(client);
117835c4bbdfSmrg    case X_XResQueryResourceBytes:
117935c4bbdfSmrg        return SProcXResQueryResourceBytes(client);
118005b261ecSmrg    default: break;
118105b261ecSmrg    }
118205b261ecSmrg
118305b261ecSmrg    return BadRequest;
118405b261ecSmrg}
118505b261ecSmrg
118605b261ecSmrgvoid
118735c4bbdfSmrgResExtensionInit(void)
118805b261ecSmrg{
118905b261ecSmrg    (void) AddExtension(XRES_NAME, 0, 0,
119035c4bbdfSmrg                        ProcResDispatch, SProcResDispatch,
119135c4bbdfSmrg                        NULL, StandardMinorOpcode);
119205b261ecSmrg}
1193