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