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 
18 static XExtensionInfo _xres_ext_info_data;
19 static XExtensionInfo *xres_ext_info = &_xres_ext_info_data;
20 static const char *xres_extension_name = XRES_NAME;
21 
22 #define XResCheckExtension(dpy,i,val) \
23   XextCheckExtension (dpy, i, xres_extension_name, val)
24 
25 static XEXT_GENERATE_CLOSE_DISPLAY (close_display, xres_ext_info)
26 
27 static 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 
41 static XEXT_GENERATE_FIND_DISPLAY (find_display, xres_ext_info,
42                                    xres_extension_name,
43                                    &xres_extension_hooks,
44                                    0, NULL)
45 
XResQueryExtension(Display * dpy,int * event_base_return,int * error_base_return)46 Bool 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 
XResQueryVersion(Display * dpy,int * major_version_return,int * minor_version_return)63 Status 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 
XResQueryClients(Display * dpy,int * num_clients,XResClient ** clients)94 Status 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 
XResQueryClientResources(Display * dpy,XID xid,int * num_types,XResType ** types)149 Status 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 
XResQueryClientPixmapBytes(Display * dpy,XID xid,unsigned long * bytes)206 Status 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 
ReadClientValues(Display * dpy,long num_ids,XResClientIdValue * client_ids)242 static 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 */
XResQueryClientIds(Display * dpy,long num_specs,XResClientIdSpec * client_specs,long * num_ids,XResClientIdValue ** client_ids)265 Status 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 
XResClientIdsDestroy(long num_ids,XResClientIdValue * client_ids)317 void 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 
XResGetClientIdType(XResClientIdValue * value)329 XResClientIdType 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 
XResGetClientPid(XResClientIdValue * value)349 pid_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 
ReadResourceSizeSpec(Display * dpy,XResResourceSizeSpec * size)360 static 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 
ReadResourceSizeValues(Display * dpy,long num_sizes,XResResourceSizeValue * sizes)379 static 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 
XResQueryResourceBytes(Display * dpy,XID client,long num_specs,XResResourceIdSpec * resource_specs,long * num_sizes,XResResourceSizeValue ** sizes)399 Status 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 
XResResourceSizeValuesDestroy(long num_sizes,XResResourceSizeValue * sizes)456 void 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