rrscreen.c revision 9ace9065
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#include "randrstr.h" 24 25static const int padlength[4] = {0, 3, 2, 1}; 26 27static CARD16 28RR10CurrentSizeID (ScreenPtr pScreen); 29 30/* 31 * Edit connection information block so that new clients 32 * see the current screen size on connect 33 */ 34static void 35RREditConnectionInfo (ScreenPtr pScreen) 36{ 37 xConnSetup *connSetup; 38 char *vendor; 39 xPixmapFormat *formats; 40 xWindowRoot *root; 41 xDepth *depth; 42 xVisualType *visual; 43 int screen = 0; 44 int d; 45 46 connSetup = (xConnSetup *) ConnectionInfo; 47 vendor = (char *) connSetup + sizeof (xConnSetup); 48 formats = (xPixmapFormat *) ((char *) vendor + 49 connSetup->nbytesVendor + 50 padlength[connSetup->nbytesVendor & 3]); 51 root = (xWindowRoot *) ((char *) formats + 52 sizeof (xPixmapFormat) * screenInfo.numPixmapFormats); 53 while (screen != pScreen->myNum) 54 { 55 depth = (xDepth *) ((char *) root + 56 sizeof (xWindowRoot)); 57 for (d = 0; d < root->nDepths; d++) 58 { 59 visual = (xVisualType *) ((char *) depth + 60 sizeof (xDepth)); 61 depth = (xDepth *) ((char *) visual + 62 depth->nVisuals * sizeof (xVisualType)); 63 } 64 root = (xWindowRoot *) ((char *) depth); 65 screen++; 66 } 67 root->pixWidth = pScreen->width; 68 root->pixHeight = pScreen->height; 69 root->mmWidth = pScreen->mmWidth; 70 root->mmHeight = pScreen->mmHeight; 71} 72 73void 74RRSendConfigNotify (ScreenPtr pScreen) 75{ 76 WindowPtr pWin = pScreen->root; 77 xEvent event; 78 79 event.u.u.type = ConfigureNotify; 80 event.u.configureNotify.window = pWin->drawable.id; 81 event.u.configureNotify.aboveSibling = None; 82 event.u.configureNotify.x = 0; 83 event.u.configureNotify.y = 0; 84 85 /* XXX xinerama stuff ? */ 86 87 event.u.configureNotify.width = pWin->drawable.width; 88 event.u.configureNotify.height = pWin->drawable.height; 89 event.u.configureNotify.borderWidth = wBorderWidth (pWin); 90 event.u.configureNotify.override = pWin->overrideRedirect; 91 DeliverEvents(pWin, &event, 1, NullWindow); 92} 93 94void 95RRDeliverScreenEvent (ClientPtr client, WindowPtr pWin, ScreenPtr pScreen) 96{ 97 rrScrPriv (pScreen); 98 xRRScreenChangeNotifyEvent se; 99 RRCrtcPtr crtc = pScrPriv->numCrtcs ? pScrPriv->crtcs[0] : NULL; 100 WindowPtr pRoot = pScreen->root; 101 102 se.type = RRScreenChangeNotify + RREventBase; 103 se.rotation = (CARD8) (crtc ? crtc->rotation : RR_Rotate_0); 104 se.timestamp = pScrPriv->lastSetTime.milliseconds; 105 se.configTimestamp = pScrPriv->lastConfigTime.milliseconds; 106 se.root = pRoot->drawable.id; 107 se.window = pWin->drawable.id; 108 se.subpixelOrder = PictureGetSubpixelOrder (pScreen); 109 110 se.sizeID = RR10CurrentSizeID (pScreen); 111 112 if (se.rotation & (RR_Rotate_90 | RR_Rotate_270)) { 113 se.widthInPixels = pScreen->height; 114 se.heightInPixels = pScreen->width; 115 se.widthInMillimeters = pScreen->mmHeight; 116 se.heightInMillimeters = pScreen->mmWidth; 117 } else { 118 se.widthInPixels = pScreen->width; 119 se.heightInPixels = pScreen->height; 120 se.widthInMillimeters = pScreen->mmWidth; 121 se.heightInMillimeters = pScreen->mmHeight; 122 } 123 124 WriteEventsToClient (client, 1, (xEvent *) &se); 125} 126 127/* 128 * Notify the extension that the screen size has been changed. 129 * The driver is responsible for calling this whenever it has changed 130 * the size of the screen 131 */ 132void 133RRScreenSizeNotify (ScreenPtr pScreen) 134{ 135 rrScrPriv(pScreen); 136 /* 137 * Deliver ConfigureNotify events when root changes 138 * pixel size 139 */ 140 if (pScrPriv->width == pScreen->width && 141 pScrPriv->height == pScreen->height && 142 pScrPriv->mmWidth == pScreen->mmWidth && 143 pScrPriv->mmHeight == pScreen->mmHeight) 144 return; 145 146 pScrPriv->width = pScreen->width; 147 pScrPriv->height = pScreen->height; 148 pScrPriv->mmWidth = pScreen->mmWidth; 149 pScrPriv->mmHeight = pScreen->mmHeight; 150 pScrPriv->changed = TRUE; 151/* pScrPriv->sizeChanged = TRUE; */ 152 153 RRTellChanged (pScreen); 154 RRSendConfigNotify (pScreen); 155 RREditConnectionInfo (pScreen); 156 157 RRPointerScreenConfigured (pScreen); 158 /* 159 * Fix pointer bounds and location 160 */ 161 ScreenRestructured (pScreen); 162} 163 164/* 165 * Request that the screen be resized 166 */ 167Bool 168RRScreenSizeSet (ScreenPtr pScreen, 169 CARD16 width, 170 CARD16 height, 171 CARD32 mmWidth, 172 CARD32 mmHeight) 173{ 174 rrScrPriv(pScreen); 175 176#if RANDR_12_INTERFACE 177 if (pScrPriv->rrScreenSetSize) 178 { 179 return (*pScrPriv->rrScreenSetSize) (pScreen, 180 width, height, 181 mmWidth, mmHeight); 182 } 183#endif 184#if RANDR_10_INTERFACE 185 if (pScrPriv->rrSetConfig) 186 { 187 return TRUE; /* can't set size separately */ 188 } 189#endif 190 return FALSE; 191} 192 193/* 194 * Retrieve valid screen size range 195 */ 196int 197ProcRRGetScreenSizeRange (ClientPtr client) 198{ 199 REQUEST(xRRGetScreenSizeRangeReq); 200 xRRGetScreenSizeRangeReply rep; 201 WindowPtr pWin; 202 ScreenPtr pScreen; 203 rrScrPrivPtr pScrPriv; 204 int rc; 205 206 REQUEST_SIZE_MATCH(xRRGetScreenInfoReq); 207 rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); 208 if (rc != Success) 209 return rc; 210 211 pScreen = pWin->drawable.pScreen; 212 pScrPriv = rrGetScrPriv(pScreen); 213 214 rep.type = X_Reply; 215 rep.pad = 0; 216 rep.sequenceNumber = client->sequence; 217 rep.length = 0; 218 219 if (pScrPriv) 220 { 221 if (!RRGetInfo (pScreen, FALSE)) 222 return BadAlloc; 223 rep.minWidth = pScrPriv->minWidth; 224 rep.minHeight = pScrPriv->minHeight; 225 rep.maxWidth = pScrPriv->maxWidth; 226 rep.maxHeight = pScrPriv->maxHeight; 227 } 228 else 229 { 230 rep.maxWidth = rep.minWidth = pScreen->width; 231 rep.maxHeight = rep.minHeight = pScreen->height; 232 } 233 if (client->swapped) 234 { 235 int n; 236 237 swaps(&rep.sequenceNumber, n); 238 swapl(&rep.length, n); 239 swaps(&rep.minWidth, n); 240 swaps(&rep.minHeight, n); 241 swaps(&rep.maxWidth, n); 242 swaps(&rep.maxHeight, n); 243 } 244 WriteToClient(client, sizeof(xRRGetScreenSizeRangeReply), (char *)&rep); 245 return Success; 246} 247 248int 249ProcRRSetScreenSize (ClientPtr client) 250{ 251 REQUEST(xRRSetScreenSizeReq); 252 WindowPtr pWin; 253 ScreenPtr pScreen; 254 rrScrPrivPtr pScrPriv; 255 int i, rc; 256 257 REQUEST_SIZE_MATCH(xRRSetScreenSizeReq); 258 rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); 259 if (rc != Success) 260 return rc; 261 262 pScreen = pWin->drawable.pScreen; 263 pScrPriv = rrGetScrPriv(pScreen); 264 if (stuff->width < pScrPriv->minWidth || pScrPriv->maxWidth < stuff->width) 265 { 266 client->errorValue = stuff->width; 267 return BadValue; 268 } 269 if (stuff->height < pScrPriv->minHeight || 270 pScrPriv->maxHeight < stuff->height) 271 { 272 client->errorValue = stuff->height; 273 return BadValue; 274 } 275 for (i = 0; i < pScrPriv->numCrtcs; i++) 276 { 277 RRCrtcPtr crtc = pScrPriv->crtcs[i]; 278 RRModePtr mode = crtc->mode; 279 if (mode) 280 { 281 int source_width = mode->mode.width; 282 int source_height = mode->mode.height; 283 Rotation rotation = crtc->rotation; 284 285 if (rotation == RR_Rotate_90 || rotation == RR_Rotate_270) 286 { 287 source_width = mode->mode.height; 288 source_height = mode->mode.width; 289 } 290 291 if (crtc->x + source_width > stuff->width || 292 crtc->y + source_height > stuff->height) 293 return BadMatch; 294 } 295 } 296 if (stuff->widthInMillimeters == 0 || stuff->heightInMillimeters == 0) 297 { 298 client->errorValue = 0; 299 return BadValue; 300 } 301 if (!RRScreenSizeSet (pScreen, 302 stuff->width, stuff->height, 303 stuff->widthInMillimeters, 304 stuff->heightInMillimeters)) 305 { 306 return BadMatch; 307 } 308 return Success; 309} 310 311static int 312rrGetScreenResources(ClientPtr client, Bool query) 313{ 314 REQUEST(xRRGetScreenResourcesReq); 315 xRRGetScreenResourcesReply rep; 316 WindowPtr pWin; 317 ScreenPtr pScreen; 318 rrScrPrivPtr pScrPriv; 319 CARD8 *extra; 320 unsigned long extraLen; 321 int i, n, rc, has_primary = 0; 322 RRCrtc *crtcs; 323 RROutput *outputs; 324 xRRModeInfo *modeinfos; 325 CARD8 *names; 326 327 REQUEST_SIZE_MATCH(xRRGetScreenResourcesReq); 328 rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); 329 if (rc != Success) 330 return rc; 331 332 pScreen = pWin->drawable.pScreen; 333 pScrPriv = rrGetScrPriv(pScreen); 334 rep.pad = 0; 335 336 if (query && pScrPriv) 337 if (!RRGetInfo (pScreen, query)) 338 return BadAlloc; 339 340 if (!pScrPriv) 341 { 342 rep.type = X_Reply; 343 rep.sequenceNumber = client->sequence; 344 rep.length = 0; 345 rep.timestamp = currentTime.milliseconds; 346 rep.configTimestamp = currentTime.milliseconds; 347 rep.nCrtcs = 0; 348 rep.nOutputs = 0; 349 rep.nModes = 0; 350 rep.nbytesNames = 0; 351 extra = NULL; 352 extraLen = 0; 353 } 354 else 355 { 356 RRModePtr *modes; 357 int num_modes; 358 359 modes = RRModesForScreen (pScreen, &num_modes); 360 if (!modes) 361 return BadAlloc; 362 363 rep.type = X_Reply; 364 rep.sequenceNumber = client->sequence; 365 rep.length = 0; 366 rep.timestamp = pScrPriv->lastSetTime.milliseconds; 367 rep.configTimestamp = pScrPriv->lastConfigTime.milliseconds; 368 rep.nCrtcs = pScrPriv->numCrtcs; 369 rep.nOutputs = pScrPriv->numOutputs; 370 rep.nModes = num_modes; 371 rep.nbytesNames = 0; 372 373 for (i = 0; i < num_modes; i++) 374 rep.nbytesNames += modes[i]->mode.nameLength; 375 376 rep.length = (pScrPriv->numCrtcs + 377 pScrPriv->numOutputs + 378 num_modes * bytes_to_int32(SIZEOF(xRRModeInfo)) + 379 bytes_to_int32(rep.nbytesNames)); 380 381 extraLen = rep.length << 2; 382 if (extraLen) 383 { 384 extra = malloc(extraLen); 385 if (!extra) 386 { 387 free(modes); 388 return BadAlloc; 389 } 390 } 391 else 392 extra = NULL; 393 394 crtcs = (RRCrtc *) extra; 395 outputs = (RROutput *) (crtcs + pScrPriv->numCrtcs); 396 modeinfos = (xRRModeInfo *) (outputs + pScrPriv->numOutputs); 397 names = (CARD8 *) (modeinfos + num_modes); 398 399 if (pScrPriv->primaryOutput && pScrPriv->primaryOutput->crtc) 400 { 401 has_primary = 1; 402 crtcs[0] = pScrPriv->primaryOutput->crtc->id; 403 if (client->swapped) 404 swapl (&crtcs[0], n); 405 } 406 407 for (i = 0; i < pScrPriv->numCrtcs; i++) 408 { 409 if (has_primary && 410 pScrPriv->primaryOutput->crtc == pScrPriv->crtcs[i]) 411 { 412 has_primary = 0; 413 continue; 414 } 415 crtcs[i + has_primary] = pScrPriv->crtcs[i]->id; 416 if (client->swapped) 417 swapl (&crtcs[i + has_primary], n); 418 } 419 420 for (i = 0; i < pScrPriv->numOutputs; i++) 421 { 422 outputs[i] = pScrPriv->outputs[i]->id; 423 if (client->swapped) 424 swapl (&outputs[i], n); 425 } 426 427 for (i = 0; i < num_modes; i++) 428 { 429 RRModePtr mode = modes[i]; 430 modeinfos[i] = mode->mode; 431 if (client->swapped) 432 { 433 swapl (&modeinfos[i].id, n); 434 swaps (&modeinfos[i].width, n); 435 swaps (&modeinfos[i].height, n); 436 swapl (&modeinfos[i].dotClock, n); 437 swaps (&modeinfos[i].hSyncStart, n); 438 swaps (&modeinfos[i].hSyncEnd, n); 439 swaps (&modeinfos[i].hTotal, n); 440 swaps (&modeinfos[i].hSkew, n); 441 swaps (&modeinfos[i].vSyncStart, n); 442 swaps (&modeinfos[i].vSyncEnd, n); 443 swaps (&modeinfos[i].vTotal, n); 444 swaps (&modeinfos[i].nameLength, n); 445 swapl (&modeinfos[i].modeFlags, n); 446 } 447 memcpy (names, mode->name, 448 mode->mode.nameLength); 449 names += mode->mode.nameLength; 450 } 451 free(modes); 452 assert (bytes_to_int32((char *) names - (char *) extra) == rep.length); 453 } 454 455 if (client->swapped) { 456 swaps(&rep.sequenceNumber, n); 457 swapl(&rep.length, n); 458 swapl(&rep.timestamp, n); 459 swapl(&rep.configTimestamp, n); 460 swaps(&rep.nCrtcs, n); 461 swaps(&rep.nOutputs, n); 462 swaps(&rep.nModes, n); 463 swaps(&rep.nbytesNames, n); 464 } 465 WriteToClient(client, sizeof(xRRGetScreenResourcesReply), (char *)&rep); 466 if (extraLen) 467 { 468 WriteToClient (client, extraLen, (char *) extra); 469 free(extra); 470 } 471 return Success; 472} 473 474int 475ProcRRGetScreenResources (ClientPtr client) 476{ 477 return rrGetScreenResources(client, TRUE); 478} 479 480int 481ProcRRGetScreenResourcesCurrent (ClientPtr client) 482{ 483 return rrGetScreenResources(client, FALSE); 484} 485 486typedef struct _RR10Data { 487 RRScreenSizePtr sizes; 488 int nsize; 489 int nrefresh; 490 int size; 491 CARD16 refresh; 492} RR10DataRec, *RR10DataPtr; 493 494/* 495 * Convert 1.2 monitor data into 1.0 screen data 496 */ 497static RR10DataPtr 498RR10GetData (ScreenPtr pScreen, RROutputPtr output) 499{ 500 RR10DataPtr data; 501 RRScreenSizePtr size; 502 int nmode = output->numModes + output->numUserModes; 503 int o, os, l, r; 504 RRScreenRatePtr refresh; 505 CARD16 vRefresh; 506 RRModePtr mode; 507 Bool *used; 508 509 /* Make sure there is plenty of space for any combination */ 510 data = malloc (sizeof (RR10DataRec) + 511 sizeof (RRScreenSize) * nmode + 512 sizeof (RRScreenRate) * nmode + 513 sizeof (Bool) * nmode); 514 if (!data) 515 return NULL; 516 size = (RRScreenSizePtr) (data + 1); 517 refresh = (RRScreenRatePtr) (size + nmode); 518 used = (Bool *) (refresh + nmode); 519 memset (used, '\0', sizeof (Bool) * nmode); 520 data->sizes = size; 521 data->nsize = 0; 522 data->nrefresh = 0; 523 data->size = 0; 524 data->refresh = 0; 525 526 /* 527 * find modes not yet listed 528 */ 529 for (o = 0; o < output->numModes + output->numUserModes; o++) 530 { 531 if (used[o]) continue; 532 533 if (o < output->numModes) 534 mode = output->modes[o]; 535 else 536 mode = output->userModes[o - output->numModes]; 537 538 l = data->nsize; 539 size[l].id = data->nsize; 540 size[l].width = mode->mode.width; 541 size[l].height = mode->mode.height; 542 if (output->mmWidth && output->mmHeight) { 543 size[l].mmWidth = output->mmWidth; 544 size[l].mmHeight = output->mmHeight; 545 } else { 546 size[l].mmWidth = pScreen->mmWidth; 547 size[l].mmHeight = pScreen->mmHeight; 548 } 549 size[l].nRates = 0; 550 size[l].pRates = &refresh[data->nrefresh]; 551 data->nsize++; 552 553 /* 554 * Find all modes with matching size 555 */ 556 for (os = o; os < output->numModes + output->numUserModes; os++) 557 { 558 if (os < output->numModes) 559 mode = output->modes[os]; 560 else 561 mode = output->userModes[os - output->numModes]; 562 if (mode->mode.width == size[l].width && 563 mode->mode.height == size[l].height) 564 { 565 vRefresh = RRVerticalRefresh (&mode->mode); 566 used[os] = TRUE; 567 568 for (r = 0; r < size[l].nRates; r++) 569 if (vRefresh == size[l].pRates[r].rate) 570 break; 571 if (r == size[l].nRates) 572 { 573 size[l].pRates[r].rate = vRefresh; 574 size[l].pRates[r].mode = mode; 575 size[l].nRates++; 576 data->nrefresh++; 577 } 578 if (mode == output->crtc->mode) 579 { 580 data->size = l; 581 data->refresh = vRefresh; 582 } 583 } 584 } 585 } 586 return data; 587} 588 589int 590ProcRRGetScreenInfo (ClientPtr client) 591{ 592 REQUEST(xRRGetScreenInfoReq); 593 xRRGetScreenInfoReply rep; 594 WindowPtr pWin; 595 int n, rc; 596 ScreenPtr pScreen; 597 rrScrPrivPtr pScrPriv; 598 CARD8 *extra; 599 unsigned long extraLen; 600 RROutputPtr output; 601 602 REQUEST_SIZE_MATCH(xRRGetScreenInfoReq); 603 rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); 604 if (rc != Success) 605 return rc; 606 607 pScreen = pWin->drawable.pScreen; 608 pScrPriv = rrGetScrPriv(pScreen); 609 rep.pad = 0; 610 611 if (pScrPriv) 612 if (!RRGetInfo (pScreen, TRUE)) 613 return BadAlloc; 614 615 output = RRFirstOutput (pScreen); 616 617 if (!pScrPriv || !output) 618 { 619 rep.type = X_Reply; 620 rep.setOfRotations = RR_Rotate_0; 621 rep.sequenceNumber = client->sequence; 622 rep.length = 0; 623 rep.root = pWin->drawable.pScreen->root->drawable.id; 624 rep.timestamp = currentTime.milliseconds; 625 rep.configTimestamp = currentTime.milliseconds; 626 rep.nSizes = 0; 627 rep.sizeID = 0; 628 rep.rotation = RR_Rotate_0; 629 rep.rate = 0; 630 rep.nrateEnts = 0; 631 extra = 0; 632 extraLen = 0; 633 } 634 else 635 { 636 int i, j; 637 xScreenSizes *size; 638 CARD16 *rates; 639 CARD8 *data8; 640 Bool has_rate = RRClientKnowsRates (client); 641 RR10DataPtr pData; 642 RRScreenSizePtr pSize; 643 644 pData = RR10GetData (pScreen, output); 645 if (!pData) 646 return BadAlloc; 647 648 rep.type = X_Reply; 649 rep.setOfRotations = output->crtc->rotations; 650 rep.sequenceNumber = client->sequence; 651 rep.length = 0; 652 rep.root = pWin->drawable.pScreen->root->drawable.id; 653 rep.timestamp = pScrPriv->lastSetTime.milliseconds; 654 rep.configTimestamp = pScrPriv->lastConfigTime.milliseconds; 655 rep.rotation = output->crtc->rotation; 656 rep.nSizes = pData->nsize; 657 rep.nrateEnts = pData->nrefresh + pData->nsize; 658 rep.sizeID = pData->size; 659 rep.rate = pData->refresh; 660 661 extraLen = rep.nSizes * sizeof (xScreenSizes); 662 if (has_rate) 663 extraLen += rep.nrateEnts * sizeof (CARD16); 664 665 if (extraLen) 666 { 667 extra = (CARD8 *) malloc(extraLen); 668 if (!extra) 669 { 670 free(pData); 671 return BadAlloc; 672 } 673 } 674 else 675 extra = NULL; 676 677 /* 678 * First comes the size information 679 */ 680 size = (xScreenSizes *) extra; 681 rates = (CARD16 *) (size + rep.nSizes); 682 for (i = 0; i < pData->nsize; i++) 683 { 684 pSize = &pData->sizes[i]; 685 size->widthInPixels = pSize->width; 686 size->heightInPixels = pSize->height; 687 size->widthInMillimeters = pSize->mmWidth; 688 size->heightInMillimeters = pSize->mmHeight; 689 if (client->swapped) 690 { 691 swaps (&size->widthInPixels, n); 692 swaps (&size->heightInPixels, n); 693 swaps (&size->widthInMillimeters, n); 694 swaps (&size->heightInMillimeters, n); 695 } 696 size++; 697 if (has_rate) 698 { 699 *rates = pSize->nRates; 700 if (client->swapped) 701 { 702 swaps (rates, n); 703 } 704 rates++; 705 for (j = 0; j < pSize->nRates; j++) 706 { 707 *rates = pSize->pRates[j].rate; 708 if (client->swapped) 709 { 710 swaps (rates, n); 711 } 712 rates++; 713 } 714 } 715 } 716 free(pData); 717 718 data8 = (CARD8 *) rates; 719 720 if (data8 - (CARD8 *) extra != extraLen) 721 FatalError ("RRGetScreenInfo bad extra len %ld != %ld\n", 722 (unsigned long)(data8 - (CARD8 *) extra), extraLen); 723 rep.length = bytes_to_int32(extraLen); 724 } 725 if (client->swapped) { 726 swaps(&rep.sequenceNumber, n); 727 swapl(&rep.length, n); 728 swapl(&rep.timestamp, n); 729 swaps(&rep.rotation, n); 730 swaps(&rep.nSizes, n); 731 swaps(&rep.sizeID, n); 732 swaps(&rep.rate, n); 733 swaps(&rep.nrateEnts, n); 734 } 735 WriteToClient(client, sizeof(xRRGetScreenInfoReply), (char *)&rep); 736 if (extraLen) 737 { 738 WriteToClient (client, extraLen, (char *) extra); 739 free(extra); 740 } 741 return Success; 742} 743 744int 745ProcRRSetScreenConfig (ClientPtr client) 746{ 747 REQUEST(xRRSetScreenConfigReq); 748 xRRSetScreenConfigReply rep; 749 DrawablePtr pDraw; 750 int n, rc; 751 ScreenPtr pScreen; 752 rrScrPrivPtr pScrPriv; 753 TimeStamp time; 754 int i; 755 Rotation rotation; 756 int rate; 757 Bool has_rate; 758 RROutputPtr output; 759 RRCrtcPtr crtc; 760 RRModePtr mode; 761 RR10DataPtr pData = NULL; 762 RRScreenSizePtr pSize; 763 int width, height; 764 765 UpdateCurrentTime (); 766 767 if (RRClientKnowsRates (client)) 768 { 769 REQUEST_SIZE_MATCH (xRRSetScreenConfigReq); 770 has_rate = TRUE; 771 } 772 else 773 { 774 REQUEST_SIZE_MATCH (xRR1_0SetScreenConfigReq); 775 has_rate = FALSE; 776 } 777 778 rc = dixLookupDrawable(&pDraw, stuff->drawable, client, 0, DixWriteAccess); 779 if (rc != Success) 780 return rc; 781 782 pScreen = pDraw->pScreen; 783 784 pScrPriv = rrGetScrPriv(pScreen); 785 786 time = ClientTimeToServerTime(stuff->timestamp); 787 788 if (!pScrPriv) 789 { 790 time = currentTime; 791 rep.status = RRSetConfigFailed; 792 goto sendReply; 793 } 794 if (!RRGetInfo (pScreen, FALSE)) 795 return BadAlloc; 796 797 output = RRFirstOutput (pScreen); 798 if (!output) 799 { 800 time = currentTime; 801 rep.status = RRSetConfigFailed; 802 goto sendReply; 803 } 804 805 crtc = output->crtc; 806 807 /* 808 * If the client's config timestamp is not the same as the last config 809 * timestamp, then the config information isn't up-to-date and 810 * can't even be validated. 811 * 812 * Note that the client only knows about the milliseconds part of the 813 * timestamp, so using CompareTimeStamps here would cause randr to suddenly 814 * stop working after several hours have passed (freedesktop bug #6502). 815 */ 816 if (stuff->configTimestamp != pScrPriv->lastConfigTime.milliseconds) 817 { 818 rep.status = RRSetConfigInvalidConfigTime; 819 goto sendReply; 820 } 821 822 pData = RR10GetData (pScreen, output); 823 if (!pData) 824 return BadAlloc; 825 826 if (stuff->sizeID >= pData->nsize) 827 { 828 /* 829 * Invalid size ID 830 */ 831 client->errorValue = stuff->sizeID; 832 free(pData); 833 return BadValue; 834 } 835 pSize = &pData->sizes[stuff->sizeID]; 836 837 /* 838 * Validate requested rotation 839 */ 840 rotation = (Rotation) stuff->rotation; 841 842 /* test the rotation bits only! */ 843 switch (rotation & 0xf) { 844 case RR_Rotate_0: 845 case RR_Rotate_90: 846 case RR_Rotate_180: 847 case RR_Rotate_270: 848 break; 849 default: 850 /* 851 * Invalid rotation 852 */ 853 client->errorValue = stuff->rotation; 854 free(pData); 855 return BadValue; 856 } 857 858 if ((~crtc->rotations) & rotation) 859 { 860 /* 861 * requested rotation or reflection not supported by screen 862 */ 863 client->errorValue = stuff->rotation; 864 free(pData); 865 return BadMatch; 866 } 867 868 /* 869 * Validate requested refresh 870 */ 871 if (has_rate) 872 rate = (int) stuff->rate; 873 else 874 rate = 0; 875 876 if (rate) 877 { 878 for (i = 0; i < pSize->nRates; i++) 879 { 880 if (pSize->pRates[i].rate == rate) 881 break; 882 } 883 if (i == pSize->nRates) 884 { 885 /* 886 * Invalid rate 887 */ 888 client->errorValue = rate; 889 free(pData); 890 return BadValue; 891 } 892 mode = pSize->pRates[i].mode; 893 } 894 else 895 mode = pSize->pRates[0].mode; 896 897 /* 898 * Make sure the requested set-time is not older than 899 * the last set-time 900 */ 901 if (CompareTimeStamps (time, pScrPriv->lastSetTime) < 0) 902 { 903 rep.status = RRSetConfigInvalidTime; 904 goto sendReply; 905 } 906 907 /* 908 * If the screen size is changing, adjust all of the other outputs 909 * to fit the new size, mirroring as much as possible 910 */ 911 width = mode->mode.width; 912 height = mode->mode.height; 913 if (width < pScrPriv->minWidth || pScrPriv->maxWidth < width) { 914 client->errorValue = width; 915 free(pData); 916 return BadValue; 917 } 918 if (height < pScrPriv->minHeight || pScrPriv->maxHeight < height) { 919 client->errorValue = height; 920 free(pData); 921 return BadValue; 922 } 923 924 if (rotation & (RR_Rotate_90|RR_Rotate_270)) 925 { 926 width = mode->mode.height; 927 height = mode->mode.width; 928 } 929 930 if (width != pScreen->width || height != pScreen->height) 931 { 932 int c; 933 934 for (c = 0; c < pScrPriv->numCrtcs; c++) 935 { 936 if (!RRCrtcSet (pScrPriv->crtcs[c], NULL, 0, 0, RR_Rotate_0, 937 0, NULL)) 938 { 939 rep.status = RRSetConfigFailed; 940 /* XXX recover from failure */ 941 goto sendReply; 942 } 943 } 944 if (!RRScreenSizeSet (pScreen, width, height, 945 pScreen->mmWidth, pScreen->mmHeight)) 946 { 947 rep.status = RRSetConfigFailed; 948 /* XXX recover from failure */ 949 goto sendReply; 950 } 951 } 952 953 if (!RRCrtcSet (crtc, mode, 0, 0, stuff->rotation, 1, &output)) 954 rep.status = RRSetConfigFailed; 955 else { 956 pScrPriv->lastSetTime = time; 957 rep.status = RRSetConfigSuccess; 958 } 959 960 /* 961 * XXX Configure other crtcs to mirror as much as possible 962 */ 963 964sendReply: 965 966 free(pData); 967 968 rep.type = X_Reply; 969 /* rep.status has already been filled in */ 970 rep.length = 0; 971 rep.sequenceNumber = client->sequence; 972 973 rep.newTimestamp = pScrPriv->lastSetTime.milliseconds; 974 rep.newConfigTimestamp = pScrPriv->lastConfigTime.milliseconds; 975 rep.root = pDraw->pScreen->root->drawable.id; 976 977 if (client->swapped) 978 { 979 swaps(&rep.sequenceNumber, n); 980 swapl(&rep.length, n); 981 swapl(&rep.newTimestamp, n); 982 swapl(&rep.newConfigTimestamp, n); 983 swapl(&rep.root, n); 984 } 985 WriteToClient(client, sizeof(xRRSetScreenConfigReply), (char *)&rep); 986 987 return Success; 988} 989 990static CARD16 991RR10CurrentSizeID (ScreenPtr pScreen) 992{ 993 CARD16 sizeID = 0xffff; 994 RROutputPtr output = RRFirstOutput (pScreen); 995 996 if (output) 997 { 998 RR10DataPtr data = RR10GetData (pScreen, output); 999 if (data) 1000 { 1001 int i; 1002 for (i = 0; i < data->nsize; i++) 1003 if (data->sizes[i].width == pScreen->width && 1004 data->sizes[i].height == pScreen->height) 1005 { 1006 sizeID = (CARD16) i; 1007 break; 1008 } 1009 free(data); 1010 } 1011 } 1012 return sizeID; 1013} 1014