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