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
RRMonitorCrtcName(RRCrtcPtr crtc)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
RRMonitorCrtcPrimary(RRCrtcPtr crtc)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
RRMonitorGetCrtcGeometry(RRCrtcPtr crtc,RRMonitorGeometryPtr geometry)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
RRMonitorSetFromServer(RRCrtcPtr crtc,RRMonitorPtr monitor)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
RRMonitorAutomaticGeometry(RRMonitorPtr monitor)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
RRMonitorGetGeometry(RRMonitorPtr monitor,RRMonitorGeometryPtr geometry)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
RRMonitorSetFromClient(RRMonitorPtr client_monitor,RRMonitorPtr monitor)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
RRMonitorInitList(ScreenPtr screen,RRMonitorListPtr mon_list,Bool get_active)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           slave;
199 
200     if (!RRGetInfo(screen, FALSE))
201         return FALSE;
202 
203     /* Count the number of crtcs in this and any slave screens */
204     numCrtcs = pScrPriv->numCrtcs;
205     xorg_list_for_each_entry(slave, &screen->slave_list, slave_head) {
206         rrScrPrivPtr pSlavePriv;
207 
208         if (!slave->is_output_slave)
209             continue;
210 
211         pSlavePriv = rrGetScrPriv(slave);
212         numCrtcs += pSlavePriv->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(slave, &screen->slave_list, slave_head) {
228         rrScrPrivPtr pSlavePriv;
229 
230         if (!slave->is_output_slave)
231             continue;
232 
233         pSlavePriv = rrGetScrPriv(slave);
234         for (sc = 0; sc < pSlavePriv->numCrtcs; sc++, c++) {
235             if (pSlavePriv->crtcs[sc]->mode != NULL)
236                 mon_list->server_crtc[c] = pSlavePriv->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
RRMonitorFiniList(RRMonitorListPtr list)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
RRMonitorMakeList(ScreenPtr screen,Bool get_active,RRMonitorPtr * monitors_ret,int * nmon_ret)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
RRMonitorCountList(ScreenPtr screen)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
RRMonitorFree(RRMonitorPtr monitor)401 RRMonitorFree(RRMonitorPtr monitor)
402 {
403     free(monitor);
404 }
405 
406 RRMonitorPtr
RRMonitorAlloc(int noutput)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
RRMonitorDelete(ClientPtr client,ScreenPtr screen,Atom name)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
RRMonitorMatchesOutputName(ScreenPtr screen,Atom name)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
RRMonitorAdd(ClientPtr client,ScreenPtr screen,RRMonitorPtr monitor)463 RRMonitorAdd(ClientPtr client, ScreenPtr screen, RRMonitorPtr monitor)
464 {
465     rrScrPrivPtr        pScrPriv = rrGetScrPriv(screen);
466     int                 m;
467     ScreenPtr           slave;
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(slave, &screen->slave_list, slave_head) {
483         if (!slave->is_output_slave)
484             continue;
485 
486         if (RRMonitorMatchesOutputName(slave, 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
RRMonitorFreeList(RRMonitorPtr monitors,int nmon)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
RRMonitorInit(ScreenPtr screen)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
RRMonitorClose(ScreenPtr screen)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
RRMonitorTimestamp(ScreenPtr screen)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
ProcRRGetMonitors(ClientPtr client)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
ProcRRSetMonitor(ClientPtr client)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
ProcRRDeleteMonitor(ClientPtr client)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 }
766