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