XRes.c revision 362b94d5
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        _XRead (dpy, client->value, client->length);
260    }
261    return True;
262}
263
264/* Returns an array of uint32_t values, not an array of long */
265Status XResQueryClientIds (
266   Display            *dpy,
267   long                num_specs,
268   XResClientIdSpec   *client_specs,   /* in */
269   long               *num_ids,        /* out */
270   XResClientIdValue **client_ids      /* out */
271)
272{
273    XExtDisplayInfo *info = find_display (dpy);
274    xXResQueryClientIdsReq *req;
275    xXResQueryClientIdsReply rep;
276    int c;
277
278    *num_ids = 0;
279
280    XResCheckExtension (dpy, info, 0);
281    LockDisplay (dpy);
282    GetReq (XResQueryClientIds, req);
283    req->reqType = info->codes->major_opcode;
284    req->XResReqType = X_XResQueryClientIds;
285    req->length += num_specs * 2; /* 2 longs per client id spec */
286    req->numSpecs = num_specs;
287
288    for (c = 0; c < num_specs; ++c) {
289        Data32(dpy, &client_specs[c].client, 4);
290        Data32(dpy, &client_specs[c].mask, 4);
291    }
292
293    if (!_XReply (dpy, (xReply *) &rep, 0, xFalse)) {
294        goto error;
295    }
296
297    *client_ids = calloc(rep.numIds, sizeof(**client_ids));
298    *num_ids = rep.numIds;
299
300    if (!ReadClientValues(dpy, *num_ids, *client_ids)) {
301        goto error;
302    }
303
304    UnlockDisplay (dpy);
305    SyncHandle ();
306    return Success;
307
308 error:
309    XResClientIdsDestroy (*num_ids, *client_ids);
310    *client_ids = NULL;
311
312    UnlockDisplay (dpy);
313    SyncHandle ();
314    return !Success;
315}
316
317void XResClientIdsDestroy (
318   long                num_ids,
319   XResClientIdValue  *client_ids
320)
321{
322    int c;
323    for (c = 0; c < num_ids; ++c) {
324        free(client_ids[c].value);
325    }
326    free(client_ids);
327}
328
329XResClientIdType XResGetClientIdType(
330    XResClientIdValue* value
331)
332{
333    int bit;
334    XResClientIdType idType = 0;
335    Bool found = False;
336    for (bit = 0; bit < XRES_CLIENT_ID_NR; ++bit) {
337        if (value->spec.mask & (1 << bit)) {
338            assert(!found);
339            found = True;
340            idType = bit;
341        }
342    }
343
344    assert(found);
345
346    return idType;
347}
348
349pid_t XResGetClientPid(
350    XResClientIdValue* value
351)
352{
353    if (value->spec.mask & XRES_CLIENT_ID_PID_MASK && value->length >= 4) {
354        return (pid_t) * (CARD32*) value->value;
355    } else {
356        return (pid_t) -1;
357    }
358}
359
360static Status ReadResourceSizeSpec(
361   Display               *dpy,
362   XResResourceSizeSpec  *size
363)
364{
365    long int value;
366    _XRead32(dpy, &value, 4);
367    size->spec.resource = value;
368    _XRead32(dpy, &value, 4);
369    size->spec.type = value;
370    _XRead32(dpy, &value, 4);
371    size->bytes = value;
372    _XRead32(dpy, &value, 4);
373    size->ref_count = value;
374    _XRead32(dpy, &value, 4);
375    size->use_count = value;
376    return 0;
377}
378
379static Status ReadResourceSizeValues(
380   Display                *dpy,
381   long                    num_sizes,
382   XResResourceSizeValue  *sizes)
383{
384    int c;
385    int d;
386    for (c = 0; c < num_sizes; ++c) {
387        long int num;
388        ReadResourceSizeSpec(dpy, &sizes[c].size);
389        _XRead32(dpy, &num, 4);
390        sizes[c].num_cross_references = num;
391        sizes[c].cross_references = num ? calloc(num, sizeof(*sizes[c].cross_references)) : NULL;
392        for (d = 0; d < num; ++d) {
393            ReadResourceSizeSpec(dpy, &sizes[c].cross_references[d]);
394        }
395    }
396    return Success;
397}
398
399Status XResQueryResourceBytes (
400   Display            *dpy,
401   XID                 client,
402   long                num_specs,
403   XResResourceIdSpec *resource_specs, /* in */
404   long               *num_sizes, /* out */
405   XResResourceSizeValue **sizes /* out */
406)
407{
408    XExtDisplayInfo *info = find_display (dpy);
409    xXResQueryResourceBytesReq *req;
410    xXResQueryResourceBytesReply rep;
411    int c;
412
413    *num_sizes = 0;
414
415    XResCheckExtension (dpy, info, 0);
416
417    LockDisplay (dpy);
418    GetReq (XResQueryResourceBytes, req);
419    req->reqType = info->codes->major_opcode;
420    req->XResReqType = X_XResQueryResourceBytes;
421    req->length += num_specs * 2; /* 2 longs per client id spec */
422    req->client = client;
423    req->numSpecs = num_specs;
424
425    for (c = 0; c < num_specs; ++c) {
426        Data32(dpy, &resource_specs[c].resource, 4);
427        Data32(dpy, &resource_specs[c].type, 4);
428    }
429
430    *num_sizes = 0;
431    *sizes = NULL;
432
433    if (!_XReply (dpy, (xReply *) &rep, 0, xFalse)) {
434        goto error;
435    }
436
437    *sizes = calloc(rep.numSizes, sizeof(**sizes));
438    *num_sizes = rep.numSizes;
439
440    if (ReadResourceSizeValues(dpy, *num_sizes, *sizes) != Success) {
441        goto error;
442    }
443
444    UnlockDisplay (dpy);
445    SyncHandle ();
446    return Success;
447
448 error:
449    XResResourceSizeValuesDestroy(*num_sizes, *sizes);
450
451    UnlockDisplay (dpy);
452    SyncHandle ();
453    return !Success;
454}
455
456void XResResourceSizeValuesDestroy (
457   long                num_sizes,
458   XResResourceSizeValue *sizes
459)
460{
461    int c;
462    for (c = 0; c < num_sizes; ++c) {
463        free(sizes[c].cross_references);
464    }
465    free(sizes);
466}
467