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 
36 Atom *
XRRListOutputProperties(Display * dpy,RROutput output,int * nprop)37 XRRListOutputProperties (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 
82 XRRPropertyInfo *
XRRQueryOutputProperty(Display * dpy,RROutput output,Atom property)83 XRRQueryOutputProperty (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 
137 void
XRRConfigureOutputProperty(Display * dpy,RROutput output,Atom property,Bool pending,Bool range,int num_values,long * values)138 XRRConfigureOutputProperty (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 
168 void
XRRChangeOutputProperty(Display * dpy,RROutput output,Atom property,Atom type,int format,int mode,_Xconst unsigned char * data,int nelements)169 XRRChangeOutputProperty (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 
231 void
XRRDeleteOutputProperty(Display * dpy,RROutput output,Atom property)232 XRRDeleteOutputProperty (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 
249 int
XRRGetOutputProperty(Display * dpy,RROutput output,Atom property,long offset,long length,Bool delete,Bool pending,Atom req_type,Atom * actual_type,int * actual_format,unsigned long * nitems,unsigned long * bytes_after,unsigned char ** prop)250 XRRGetOutputProperty (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