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