rroutput.c revision 05b261ec
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 25RESTYPE RROutputType; 26 27/* 28 * Notify the output of some change 29 */ 30void 31RROutputChanged (RROutputPtr output, Bool configChanged) 32{ 33 ScreenPtr pScreen = output->pScreen; 34 35 output->changed = TRUE; 36 if (pScreen) 37 { 38 rrScrPriv (pScreen); 39 pScrPriv->changed = TRUE; 40 if (configChanged) 41 pScrPriv->configChanged = TRUE; 42 } 43} 44 45/* 46 * Create an output 47 */ 48 49RROutputPtr 50RROutputCreate (ScreenPtr pScreen, 51 const char *name, 52 int nameLength, 53 void *devPrivate) 54{ 55 RROutputPtr output; 56 RROutputPtr *outputs; 57 rrScrPrivPtr pScrPriv; 58 59 if (!RRInit()) 60 return NULL; 61 62 pScrPriv = rrGetScrPriv(pScreen); 63 64 if (pScrPriv->numOutputs) 65 outputs = xrealloc (pScrPriv->outputs, 66 (pScrPriv->numOutputs + 1) * sizeof (RROutputPtr)); 67 else 68 outputs = xalloc (sizeof (RROutputPtr)); 69 if (!outputs) 70 return FALSE; 71 72 pScrPriv->outputs = outputs; 73 74 output = xalloc (sizeof (RROutputRec) + nameLength + 1); 75 if (!output) 76 return NULL; 77 output->id = FakeClientID (0); 78 output->pScreen = pScreen; 79 output->name = (char *) (output + 1); 80 output->nameLength = nameLength; 81 memcpy (output->name, name, nameLength); 82 output->name[nameLength] = '\0'; 83 output->connection = RR_UnknownConnection; 84 output->subpixelOrder = SubPixelUnknown; 85 output->mmWidth = 0; 86 output->mmHeight = 0; 87 output->crtc = NULL; 88 output->numCrtcs = 0; 89 output->crtcs = NULL; 90 output->numClones = 0; 91 output->clones = NULL; 92 output->numModes = 0; 93 output->numPreferred = 0; 94 output->modes = NULL; 95 output->numUserModes = 0; 96 output->userModes = NULL; 97 output->properties = NULL; 98 output->changed = FALSE; 99 output->devPrivate = devPrivate; 100 101 if (!AddResource (output->id, RROutputType, (pointer) output)) 102 return NULL; 103 104 pScrPriv->outputs[pScrPriv->numOutputs++] = output; 105 return output; 106} 107 108/* 109 * Notify extension that output parameters have been changed 110 */ 111Bool 112RROutputSetClones (RROutputPtr output, 113 RROutputPtr *clones, 114 int numClones) 115{ 116 RROutputPtr *newClones; 117 int i; 118 119 if (numClones == output->numClones) 120 { 121 for (i = 0; i < numClones; i++) 122 if (output->clones[i] != clones[i]) 123 break; 124 if (i == numClones) 125 return TRUE; 126 } 127 if (numClones) 128 { 129 newClones = xalloc (numClones * sizeof (RROutputPtr)); 130 if (!newClones) 131 return FALSE; 132 } 133 else 134 newClones = NULL; 135 if (output->clones) 136 xfree (output->clones); 137 memcpy (newClones, clones, numClones * sizeof (RROutputPtr)); 138 output->clones = newClones; 139 output->numClones = numClones; 140 RROutputChanged (output, TRUE); 141 return TRUE; 142} 143 144Bool 145RROutputSetModes (RROutputPtr output, 146 RRModePtr *modes, 147 int numModes, 148 int numPreferred) 149{ 150 RRModePtr *newModes; 151 int i; 152 153 if (numModes == output->numModes && numPreferred == output->numPreferred) 154 { 155 for (i = 0; i < numModes; i++) 156 if (output->modes[i] != modes[i]) 157 break; 158 if (i == numModes) 159 { 160 for (i = 0; i < numModes; i++) 161 RRModeDestroy (modes[i]); 162 return TRUE; 163 } 164 } 165 166 if (numModes) 167 { 168 newModes = xalloc (numModes * sizeof (RRModePtr)); 169 if (!newModes) 170 return FALSE; 171 } 172 else 173 newModes = NULL; 174 if (output->modes) 175 { 176 for (i = 0; i < output->numModes; i++) 177 RRModeDestroy (output->modes[i]); 178 xfree (output->modes); 179 } 180 memcpy (newModes, modes, numModes * sizeof (RRModePtr)); 181 output->modes = newModes; 182 output->numModes = numModes; 183 output->numPreferred = numPreferred; 184 RROutputChanged (output, TRUE); 185 return TRUE; 186} 187 188int 189RROutputAddUserMode (RROutputPtr output, 190 RRModePtr mode) 191{ 192 int m; 193 ScreenPtr pScreen = output->pScreen; 194 rrScrPriv(pScreen); 195 RRModePtr *newModes; 196 197 /* Check to see if this mode is already listed for this output */ 198 for (m = 0; m < output->numModes + output->numUserModes; m++) 199 { 200 RRModePtr e = (m < output->numModes ? 201 output->modes[m] : 202 output->userModes[m - output->numModes]); 203 if (mode == e) 204 return Success; 205 } 206 207 /* Check with the DDX to see if this mode is OK */ 208 if (pScrPriv->rrOutputValidateMode) 209 if (!pScrPriv->rrOutputValidateMode (pScreen, output, mode)) 210 return BadMatch; 211 212 if (output->userModes) 213 newModes = xrealloc (output->userModes, 214 (output->numUserModes + 1) * sizeof (RRModePtr)); 215 else 216 newModes = xalloc (sizeof (RRModePtr)); 217 if (!newModes) 218 return BadAlloc; 219 220 output->userModes = newModes; 221 output->userModes[output->numUserModes++] = mode; 222 ++mode->refcnt; 223 RROutputChanged (output, TRUE); 224 RRTellChanged (pScreen); 225 return Success; 226} 227 228int 229RROutputDeleteUserMode (RROutputPtr output, 230 RRModePtr mode) 231{ 232 int m; 233 234 /* Find this mode in the user mode list */ 235 for (m = 0; m < output->numUserModes; m++) 236 { 237 RRModePtr e = output->userModes[m]; 238 239 if (mode == e) 240 break; 241 } 242 /* Not there, access error */ 243 if (m == output->numUserModes) 244 return BadAccess; 245 246 /* make sure the mode isn't active for this output */ 247 if (output->crtc && output->crtc->mode == mode) 248 return BadMatch; 249 250 memmove (output->userModes + m, output->userModes + m + 1, 251 (output->numUserModes - m - 1) * sizeof (RRModePtr)); 252 output->numUserModes--; 253 RRModeDestroy (mode); 254 return Success; 255} 256 257Bool 258RROutputSetCrtcs (RROutputPtr output, 259 RRCrtcPtr *crtcs, 260 int numCrtcs) 261{ 262 RRCrtcPtr *newCrtcs; 263 int i; 264 265 if (numCrtcs == output->numCrtcs) 266 { 267 for (i = 0; i < numCrtcs; i++) 268 if (output->crtcs[i] != crtcs[i]) 269 break; 270 if (i == numCrtcs) 271 return TRUE; 272 } 273 if (numCrtcs) 274 { 275 newCrtcs = xalloc (numCrtcs * sizeof (RRCrtcPtr)); 276 if (!newCrtcs) 277 return FALSE; 278 } 279 else 280 newCrtcs = NULL; 281 if (output->crtcs) 282 xfree (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.sequenceNumber = client->sequence; 339 oe.timestamp = pScrPriv->lastSetTime.milliseconds; 340 oe.configTimestamp = pScrPriv->lastConfigTime.milliseconds; 341 oe.window = pWin->drawable.id; 342 oe.output = output->id; 343 if (crtc) 344 { 345 oe.crtc = crtc->id; 346 oe.mode = mode ? mode->mode.id : None; 347 oe.rotation = crtc->rotation; 348 } 349 else 350 { 351 oe.crtc = None; 352 oe.mode = None; 353 oe.rotation = RR_Rotate_0; 354 } 355 oe.connection = output->connection; 356 oe.subpixelOrder = output->subpixelOrder; 357 WriteEventsToClient (client, 1, (xEvent *) &oe); 358} 359 360/* 361 * Destroy a Output at shutdown 362 */ 363void 364RROutputDestroy (RROutputPtr output) 365{ 366 FreeResource (output->id, 0); 367} 368 369static int 370RROutputDestroyResource (pointer value, XID pid) 371{ 372 RROutputPtr output = (RROutputPtr) value; 373 ScreenPtr pScreen = output->pScreen; 374 int m; 375 376 if (pScreen) 377 { 378 rrScrPriv(pScreen); 379 int i; 380 381 for (i = 0; i < pScrPriv->numOutputs; i++) 382 { 383 if (pScrPriv->outputs[i] == output) 384 { 385 memmove (pScrPriv->outputs + i, pScrPriv->outputs + i + 1, 386 (pScrPriv->numOutputs - (i + 1)) * sizeof (RROutputPtr)); 387 --pScrPriv->numOutputs; 388 break; 389 } 390 } 391 } 392 if (output->modes) 393 { 394 for (m = 0; m < output->numModes; m++) 395 RRModeDestroy (output->modes[m]); 396 xfree (output->modes); 397 } 398 399 for (m = 0; m < output->numUserModes; m++) 400 RRModeDestroy (output->userModes[m]); 401 if (output->userModes) 402 xfree (output->userModes); 403 404 if (output->crtcs) 405 xfree (output->crtcs); 406 if (output->clones) 407 xfree (output->clones); 408 RRDeleteAllOutputProperties (output); 409 xfree (output); 410 return 1; 411} 412 413/* 414 * Initialize output type 415 */ 416Bool 417RROutputInit (void) 418{ 419 RROutputType = CreateNewResourceType (RROutputDestroyResource); 420 if (!RROutputType) 421 return FALSE; 422#ifdef XResExtension 423 RegisterResourceName (RROutputType, "OUTPUT"); 424#endif 425 return TRUE; 426} 427 428#define OutputInfoExtra (SIZEOF(xRRGetOutputInfoReply) - 32) 429 430int 431ProcRRGetOutputInfo (ClientPtr client) 432{ 433 REQUEST(xRRGetOutputInfoReq); 434 xRRGetOutputInfoReply rep; 435 RROutputPtr output; 436 CARD8 *extra; 437 unsigned long extraLen; 438 ScreenPtr pScreen; 439 rrScrPrivPtr pScrPriv; 440 RRCrtc *crtcs; 441 RRMode *modes; 442 RROutput *clones; 443 char *name; 444 int i, n; 445 446 REQUEST_SIZE_MATCH(xRRGetOutputInfoReq); 447 output = LookupOutput(client, stuff->output, DixReadAccess); 448 449 if (!output) 450 { 451 client->errorValue = stuff->output; 452 return RRErrorBase + BadRROutput; 453 } 454 455 pScreen = output->pScreen; 456 pScrPriv = rrGetScrPriv(pScreen); 457 458 rep.type = X_Reply; 459 rep.sequenceNumber = client->sequence; 460 rep.length = OutputInfoExtra >> 2; 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 ((rep.nameLength + 3) >> 2)) << 2); 477 478 if (extraLen) 479 { 480 rep.length += extraLen >> 2; 481 extra = xalloc (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 xfree (extra); 532 } 533 534 return client->noClientException; 535} 536