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