XRes.c revision 7bf574cc
1/*
2   Copyright (c) 2002  XFree86 Inc
3*/
4
5#ifdef HAVE_CONFIG_H
6#include <config.h>
7#endif
8#include <stdlib.h>
9#include <X11/Xlibint.h>
10#include <X11/Xutil.h>
11#include <X11/extensions/Xext.h>
12#include <X11/extensions/extutil.h>
13#include <X11/extensions/XResproto.h>
14#include <X11/extensions/XRes.h>
15#include <assert.h>
16#include <limits.h>
17
18static XExtensionInfo _xres_ext_info_data;
19static XExtensionInfo *xres_ext_info = &_xres_ext_info_data;
20static const char *xres_extension_name = XRES_NAME;
21
22#define XResCheckExtension(dpy,i,val) \
23  XextCheckExtension (dpy, i, xres_extension_name, val)
24
25static XEXT_GENERATE_CLOSE_DISPLAY(close_display, xres_ext_info)
26
27static XExtensionHooks xres_extension_hooks = {
28    NULL,                       /* create_gc */
29    NULL,                       /* copy_gc */
30    NULL,                       /* flush_gc */
31    NULL,                       /* free_gc */
32    NULL,                       /* create_font */
33    NULL,                       /* free_font */
34    close_display,              /* close_display */
35    NULL,                       /* wire_to_event */
36    NULL,                       /* event_to_wire */
37    NULL,                       /* error */
38    NULL,                       /* error_string */
39};
40
41static
42XEXT_GENERATE_FIND_DISPLAY(find_display, xres_ext_info, xres_extension_name,
43                           &xres_extension_hooks, 0, NULL)
44
45Bool
46XResQueryExtension(Display *dpy,
47                   int *event_base_return, int *error_base_return)
48{
49    XExtDisplayInfo *info = find_display(dpy);
50
51    if (XextHasExtension(info)) {
52        *event_base_return = info->codes->first_event;
53        *error_base_return = info->codes->first_error;
54        return True;
55    }
56    else {
57        return False;
58    }
59}
60
61Status
62XResQueryVersion(Display *dpy,
63                 int *major_version_return, int *minor_version_return)
64{
65    XExtDisplayInfo *info = find_display(dpy);
66    xXResQueryVersionReply rep;
67    xXResQueryVersionReq *req;
68
69    XResCheckExtension(dpy, info, 0);
70
71    LockDisplay(dpy);
72    GetReq(XResQueryVersion, req);
73    req->reqType = (CARD8) info->codes->major_opcode;
74    req->XResReqType = X_XResQueryVersion;
75    req->client_major = XRES_MAJOR_VERSION;
76    req->client_minor = XRES_MINOR_VERSION;
77    if (!_XReply(dpy, (xReply *) &rep, 0, xTrue)) {
78        UnlockDisplay(dpy);
79        SyncHandle();
80        return 0;
81    }
82    *major_version_return = rep.server_major;
83    *minor_version_return = rep.server_minor;
84    UnlockDisplay(dpy);
85    SyncHandle();
86    return 1;
87}
88
89Status
90XResQueryClients(Display *dpy, int *num_clients, XResClient **clients)
91{
92    XExtDisplayInfo *info = find_display(dpy);
93    xXResQueryClientsReq *req;
94    xXResQueryClientsReply rep;
95    int result = 0;
96
97    *num_clients = 0;
98    *clients = NULL;
99
100    XResCheckExtension(dpy, info, 0);
101
102    LockDisplay(dpy);
103    GetReq(XResQueryClients, req);
104    req->reqType = (CARD8) info->codes->major_opcode;
105    req->XResReqType = X_XResQueryClients;
106    if (!_XReply(dpy, (xReply *) &rep, 0, xFalse)) {
107        UnlockDisplay(dpy);
108        SyncHandle();
109        return 0;
110    }
111
112    if (rep.num_clients) {
113        XResClient *clnts;
114
115        if (rep.num_clients < (INT_MAX / sizeof(XResClient)))
116            clnts = Xcalloc(rep.num_clients, sizeof(XResClient));
117        else
118            clnts = NULL;
119
120        if (clnts != NULL) {
121            for (CARD32 i = 0; i < rep.num_clients; i++) {
122                xXResClient scratch;
123
124                _XRead(dpy, (char *) &scratch, sz_xXResClient);
125                clnts[i].resource_base = scratch.resource_base;
126                clnts[i].resource_mask = scratch.resource_mask;
127            }
128            *clients = clnts;
129            *num_clients = (int) rep.num_clients;
130            result = 1;
131        }
132        else {
133            _XEatDataWords(dpy, rep.length);
134        }
135    }
136
137    UnlockDisplay(dpy);
138    SyncHandle();
139    return result;
140}
141
142Status
143XResQueryClientResources(Display *dpy, XID xid,
144                         int *num_types, XResType **types)
145{
146    XExtDisplayInfo *info = find_display(dpy);
147    xXResQueryClientResourcesReq *req;
148    xXResQueryClientResourcesReply rep;
149    int result = 0;
150
151    *num_types = 0;
152    *types = NULL;
153
154    XResCheckExtension(dpy, info, 0);
155
156    LockDisplay(dpy);
157    GetReq(XResQueryClientResources, req);
158    req->reqType = (CARD8) info->codes->major_opcode;
159    req->XResReqType = X_XResQueryClientResources;
160    req->xid = (CARD32) xid;
161    if (!_XReply(dpy, (xReply *) &rep, 0, xFalse)) {
162        UnlockDisplay(dpy);
163        SyncHandle();
164        return 0;
165    }
166
167    if (rep.num_types) {
168        XResType *typs;
169
170        if (rep.num_types < (INT_MAX / sizeof(XResType)))
171            typs = Xcalloc(rep.num_types, sizeof(XResType));
172        else
173            typs = NULL;
174
175        if (typs != NULL) {
176            for (CARD32 i = 0; i < rep.num_types; i++) {
177                xXResType scratch;
178
179                _XRead(dpy, (char *) &scratch, sz_xXResType);
180                typs[i].resource_type = scratch.resource_type;
181                typs[i].count = scratch.count;
182            }
183            *types = typs;
184            *num_types = (int) rep.num_types;
185            result = 1;
186        }
187        else {
188            _XEatDataWords(dpy, rep.length);
189        }
190    }
191
192    UnlockDisplay(dpy);
193    SyncHandle();
194    return result;
195}
196
197Status
198XResQueryClientPixmapBytes(Display *dpy, XID xid, unsigned long *bytes)
199{
200    XExtDisplayInfo *info = find_display(dpy);
201    xXResQueryClientPixmapBytesReq *req;
202    xXResQueryClientPixmapBytesReply rep;
203
204    *bytes = 0;
205
206    XResCheckExtension(dpy, info, 0);
207
208    LockDisplay(dpy);
209    GetReq(XResQueryClientPixmapBytes, req);
210    req->reqType = (CARD8) info->codes->major_opcode;
211    req->XResReqType = X_XResQueryClientPixmapBytes;
212    req->xid = (CARD32) xid;
213    if (!_XReply(dpy, (xReply *) &rep, 0, xTrue)) {
214        UnlockDisplay(dpy);
215        SyncHandle();
216        return 0;
217    }
218
219#ifdef LONG64
220    *bytes = (rep.bytes_overflow * 4294967296UL) + rep.bytes;
221#else
222    *bytes = rep.bytes_overflow ? 0xffffffff : rep.bytes;
223#endif
224
225    UnlockDisplay(dpy);
226    SyncHandle();
227    return 1;
228}
229
230static Bool
231ReadClientValues(Display *dpy, long num_ids,
232                 XResClientIdValue *client_ids    /* out */)
233{
234    for (int c = 0; c < num_ids; ++c) {
235        XResClientIdValue *client = client_ids + c;
236        long int value;
237
238        _XRead32(dpy, &value, 4);
239        client->spec.client = (XID) value;
240        _XRead32(dpy, &value, 4);
241        client->spec.mask = (unsigned int) value;
242        _XRead32(dpy, &value, 4);
243        client->length = value;
244        client->value = malloc((unsigned long) client->length);
245        _XRead(dpy, client->value, client->length);
246    }
247    return True;
248}
249
250/* Returns an array of uint32_t values, not an array of long */
251Status
252XResQueryClientIds(
253    Display            *dpy,
254    long                num_specs,
255    XResClientIdSpec   *client_specs,   /* in */
256    long               *num_ids,        /* out */
257    XResClientIdValue **client_ids      /* out */
258)
259{
260    XExtDisplayInfo *info = find_display(dpy);
261    xXResQueryClientIdsReq *req;
262    xXResQueryClientIdsReply rep;
263
264    *num_ids = 0;
265
266    XResCheckExtension(dpy, info, 0);
267    LockDisplay(dpy);
268    GetReq(XResQueryClientIds, req);
269    req->reqType = (CARD8) info->codes->major_opcode;
270    req->XResReqType = X_XResQueryClientIds;
271    req->length += num_specs * 2;       /* 2 longs per client id spec */
272    req->numSpecs = (CARD32) num_specs;
273
274    for (int c = 0; c < num_specs; ++c) {
275        Data32(dpy, &client_specs[c].client, 4);
276        Data32(dpy, &client_specs[c].mask, 4);
277    }
278
279    if (!_XReply(dpy, (xReply *) &rep, 0, xFalse)) {
280        goto error;
281    }
282
283    *client_ids = calloc(rep.numIds, sizeof(**client_ids));
284    *num_ids = rep.numIds;
285
286    if (!ReadClientValues(dpy, *num_ids, *client_ids)) {
287        goto error;
288    }
289
290    UnlockDisplay(dpy);
291    SyncHandle();
292    return Success;
293
294 error:
295    XResClientIdsDestroy(*num_ids, *client_ids);
296    *client_ids = NULL;
297
298    UnlockDisplay(dpy);
299    SyncHandle();
300    return !Success;
301}
302
303void
304XResClientIdsDestroy(long num_ids, XResClientIdValue *client_ids)
305{
306    for (int c = 0; c < num_ids; ++c) {
307        free(client_ids[c].value);
308    }
309    free(client_ids);
310}
311
312XResClientIdType
313XResGetClientIdType(XResClientIdValue *value)
314{
315    XResClientIdType idType = 0;
316    Bool found = False;
317
318    for (unsigned int bit = 0; bit < XRES_CLIENT_ID_NR; ++bit) {
319        if (value->spec.mask & (1 << bit)) {
320            assert(!found);
321            found = True;
322            idType = bit;
323        }
324    }
325
326    assert(found);
327
328    return idType;
329}
330
331pid_t
332XResGetClientPid(XResClientIdValue *value)
333{
334    if (value->spec.mask & XRES_CLIENT_ID_PID_MASK && value->length >= 4) {
335        return (pid_t) * (CARD32 *) value->value;
336    }
337    else {
338        return (pid_t) - 1;
339    }
340}
341
342static Status
343ReadResourceSizeSpec(Display *dpy, XResResourceSizeSpec *size)
344{
345    long int value;
346
347    _XRead32(dpy, &value, 4);
348    size->spec.resource = (XID) value;
349    _XRead32(dpy, &value, 4);
350    size->spec.type = (Atom) value;
351    _XRead32(dpy, &value, 4);
352    size->bytes = value;
353    _XRead32(dpy, &value, 4);
354    size->ref_count = value;
355    _XRead32(dpy, &value, 4);
356    size->use_count = value;
357    return 0;
358}
359
360static Status
361ReadResourceSizeValues(Display *dpy,
362                       long num_sizes, XResResourceSizeValue *sizes)
363{
364    for (int c = 0; c < num_sizes; ++c) {
365        long int num;
366
367        ReadResourceSizeSpec(dpy, &sizes[c].size);
368        _XRead32(dpy, &num, 4);
369        sizes[c].num_cross_references = num;
370        sizes[c].cross_references =
371            num ? calloc(num, sizeof(*sizes[c].cross_references)) : NULL;
372        for (int d = 0; d < num; ++d) {
373            ReadResourceSizeSpec(dpy, &sizes[c].cross_references[d]);
374        }
375    }
376    return Success;
377}
378
379Status
380XResQueryResourceBytes(
381    Display            *dpy,
382    XID                 client,
383    long                num_specs,
384    XResResourceIdSpec *resource_specs, /* in */
385    long               *num_sizes, /* out */
386    XResResourceSizeValue **sizes /* out */
387)
388{
389    XExtDisplayInfo *info = find_display(dpy);
390    xXResQueryResourceBytesReq *req;
391    xXResQueryResourceBytesReply rep;
392
393    *num_sizes = 0;
394
395    XResCheckExtension(dpy, info, 0);
396
397    LockDisplay(dpy);
398    GetReq(XResQueryResourceBytes, req);
399    req->reqType = (CARD8) info->codes->major_opcode;
400    req->XResReqType = X_XResQueryResourceBytes;
401    req->length += num_specs * 2;       /* 2 longs per client id spec */
402    req->client = (CARD32) client;
403    req->numSpecs = (CARD32) num_specs;
404
405    for (int c = 0; c < num_specs; ++c) {
406        Data32(dpy, &resource_specs[c].resource, 4);
407        Data32(dpy, &resource_specs[c].type, 4);
408    }
409
410    *num_sizes = 0;
411    *sizes = NULL;
412
413    if (!_XReply(dpy, (xReply *) &rep, 0, xFalse)) {
414        goto error;
415    }
416
417    *sizes = calloc(rep.numSizes, sizeof(**sizes));
418    *num_sizes = rep.numSizes;
419
420    if (ReadResourceSizeValues(dpy, *num_sizes, *sizes) != Success) {
421        goto error;
422    }
423
424    UnlockDisplay(dpy);
425    SyncHandle();
426    return Success;
427
428 error:
429    XResResourceSizeValuesDestroy(*num_sizes, *sizes);
430
431    UnlockDisplay(dpy);
432    SyncHandle();
433    return !Success;
434}
435
436void
437XResResourceSizeValuesDestroy(long num_sizes, XResResourceSizeValue *sizes)
438{
439    for (int c = 0; c < num_sizes; ++c) {
440        free(sizes[c].cross_references);
441    }
442    free(sizes);
443}
444