XrrProperty.c revision 67594505
1/*
2 * Copyright © 2006 Keith Packard
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that copyright
7 * notice and this permission notice appear in supporting documentation, and
8 * that the name of the copyright holders not be used in advertising or
9 * publicity pertaining to distribution of the software without specific,
10 * written prior permission.  The copyright holders make no representations
11 * about the suitability of this software for any purpose.  It is provided "as
12 * is" without express or implied warranty.
13 *
14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
20 * OF THIS SOFTWARE.
21 */
22
23#ifdef HAVE_CONFIG_H
24#include <config.h>
25#endif
26
27#include <stdio.h>
28#include <X11/Xlib.h>
29/* we need to be able to manipulate the Display structure on events */
30#include <X11/Xlibint.h>
31#include <X11/extensions/render.h>
32#include <X11/extensions/Xrender.h>
33#include "Xrandrint.h"
34#include <limits.h>
35
36Atom *
37XRRListOutputProperties (Display *dpy, RROutput output, int *nprop)
38{
39    XExtDisplayInfo		*info = XRRFindDisplay(dpy);
40    xRRListOutputPropertiesReply rep;
41    xRRListOutputPropertiesReq	*req;
42    int				nbytes, rbytes;
43    Atom			*props = NULL;
44
45    RRCheckExtension (dpy, info, NULL);
46
47    LockDisplay (dpy);
48    GetReq (RRListOutputProperties, req);
49    req->reqType = info->codes->major_opcode;
50    req->randrReqType = X_RRListOutputProperties;
51    req->output = output;
52
53    if (!_XReply (dpy, (xReply *) &rep, 0, xFalse)) {
54	UnlockDisplay (dpy);
55	SyncHandle ();
56	*nprop = 0;
57	return NULL;
58    }
59
60    if (rep.nAtoms) {
61	rbytes = rep.nAtoms * sizeof (Atom);
62	nbytes = rep.nAtoms << 2;
63
64	props = (Atom *) Xmalloc (rbytes);
65	if (props == NULL) {
66	    _XEatDataWords (dpy, rep.length);
67	    UnlockDisplay (dpy);
68	    SyncHandle ();
69	    *nprop = 0;
70	    return NULL;
71	}
72
73	_XRead32 (dpy, (long *) props, nbytes);
74    }
75
76    *nprop = rep.nAtoms;
77    UnlockDisplay (dpy);
78    SyncHandle ();
79    return props;
80}
81
82XRRPropertyInfo *
83XRRQueryOutputProperty (Display *dpy, RROutput output, Atom property)
84{
85    XExtDisplayInfo		*info = XRRFindDisplay(dpy);
86    xRRQueryOutputPropertyReply rep;
87    xRRQueryOutputPropertyReq	*req;
88    unsigned int		rbytes, nbytes;
89    XRRPropertyInfo		*prop_info;
90
91    RRCheckExtension (dpy, info, NULL);
92
93    LockDisplay (dpy);
94    GetReq (RRQueryOutputProperty, req);
95    req->reqType = info->codes->major_opcode;
96    req->randrReqType = X_RRQueryOutputProperty;
97    req->output = output;
98    req->property = property;
99
100    if (!_XReply (dpy, (xReply *) &rep, 0, xFalse)) {
101	UnlockDisplay (dpy);
102	SyncHandle ();
103	return NULL;
104    }
105
106    if (rep.length < ((INT_MAX / sizeof(long)) - sizeof (XRRPropertyInfo))) {
107        rbytes = sizeof (XRRPropertyInfo) + (rep.length * sizeof (long));
108        nbytes = rep.length << 2;
109
110        prop_info = Xmalloc (rbytes);
111    } else
112        prop_info = NULL;
113
114    if (prop_info == NULL) {
115	_XEatDataWords(dpy, rep.length);
116	UnlockDisplay (dpy);
117	SyncHandle ();
118	return NULL;
119    }
120
121    prop_info->pending = rep.pending;
122    prop_info->range = rep.range;
123    prop_info->immutable = rep.immutable;
124    prop_info->num_values = rep.length;
125    if (rep.length != 0) {
126	prop_info->values = (long *) (prop_info + 1);
127	_XRead32 (dpy, prop_info->values, nbytes);
128    } else {
129	prop_info->values = NULL;
130    }
131
132    UnlockDisplay (dpy);
133    SyncHandle ();
134    return prop_info;
135}
136
137void
138XRRConfigureOutputProperty (Display *dpy, RROutput output, Atom property,
139			    Bool pending, Bool range, int num_values,
140			    long *values)
141{
142    XExtDisplayInfo		    *info = XRRFindDisplay(dpy);
143    xRRConfigureOutputPropertyReq   *req;
144    long len;
145
146    RRSimpleCheckExtension (dpy, info);
147
148    LockDisplay(dpy);
149    GetReq (RRConfigureOutputProperty, req);
150    req->reqType = info->codes->major_opcode;
151    req->randrReqType = X_RRConfigureOutputProperty;
152    req->output = output;
153    req->property = property;
154    req->pending = pending;
155    req->range = range;
156
157    len = num_values;
158    if (dpy->bigreq_size || req->length + len <= (unsigned) 65535) {
159	SetReqLen(req, len, len);
160	len = (long)num_values << 2;
161	Data32 (dpy, values, len);
162    } /* else force BadLength */
163
164    UnlockDisplay(dpy);
165    SyncHandle();
166}
167
168void
169XRRChangeOutputProperty (Display *dpy, RROutput output,
170			 Atom property, Atom type,
171			 int format, int mode,
172			 _Xconst unsigned char *data, int nelements)
173{
174    XExtDisplayInfo		*info = XRRFindDisplay(dpy);
175    xRRChangeOutputPropertyReq	*req;
176    long len;
177
178    RRSimpleCheckExtension (dpy, info);
179
180    LockDisplay(dpy);
181    GetReq (RRChangeOutputProperty, req);
182    req->reqType = info->codes->major_opcode;
183    req->randrReqType = X_RRChangeOutputProperty;
184    req->output = output;
185    req->property = property;
186    req->type = type;
187    req->mode = mode;
188    if (nelements < 0) {
189	req->nUnits = 0;
190	req->format = 0; /* ask for garbage, get garbage */
191    } else {
192	req->nUnits = nelements;
193	req->format = format;
194    }
195
196    switch (req->format) {
197    case 8:
198	len = ((long)nelements + 3) >> 2;
199	if (dpy->bigreq_size || req->length + len <= (unsigned) 65535) {
200	    SetReqLen(req, len, len);
201	    Data (dpy, (char *)data, nelements);
202	} /* else force BadLength */
203	break;
204
205    case 16:
206	len = ((long)nelements + 1) >> 1;
207	if (dpy->bigreq_size || req->length + len <= (unsigned) 65535) {
208	    SetReqLen(req, len, len);
209	    len = (long)nelements << 1;
210	    Data16 (dpy, (short *) data, len);
211	} /* else force BadLength */
212	break;
213
214    case 32:
215	len = nelements;
216	if (dpy->bigreq_size || req->length + len <= (unsigned) 65535) {
217	    SetReqLen(req, len, len);
218	    len = (long)nelements << 2;
219	    Data32 (dpy, (long *) data, len);
220	} /* else force BadLength */
221	break;
222
223    default:
224	/* BadValue will be generated */ ;
225    }
226
227    UnlockDisplay(dpy);
228    SyncHandle();
229}
230
231void
232XRRDeleteOutputProperty (Display *dpy, RROutput output, Atom property)
233{
234    XExtDisplayInfo		*info = XRRFindDisplay(dpy);
235    xRRDeleteOutputPropertyReq *req;
236
237    RRSimpleCheckExtension (dpy, info);
238
239    LockDisplay(dpy);
240    GetReq(RRDeleteOutputProperty, req);
241    req->reqType = info->codes->major_opcode;
242    req->randrReqType = X_RRDeleteOutputProperty;
243    req->output = output;
244    req->property = property;
245    UnlockDisplay(dpy);
246    SyncHandle();
247}
248
249int
250XRRGetOutputProperty (Display *dpy, RROutput output,
251		      Atom property, long offset, long length,
252		      Bool delete, Bool pending, Atom req_type,
253		      Atom *actual_type, int *actual_format,
254		      unsigned long *nitems, unsigned long *bytes_after,
255		      unsigned char **prop)
256{
257    XExtDisplayInfo		*info = XRRFindDisplay(dpy);
258    xRRGetOutputPropertyReply	rep;
259    xRRGetOutputPropertyReq	*req;
260    unsigned long		nbytes, rbytes;
261
262    /* Always initialize return values, in case callers fail to initialize
263       them and fail to check the return code for an error. */
264    *actual_type = None;
265    *actual_format = 0;
266    *nitems = *bytes_after = 0L;
267    *prop = (unsigned char *) NULL;
268
269    RRCheckExtension (dpy, info, 1);
270
271    LockDisplay (dpy);
272    GetReq (RRGetOutputProperty, req);
273    req->reqType = info->codes->major_opcode;
274    req->randrReqType = X_RRGetOutputProperty;
275    req->output = output;
276    req->property = property;
277    req->type = req_type;
278    req->longOffset = offset;
279    req->longLength = length;
280    req->delete = delete;
281    req->pending = pending;
282
283    if (!_XReply (dpy, (xReply *) &rep, 0, xFalse))
284    {
285	UnlockDisplay (dpy);
286	SyncHandle ();
287	return ((xError *)&rep)->errorCode;
288    }
289
290    if (rep.propertyType != None) {
291	int format = rep.format;
292
293	/*
294	 * Protect against both integer overflow and just plain oversized
295	 * memory allocation - no server should ever return this many props.
296	 */
297	if (rep.nItems >= (INT_MAX >> 4))
298	    format = -1;        /* fall through to default error case */
299
300	/*
301	 * One extra byte is malloced than is needed to contain the property
302	 * data, but this last byte is null terminated and convenient for
303	 * returning string properties, so the client doesn't then have to
304	 * recopy the string to make it null terminated.
305	 */
306	switch (format) {
307	case 8:
308	    nbytes = rep.nItems;
309	    rbytes = rep.nItems + 1;
310	    if (rbytes > 0 && (*prop = Xmalloc (rbytes)))
311		_XReadPad (dpy, (char *) *prop, nbytes);
312	    break;
313
314	case 16:
315	    nbytes = rep.nItems << 1;
316	    rbytes = rep.nItems * sizeof (short) + 1;
317	    if (rbytes > 0 && (*prop = Xmalloc (rbytes)))
318		_XRead16Pad (dpy, (short *) *prop, nbytes);
319	    break;
320
321	case 32:
322	    nbytes = rep.nItems << 2;
323	    rbytes = rep.nItems * sizeof (long) + 1;
324	    if (rbytes > 0 && (*prop = Xmalloc (rbytes)))
325		_XRead32 (dpy, (long *) *prop, nbytes);
326	    break;
327
328	default:
329	    /*
330	     * This part of the code should never be reached.  If it is,
331	     * the server sent back a property with an invalid format.
332	     */
333	    _XEatDataWords(dpy, rep.length);
334	    UnlockDisplay(dpy);
335	    SyncHandle();
336	    return(BadImplementation);
337	}
338	if (! *prop) {
339	    _XEatDataWords(dpy, rep.length);
340	    UnlockDisplay(dpy);
341	    SyncHandle();
342	    return(BadAlloc);
343	}
344	(*prop)[rbytes - 1] = '\0';
345    }
346
347    *actual_type = rep.propertyType;
348    *actual_format = rep.format;
349    *nitems = rep.nItems;
350    *bytes_after = rep.bytesAfter;
351    UnlockDisplay (dpy);
352    SyncHandle ();
353
354    return Success;
355}
356