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 26static Atom 27RRMonitorCrtcName(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 39static Bool 40RRMonitorCrtcPrimary(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 54static void 55RRMonitorGetCrtcGeometry(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 87static Bool 88RRMonitorSetFromServer(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 106static Bool 107RRMonitorAutomaticGeometry(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 115static void 116RRMonitorGetGeometry(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 167static Bool 168RRMonitorSetFromClient(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 183typedef 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 192static Bool 193RRMonitorInitList(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 297static void 298RRMonitorFiniList(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 308Bool 309RRMonitorMakeList(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 387int 388RRMonitorCountList(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 400void 401RRMonitorFree(RRMonitorPtr monitor) 402{ 403 free(monitor); 404} 405 406RRMonitorPtr 407RRMonitorAlloc(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 419static int 420RRMonitorDelete(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 445static Bool 446RRMonitorMatchesOutputName(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 462int 463RRMonitorAdd(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 522 /* If 'name' matches an existing Monitor on the screen, the 523 * existing one will be deleted as if RRDeleteMonitor were called. 524 */ 525 if (existing->name == monitor->name) { 526 (void) RRMonitorDelete(client, screen, existing->name); 527 continue; 528 } 529 530 if (monitor->primary) 531 existing->primary = FALSE; 532 } 533 534 /* Add the new one to the list 535 */ 536 pScrPriv->monitors[pScrPriv->numMonitors++] = monitor; 537 538 return Success; 539} 540 541void 542RRMonitorFreeList(RRMonitorPtr monitors, int nmon) 543{ 544 int m; 545 546 for (m = 0; m < nmon; m++) 547 free(monitors[m].outputs); 548 free(monitors); 549} 550 551void 552RRMonitorInit(ScreenPtr screen) 553{ 554 rrScrPrivPtr pScrPriv = rrGetScrPriv(screen); 555 556 if (!pScrPriv) 557 return; 558 559 pScrPriv->numMonitors = 0; 560 pScrPriv->monitors = NULL; 561} 562 563void 564RRMonitorClose(ScreenPtr screen) 565{ 566 rrScrPrivPtr pScrPriv = rrGetScrPriv(screen); 567 int m; 568 569 if (!pScrPriv) 570 return; 571 572 for (m = 0; m < pScrPriv->numMonitors; m++) 573 RRMonitorFree(pScrPriv->monitors[m]); 574 free(pScrPriv->monitors); 575 pScrPriv->monitors = NULL; 576 pScrPriv->numMonitors = 0; 577} 578 579static CARD32 580RRMonitorTimestamp(ScreenPtr screen) 581{ 582 rrScrPrivPtr pScrPriv = rrGetScrPriv(screen); 583 584 /* XXX should take client monitor changes into account */ 585 return pScrPriv->lastConfigTime.milliseconds; 586} 587 588int 589ProcRRGetMonitors(ClientPtr client) 590{ 591 REQUEST(xRRGetMonitorsReq); 592 xRRGetMonitorsReply rep = { 593 .type = X_Reply, 594 .sequenceNumber = client->sequence, 595 .length = 0, 596 }; 597 WindowPtr window; 598 ScreenPtr screen; 599 int r; 600 RRMonitorPtr monitors; 601 int nmonitors; 602 int noutputs; 603 int m; 604 Bool get_active; 605 REQUEST_SIZE_MATCH(xRRGetMonitorsReq); 606 r = dixLookupWindow(&window, stuff->window, client, DixGetAttrAccess); 607 if (r != Success) 608 return r; 609 screen = window->drawable.pScreen; 610 611 get_active = stuff->get_active; 612 if (!RRMonitorMakeList(screen, get_active, &monitors, &nmonitors)) 613 return BadAlloc; 614 615 rep.timestamp = RRMonitorTimestamp(screen); 616 617 noutputs = 0; 618 for (m = 0; m < nmonitors; m++) { 619 rep.length += SIZEOF(xRRMonitorInfo) >> 2; 620 rep.length += monitors[m].numOutputs; 621 noutputs += monitors[m].numOutputs; 622 } 623 624 rep.nmonitors = nmonitors; 625 rep.noutputs = noutputs; 626 627 if (client->swapped) { 628 swaps(&rep.sequenceNumber); 629 swapl(&rep.length); 630 swapl(&rep.timestamp); 631 swapl(&rep.nmonitors); 632 swapl(&rep.noutputs); 633 } 634 WriteToClient(client, sizeof(xRRGetMonitorsReply), &rep); 635 636 client->pSwapReplyFunc = (ReplySwapPtr) CopySwap32Write; 637 638 for (m = 0; m < nmonitors; m++) { 639 RRMonitorPtr monitor = &monitors[m]; 640 xRRMonitorInfo info = { 641 .name = monitor->name, 642 .primary = monitor->primary, 643 .automatic = monitor->automatic, 644 .noutput = monitor->numOutputs, 645 .x = monitor->geometry.box.x1, 646 .y = monitor->geometry.box.y1, 647 .width = monitor->geometry.box.x2 - monitor->geometry.box.x1, 648 .height = monitor->geometry.box.y2 - monitor->geometry.box.y1, 649 .widthInMillimeters = monitor->geometry.mmWidth, 650 .heightInMillimeters = monitor->geometry.mmHeight, 651 }; 652 if (client->swapped) { 653 swapl(&info.name); 654 swaps(&info.noutput); 655 swaps(&info.x); 656 swaps(&info.y); 657 swaps(&info.width); 658 swaps(&info.height); 659 swapl(&info.widthInMillimeters); 660 swapl(&info.heightInMillimeters); 661 } 662 663 WriteToClient(client, sizeof(xRRMonitorInfo), &info); 664 WriteSwappedDataToClient(client, monitor->numOutputs * sizeof (RROutput), monitor->outputs); 665 } 666 667 RRMonitorFreeList(monitors, nmonitors); 668 669 return Success; 670} 671 672int 673ProcRRSetMonitor(ClientPtr client) 674{ 675 REQUEST(xRRSetMonitorReq); 676 WindowPtr window; 677 ScreenPtr screen; 678 RRMonitorPtr monitor; 679 int r; 680 681 REQUEST_AT_LEAST_SIZE(xRRSetMonitorReq); 682 683 if (stuff->monitor.noutput != stuff->length - (SIZEOF(xRRSetMonitorReq) >> 2)) 684 return BadLength; 685 686 r = dixLookupWindow(&window, stuff->window, client, DixGetAttrAccess); 687 if (r != Success) 688 return r; 689 screen = window->drawable.pScreen; 690 691 if (!ValidAtom(stuff->monitor.name)) 692 return BadAtom; 693 694 /* Allocate the new monitor */ 695 monitor = RRMonitorAlloc(stuff->monitor.noutput); 696 if (!monitor) 697 return BadAlloc; 698 699 /* Fill in the bits from the request */ 700 monitor->pScreen = screen; 701 monitor->name = stuff->monitor.name; 702 monitor->primary = stuff->monitor.primary; 703 monitor->automatic = FALSE; 704 memcpy(monitor->outputs, stuff + 1, stuff->monitor.noutput * sizeof (RROutput)); 705 monitor->geometry.box.x1 = stuff->monitor.x; 706 monitor->geometry.box.y1 = stuff->monitor.y; 707 monitor->geometry.box.x2 = stuff->monitor.x + stuff->monitor.width; 708 monitor->geometry.box.y2 = stuff->monitor.y + stuff->monitor.height; 709 monitor->geometry.mmWidth = stuff->monitor.widthInMillimeters; 710 monitor->geometry.mmHeight = stuff->monitor.heightInMillimeters; 711 712 r = RRMonitorAdd(client, screen, monitor); 713 if (r == Success) 714 RRSendConfigNotify(screen); 715 else 716 RRMonitorFree(monitor); 717 return r; 718} 719 720int 721ProcRRDeleteMonitor(ClientPtr client) 722{ 723 REQUEST(xRRDeleteMonitorReq); 724 WindowPtr window; 725 ScreenPtr screen; 726 int r; 727 728 REQUEST_SIZE_MATCH(xRRDeleteMonitorReq); 729 r = dixLookupWindow(&window, stuff->window, client, DixGetAttrAccess); 730 if (r != Success) 731 return r; 732 screen = window->drawable.pScreen; 733 734 if (!ValidAtom(stuff->name)) { 735 client->errorValue = stuff->name; 736 return BadAtom; 737 } 738 739 r = RRMonitorDelete(client, screen, stuff->name); 740 if (r == Success) 741 RRSendConfigNotify(screen); 742 return r; 743} 744