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    Atom			*props = NULL;
43
44    RRCheckExtension (dpy, info, NULL);
45
46    LockDisplay (dpy);
47    GetReq (RRListOutputProperties, req);
48    req->reqType = info->codes->major_opcode;
49    req->randrReqType = X_RRListOutputProperties;
50    req->output = output;
51
52    if (!_XReply (dpy, (xReply *) &rep, 0, xFalse)) {
53	UnlockDisplay (dpy);
54	SyncHandle ();
55	*nprop = 0;
56	return NULL;
57    }
58
59    if (rep.nAtoms) {
60	size_t rbytes = rep.nAtoms * sizeof (Atom);
61	size_t nbytes = rep.nAtoms << 2;
62
63	props = Xmalloc (rbytes);
64	if (props == NULL) {
65	    _XEatDataWords (dpy, rep.length);
66	    UnlockDisplay (dpy);
67	    SyncHandle ();
68	    *nprop = 0;
69	    return NULL;
70	}
71
72	_XRead32 (dpy, (long *) props, nbytes);
73    }
74
75    *nprop = rep.nAtoms;
76    UnlockDisplay (dpy);
77    SyncHandle ();
78    return props;
79}
80
81XRRPropertyInfo *
82XRRQueryOutputProperty (Display *dpy, RROutput output, Atom property)
83{
84    XExtDisplayInfo		*info = XRRFindDisplay(dpy);
85    xRRQueryOutputPropertyReply rep;
86    xRRQueryOutputPropertyReq	*req;
87    unsigned int		nbytes;
88    XRRPropertyInfo		*prop_info;
89
90    RRCheckExtension (dpy, info, NULL);
91
92    LockDisplay (dpy);
93    GetReq (RRQueryOutputProperty, req);
94    req->reqType = info->codes->major_opcode;
95    req->randrReqType = X_RRQueryOutputProperty;
96    req->output = output;
97    req->property = property;
98
99    if (!_XReply (dpy, (xReply *) &rep, 0, xFalse)) {
100	UnlockDisplay (dpy);
101	SyncHandle ();
102	return NULL;
103    }
104
105    if (rep.length < ((INT_MAX / sizeof(long)) - sizeof (XRRPropertyInfo))) {
106        size_t rbytes = sizeof (XRRPropertyInfo) + (rep.length * sizeof (long));
107        nbytes = rep.length << 2;
108
109        prop_info = Xmalloc (rbytes);
110    } else
111        prop_info = NULL;
112
113    if (prop_info == NULL) {
114	_XEatDataWords(dpy, rep.length);
115	UnlockDisplay (dpy);
116	SyncHandle ();
117	return NULL;
118    }
119
120    prop_info->pending = rep.pending;
121    prop_info->range = rep.range;
122    prop_info->immutable = rep.immutable;
123    prop_info->num_values = rep.length;
124    if (rep.length != 0) {
125	prop_info->values = (long *) (prop_info + 1);
126	_XRead32 (dpy, prop_info->values, nbytes);
127    } else {
128	prop_info->values = NULL;
129    }
130
131    UnlockDisplay (dpy);
132    SyncHandle ();
133    return prop_info;
134}
135
136void
137XRRConfigureOutputProperty (Display *dpy, RROutput output, Atom property,
138			    Bool pending, Bool range, int num_values,
139			    long *values)
140{
141    XExtDisplayInfo		    *info = XRRFindDisplay(dpy);
142    xRRConfigureOutputPropertyReq   *req;
143    long len;
144
145    RRSimpleCheckExtension (dpy, info);
146
147    LockDisplay(dpy);
148    GetReq (RRConfigureOutputProperty, req);
149    req->reqType = info->codes->major_opcode;
150    req->randrReqType = X_RRConfigureOutputProperty;
151    req->output = output;
152    req->property = property;
153    req->pending = pending;
154    req->range = range;
155
156    len = num_values;
157    if (dpy->bigreq_size || req->length + len <= (unsigned) 65535) {
158	SetReqLen(req, len, len);
159	len = (long)num_values << 2;
160	Data32 (dpy, values, len);
161    } /* else force BadLength */
162
163    UnlockDisplay(dpy);
164    SyncHandle();
165}
166
167void
168XRRChangeOutputProperty (Display *dpy, RROutput output,
169			 Atom property, Atom type,
170			 int format, int mode,
171			 _Xconst unsigned char *data, int nelements)
172{
173    XExtDisplayInfo		*info = XRRFindDisplay(dpy);
174    xRRChangeOutputPropertyReq	*req;
175    long len;
176
177    RRSimpleCheckExtension (dpy, info);
178
179    LockDisplay(dpy);
180    GetReq (RRChangeOutputProperty, req);
181    req->reqType = info->codes->major_opcode;
182    req->randrReqType = X_RRChangeOutputProperty;
183    req->output = output;
184    req->property = property;
185    req->type = type;
186    req->mode = mode;
187    if (nelements < 0) {
188	req->nUnits = 0;
189	req->format = 0; /* ask for garbage, get garbage */
190    } else {
191	req->nUnits = nelements;
192	req->format = format;
193    }
194
195    switch (req->format) {
196    case 8:
197	len = ((long)nelements + 3) >> 2;
198	if (dpy->bigreq_size || req->length + len <= (unsigned) 65535) {
199	    SetReqLen(req, len, len);
200	    Data (dpy, (char *)data, nelements);
201	} /* else force BadLength */
202	break;
203
204    case 16:
205	len = ((long)nelements + 1) >> 1;
206	if (dpy->bigreq_size || req->length + len <= (unsigned) 65535) {
207	    SetReqLen(req, len, len);
208	    len = (long)nelements << 1;
209	    Data16 (dpy, (short *) data, len);
210	} /* else force BadLength */
211	break;
212
213    case 32:
214	len = nelements;
215	if (dpy->bigreq_size || req->length + len <= (unsigned) 65535) {
216	    SetReqLen(req, len, len);
217	    len = (long)nelements << 2;
218	    Data32 (dpy, (long *) data, len);
219	} /* else force BadLength */
220	break;
221
222    default:
223	/* BadValue will be generated */ ;
224    }
225
226    UnlockDisplay(dpy);
227    SyncHandle();
228}
229
230void
231XRRDeleteOutputProperty (Display *dpy, RROutput output, Atom property)
232{
233    XExtDisplayInfo		*info = XRRFindDisplay(dpy);
234    xRRDeleteOutputPropertyReq *req;
235
236    RRSimpleCheckExtension (dpy, info);
237
238    LockDisplay(dpy);
239    GetReq(RRDeleteOutputProperty, req);
240    req->reqType = info->codes->major_opcode;
241    req->randrReqType = X_RRDeleteOutputProperty;
242    req->output = output;
243    req->property = property;
244    UnlockDisplay(dpy);
245    SyncHandle();
246}
247
248int
249XRRGetOutputProperty (Display *dpy, RROutput output,
250		      Atom property, long offset, long length,
251		      Bool delete, Bool pending, Atom req_type,
252		      Atom *actual_type, int *actual_format,
253		      unsigned long *nitems, unsigned long *bytes_after,
254		      unsigned char **prop)
255{
256    XExtDisplayInfo		*info = XRRFindDisplay(dpy);
257    xRRGetOutputPropertyReply	rep;
258    xRRGetOutputPropertyReq	*req;
259
260    /* Always initialize return values, in case callers fail to initialize
261       them and fail to check the return code for an error. */
262    *actual_type = None;
263    *actual_format = 0;
264    *nitems = *bytes_after = 0L;
265    *prop = (unsigned char *) NULL;
266
267    RRCheckExtension (dpy, info, 1);
268
269    LockDisplay (dpy);
270    GetReq (RRGetOutputProperty, req);
271    req->reqType = info->codes->major_opcode;
272    req->randrReqType = X_RRGetOutputProperty;
273    req->output = output;
274    req->property = property;
275    req->type = req_type;
276    req->longOffset = offset;
277    req->longLength = length;
278    req->delete = delete;
279    req->pending = pending;
280
281    if (!_XReply (dpy, (xReply *) &rep, 0, xFalse))
282    {
283	UnlockDisplay (dpy);
284	SyncHandle ();
285	return ((xError *)&rep)->errorCode;
286    }
287
288    if (rep.propertyType != None) {
289	int format = rep.format;
290	size_t nbytes, rbytes;
291
292	/*
293	 * Protect against both integer overflow and just plain oversized
294	 * memory allocation - no server should ever return this many props.
295	 */
296	if (rep.nItems >= (INT_MAX >> 4))
297	    format = -1;        /* fall through to default error case */
298
299	/*
300	 * One extra byte is malloced than is needed to contain the property
301	 * data, but this last byte is null terminated and convenient for
302	 * returning string properties, so the client doesn't then have to
303	 * recopy the string to make it null terminated.
304	 */
305	switch (format) {
306	case 8:
307	    nbytes = rep.nItems;
308	    rbytes = rep.nItems + 1;
309	    if (rbytes > 0 && (*prop = Xmalloc (rbytes)))
310		_XReadPad (dpy, (char *) *prop, nbytes);
311	    break;
312
313	case 16:
314	    nbytes = rep.nItems << 1;
315	    rbytes = rep.nItems * sizeof (short) + 1;
316	    if (rbytes > 0 && (*prop = Xmalloc (rbytes)))
317		_XRead16Pad (dpy, (short *) *prop, nbytes);
318	    break;
319
320	case 32:
321	    nbytes = rep.nItems << 2;
322	    rbytes = rep.nItems * sizeof (long) + 1;
323	    if (rbytes > 0 && (*prop = Xmalloc (rbytes)))
324		_XRead32 (dpy, (long *) *prop, nbytes);
325	    break;
326
327	default:
328	    /*
329	     * This part of the code should never be reached.  If it is,
330	     * the server sent back a property with an invalid format.
331	     */
332	    _XEatDataWords(dpy, rep.length);
333	    UnlockDisplay(dpy);
334	    SyncHandle();
335	    return(BadImplementation);
336	}
337	if (! *prop) {
338	    _XEatDataWords(dpy, rep.length);
339	    UnlockDisplay(dpy);
340	    SyncHandle();
341	    return(BadAlloc);
342	}
343	(*prop)[rbytes - 1] = '\0';
344    }
345
346    *actual_type = rep.propertyType;
347    *actual_format = rep.format;
348    *nitems = rep.nItems;
349    *bytes_after = rep.bytesAfter;
350    UnlockDisplay (dpy);
351    SyncHandle ();
352
353    return Success;
354}
355