1/* 2 * Copyright © 2000 Compaq Computer Corporation 3 * Copyright © 2002 Hewlett-Packard Company 4 * Copyright © 2006 Intel Corporation 5 * Copyright © 2017 Keith Packard 6 * 7 * Permission to use, copy, modify, distribute, and sell this software and its 8 * documentation for any purpose is hereby granted without fee, provided that 9 * the above copyright notice appear in all copies and that both that copyright 10 * notice and this permission notice appear in supporting documentation, and 11 * that the name of the copyright holders not be used in advertising or 12 * publicity pertaining to distribution of the software without specific, 13 * written prior permission. The copyright holders make no representations 14 * about the suitability of this software for any purpose. It is provided "as 15 * is" without express or implied warranty. 16 * 17 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 18 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 19 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 20 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 21 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 22 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 23 * OF THIS SOFTWARE. 24 * 25 * Author: Jim Gettys, Hewlett-Packard Company, Inc. 26 * Keith Packard, Intel Corporation 27 */ 28 29#ifdef HAVE_DIX_CONFIG_H 30#include <dix-config.h> 31#endif 32 33#include "randrstr.h" 34#include "extinit.h" 35 36/* From render.h */ 37#ifndef SubPixelUnknown 38#define SubPixelUnknown 0 39#endif 40 41#define RR_VALIDATE 42static int RRNScreens; 43 44#define wrap(priv,real,mem,func) {\ 45 priv->mem = real->mem; \ 46 real->mem = func; \ 47} 48 49#define unwrap(priv,real,mem) {\ 50 real->mem = priv->mem; \ 51} 52 53static int ProcRRDispatch(ClientPtr pClient); 54static int SProcRRDispatch(ClientPtr pClient); 55 56int RREventBase; 57int RRErrorBase; 58RESTYPE RRClientType, RREventType; /* resource types for event masks */ 59DevPrivateKeyRec RRClientPrivateKeyRec; 60 61DevPrivateKeyRec rrPrivKeyRec; 62 63static void 64RRClientCallback(CallbackListPtr *list, void *closure, void *data) 65{ 66 NewClientInfoRec *clientinfo = (NewClientInfoRec *) data; 67 ClientPtr pClient = clientinfo->client; 68 69 rrClientPriv(pClient); 70 RRTimesPtr pTimes = (RRTimesPtr) (pRRClient + 1); 71 int i; 72 73 pRRClient->major_version = 0; 74 pRRClient->minor_version = 0; 75 for (i = 0; i < screenInfo.numScreens; i++) { 76 ScreenPtr pScreen = screenInfo.screens[i]; 77 78 rrScrPriv(pScreen); 79 80 if (pScrPriv) { 81 pTimes[i].setTime = pScrPriv->lastSetTime; 82 pTimes[i].configTime = pScrPriv->lastConfigTime; 83 } 84 } 85} 86 87static Bool 88RRCloseScreen(ScreenPtr pScreen) 89{ 90 rrScrPriv(pScreen); 91 int j; 92 RRLeasePtr lease, next; 93 94 unwrap(pScrPriv, pScreen, CloseScreen); 95 96 xorg_list_for_each_entry_safe(lease, next, &pScrPriv->leases, list) 97 RRTerminateLease(lease); 98 for (j = pScrPriv->numCrtcs - 1; j >= 0; j--) 99 RRCrtcDestroy(pScrPriv->crtcs[j]); 100 for (j = pScrPriv->numOutputs - 1; j >= 0; j--) 101 RROutputDestroy(pScrPriv->outputs[j]); 102 103 if (pScrPriv->provider) 104 RRProviderDestroy(pScrPriv->provider); 105 106 RRMonitorClose(pScreen); 107 108 free(pScrPriv->crtcs); 109 free(pScrPriv->outputs); 110 free(pScrPriv); 111 RRNScreens -= 1; /* ok, one fewer screen with RandR running */ 112 return (*pScreen->CloseScreen) (pScreen); 113} 114 115static void 116SRRScreenChangeNotifyEvent(xRRScreenChangeNotifyEvent * from, 117 xRRScreenChangeNotifyEvent * to) 118{ 119 to->type = from->type; 120 to->rotation = from->rotation; 121 cpswaps(from->sequenceNumber, to->sequenceNumber); 122 cpswapl(from->timestamp, to->timestamp); 123 cpswapl(from->configTimestamp, to->configTimestamp); 124 cpswapl(from->root, to->root); 125 cpswapl(from->window, to->window); 126 cpswaps(from->sizeID, to->sizeID); 127 cpswaps(from->subpixelOrder, to->subpixelOrder); 128 cpswaps(from->widthInPixels, to->widthInPixels); 129 cpswaps(from->heightInPixels, to->heightInPixels); 130 cpswaps(from->widthInMillimeters, to->widthInMillimeters); 131 cpswaps(from->heightInMillimeters, to->heightInMillimeters); 132} 133 134static void 135SRRCrtcChangeNotifyEvent(xRRCrtcChangeNotifyEvent * from, 136 xRRCrtcChangeNotifyEvent * to) 137{ 138 to->type = from->type; 139 to->subCode = from->subCode; 140 cpswaps(from->sequenceNumber, to->sequenceNumber); 141 cpswapl(from->timestamp, to->timestamp); 142 cpswapl(from->window, to->window); 143 cpswapl(from->crtc, to->crtc); 144 cpswapl(from->mode, to->mode); 145 cpswaps(from->rotation, to->rotation); 146 /* pad1 */ 147 cpswaps(from->x, to->x); 148 cpswaps(from->y, to->y); 149 cpswaps(from->width, to->width); 150 cpswaps(from->height, to->height); 151} 152 153static void 154SRROutputChangeNotifyEvent(xRROutputChangeNotifyEvent * from, 155 xRROutputChangeNotifyEvent * to) 156{ 157 to->type = from->type; 158 to->subCode = from->subCode; 159 cpswaps(from->sequenceNumber, to->sequenceNumber); 160 cpswapl(from->timestamp, to->timestamp); 161 cpswapl(from->configTimestamp, to->configTimestamp); 162 cpswapl(from->window, to->window); 163 cpswapl(from->output, to->output); 164 cpswapl(from->crtc, to->crtc); 165 cpswapl(from->mode, to->mode); 166 cpswaps(from->rotation, to->rotation); 167 to->connection = from->connection; 168 to->subpixelOrder = from->subpixelOrder; 169} 170 171static void 172SRROutputPropertyNotifyEvent(xRROutputPropertyNotifyEvent * from, 173 xRROutputPropertyNotifyEvent * to) 174{ 175 to->type = from->type; 176 to->subCode = from->subCode; 177 cpswaps(from->sequenceNumber, to->sequenceNumber); 178 cpswapl(from->window, to->window); 179 cpswapl(from->output, to->output); 180 cpswapl(from->atom, to->atom); 181 cpswapl(from->timestamp, to->timestamp); 182 to->state = from->state; 183 /* pad1 */ 184 /* pad2 */ 185 /* pad3 */ 186 /* pad4 */ 187} 188 189static void 190SRRProviderChangeNotifyEvent(xRRProviderChangeNotifyEvent * from, 191 xRRProviderChangeNotifyEvent * to) 192{ 193 to->type = from->type; 194 to->subCode = from->subCode; 195 cpswaps(from->sequenceNumber, to->sequenceNumber); 196 cpswapl(from->timestamp, to->timestamp); 197 cpswapl(from->window, to->window); 198 cpswapl(from->provider, to->provider); 199} 200 201static void 202SRRProviderPropertyNotifyEvent(xRRProviderPropertyNotifyEvent * from, 203 xRRProviderPropertyNotifyEvent * to) 204{ 205 to->type = from->type; 206 to->subCode = from->subCode; 207 cpswaps(from->sequenceNumber, to->sequenceNumber); 208 cpswapl(from->window, to->window); 209 cpswapl(from->provider, to->provider); 210 cpswapl(from->atom, to->atom); 211 cpswapl(from->timestamp, to->timestamp); 212 to->state = from->state; 213 /* pad1 */ 214 /* pad2 */ 215 /* pad3 */ 216 /* pad4 */ 217} 218 219static void _X_COLD 220SRRResourceChangeNotifyEvent(xRRResourceChangeNotifyEvent * from, 221 xRRResourceChangeNotifyEvent * to) 222{ 223 to->type = from->type; 224 to->subCode = from->subCode; 225 cpswaps(from->sequenceNumber, to->sequenceNumber); 226 cpswapl(from->timestamp, to->timestamp); 227 cpswapl(from->window, to->window); 228} 229 230static void _X_COLD 231SRRLeaseNotifyEvent(xRRLeaseNotifyEvent * from, 232 xRRLeaseNotifyEvent * to) 233{ 234 to->type = from->type; 235 to->subCode = from->subCode; 236 cpswaps(from->sequenceNumber, to->sequenceNumber); 237 cpswapl(from->timestamp, to->timestamp); 238 cpswapl(from->window, to->window); 239 cpswapl(from->lease, to->lease); 240 to->created = from->created; 241} 242 243static void _X_COLD 244SRRNotifyEvent(xEvent *from, xEvent *to) 245{ 246 switch (from->u.u.detail) { 247 case RRNotify_CrtcChange: 248 SRRCrtcChangeNotifyEvent((xRRCrtcChangeNotifyEvent *) from, 249 (xRRCrtcChangeNotifyEvent *) to); 250 break; 251 case RRNotify_OutputChange: 252 SRROutputChangeNotifyEvent((xRROutputChangeNotifyEvent *) from, 253 (xRROutputChangeNotifyEvent *) to); 254 break; 255 case RRNotify_OutputProperty: 256 SRROutputPropertyNotifyEvent((xRROutputPropertyNotifyEvent *) from, 257 (xRROutputPropertyNotifyEvent *) to); 258 break; 259 case RRNotify_ProviderChange: 260 SRRProviderChangeNotifyEvent((xRRProviderChangeNotifyEvent *) from, 261 (xRRProviderChangeNotifyEvent *) to); 262 break; 263 case RRNotify_ProviderProperty: 264 SRRProviderPropertyNotifyEvent((xRRProviderPropertyNotifyEvent *) from, 265 (xRRProviderPropertyNotifyEvent *) to); 266 break; 267 case RRNotify_ResourceChange: 268 SRRResourceChangeNotifyEvent((xRRResourceChangeNotifyEvent *) from, 269 (xRRResourceChangeNotifyEvent *) to); 270 break; 271 case RRNotify_Lease: 272 SRRLeaseNotifyEvent((xRRLeaseNotifyEvent *) from, 273 (xRRLeaseNotifyEvent *) to); 274 break; 275 default: 276 break; 277 } 278} 279 280static int RRGeneration; 281 282Bool 283RRInit(void) 284{ 285 if (RRGeneration != serverGeneration) { 286 if (!RRModeInit()) 287 return FALSE; 288 if (!RRCrtcInit()) 289 return FALSE; 290 if (!RROutputInit()) 291 return FALSE; 292 if (!RRProviderInit()) 293 return FALSE; 294 if (!RRLeaseInit()) 295 return FALSE; 296 RRGeneration = serverGeneration; 297 } 298 if (!dixRegisterPrivateKey(&rrPrivKeyRec, PRIVATE_SCREEN, 0)) 299 return FALSE; 300 301 return TRUE; 302} 303 304Bool 305RRScreenInit(ScreenPtr pScreen) 306{ 307 rrScrPrivPtr pScrPriv; 308 309 if (!RRInit()) 310 return FALSE; 311 312 pScrPriv = (rrScrPrivPtr) calloc(1, sizeof(rrScrPrivRec)); 313 if (!pScrPriv) 314 return FALSE; 315 316 SetRRScreen(pScreen, pScrPriv); 317 318 /* 319 * Calling function best set these function vectors 320 */ 321 pScrPriv->rrGetInfo = 0; 322 pScrPriv->maxWidth = pScrPriv->minWidth = pScreen->width; 323 pScrPriv->maxHeight = pScrPriv->minHeight = pScreen->height; 324 325 pScrPriv->width = pScreen->width; 326 pScrPriv->height = pScreen->height; 327 pScrPriv->mmWidth = pScreen->mmWidth; 328 pScrPriv->mmHeight = pScreen->mmHeight; 329#if RANDR_12_INTERFACE 330 pScrPriv->rrScreenSetSize = NULL; 331 pScrPriv->rrCrtcSet = NULL; 332 pScrPriv->rrCrtcSetGamma = NULL; 333#endif 334#if RANDR_10_INTERFACE 335 pScrPriv->rrSetConfig = 0; 336 pScrPriv->rotations = RR_Rotate_0; 337 pScrPriv->reqWidth = pScreen->width; 338 pScrPriv->reqHeight = pScreen->height; 339 pScrPriv->nSizes = 0; 340 pScrPriv->pSizes = NULL; 341 pScrPriv->rotation = RR_Rotate_0; 342 pScrPriv->rate = 0; 343 pScrPriv->size = 0; 344#endif 345 346 /* 347 * This value doesn't really matter -- any client must call 348 * GetScreenInfo before reading it which will automatically update 349 * the time 350 */ 351 pScrPriv->lastSetTime = currentTime; 352 pScrPriv->lastConfigTime = currentTime; 353 354 wrap(pScrPriv, pScreen, CloseScreen, RRCloseScreen); 355 356 pScreen->ConstrainCursorHarder = RRConstrainCursorHarder; 357 pScreen->ReplaceScanoutPixmap = RRReplaceScanoutPixmap; 358 pScrPriv->numOutputs = 0; 359 pScrPriv->outputs = NULL; 360 pScrPriv->numCrtcs = 0; 361 pScrPriv->crtcs = NULL; 362 363 xorg_list_init(&pScrPriv->leases); 364 365 RRMonitorInit(pScreen); 366 367 RRNScreens += 1; /* keep count of screens that implement randr */ 368 return TRUE; 369} 370 371 /*ARGSUSED*/ static int 372RRFreeClient(void *data, XID id) 373{ 374 RREventPtr pRREvent; 375 WindowPtr pWin; 376 RREventPtr *pHead, pCur, pPrev; 377 378 pRREvent = (RREventPtr) data; 379 pWin = pRREvent->window; 380 dixLookupResourceByType((void **) &pHead, pWin->drawable.id, 381 RREventType, serverClient, DixDestroyAccess); 382 if (pHead) { 383 pPrev = 0; 384 for (pCur = *pHead; pCur && pCur != pRREvent; pCur = pCur->next) 385 pPrev = pCur; 386 if (pCur) { 387 if (pPrev) 388 pPrev->next = pRREvent->next; 389 else 390 *pHead = pRREvent->next; 391 } 392 } 393 free((void *) pRREvent); 394 return 1; 395} 396 397 /*ARGSUSED*/ static int 398RRFreeEvents(void *data, XID id) 399{ 400 RREventPtr *pHead, pCur, pNext; 401 402 pHead = (RREventPtr *) data; 403 for (pCur = *pHead; pCur; pCur = pNext) { 404 pNext = pCur->next; 405 FreeResource(pCur->clientResource, RRClientType); 406 free((void *) pCur); 407 } 408 free((void *) pHead); 409 return 1; 410} 411 412void 413RRExtensionInit(void) 414{ 415 ExtensionEntry *extEntry; 416 417 if (RRNScreens == 0) 418 return; 419 420 if (!dixRegisterPrivateKey(&RRClientPrivateKeyRec, PRIVATE_CLIENT, 421 sizeof(RRClientRec) + 422 screenInfo.numScreens * sizeof(RRTimesRec))) 423 return; 424 if (!AddCallback(&ClientStateCallback, RRClientCallback, 0)) 425 return; 426 427 RRClientType = CreateNewResourceType(RRFreeClient, "RandRClient"); 428 if (!RRClientType) 429 return; 430 RREventType = CreateNewResourceType(RRFreeEvents, "RandREvent"); 431 if (!RREventType) 432 return; 433 extEntry = AddExtension(RANDR_NAME, RRNumberEvents, RRNumberErrors, 434 ProcRRDispatch, SProcRRDispatch, 435 NULL, StandardMinorOpcode); 436 if (!extEntry) 437 return; 438 RRErrorBase = extEntry->errorBase; 439 RREventBase = extEntry->eventBase; 440 EventSwapVector[RREventBase + RRScreenChangeNotify] = (EventSwapPtr) 441 SRRScreenChangeNotifyEvent; 442 EventSwapVector[RREventBase + RRNotify] = (EventSwapPtr) 443 SRRNotifyEvent; 444 445 RRModeInitErrorValue(); 446 RRCrtcInitErrorValue(); 447 RROutputInitErrorValue(); 448 RRProviderInitErrorValue(); 449#ifdef PANORAMIX 450 RRXineramaExtensionInit(); 451#endif 452} 453 454void 455RRResourcesChanged(ScreenPtr pScreen) 456{ 457 rrScrPriv(pScreen); 458 pScrPriv->resourcesChanged = TRUE; 459 460 RRSetChanged(pScreen); 461} 462 463static void 464RRDeliverResourceEvent(ClientPtr client, WindowPtr pWin) 465{ 466 ScreenPtr pScreen = pWin->drawable.pScreen; 467 468 rrScrPriv(pScreen); 469 470 xRRResourceChangeNotifyEvent re = { 471 .type = RRNotify + RREventBase, 472 .subCode = RRNotify_ResourceChange, 473 .timestamp = pScrPriv->lastSetTime.milliseconds, 474 .window = pWin->drawable.id 475 }; 476 477 WriteEventsToClient(client, 1, (xEvent *) &re); 478} 479 480static int 481TellChanged(WindowPtr pWin, void *value) 482{ 483 RREventPtr *pHead, pRREvent; 484 ClientPtr client; 485 ScreenPtr pScreen = pWin->drawable.pScreen; 486 ScreenPtr iter; 487 rrScrPrivPtr pSecondaryScrPriv; 488 489 rrScrPriv(pScreen); 490 int i; 491 492 dixLookupResourceByType((void **) &pHead, pWin->drawable.id, 493 RREventType, serverClient, DixReadAccess); 494 if (!pHead) 495 return WT_WALKCHILDREN; 496 497 for (pRREvent = *pHead; pRREvent; pRREvent = pRREvent->next) { 498 client = pRREvent->client; 499 if (client == serverClient || client->clientGone) 500 continue; 501 502 if (pRREvent->mask & RRScreenChangeNotifyMask) 503 RRDeliverScreenEvent(client, pWin, pScreen); 504 505 if (pRREvent->mask & RRCrtcChangeNotifyMask) { 506 for (i = 0; i < pScrPriv->numCrtcs; i++) { 507 RRCrtcPtr crtc = pScrPriv->crtcs[i]; 508 509 if (crtc->changed) 510 RRDeliverCrtcEvent(client, pWin, crtc); 511 } 512 513 xorg_list_for_each_entry(iter, &pScreen->secondary_list, secondary_head) { 514 if (!iter->is_output_secondary) 515 continue; 516 517 pSecondaryScrPriv = rrGetScrPriv(iter); 518 for (i = 0; i < pSecondaryScrPriv->numCrtcs; i++) { 519 RRCrtcPtr crtc = pSecondaryScrPriv->crtcs[i]; 520 521 if (crtc->changed) 522 RRDeliverCrtcEvent(client, pWin, crtc); 523 } 524 } 525 } 526 527 if (pRREvent->mask & RROutputChangeNotifyMask) { 528 for (i = 0; i < pScrPriv->numOutputs; i++) { 529 RROutputPtr output = pScrPriv->outputs[i]; 530 531 if (output->changed) 532 RRDeliverOutputEvent(client, pWin, output); 533 } 534 535 xorg_list_for_each_entry(iter, &pScreen->secondary_list, secondary_head) { 536 if (!iter->is_output_secondary) 537 continue; 538 539 pSecondaryScrPriv = rrGetScrPriv(iter); 540 for (i = 0; i < pSecondaryScrPriv->numOutputs; i++) { 541 RROutputPtr output = pSecondaryScrPriv->outputs[i]; 542 543 if (output->changed) 544 RRDeliverOutputEvent(client, pWin, output); 545 } 546 } 547 } 548 549 if (pRREvent->mask & RRProviderChangeNotifyMask) { 550 xorg_list_for_each_entry(iter, &pScreen->secondary_list, secondary_head) { 551 pSecondaryScrPriv = rrGetScrPriv(iter); 552 if (pSecondaryScrPriv->provider->changed) 553 RRDeliverProviderEvent(client, pWin, pSecondaryScrPriv->provider); 554 } 555 } 556 557 if (pRREvent->mask & RRResourceChangeNotifyMask) { 558 if (pScrPriv->resourcesChanged) { 559 RRDeliverResourceEvent(client, pWin); 560 } 561 } 562 563 if (pRREvent->mask & RRLeaseNotifyMask) { 564 if (pScrPriv->leasesChanged) { 565 RRDeliverLeaseEvent(client, pWin); 566 } 567 } 568 } 569 return WT_WALKCHILDREN; 570} 571 572void 573RRSetChanged(ScreenPtr pScreen) 574{ 575 /* set changed bits on the primary screen only */ 576 ScreenPtr primary; 577 rrScrPriv(pScreen); 578 rrScrPrivPtr primarysp; 579 580 if (pScreen->isGPU) { 581 primary = pScreen->current_primary; 582 if (!primary) 583 return; 584 primarysp = rrGetScrPriv(primary); 585 } 586 else { 587 primary = pScreen; 588 primarysp = pScrPriv; 589 } 590 591 primarysp->changed = TRUE; 592} 593 594/* 595 * Something changed; send events and adjust pointer position 596 */ 597void 598RRTellChanged(ScreenPtr pScreen) 599{ 600 ScreenPtr primary; 601 rrScrPriv(pScreen); 602 rrScrPrivPtr primarysp; 603 int i; 604 ScreenPtr iter; 605 rrScrPrivPtr pSecondaryScrPriv; 606 607 if (pScreen->isGPU) { 608 primary = pScreen->current_primary; 609 if (!primary) 610 return; 611 primarysp = rrGetScrPriv(primary); 612 } 613 else { 614 primary = pScreen; 615 primarysp = pScrPriv; 616 } 617 618 /* If there's no root window yet, can't send events */ 619 if (!primary->root) 620 return; 621 622 xorg_list_for_each_entry(iter, &primary->secondary_list, secondary_head) { 623 pSecondaryScrPriv = rrGetScrPriv(iter); 624 625 if (!iter->is_output_secondary) 626 continue; 627 628 if (CompareTimeStamps(primarysp->lastSetTime, 629 pSecondaryScrPriv->lastSetTime) == EARLIER) { 630 primarysp->lastSetTime = pSecondaryScrPriv->lastSetTime; 631 } 632 } 633 634 if (primarysp->changed) { 635 UpdateCurrentTimeIf(); 636 if (primarysp->configChanged) { 637 primarysp->lastConfigTime = currentTime; 638 primarysp->configChanged = FALSE; 639 } 640 pScrPriv->changed = FALSE; 641 primarysp->changed = FALSE; 642 643 WalkTree(primary, TellChanged, (void *) primary); 644 645 primarysp->resourcesChanged = FALSE; 646 647 for (i = 0; i < pScrPriv->numOutputs; i++) 648 pScrPriv->outputs[i]->changed = FALSE; 649 for (i = 0; i < pScrPriv->numCrtcs; i++) 650 pScrPriv->crtcs[i]->changed = FALSE; 651 652 xorg_list_for_each_entry(iter, &primary->secondary_list, secondary_head) { 653 pSecondaryScrPriv = rrGetScrPriv(iter); 654 pSecondaryScrPriv->provider->changed = FALSE; 655 if (iter->is_output_secondary) { 656 for (i = 0; i < pSecondaryScrPriv->numOutputs; i++) 657 pSecondaryScrPriv->outputs[i]->changed = FALSE; 658 for (i = 0; i < pSecondaryScrPriv->numCrtcs; i++) 659 pSecondaryScrPriv->crtcs[i]->changed = FALSE; 660 } 661 } 662 663 if (primarysp->layoutChanged) { 664 pScrPriv->layoutChanged = FALSE; 665 RRPointerScreenConfigured(primary); 666 RRSendConfigNotify(primary); 667 } 668 } 669} 670 671/* 672 * Return the first output which is connected to an active CRTC 673 * Used in emulating 1.0 behaviour 674 */ 675RROutputPtr 676RRFirstOutput(ScreenPtr pScreen) 677{ 678 rrScrPriv(pScreen); 679 RROutputPtr output; 680 int i, j; 681 682 if (!pScrPriv) 683 return NULL; 684 685 if (pScrPriv->primaryOutput && pScrPriv->primaryOutput->crtc) 686 return pScrPriv->primaryOutput; 687 688 for (i = 0; i < pScrPriv->numCrtcs; i++) { 689 RRCrtcPtr crtc = pScrPriv->crtcs[i]; 690 691 for (j = 0; j < pScrPriv->numOutputs; j++) { 692 output = pScrPriv->outputs[j]; 693 if (output->crtc == crtc) 694 return output; 695 } 696 } 697 return NULL; 698} 699 700RRCrtcPtr 701RRFirstEnabledCrtc(ScreenPtr pScreen) 702{ 703 rrScrPriv(pScreen); 704 RROutputPtr output; 705 int i, j; 706 707 if (!pScrPriv) 708 return NULL; 709 710 if (pScrPriv->primaryOutput && pScrPriv->primaryOutput->crtc && 711 pScrPriv->primaryOutput->pScreen == pScreen) 712 return pScrPriv->primaryOutput->crtc; 713 714 for (i = 0; i < pScrPriv->numCrtcs; i++) { 715 RRCrtcPtr crtc = pScrPriv->crtcs[i]; 716 717 for (j = 0; j < pScrPriv->numOutputs; j++) { 718 output = pScrPriv->outputs[j]; 719 if (output->crtc == crtc && crtc->mode) 720 return crtc; 721 } 722 } 723 return NULL; 724} 725 726 727CARD16 728RRVerticalRefresh(xRRModeInfo * mode) 729{ 730 CARD32 refresh; 731 CARD32 dots = mode->hTotal * mode->vTotal; 732 733 if (!dots) 734 return 0; 735 refresh = (mode->dotClock + dots / 2) / dots; 736 if (refresh > 0xffff) 737 refresh = 0xffff; 738 return (CARD16) refresh; 739} 740 741static int 742ProcRRDispatch(ClientPtr client) 743{ 744 REQUEST(xReq); 745 if (stuff->data >= RRNumberRequests || !ProcRandrVector[stuff->data]) 746 return BadRequest; 747 UpdateCurrentTimeIf(); 748 return (*ProcRandrVector[stuff->data]) (client); 749} 750 751static int _X_COLD 752SProcRRDispatch(ClientPtr client) 753{ 754 REQUEST(xReq); 755 if (stuff->data >= RRNumberRequests || !SProcRandrVector[stuff->data]) 756 return BadRequest; 757 UpdateCurrentTimeIf(); 758 return (*SProcRandrVector[stuff->data]) (client); 759} 760