rrmonitor.c (23653B)
1 /* 2 * Copyright © 2014 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 #include "swaprep.h" 25 26 static Atom 27 RRMonitorCrtcName(RRCrtcPtr crtc) 28 { 29 char name[20]; 30 31 if (crtc->numOutputs) { 32 RROutputPtr output = crtc->outputs[0]; 33 return MakeAtom(output->name, output->nameLength, TRUE); 34 } 35 sprintf(name, "Monitor-%08lx", (unsigned long int)crtc->id); 36 return MakeAtom(name, strlen(name), TRUE); 37 } 38 39 static Bool 40 RRMonitorCrtcPrimary(RRCrtcPtr crtc) 41 { 42 ScreenPtr screen = crtc->pScreen; 43 rrScrPrivPtr pScrPriv = rrGetScrPriv(screen); 44 int o; 45 46 for (o = 0; o < crtc->numOutputs; o++) 47 if (crtc->outputs[o] == pScrPriv->primaryOutput) 48 return TRUE; 49 return FALSE; 50 } 51 52 #define DEFAULT_PIXELS_PER_MM (96.0 / 25.4) 53 54 static void 55 RRMonitorGetCrtcGeometry(RRCrtcPtr crtc, RRMonitorGeometryPtr geometry) 56 { 57 ScreenPtr screen = crtc->pScreen; 58 rrScrPrivPtr pScrPriv = rrGetScrPriv(screen); 59 BoxRec panned_area; 60 61 /* Check to see if crtc is panned and return the full area when applicable. */ 62 if (pScrPriv && pScrPriv->rrGetPanning && 63 pScrPriv->rrGetPanning(screen, crtc, &panned_area, NULL, NULL) && 64 (panned_area.x2 > panned_area.x1) && 65 (panned_area.y2 > panned_area.y1)) { 66 geometry->box = panned_area; 67 } 68 else { 69 int width, height; 70 71 RRCrtcGetScanoutSize(crtc, &width, &height); 72 geometry->box.x1 = crtc->x; 73 geometry->box.y1 = crtc->y; 74 geometry->box.x2 = geometry->box.x1 + width; 75 geometry->box.y2 = geometry->box.y1 + height; 76 } 77 if (crtc->numOutputs && crtc->outputs[0]->mmWidth && crtc->outputs[0]->mmHeight) { 78 RROutputPtr output = crtc->outputs[0]; 79 geometry->mmWidth = output->mmWidth; 80 geometry->mmHeight = output->mmHeight; 81 } else { 82 geometry->mmWidth = floor ((geometry->box.x2 - geometry->box.x1) / DEFAULT_PIXELS_PER_MM + 0.5); 83 geometry->mmHeight = floor ((geometry->box.y2 - geometry->box.y1) / DEFAULT_PIXELS_PER_MM + 0.5); 84 } 85 } 86 87 static Bool 88 RRMonitorSetFromServer(RRCrtcPtr crtc, RRMonitorPtr monitor) 89 { 90 int o; 91 92 monitor->name = RRMonitorCrtcName(crtc); 93 monitor->pScreen = crtc->pScreen; 94 monitor->numOutputs = crtc->numOutputs; 95 monitor->outputs = calloc(crtc->numOutputs, sizeof(RROutput)); 96 if (!monitor->outputs) 97 return FALSE; 98 for (o = 0; o < crtc->numOutputs; o++) 99 monitor->outputs[o] = crtc->outputs[o]->id; 100 monitor->primary = RRMonitorCrtcPrimary(crtc); 101 monitor->automatic = TRUE; 102 RRMonitorGetCrtcGeometry(crtc, &monitor->geometry); 103 return TRUE; 104 } 105 106 static Bool 107 RRMonitorAutomaticGeometry(RRMonitorPtr monitor) 108 { 109 return (monitor->geometry.box.x1 == 0 && 110 monitor->geometry.box.y1 == 0 && 111 monitor->geometry.box.x2 == 0 && 112 monitor->geometry.box.y2 == 0); 113 } 114 115 static void 116 RRMonitorGetGeometry(RRMonitorPtr monitor, RRMonitorGeometryPtr geometry) 117 { 118 if (RRMonitorAutomaticGeometry(monitor) && monitor->numOutputs > 0) { 119 ScreenPtr screen = monitor->pScreen; 120 rrScrPrivPtr pScrPriv = rrGetScrPriv(screen); 121 RRMonitorGeometryRec first = { .box = { 0, 0, 0, 0 }, .mmWidth = 0, .mmHeight = 0 }; 122 RRMonitorGeometryRec this; 123 int c, o, co; 124 int active_crtcs = 0; 125 126 *geometry = first; 127 for (o = 0; o < monitor->numOutputs; o++) { 128 RRCrtcPtr crtc = NULL; 129 Bool in_use = FALSE; 130 131 for (c = 0; !in_use && c < pScrPriv->numCrtcs; c++) { 132 crtc = pScrPriv->crtcs[c]; 133 if (!crtc->mode) 134 continue; 135 for (co = 0; !in_use && co < crtc->numOutputs; co++) 136 if (monitor->outputs[o] == crtc->outputs[co]->id) 137 in_use = TRUE; 138 } 139 140 if (!in_use) 141 continue; 142 143 RRMonitorGetCrtcGeometry(crtc, &this); 144 145 if (active_crtcs == 0) { 146 first = this; 147 *geometry = this; 148 } else { 149 geometry->box.x1 = min(this.box.x1, geometry->box.x1); 150 geometry->box.x2 = max(this.box.x2, geometry->box.x2); 151 geometry->box.y1 = min(this.box.y1, geometry->box.y1); 152 geometry->box.y2 = max(this.box.y2, geometry->box.y2); 153 } 154 active_crtcs++; 155 } 156 157 /* Adjust physical sizes to account for total area */ 158 if (active_crtcs > 1 && first.box.x2 != first.box.x1 && first.box.y2 != first.box.y1) { 159 geometry->mmWidth = (this.box.x2 - this.box.x1) / (first.box.x2 - first.box.x1) * first.mmWidth; 160 geometry->mmHeight = (this.box.y2 - this.box.y1) / (first.box.y2 - first.box.y1) * first.mmHeight; 161 } 162 } else { 163 *geometry = monitor->geometry; 164 } 165 } 166 167 static Bool 168 RRMonitorSetFromClient(RRMonitorPtr client_monitor, RRMonitorPtr monitor) 169 { 170 monitor->name = client_monitor->name; 171 monitor->pScreen = client_monitor->pScreen; 172 monitor->numOutputs = client_monitor->numOutputs; 173 monitor->outputs = calloc(client_monitor->numOutputs, sizeof (RROutput)); 174 if (!monitor->outputs && client_monitor->numOutputs) 175 return FALSE; 176 memcpy(monitor->outputs, client_monitor->outputs, client_monitor->numOutputs * sizeof (RROutput)); 177 monitor->primary = client_monitor->primary; 178 monitor->automatic = client_monitor->automatic; 179 RRMonitorGetGeometry(client_monitor, &monitor->geometry); 180 return TRUE; 181 } 182 183 typedef struct _rrMonitorList { 184 int num_client; 185 int num_server; 186 RRCrtcPtr *server_crtc; 187 int num_crtcs; 188 int client_primary; 189 int server_primary; 190 } RRMonitorListRec, *RRMonitorListPtr; 191 192 static Bool 193 RRMonitorInitList(ScreenPtr screen, RRMonitorListPtr mon_list, Bool get_active) 194 { 195 rrScrPrivPtr pScrPriv = rrGetScrPriv(screen); 196 int m, o, c, sc; 197 int numCrtcs; 198 ScreenPtr secondary; 199 200 if (!RRGetInfo(screen, FALSE)) 201 return FALSE; 202 203 /* Count the number of crtcs in this and any secondary screens */ 204 numCrtcs = pScrPriv->numCrtcs; 205 xorg_list_for_each_entry(secondary, &screen->secondary_list, secondary_head) { 206 rrScrPrivPtr pSecondaryPriv; 207 208 if (!secondary->is_output_secondary) 209 continue; 210 211 pSecondaryPriv = rrGetScrPriv(secondary); 212 numCrtcs += pSecondaryPriv->numCrtcs; 213 } 214 mon_list->num_crtcs = numCrtcs; 215 216 mon_list->server_crtc = calloc(numCrtcs * 2, sizeof (RRCrtcPtr)); 217 if (!mon_list->server_crtc) 218 return FALSE; 219 220 /* Collect pointers to all of the active crtcs */ 221 c = 0; 222 for (sc = 0; sc < pScrPriv->numCrtcs; sc++, c++) { 223 if (pScrPriv->crtcs[sc]->mode != NULL) 224 mon_list->server_crtc[c] = pScrPriv->crtcs[sc]; 225 } 226 227 xorg_list_for_each_entry(secondary, &screen->secondary_list, secondary_head) { 228 rrScrPrivPtr pSecondaryPriv; 229 230 if (!secondary->is_output_secondary) 231 continue; 232 233 pSecondaryPriv = rrGetScrPriv(secondary); 234 for (sc = 0; sc < pSecondaryPriv->numCrtcs; sc++, c++) { 235 if (pSecondaryPriv->crtcs[sc]->mode != NULL) 236 mon_list->server_crtc[c] = pSecondaryPriv->crtcs[sc]; 237 } 238 } 239 240 /* Walk the list of client-defined monitors, clearing the covered 241 * CRTCs from the full list and finding whether one of the 242 * monitors is primary 243 */ 244 mon_list->num_client = pScrPriv->numMonitors; 245 mon_list->client_primary = -1; 246 247 for (m = 0; m < pScrPriv->numMonitors; m++) { 248 RRMonitorPtr monitor = pScrPriv->monitors[m]; 249 if (get_active) { 250 RRMonitorGeometryRec geom; 251 252 RRMonitorGetGeometry(monitor, &geom); 253 if (geom.box.x2 - geom.box.x1 == 0 || 254 geom.box.y2 - geom.box.y1 == 0) { 255 mon_list->num_client--; 256 continue; 257 } 258 } 259 if (monitor->primary && mon_list->client_primary == -1) 260 mon_list->client_primary = m; 261 for (o = 0; o < monitor->numOutputs; o++) { 262 for (c = 0; c < numCrtcs; c++) { 263 RRCrtcPtr crtc = mon_list->server_crtc[c]; 264 if (crtc) { 265 int co; 266 for (co = 0; co < crtc->numOutputs; co++) 267 if (crtc->outputs[co]->id == monitor->outputs[o]) { 268 mon_list->server_crtc[c] = NULL; 269 break; 270 } 271 } 272 } 273 } 274 } 275 276 /* Now look at the active CRTCs, and count 277 * those not covered by a client monitor, as well 278 * as finding whether one of them is marked primary 279 */ 280 mon_list->num_server = 0; 281 mon_list->server_primary = -1; 282 283 for (c = 0; c < mon_list->num_crtcs; c++) { 284 RRCrtcPtr crtc = mon_list->server_crtc[c]; 285 286 if (!crtc) 287 continue; 288 289 mon_list->num_server++; 290 291 if (RRMonitorCrtcPrimary(crtc) && mon_list->server_primary == -1) 292 mon_list->server_primary = c; 293 } 294 return TRUE; 295 } 296 297 static void 298 RRMonitorFiniList(RRMonitorListPtr list) 299 { 300 free(list->server_crtc); 301 } 302 303 /* Construct a complete list of protocol-visible monitors, including 304 * the manually generated ones as well as those generated 305 * automatically from the remaining CRCTs 306 */ 307 308 Bool 309 RRMonitorMakeList(ScreenPtr screen, Bool get_active, RRMonitorPtr *monitors_ret, int *nmon_ret) 310 { 311 rrScrPrivPtr pScrPriv = rrGetScrPriv(screen); 312 RRMonitorListRec list; 313 int m, c; 314 RRMonitorPtr mon, monitors; 315 Bool has_primary = FALSE; 316 317 if (!pScrPriv) 318 return FALSE; 319 320 if (!RRMonitorInitList(screen, &list, get_active)) 321 return FALSE; 322 323 monitors = calloc(list.num_client + list.num_server, sizeof (RRMonitorRec)); 324 if (!monitors) { 325 RRMonitorFiniList(&list); 326 return FALSE; 327 } 328 329 mon = monitors; 330 331 /* Fill in the primary monitor data first 332 */ 333 if (list.client_primary >= 0) { 334 RRMonitorSetFromClient(pScrPriv->monitors[list.client_primary], mon); 335 mon++; 336 } else if (list.server_primary >= 0) { 337 RRMonitorSetFromServer(list.server_crtc[list.server_primary], mon); 338 mon++; 339 } 340 341 /* Fill in the client-defined monitors next 342 */ 343 for (m = 0; m < pScrPriv->numMonitors; m++) { 344 if (m == list.client_primary) 345 continue; 346 if (get_active) { 347 RRMonitorGeometryRec geom; 348 349 RRMonitorGetGeometry(pScrPriv->monitors[m], &geom); 350 if (geom.box.x2 - geom.box.x1 == 0 || 351 geom.box.y2 - geom.box.y1 == 0) { 352 continue; 353 } 354 } 355 RRMonitorSetFromClient(pScrPriv->monitors[m], mon); 356 if (has_primary) 357 mon->primary = FALSE; 358 else if (mon->primary) 359 has_primary = TRUE; 360 mon++; 361 } 362 363 /* And finish with the list of crtc-inspired monitors 364 */ 365 for (c = 0; c < list.num_crtcs; c++) { 366 RRCrtcPtr crtc = list.server_crtc[c]; 367 if (c == list.server_primary && list.client_primary < 0) 368 continue; 369 370 if (!list.server_crtc[c]) 371 continue; 372 373 RRMonitorSetFromServer(crtc, mon); 374 if (has_primary) 375 mon->primary = FALSE; 376 else if (mon->primary) 377 has_primary = TRUE; 378 mon++; 379 } 380 381 RRMonitorFiniList(&list); 382 *nmon_ret = list.num_client + list.num_server; 383 *monitors_ret = monitors; 384 return TRUE; 385 } 386 387 int 388 RRMonitorCountList(ScreenPtr screen) 389 { 390 RRMonitorListRec list; 391 int nmon; 392 393 if (!RRMonitorInitList(screen, &list, FALSE)) 394 return -1; 395 nmon = list.num_client + list.num_server; 396 RRMonitorFiniList(&list); 397 return nmon; 398 } 399 400 void 401 RRMonitorFree(RRMonitorPtr monitor) 402 { 403 free(monitor); 404 } 405 406 RRMonitorPtr 407 RRMonitorAlloc(int noutput) 408 { 409 RRMonitorPtr monitor; 410 411 monitor = calloc(1, sizeof (RRMonitorRec) + noutput * sizeof (RROutput)); 412 if (!monitor) 413 return NULL; 414 monitor->numOutputs = noutput; 415 monitor->outputs = (RROutput *) (monitor + 1); 416 return monitor; 417 } 418 419 static int 420 RRMonitorDelete(ClientPtr client, ScreenPtr screen, Atom name) 421 { 422 rrScrPrivPtr pScrPriv = rrGetScrPriv(screen); 423 int m; 424 425 if (!pScrPriv) { 426 client->errorValue = name; 427 return BadAtom; 428 } 429 430 for (m = 0; m < pScrPriv->numMonitors; m++) { 431 RRMonitorPtr monitor = pScrPriv->monitors[m]; 432 if (monitor->name == name) { 433 memmove(pScrPriv->monitors + m, pScrPriv->monitors + m + 1, 434 (pScrPriv->numMonitors - (m + 1)) * sizeof (RRMonitorPtr)); 435 --pScrPriv->numMonitors; 436 RRMonitorFree(monitor); 437 return Success; 438 } 439 } 440 441 client->errorValue = name; 442 return BadValue; 443 } 444 445 static Bool 446 RRMonitorMatchesOutputName(ScreenPtr screen, Atom name) 447 { 448 rrScrPrivPtr pScrPriv = rrGetScrPriv(screen); 449 int o; 450 const char *str = NameForAtom(name); 451 int len = strlen(str); 452 453 for (o = 0; o < pScrPriv->numOutputs; o++) { 454 RROutputPtr output = pScrPriv->outputs[o]; 455 456 if (output->nameLength == len && !memcmp(output->name, str, len)) 457 return TRUE; 458 } 459 return FALSE; 460 } 461 462 int 463 RRMonitorAdd(ClientPtr client, ScreenPtr screen, RRMonitorPtr monitor) 464 { 465 rrScrPrivPtr pScrPriv = rrGetScrPriv(screen); 466 int m; 467 ScreenPtr secondary; 468 RRMonitorPtr *monitors; 469 470 if (!pScrPriv) 471 return BadAlloc; 472 473 /* 'name' must not match the name of any Output on the screen, or 474 * a Value error results. 475 */ 476 477 if (RRMonitorMatchesOutputName(screen, monitor->name)) { 478 client->errorValue = monitor->name; 479 return BadValue; 480 } 481 482 xorg_list_for_each_entry(secondary, &screen->secondary_list, secondary_head) { 483 if (!secondary->is_output_secondary) 484 continue; 485 486 if (RRMonitorMatchesOutputName(secondary, monitor->name)) { 487 client->errorValue = monitor->name; 488 return BadValue; 489 } 490 } 491 492 /* 'name' must not match the name of any Monitor on the screen, or 493 * a Value error results. 494 */ 495 496 for (m = 0; m < pScrPriv->numMonitors; m++) { 497 if (pScrPriv->monitors[m]->name == monitor->name) { 498 client->errorValue = monitor->name; 499 return BadValue; 500 } 501 } 502 503 /* Allocate space for the new pointer. This is done before 504 * removing matching monitors as it may fail, and the request 505 * needs to not have any side-effects on failure 506 */ 507 if (pScrPriv->numMonitors) 508 monitors = reallocarray(pScrPriv->monitors, 509 pScrPriv->numMonitors + 1, 510 sizeof (RRMonitorPtr)); 511 else 512 monitors = malloc(sizeof (RRMonitorPtr)); 513 514 if (!monitors) 515 return BadAlloc; 516 517 pScrPriv->monitors = monitors; 518 519 for (m = 0; m < pScrPriv->numMonitors; m++) { 520 RRMonitorPtr existing = pScrPriv->monitors[m]; 521 int o, eo; 522 523 /* If 'name' matches an existing Monitor on the screen, the 524 * existing one will be deleted as if RRDeleteMonitor were called. 525 */ 526 if (existing->name == monitor->name) { 527 (void) RRMonitorDelete(client, screen, existing->name); 528 continue; 529 } 530 531 /* For each output in 'info.outputs', each one is removed from all 532 * pre-existing Monitors. If removing the output causes the list 533 * of outputs for that Monitor to become empty, then that 534 * Monitor will be deleted as if RRDeleteMonitor were called. 535 */ 536 537 for (eo = 0; eo < existing->numOutputs; eo++) { 538 for (o = 0; o < monitor->numOutputs; o++) { 539 if (monitor->outputs[o] == existing->outputs[eo]) { 540 memmove(existing->outputs + eo, existing->outputs + eo + 1, 541 (existing->numOutputs - (eo + 1)) * sizeof (RROutput)); 542 --existing->numOutputs; 543 --eo; 544 break; 545 } 546 } 547 if (existing->numOutputs == 0) { 548 (void) RRMonitorDelete(client, screen, existing->name); 549 break; 550 } 551 } 552 if (monitor->primary) 553 existing->primary = FALSE; 554 } 555 556 /* Add the new one to the list 557 */ 558 pScrPriv->monitors[pScrPriv->numMonitors++] = monitor; 559 560 return Success; 561 } 562 563 void 564 RRMonitorFreeList(RRMonitorPtr monitors, int nmon) 565 { 566 int m; 567 568 for (m = 0; m < nmon; m++) 569 free(monitors[m].outputs); 570 free(monitors); 571 } 572 573 void 574 RRMonitorInit(ScreenPtr screen) 575 { 576 rrScrPrivPtr pScrPriv = rrGetScrPriv(screen); 577 578 if (!pScrPriv) 579 return; 580 581 pScrPriv->numMonitors = 0; 582 pScrPriv->monitors = NULL; 583 } 584 585 void 586 RRMonitorClose(ScreenPtr screen) 587 { 588 rrScrPrivPtr pScrPriv = rrGetScrPriv(screen); 589 int m; 590 591 if (!pScrPriv) 592 return; 593 594 for (m = 0; m < pScrPriv->numMonitors; m++) 595 RRMonitorFree(pScrPriv->monitors[m]); 596 free(pScrPriv->monitors); 597 pScrPriv->monitors = NULL; 598 pScrPriv->numMonitors = 0; 599 } 600 601 static CARD32 602 RRMonitorTimestamp(ScreenPtr screen) 603 { 604 rrScrPrivPtr pScrPriv = rrGetScrPriv(screen); 605 606 /* XXX should take client monitor changes into account */ 607 return pScrPriv->lastConfigTime.milliseconds; 608 } 609 610 int 611 ProcRRGetMonitors(ClientPtr client) 612 { 613 REQUEST(xRRGetMonitorsReq); 614 xRRGetMonitorsReply rep = { 615 .type = X_Reply, 616 .sequenceNumber = client->sequence, 617 .length = 0, 618 }; 619 WindowPtr window; 620 ScreenPtr screen; 621 int r; 622 RRMonitorPtr monitors; 623 int nmonitors; 624 int noutputs; 625 int m; 626 Bool get_active; 627 REQUEST_SIZE_MATCH(xRRGetMonitorsReq); 628 r = dixLookupWindow(&window, stuff->window, client, DixGetAttrAccess); 629 if (r != Success) 630 return r; 631 screen = window->drawable.pScreen; 632 633 get_active = stuff->get_active; 634 if (!RRMonitorMakeList(screen, get_active, &monitors, &nmonitors)) 635 return BadAlloc; 636 637 rep.timestamp = RRMonitorTimestamp(screen); 638 639 noutputs = 0; 640 for (m = 0; m < nmonitors; m++) { 641 rep.length += SIZEOF(xRRMonitorInfo) >> 2; 642 rep.length += monitors[m].numOutputs; 643 noutputs += monitors[m].numOutputs; 644 } 645 646 rep.nmonitors = nmonitors; 647 rep.noutputs = noutputs; 648 649 if (client->swapped) { 650 swaps(&rep.sequenceNumber); 651 swapl(&rep.length); 652 swapl(&rep.timestamp); 653 swapl(&rep.nmonitors); 654 swapl(&rep.noutputs); 655 } 656 WriteToClient(client, sizeof(xRRGetMonitorsReply), &rep); 657 658 client->pSwapReplyFunc = (ReplySwapPtr) CopySwap32Write; 659 660 for (m = 0; m < nmonitors; m++) { 661 RRMonitorPtr monitor = &monitors[m]; 662 xRRMonitorInfo info = { 663 .name = monitor->name, 664 .primary = monitor->primary, 665 .automatic = monitor->automatic, 666 .noutput = monitor->numOutputs, 667 .x = monitor->geometry.box.x1, 668 .y = monitor->geometry.box.y1, 669 .width = monitor->geometry.box.x2 - monitor->geometry.box.x1, 670 .height = monitor->geometry.box.y2 - monitor->geometry.box.y1, 671 .widthInMillimeters = monitor->geometry.mmWidth, 672 .heightInMillimeters = monitor->geometry.mmHeight, 673 }; 674 if (client->swapped) { 675 swapl(&info.name); 676 swaps(&info.noutput); 677 swaps(&info.x); 678 swaps(&info.y); 679 swaps(&info.width); 680 swaps(&info.height); 681 swapl(&info.widthInMillimeters); 682 swapl(&info.heightInMillimeters); 683 } 684 685 WriteToClient(client, sizeof(xRRMonitorInfo), &info); 686 WriteSwappedDataToClient(client, monitor->numOutputs * sizeof (RROutput), monitor->outputs); 687 } 688 689 RRMonitorFreeList(monitors, nmonitors); 690 691 return Success; 692 } 693 694 int 695 ProcRRSetMonitor(ClientPtr client) 696 { 697 REQUEST(xRRSetMonitorReq); 698 WindowPtr window; 699 ScreenPtr screen; 700 RRMonitorPtr monitor; 701 int r; 702 703 REQUEST_AT_LEAST_SIZE(xRRSetMonitorReq); 704 705 if (stuff->monitor.noutput != stuff->length - (SIZEOF(xRRSetMonitorReq) >> 2)) 706 return BadLength; 707 708 r = dixLookupWindow(&window, stuff->window, client, DixGetAttrAccess); 709 if (r != Success) 710 return r; 711 screen = window->drawable.pScreen; 712 713 if (!ValidAtom(stuff->monitor.name)) 714 return BadAtom; 715 716 /* Allocate the new monitor */ 717 monitor = RRMonitorAlloc(stuff->monitor.noutput); 718 if (!monitor) 719 return BadAlloc; 720 721 /* Fill in the bits from the request */ 722 monitor->pScreen = screen; 723 monitor->name = stuff->monitor.name; 724 monitor->primary = stuff->monitor.primary; 725 monitor->automatic = FALSE; 726 memcpy(monitor->outputs, stuff + 1, stuff->monitor.noutput * sizeof (RROutput)); 727 monitor->geometry.box.x1 = stuff->monitor.x; 728 monitor->geometry.box.y1 = stuff->monitor.y; 729 monitor->geometry.box.x2 = stuff->monitor.x + stuff->monitor.width; 730 monitor->geometry.box.y2 = stuff->monitor.y + stuff->monitor.height; 731 monitor->geometry.mmWidth = stuff->monitor.widthInMillimeters; 732 monitor->geometry.mmHeight = stuff->monitor.heightInMillimeters; 733 734 r = RRMonitorAdd(client, screen, monitor); 735 if (r == Success) 736 RRSendConfigNotify(screen); 737 else 738 RRMonitorFree(monitor); 739 return r; 740 } 741 742 int 743 ProcRRDeleteMonitor(ClientPtr client) 744 { 745 REQUEST(xRRDeleteMonitorReq); 746 WindowPtr window; 747 ScreenPtr screen; 748 int r; 749 750 REQUEST_SIZE_MATCH(xRRDeleteMonitorReq); 751 r = dixLookupWindow(&window, stuff->window, client, DixGetAttrAccess); 752 if (r != Success) 753 return r; 754 screen = window->drawable.pScreen; 755 756 if (!ValidAtom(stuff->name)) { 757 client->errorValue = stuff->name; 758 return BadAtom; 759 } 760 761 r = RRMonitorDelete(client, screen, stuff->name); 762 if (r == Success) 763 RRSendConfigNotify(screen); 764 return r; 765 }