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