rroutput.c revision 4642e01f
1/* 2 * Copyright © 2006 Keith Packard 3 * Copyright © 2008 Red Hat, Inc. 4 * 5 * Permission to use, copy, modify, distribute, and sell this software and its 6 * documentation for any purpose is hereby granted without fee, provided that 7 * the above copyright notice appear in all copies and that both that copyright 8 * notice and this permission notice appear in supporting documentation, and 9 * that the name of the copyright holders not be used in advertising or 10 * publicity pertaining to distribution of the software without specific, 11 * written prior permission. The copyright holders make no representations 12 * about the suitability of this software for any purpose. It is provided "as 13 * is" without express or implied warranty. 14 * 15 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 16 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 17 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 18 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 19 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 20 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 21 * OF THIS SOFTWARE. 22 */ 23 24#include "randrstr.h" 25#include "registry.h" 26 27RESTYPE RROutputType; 28 29/* 30 * Notify the output of some change 31 */ 32void 33RROutputChanged (RROutputPtr output, Bool configChanged) 34{ 35 ScreenPtr pScreen = output->pScreen; 36 37 output->changed = TRUE; 38 if (pScreen) 39 { 40 rrScrPriv (pScreen); 41 pScrPriv->changed = TRUE; 42 if (configChanged) 43 pScrPriv->configChanged = TRUE; 44 } 45} 46 47/* 48 * Create an output 49 */ 50 51RROutputPtr 52RROutputCreate (ScreenPtr pScreen, 53 const char *name, 54 int nameLength, 55 void *devPrivate) 56{ 57 RROutputPtr output; 58 RROutputPtr *outputs; 59 rrScrPrivPtr pScrPriv; 60 61 if (!RRInit()) 62 return NULL; 63 64 pScrPriv = rrGetScrPriv(pScreen); 65 66 if (pScrPriv->numOutputs) 67 outputs = xrealloc (pScrPriv->outputs, 68 (pScrPriv->numOutputs + 1) * sizeof (RROutputPtr)); 69 else 70 outputs = xalloc (sizeof (RROutputPtr)); 71 if (!outputs) 72 return FALSE; 73 74 pScrPriv->outputs = outputs; 75 76 output = xalloc (sizeof (RROutputRec) + nameLength + 1); 77 if (!output) 78 return NULL; 79 output->id = FakeClientID (0); 80 output->pScreen = pScreen; 81 output->name = (char *) (output + 1); 82 output->nameLength = nameLength; 83 memcpy (output->name, name, nameLength); 84 output->name[nameLength] = '\0'; 85 output->connection = RR_UnknownConnection; 86 output->subpixelOrder = SubPixelUnknown; 87 output->mmWidth = 0; 88 output->mmHeight = 0; 89 output->crtc = NULL; 90 output->numCrtcs = 0; 91 output->crtcs = NULL; 92 output->numClones = 0; 93 output->clones = NULL; 94 output->numModes = 0; 95 output->numPreferred = 0; 96 output->modes = NULL; 97 output->numUserModes = 0; 98 output->userModes = NULL; 99 output->properties = NULL; 100 output->pendingProperties = FALSE; 101 output->changed = FALSE; 102 output->devPrivate = devPrivate; 103 104 if (!AddResource (output->id, RROutputType, (pointer) output)) 105 return NULL; 106 107 pScrPriv->outputs[pScrPriv->numOutputs++] = output; 108 return output; 109} 110 111/* 112 * Notify extension that output parameters have been changed 113 */ 114Bool 115RROutputSetClones (RROutputPtr output, 116 RROutputPtr *clones, 117 int numClones) 118{ 119 RROutputPtr *newClones; 120 int i; 121 122 if (numClones == output->numClones) 123 { 124 for (i = 0; i < numClones; i++) 125 if (output->clones[i] != clones[i]) 126 break; 127 if (i == numClones) 128 return TRUE; 129 } 130 if (numClones) 131 { 132 newClones = xalloc (numClones * sizeof (RROutputPtr)); 133 if (!newClones) 134 return FALSE; 135 } 136 else 137 newClones = NULL; 138 if (output->clones) 139 xfree (output->clones); 140 memcpy (newClones, clones, numClones * sizeof (RROutputPtr)); 141 output->clones = newClones; 142 output->numClones = numClones; 143 RROutputChanged (output, TRUE); 144 return TRUE; 145} 146 147Bool 148RROutputSetModes (RROutputPtr output, 149 RRModePtr *modes, 150 int numModes, 151 int numPreferred) 152{ 153 RRModePtr *newModes; 154 int i; 155 156 if (numModes == output->numModes && numPreferred == output->numPreferred) 157 { 158 for (i = 0; i < numModes; i++) 159 if (output->modes[i] != modes[i]) 160 break; 161 if (i == numModes) 162 { 163 for (i = 0; i < numModes; i++) 164 RRModeDestroy (modes[i]); 165 return TRUE; 166 } 167 } 168 169 if (numModes) 170 { 171 newModes = xalloc (numModes * sizeof (RRModePtr)); 172 if (!newModes) 173 return FALSE; 174 } 175 else 176 newModes = NULL; 177 if (output->modes) 178 { 179 for (i = 0; i < output->numModes; i++) 180 RRModeDestroy (output->modes[i]); 181 xfree (output->modes); 182 } 183 memcpy (newModes, modes, numModes * sizeof (RRModePtr)); 184 output->modes = newModes; 185 output->numModes = numModes; 186 output->numPreferred = numPreferred; 187 RROutputChanged (output, TRUE); 188 return TRUE; 189} 190 191int 192RROutputAddUserMode (RROutputPtr output, 193 RRModePtr mode) 194{ 195 int m; 196 ScreenPtr pScreen = output->pScreen; 197 rrScrPriv(pScreen); 198 RRModePtr *newModes; 199 200 /* Check to see if this mode is already listed for this output */ 201 for (m = 0; m < output->numModes + output->numUserModes; m++) 202 { 203 RRModePtr e = (m < output->numModes ? 204 output->modes[m] : 205 output->userModes[m - output->numModes]); 206 if (mode == e) 207 return Success; 208 } 209 210 /* Check with the DDX to see if this mode is OK */ 211 if (pScrPriv->rrOutputValidateMode) 212 if (!pScrPriv->rrOutputValidateMode (pScreen, output, mode)) 213 return BadMatch; 214 215 if (output->userModes) 216 newModes = xrealloc (output->userModes, 217 (output->numUserModes + 1) * sizeof (RRModePtr)); 218 else 219 newModes = xalloc (sizeof (RRModePtr)); 220 if (!newModes) 221 return BadAlloc; 222 223 output->userModes = newModes; 224 output->userModes[output->numUserModes++] = mode; 225 ++mode->refcnt; 226 RROutputChanged (output, TRUE); 227 RRTellChanged (pScreen); 228 return Success; 229} 230 231int 232RROutputDeleteUserMode (RROutputPtr output, 233 RRModePtr mode) 234{ 235 int m; 236 237 /* Find this mode in the user mode list */ 238 for (m = 0; m < output->numUserModes; m++) 239 { 240 RRModePtr e = output->userModes[m]; 241 242 if (mode == e) 243 break; 244 } 245 /* Not there, access error */ 246 if (m == output->numUserModes) 247 return BadAccess; 248 249 /* make sure the mode isn't active for this output */ 250 if (output->crtc && output->crtc->mode == mode) 251 return BadMatch; 252 253 memmove (output->userModes + m, output->userModes + m + 1, 254 (output->numUserModes - m - 1) * sizeof (RRModePtr)); 255 output->numUserModes--; 256 RRModeDestroy (mode); 257 return Success; 258} 259 260Bool 261RROutputSetCrtcs (RROutputPtr output, 262 RRCrtcPtr *crtcs, 263 int numCrtcs) 264{ 265 RRCrtcPtr *newCrtcs; 266 int i; 267 268 if (numCrtcs == output->numCrtcs) 269 { 270 for (i = 0; i < numCrtcs; i++) 271 if (output->crtcs[i] != crtcs[i]) 272 break; 273 if (i == numCrtcs) 274 return TRUE; 275 } 276 if (numCrtcs) 277 { 278 newCrtcs = xalloc (numCrtcs * sizeof (RRCrtcPtr)); 279 if (!newCrtcs) 280 return FALSE; 281 } 282 else 283 newCrtcs = NULL; 284 if (output->crtcs) 285 xfree (output->crtcs); 286 memcpy (newCrtcs, crtcs, numCrtcs * sizeof (RRCrtcPtr)); 287 output->crtcs = newCrtcs; 288 output->numCrtcs = numCrtcs; 289 RROutputChanged (output, TRUE); 290 return TRUE; 291} 292 293Bool 294RROutputSetConnection (RROutputPtr output, 295 CARD8 connection) 296{ 297 if (output->connection == connection) 298 return TRUE; 299 output->connection = connection; 300 RROutputChanged (output, TRUE); 301 return TRUE; 302} 303 304Bool 305RROutputSetSubpixelOrder (RROutputPtr output, 306 int subpixelOrder) 307{ 308 if (output->subpixelOrder == subpixelOrder) 309 return TRUE; 310 311 output->subpixelOrder = subpixelOrder; 312 RROutputChanged (output, FALSE); 313 return TRUE; 314} 315 316Bool 317RROutputSetPhysicalSize (RROutputPtr output, 318 int mmWidth, 319 int mmHeight) 320{ 321 if (output->mmWidth == mmWidth && output->mmHeight == mmHeight) 322 return TRUE; 323 output->mmWidth = mmWidth; 324 output->mmHeight = mmHeight; 325 RROutputChanged (output, FALSE); 326 return TRUE; 327} 328 329 330void 331RRDeliverOutputEvent(ClientPtr client, WindowPtr pWin, RROutputPtr output) 332{ 333 ScreenPtr pScreen = pWin->drawable.pScreen; 334 rrScrPriv (pScreen); 335 xRROutputChangeNotifyEvent oe; 336 RRCrtcPtr crtc = output->crtc; 337 RRModePtr mode = crtc ? crtc->mode : 0; 338 339 oe.type = RRNotify + RREventBase; 340 oe.subCode = RRNotify_OutputChange; 341 oe.sequenceNumber = client->sequence; 342 oe.timestamp = pScrPriv->lastSetTime.milliseconds; 343 oe.configTimestamp = pScrPriv->lastConfigTime.milliseconds; 344 oe.window = pWin->drawable.id; 345 oe.output = output->id; 346 if (crtc) 347 { 348 oe.crtc = crtc->id; 349 oe.mode = mode ? mode->mode.id : None; 350 oe.rotation = crtc->rotation; 351 } 352 else 353 { 354 oe.crtc = None; 355 oe.mode = None; 356 oe.rotation = RR_Rotate_0; 357 } 358 oe.connection = output->connection; 359 oe.subpixelOrder = output->subpixelOrder; 360 WriteEventsToClient (client, 1, (xEvent *) &oe); 361} 362 363/* 364 * Destroy a Output at shutdown 365 */ 366void 367RROutputDestroy (RROutputPtr output) 368{ 369 FreeResource (output->id, 0); 370} 371 372static int 373RROutputDestroyResource (pointer value, XID pid) 374{ 375 RROutputPtr output = (RROutputPtr) value; 376 ScreenPtr pScreen = output->pScreen; 377 int m; 378 379 if (pScreen) 380 { 381 rrScrPriv(pScreen); 382 int i; 383 384 if (pScrPriv->primaryOutput == output) 385 pScrPriv->primaryOutput = NULL; 386 387 for (i = 0; i < pScrPriv->numOutputs; i++) 388 { 389 if (pScrPriv->outputs[i] == output) 390 { 391 memmove (pScrPriv->outputs + i, pScrPriv->outputs + i + 1, 392 (pScrPriv->numOutputs - (i + 1)) * sizeof (RROutputPtr)); 393 --pScrPriv->numOutputs; 394 break; 395 } 396 } 397 } 398 if (output->modes) 399 { 400 for (m = 0; m < output->numModes; m++) 401 RRModeDestroy (output->modes[m]); 402 xfree (output->modes); 403 } 404 405 for (m = 0; m < output->numUserModes; m++) 406 RRModeDestroy (output->userModes[m]); 407 if (output->userModes) 408 xfree (output->userModes); 409 410 if (output->crtcs) 411 xfree (output->crtcs); 412 if (output->clones) 413 xfree (output->clones); 414 RRDeleteAllOutputProperties (output); 415 xfree (output); 416 return 1; 417} 418 419/* 420 * Initialize output type 421 */ 422Bool 423RROutputInit (void) 424{ 425 RROutputType = CreateNewResourceType (RROutputDestroyResource); 426 if (!RROutputType) 427 return FALSE; 428 RegisterResourceName (RROutputType, "OUTPUT"); 429 return TRUE; 430} 431 432#define OutputInfoExtra (SIZEOF(xRRGetOutputInfoReply) - 32) 433 434int 435ProcRRGetOutputInfo (ClientPtr client) 436{ 437 REQUEST(xRRGetOutputInfoReq); 438 xRRGetOutputInfoReply rep; 439 RROutputPtr output; 440 CARD8 *extra; 441 unsigned long extraLen; 442 ScreenPtr pScreen; 443 rrScrPrivPtr pScrPriv; 444 RRCrtc *crtcs; 445 RRMode *modes; 446 RROutput *clones; 447 char *name; 448 int i, n; 449 450 REQUEST_SIZE_MATCH(xRRGetOutputInfoReq); 451 output = LookupOutput(client, stuff->output, DixReadAccess); 452 453 if (!output) 454 { 455 client->errorValue = stuff->output; 456 return RRErrorBase + BadRROutput; 457 } 458 459 pScreen = output->pScreen; 460 pScrPriv = rrGetScrPriv(pScreen); 461 462 rep.type = X_Reply; 463 rep.sequenceNumber = client->sequence; 464 rep.length = OutputInfoExtra >> 2; 465 rep.timestamp = pScrPriv->lastSetTime.milliseconds; 466 rep.crtc = output->crtc ? output->crtc->id : None; 467 rep.mmWidth = output->mmWidth; 468 rep.mmHeight = output->mmHeight; 469 rep.connection = output->connection; 470 rep.subpixelOrder = output->subpixelOrder; 471 rep.nCrtcs = output->numCrtcs; 472 rep.nModes = output->numModes + output->numUserModes; 473 rep.nPreferred = output->numPreferred; 474 rep.nClones = output->numClones; 475 rep.nameLength = output->nameLength; 476 477 extraLen = ((output->numCrtcs + 478 output->numModes + output->numUserModes + 479 output->numClones + 480 ((rep.nameLength + 3) >> 2)) << 2); 481 482 if (extraLen) 483 { 484 rep.length += extraLen >> 2; 485 extra = xalloc (extraLen); 486 if (!extra) 487 return BadAlloc; 488 } 489 else 490 extra = NULL; 491 492 crtcs = (RRCrtc *) extra; 493 modes = (RRMode *) (crtcs + output->numCrtcs); 494 clones = (RROutput *) (modes + output->numModes + output->numUserModes); 495 name = (char *) (clones + output->numClones); 496 497 for (i = 0; i < output->numCrtcs; i++) 498 { 499 crtcs[i] = output->crtcs[i]->id; 500 if (client->swapped) 501 swapl (&crtcs[i], n); 502 } 503 for (i = 0; i < output->numModes + output->numUserModes; i++) 504 { 505 if (i < output->numModes) 506 modes[i] = output->modes[i]->mode.id; 507 else 508 modes[i] = output->userModes[i - output->numModes]->mode.id; 509 if (client->swapped) 510 swapl (&modes[i], n); 511 } 512 for (i = 0; i < output->numClones; i++) 513 { 514 clones[i] = output->clones[i]->id; 515 if (client->swapped) 516 swapl (&clones[i], n); 517 } 518 memcpy (name, output->name, output->nameLength); 519 if (client->swapped) { 520 swaps(&rep.sequenceNumber, n); 521 swapl(&rep.length, n); 522 swapl(&rep.timestamp, n); 523 swapl(&rep.crtc, n); 524 swapl(&rep.mmWidth, n); 525 swapl(&rep.mmHeight, n); 526 swaps(&rep.nCrtcs, n); 527 swaps(&rep.nModes, n); 528 swaps(&rep.nClones, n); 529 swaps(&rep.nameLength, n); 530 } 531 WriteToClient(client, sizeof(xRRGetOutputInfoReply), (char *)&rep); 532 if (extraLen) 533 { 534 WriteToClient (client, extraLen, (char *) extra); 535 xfree (extra); 536 } 537 538 return client->noClientException; 539} 540 541void 542RRSetPrimaryOutput(ScreenPtr pScreen, rrScrPrivPtr pScrPriv, 543 RROutputPtr output) 544{ 545 if (pScrPriv->primaryOutput == output) 546 return; 547 548 /* clear the old primary */ 549 if (pScrPriv->primaryOutput) { 550 RROutputChanged(pScrPriv->primaryOutput, 0); 551 pScrPriv->primaryOutput = NULL; 552 } 553 554 /* set the new primary */ 555 if (output) { 556 pScrPriv->primaryOutput = output; 557 RROutputChanged(output, 0); 558 } 559 560 pScrPriv->layoutChanged = TRUE; 561 562 RRTellChanged(pScreen); 563} 564 565int 566ProcRRSetOutputPrimary(ClientPtr client) 567{ 568 REQUEST(xRRSetOutputPrimaryReq); 569 RROutputPtr output = NULL; 570 WindowPtr pWin; 571 rrScrPrivPtr pScrPriv; 572 573 REQUEST_SIZE_MATCH(xRRSetOutputPrimaryReq); 574 575 pWin = SecurityLookupIDByType(client, stuff->window, RT_WINDOW, 576 DixReadAccess); 577 578 if (!pWin) { 579 client->errorValue = stuff->window; 580 return BadWindow; 581 } 582 583 if (stuff->output) { 584 output = LookupOutput(client, stuff->output, DixReadAccess); 585 586 if (!output) { 587 client->errorValue = stuff->output; 588 return RRErrorBase + BadRROutput; 589 } 590 591 if (output->pScreen != pWin->drawable.pScreen) { 592 client->errorValue = stuff->window; 593 return BadMatch; 594 } 595 } 596 597 pScrPriv = rrGetScrPriv(pWin->drawable.pScreen); 598 RRSetPrimaryOutput(pWin->drawable.pScreen, pScrPriv, output); 599 600 return client->noClientException; 601} 602 603int 604ProcRRGetOutputPrimary(ClientPtr client) 605{ 606 REQUEST(xRRGetOutputPrimaryReq); 607 WindowPtr pWin; 608 rrScrPrivPtr pScrPriv; 609 xRRGetOutputPrimaryReply rep; 610 RROutputPtr primary = NULL; 611 612 REQUEST_SIZE_MATCH(xRRGetOutputPrimaryReq); 613 614 pWin = SecurityLookupIDByType(client, stuff->window, RT_WINDOW, 615 DixReadAccess); 616 617 if (!pWin) { 618 client->errorValue = stuff->window; 619 return BadWindow; 620 } 621 622 pScrPriv = rrGetScrPriv(pWin->drawable.pScreen); 623 if (pScrPriv) 624 primary = pScrPriv->primaryOutput; 625 626 memset(&rep, 0, sizeof(rep)); 627 rep.type = X_Reply; 628 rep.sequenceNumber = client->sequence; 629 rep.output = primary ? primary->id : None; 630 631 if (client->swapped) { 632 int n; 633 swaps(&rep.sequenceNumber, n); 634 swapl(&rep.output, n); 635 } 636 637 WriteToClient(client, sizeof(xRRGetOutputPrimaryReply), &rep); 638 639 return client->noClientException; 640} 641