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