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