XrrCrtc.c revision 8d0bc965
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 <limits.h> 28#include <stdio.h> 29#include <X11/Xlib.h> 30/* we need to be able to manipulate the Display structure on events */ 31#include <X11/Xlibint.h> 32#include <X11/extensions/render.h> 33#include <X11/extensions/Xrender.h> 34#include "Xrandrint.h" 35 36XRRCrtcInfo * 37XRRGetCrtcInfo (Display *dpy, XRRScreenResources *resources, RRCrtc crtc) 38{ 39 XExtDisplayInfo *info = XRRFindDisplay(dpy); 40 xRRGetCrtcInfoReply rep; 41 xRRGetCrtcInfoReq *req; 42 int nbytes, nbytesRead, rbytes; 43 XRRCrtcInfo *xci; 44 45 RRCheckExtension (dpy, info, NULL); 46 47 LockDisplay (dpy); 48 GetReq (RRGetCrtcInfo, req); 49 req->reqType = info->codes->major_opcode; 50 req->randrReqType = X_RRGetCrtcInfo; 51 req->crtc = crtc; 52 req->configTimestamp = resources->configTimestamp; 53 54 if (!_XReply (dpy, (xReply *) &rep, 0, xFalse)) 55 { 56 UnlockDisplay (dpy); 57 SyncHandle (); 58 return NULL; 59 } 60 61 if (rep.length < INT_MAX >> 2) 62 { 63 nbytes = (long) rep.length << 2; 64 65 nbytesRead = (long) (rep.nOutput * 4 + 66 rep.nPossibleOutput * 4); 67 68 /* 69 * first we must compute how much space to allocate for 70 * randr library's use; we'll allocate the structures in a single 71 * allocation, on cleanlyness grounds. 72 */ 73 74 rbytes = (sizeof (XRRCrtcInfo) + 75 rep.nOutput * sizeof (RROutput) + 76 rep.nPossibleOutput * sizeof (RROutput)); 77 78 xci = Xmalloc(rbytes); 79 } 80 else 81 { 82 nbytes = 0; 83 nbytesRead = 0; 84 rbytes = 0; 85 xci = NULL; 86 } 87 88 if (xci == NULL) { 89 _XEatDataWords (dpy, rep.length); 90 UnlockDisplay (dpy); 91 SyncHandle (); 92 return NULL; 93 } 94 95 xci->timestamp = rep.timestamp; 96 xci->x = rep.x; 97 xci->y = rep.y; 98 xci->width = rep.width; 99 xci->height = rep.height; 100 xci->mode = rep.mode; 101 xci->rotation = rep.rotation; 102 xci->noutput = rep.nOutput; 103 xci->outputs = (RROutput *) (xci + 1); 104 xci->rotations = rep.rotations; 105 xci->npossible = rep.nPossibleOutput; 106 xci->possible = (RROutput *) (xci->outputs + rep.nOutput); 107 108 _XRead32 (dpy, (long *) xci->outputs, rep.nOutput << 2); 109 _XRead32 (dpy, (long *) xci->possible, rep.nPossibleOutput << 2); 110 111 /* 112 * Skip any extra data 113 */ 114 if (nbytes > nbytesRead) 115 _XEatData (dpy, (unsigned long) (nbytes - nbytesRead)); 116 117 UnlockDisplay (dpy); 118 SyncHandle (); 119 return (XRRCrtcInfo *) xci; 120} 121 122void 123XRRFreeCrtcInfo (XRRCrtcInfo *crtcInfo) 124{ 125 Xfree (crtcInfo); 126} 127 128Status 129XRRSetCrtcConfig (Display *dpy, 130 XRRScreenResources *resources, 131 RRCrtc crtc, 132 Time timestamp, 133 int x, int y, 134 RRMode mode, 135 Rotation rotation, 136 RROutput *outputs, 137 int noutputs) 138{ 139 XExtDisplayInfo *info = XRRFindDisplay(dpy); 140 xRRSetCrtcConfigReply rep; 141 xRRSetCrtcConfigReq *req; 142 143 RRCheckExtension (dpy, info, 0); 144 145 LockDisplay(dpy); 146 GetReq (RRSetCrtcConfig, req); 147 req->reqType = info->codes->major_opcode; 148 req->randrReqType = X_RRSetCrtcConfig; 149 req->length += noutputs; 150 req->crtc = crtc; 151 req->timestamp = timestamp; 152 req->configTimestamp = resources->configTimestamp; 153 req->x = x; 154 req->y = y; 155 req->mode = mode; 156 req->rotation = rotation; 157 Data32 (dpy, outputs, noutputs << 2); 158 159 if (!_XReply (dpy, (xReply *) &rep, 0, xFalse)) 160 rep.status = RRSetConfigFailed; 161 UnlockDisplay (dpy); 162 SyncHandle (); 163 return rep.status; 164} 165 166int 167XRRGetCrtcGammaSize (Display *dpy, RRCrtc crtc) 168{ 169 XExtDisplayInfo *info = XRRFindDisplay(dpy); 170 xRRGetCrtcGammaSizeReply rep; 171 xRRGetCrtcGammaSizeReq *req; 172 173 RRCheckExtension (dpy, info, 0); 174 175 LockDisplay(dpy); 176 GetReq (RRGetCrtcGammaSize, req); 177 req->reqType = info->codes->major_opcode; 178 req->randrReqType = X_RRGetCrtcGammaSize; 179 req->crtc = crtc; 180 181 if (!_XReply (dpy, (xReply *) &rep, 0, xFalse)) 182 rep.size = 0; 183 UnlockDisplay (dpy); 184 SyncHandle (); 185 return rep.size; 186} 187 188XRRCrtcGamma * 189XRRGetCrtcGamma (Display *dpy, RRCrtc crtc) 190{ 191 XExtDisplayInfo *info = XRRFindDisplay(dpy); 192 xRRGetCrtcGammaReply rep; 193 xRRGetCrtcGammaReq *req; 194 XRRCrtcGamma *crtc_gamma = NULL; 195 long nbytes; 196 long nbytesRead; 197 198 RRCheckExtension (dpy, info, NULL); 199 200 LockDisplay(dpy); 201 GetReq (RRGetCrtcGamma, req); 202 req->reqType = info->codes->major_opcode; 203 req->randrReqType = X_RRGetCrtcGamma; 204 req->crtc = crtc; 205 206 if (!_XReply (dpy, (xReply *) &rep, 0, xFalse)) 207 goto out; 208 209 if (rep.length < INT_MAX >> 2) 210 { 211 nbytes = (long) rep.length << 2; 212 213 /* three channels of CARD16 data */ 214 nbytesRead = (rep.size * 2 * 3); 215 216 crtc_gamma = XRRAllocGamma (rep.size); 217 } 218 else 219 { 220 nbytes = 0; 221 nbytesRead = 0; 222 crtc_gamma = NULL; 223 } 224 225 if (!crtc_gamma) 226 { 227 _XEatDataWords (dpy, rep.length); 228 goto out; 229 } 230 _XRead16 (dpy, crtc_gamma->red, rep.size * 2); 231 _XRead16 (dpy, crtc_gamma->green, rep.size * 2); 232 _XRead16 (dpy, crtc_gamma->blue, rep.size * 2); 233 234 if (nbytes > nbytesRead) 235 _XEatData (dpy, (unsigned long) (nbytes - nbytesRead)); 236 237out: 238 UnlockDisplay (dpy); 239 SyncHandle (); 240 return crtc_gamma; 241} 242 243XRRCrtcGamma * 244XRRAllocGamma (int size) 245{ 246 XRRCrtcGamma *crtc_gamma; 247 248 crtc_gamma = Xmalloc (sizeof (XRRCrtcGamma) + 249 sizeof (crtc_gamma->red[0]) * size * 3); 250 if (!crtc_gamma) 251 return NULL; 252 crtc_gamma->size = size; 253 crtc_gamma->red = (unsigned short *) (crtc_gamma + 1); 254 crtc_gamma->green = crtc_gamma->red + size; 255 crtc_gamma->blue = crtc_gamma->green + size; 256 return crtc_gamma; 257} 258 259void 260XRRSetCrtcGamma (Display *dpy, RRCrtc crtc, XRRCrtcGamma *crtc_gamma) 261{ 262 XExtDisplayInfo *info = XRRFindDisplay(dpy); 263 xRRSetCrtcGammaReq *req; 264 265 RRSimpleCheckExtension (dpy, info); 266 267 LockDisplay(dpy); 268 GetReq (RRSetCrtcGamma, req); 269 req->reqType = info->codes->major_opcode; 270 req->randrReqType = X_RRSetCrtcGamma; 271 req->crtc = crtc; 272 req->size = crtc_gamma->size; 273 req->length += (crtc_gamma->size * 2 * 3 + 3) >> 2; 274 /* 275 * Note this assumes the structure was allocated with XRRAllocGamma, 276 * otherwise the channels might not be contiguous 277 */ 278 Data16 (dpy, crtc_gamma->red, crtc_gamma->size * 2 * 3); 279 280 UnlockDisplay (dpy); 281 SyncHandle (); 282} 283 284void 285XRRFreeGamma (XRRCrtcGamma *crtc_gamma) 286{ 287 Xfree (crtc_gamma); 288} 289 290/* Version 1.3 additions */ 291 292static void 293XTransform_from_xRenderTransform (XTransform *x, 294 xRenderTransform *render) 295{ 296 x->matrix[0][0] = render->matrix11; 297 x->matrix[0][1] = render->matrix12; 298 x->matrix[0][2] = render->matrix13; 299 300 x->matrix[1][0] = render->matrix21; 301 x->matrix[1][1] = render->matrix22; 302 x->matrix[1][2] = render->matrix23; 303 304 x->matrix[2][0] = render->matrix31; 305 x->matrix[2][1] = render->matrix32; 306 x->matrix[2][2] = render->matrix33; 307} 308 309static void 310xRenderTransform_from_XTransform (xRenderTransform *render, 311 XTransform *x) 312{ 313 render->matrix11 = x->matrix[0][0]; 314 render->matrix12 = x->matrix[0][1]; 315 render->matrix13 = x->matrix[0][2]; 316 317 render->matrix21 = x->matrix[1][0]; 318 render->matrix22 = x->matrix[1][1]; 319 render->matrix23 = x->matrix[1][2]; 320 321 render->matrix31 = x->matrix[2][0]; 322 render->matrix32 = x->matrix[2][1]; 323 render->matrix33 = x->matrix[2][2]; 324} 325 326void 327XRRSetCrtcTransform (Display *dpy, 328 RRCrtc crtc, 329 XTransform *transform, 330 _Xconst char *filter, 331 XFixed *params, 332 int nparams) 333{ 334 XExtDisplayInfo *info = XRRFindDisplay(dpy); 335 xRRSetCrtcTransformReq *req; 336 int nbytes = strlen (filter); 337 338 RRSimpleCheckExtension (dpy, info); 339 340 LockDisplay(dpy); 341 GetReq (RRSetCrtcTransform, req); 342 req->reqType = info->codes->major_opcode; 343 req->randrReqType = X_RRSetCrtcTransform; 344 req->crtc = crtc; 345 346 xRenderTransform_from_XTransform (&req->transform, transform); 347 348 req->nbytesFilter = nbytes; 349 req->length += ((nbytes + 3) >> 2) + nparams; 350 Data (dpy, filter, nbytes); 351 Data32 (dpy, params, nparams << 2); 352 353 UnlockDisplay (dpy); 354 SyncHandle (); 355} 356 357#define CrtcTransformExtra (SIZEOF(xRRGetCrtcTransformReply) - 32) 358 359static const xRenderTransform identity = { 360 0x10000, 0, 0, 361 0, 0x10000, 0, 362 0, 0, 0x10000, 363}; 364 365static Bool 366_XRRHasTransform (int major, int minor) 367{ 368 return major > 1 || (major == 1 && minor >= 3); 369} 370 371Status 372XRRGetCrtcTransform (Display *dpy, 373 RRCrtc crtc, 374 XRRCrtcTransformAttributes **attributes) 375{ 376 XExtDisplayInfo *info = XRRFindDisplay(dpy); 377 xRRGetCrtcTransformReply rep; 378 int major_version, minor_version; 379 XRRCrtcTransformAttributes *attr; 380 char *extra = NULL, *end = NULL, *e; 381 382 *attributes = NULL; 383 384 RRCheckExtension (dpy, info, False); 385 386 if (!XRRQueryVersion (dpy, &major_version, &minor_version) || 387 !_XRRHasTransform (major_version, minor_version)) 388 { 389 /* For pre-1.3 servers, just report identity matrices everywhere */ 390 rep.pendingTransform = identity; 391 rep.pendingNbytesFilter = 0; 392 rep.pendingNparamsFilter = 0; 393 rep.currentTransform = identity; 394 rep.currentNbytesFilter = 0; 395 rep.currentNparamsFilter = 0; 396 } 397 else 398 { 399 xRRGetCrtcTransformReq *req; 400 401 LockDisplay (dpy); 402 GetReq (RRGetCrtcTransform, req); 403 req->reqType = info->codes->major_opcode; 404 req->randrReqType = X_RRGetCrtcTransform; 405 req->crtc = crtc; 406 407 if (!_XReply (dpy, (xReply *) &rep, CrtcTransformExtra >> 2, xFalse)) 408 { 409 rep.pendingTransform = identity; 410 rep.pendingNbytesFilter = 0; 411 rep.pendingNparamsFilter = 0; 412 rep.currentTransform = identity; 413 rep.currentNbytesFilter = 0; 414 rep.currentNparamsFilter = 0; 415 } 416 else 417 { 418 int extraBytes = rep.length * 4 - CrtcTransformExtra; 419 if (rep.length < INT_MAX / 4 && 420 rep.length * 4 >= CrtcTransformExtra) { 421 extra = Xmalloc (extraBytes); 422 end = extra + extraBytes; 423 } else 424 extra = NULL; 425 if (!extra) { 426 if (rep.length > (CrtcTransformExtra >> 2)) 427 _XEatDataWords (dpy, rep.length - (CrtcTransformExtra >> 2)); 428 else 429 _XEatDataWords (dpy, rep.length); 430 UnlockDisplay (dpy); 431 SyncHandle (); 432 return False; 433 } 434 _XRead (dpy, extra, extraBytes); 435 } 436 437 UnlockDisplay (dpy); 438 SyncHandle (); 439 } 440 441 attr = Xmalloc (sizeof (XRRCrtcTransformAttributes) + 442 rep.pendingNparamsFilter * sizeof (XFixed) + 443 rep.currentNparamsFilter * sizeof (XFixed) + 444 rep.pendingNbytesFilter + 1 + 445 rep.currentNbytesFilter + 1); 446 447 if (!attr) { 448 XFree (extra); 449 return False; 450 } 451 XTransform_from_xRenderTransform (&attr->pendingTransform, &rep.pendingTransform); 452 XTransform_from_xRenderTransform (&attr->currentTransform, &rep.currentTransform); 453 454 attr->pendingParams = (XFixed *) (attr + 1); 455 attr->currentParams = attr->pendingParams + rep.pendingNparamsFilter; 456 attr->pendingFilter = (char *) (attr->currentParams + rep.currentNparamsFilter); 457 attr->currentFilter = attr->pendingFilter + rep.pendingNbytesFilter + 1; 458 459 e = extra; 460 461 if (e + rep.pendingNbytesFilter > end) { 462 XFree (attr); 463 XFree (extra); 464 return False; 465 } 466 memcpy (attr->pendingFilter, e, rep.pendingNbytesFilter); 467 attr->pendingFilter[rep.pendingNbytesFilter] = '\0'; 468 e += (rep.pendingNbytesFilter + 3) & ~3; 469 for (unsigned int p = 0; p < rep.pendingNparamsFilter; p++) { 470 INT32 f; 471 if (e + 4 > end) { 472 XFree (attr); 473 XFree (extra); 474 return False; 475 } 476 memcpy (&f, e, 4); 477 e += 4; 478 attr->pendingParams[p] = (XFixed) f; 479 } 480 attr->pendingNparams = rep.pendingNparamsFilter; 481 482 if (e + rep.currentNbytesFilter > end) { 483 XFree (attr); 484 XFree (extra); 485 return False; 486 } 487 memcpy (attr->currentFilter, e, rep.currentNbytesFilter); 488 attr->currentFilter[rep.currentNbytesFilter] = '\0'; 489 e += (rep.currentNbytesFilter + 3) & ~3; 490 for (unsigned int p = 0; p < rep.currentNparamsFilter; p++) { 491 INT32 f; 492 if (e + 4 > end) { 493 XFree (attr); 494 XFree (extra); 495 return False; 496 } 497 memcpy (&f, e, 4); 498 e += 4; 499 attr->currentParams[p] = (XFixed) f; 500 } 501 attr->currentNparams = rep.currentNparamsFilter; 502 503 if (extra) 504 XFree (extra); 505 *attributes = attr; 506 507 return True; 508} 509 510XRRPanning * 511XRRGetPanning (Display *dpy, XRRScreenResources *resources, RRCrtc crtc) 512{ 513 XExtDisplayInfo *info = XRRFindDisplay(dpy); 514 xRRGetPanningReply rep; 515 xRRGetPanningReq *req; 516 XRRPanning *xp; 517 518 RRCheckExtension (dpy, info, NULL); 519 520 LockDisplay (dpy); 521 GetReq (RRGetPanning, req); 522 req->reqType = info->codes->major_opcode; 523 req->randrReqType = X_RRGetPanning; 524 req->crtc = crtc; 525 526 if (!_XReply (dpy, (xReply *) &rep, 1, xFalse)) 527 { 528 UnlockDisplay (dpy); 529 SyncHandle (); 530 return NULL; 531 } 532 533 if (! (xp = Xmalloc(sizeof(XRRPanning))) ) { 534 _XEatData (dpy, sizeof(XRRPanning)); 535 UnlockDisplay (dpy); 536 SyncHandle (); 537 return NULL; 538 } 539 540 xp->timestamp = rep.timestamp; 541 xp->left = rep.left; 542 xp->top = rep.top; 543 xp->width = rep.width; 544 xp->height = rep.height; 545 xp->track_left = rep.track_left; 546 xp->track_top = rep.track_top; 547 xp->track_width = rep.track_width; 548 xp->track_height = rep.track_height; 549 xp->border_left = rep.border_left; 550 xp->border_top = rep.border_top; 551 xp->border_right = rep.border_right; 552 xp->border_bottom = rep.border_bottom; 553 554 UnlockDisplay (dpy); 555 SyncHandle (); 556 return (XRRPanning *) xp; 557} 558 559void 560XRRFreePanning (XRRPanning *panning) 561{ 562 Xfree (panning); 563} 564 565Status 566XRRSetPanning (Display *dpy, 567 XRRScreenResources *resources, 568 RRCrtc crtc, 569 XRRPanning *panning) 570{ 571 XExtDisplayInfo *info = XRRFindDisplay(dpy); 572 xRRSetPanningReply rep; 573 xRRSetPanningReq *req; 574 575 RRCheckExtension (dpy, info, 0); 576 577 LockDisplay(dpy); 578 GetReq (RRSetPanning, req); 579 req->reqType = info->codes->major_opcode; 580 req->randrReqType = X_RRSetPanning; 581 req->crtc = crtc; 582 req->timestamp = panning->timestamp; 583 req->left = panning->left; 584 req->top = panning->top; 585 req->width = panning->width; 586 req->height = panning->height; 587 req->track_left = panning->track_left; 588 req->track_top = panning->track_top; 589 req->track_width = panning->track_width; 590 req->track_height = panning->track_height; 591 req->border_left = panning->border_left; 592 req->border_top = panning->border_top; 593 req->border_right = panning->border_right; 594 req->border_bottom = panning->border_bottom; 595 596 if (!_XReply (dpy, (xReply *) &rep, 0, xFalse)) 597 rep.status = RRSetConfigFailed; 598 UnlockDisplay (dpy); 599 SyncHandle (); 600 return rep.status; 601} 602 603