Missing return statement from output_rotation.
[xorg/xrandr] / xrandr.c
1 /* 
2  * Copyright © 2001 Keith Packard, member of The XFree86 Project, Inc.
3  * Copyright © 2002 Hewlett Packard Company, Inc.
4  * Copyright © 2006 Intel Corporation
5  *
6  * Permission to use, copy, modify, distribute, and sell this software and its
7  * documentation for any purpose is hereby granted without fee, provided that
8  * the above copyright notice appear in all copies and that both that copyright
9  * notice and this permission notice appear in supporting documentation, and
10  * that the name of the copyright holders not be used in advertising or
11  * publicity pertaining to distribution of the software without specific,
12  * written prior permission.  The copyright holders make no representations
13  * about the suitability of this software for any purpose.  It is provided "as
14  * is" without express or implied warranty.
15  *
16  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
19  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
20  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
21  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
22  * OF THIS SOFTWARE.
23  *
24  * Thanks to Jim Gettys who wrote most of the client side code,
25  * and part of the server code for randr.
26  */
27
28 #include <stdio.h>
29 #include <X11/Xlib.h>
30 #include <X11/Xlibint.h>
31 #include <X11/Xproto.h>
32 #include <X11/Xatom.h>
33 #include <X11/extensions/Xrandr.h>
34 #include <X11/extensions/Xrender.h>     /* we share subpixel information */
35 #include <string.h>
36 #include <stdlib.h>
37 #include <stdarg.h>
38 #include <math.h>
39
40 #if RANDR_MAJOR > 1 || (RANDR_MAJOR == 1 && RANDR_MINOR >= 2)
41 #define HAS_RANDR_1_2 1
42 #endif
43
44 static char     *program_name;
45 static Display  *dpy;
46 static Window   root;
47 static int      screen = -1;
48 static Bool     verbose = False;
49 static Bool     automatic = False;
50 static Bool     properties = False;
51
52 static char *direction[5] = {
53     "normal", 
54     "left", 
55     "inverted", 
56     "right",
57     "\n"};
58
59 static char *reflections[5] = {
60     "normal", 
61     "x", 
62     "y", 
63     "xy",
64     "\n"};
65
66 /* subpixel order */
67 static char *order[6] = {
68     "unknown",
69     "horizontal rgb",
70     "horizontal bgr",
71     "vertical rgb",
72     "vertical bgr",
73     "no subpixels"};
74
75 static void
76 usage(void)
77 {
78     fprintf(stderr, "usage: %s [options]\n", program_name);
79     fprintf(stderr, "  where options are:\n");
80     fprintf(stderr, "  -display <display> or -d <display>\n");
81     fprintf(stderr, "  -help\n");
82     fprintf(stderr, "  -o <normal,inverted,left,right,0,1,2,3>\n");
83     fprintf(stderr, "            or --orientation <normal,inverted,left,right,0,1,2,3>\n");
84     fprintf(stderr, "  -q        or --query\n");
85     fprintf(stderr, "  -s <size>/<width>x<height> or --size <size>/<width>x<height>\n");
86     fprintf(stderr, "  -r <rate> or --rate <rate> or --refresh <rate>\n");
87     fprintf(stderr, "  -v        or --version\n");
88     fprintf(stderr, "  -x        (reflect in x)\n");
89     fprintf(stderr, "  -y        (reflect in y)\n");
90     fprintf(stderr, "  --screen <screen>\n");
91     fprintf(stderr, "  --verbose\n");
92     fprintf(stderr, "  --dryrun\n");
93 #if HAS_RANDR_1_2
94     fprintf(stderr, "  --prop or --properties\n");
95     fprintf(stderr, "  --fb <width>x<height>\n");
96     fprintf(stderr, "  --fbmm <width>x<height>\n");
97     fprintf(stderr, "  --dpi <dpi>/<output>\n");
98 #if 0
99     fprintf(stderr, "  --clone\n");
100     fprintf(stderr, "  --extend\n");
101 #endif
102     fprintf(stderr, "  --output <output>\n");
103     fprintf(stderr, "      --crtc <crtc>\n");
104     fprintf(stderr, "      --mode <mode>\n");
105     fprintf(stderr, "      --rate <rate> or --refresh <rate>\n");
106     fprintf(stderr, "      --preferred\n");
107     fprintf(stderr, "      --pos <x>x<y>\n");
108     fprintf(stderr, "      --rotate normal,inverted,left,right\n");
109     fprintf(stderr, "      --reflect normal,x,y,xy\n");
110     fprintf(stderr, "      --auto\n");
111     fprintf(stderr, "      --left-of <output>\n");
112     fprintf(stderr, "      --right-of <output>\n");
113     fprintf(stderr, "      --above <output>\n");
114     fprintf(stderr, "      --below <output>\n");
115     fprintf(stderr, "      --off\n");
116 #endif
117
118     exit(1);
119     /*NOTREACHED*/
120 }
121
122 static void
123 fatal (const char *format, ...)
124 {
125     va_list ap;
126     
127     va_start (ap, format);
128     fprintf (stderr, "%s: ", program_name);
129     vfprintf (stderr, format, ap);
130     va_end (ap);
131     exit (1);
132     /*NOTREACHED*/
133 }
134
135 static char *
136 rotation_name (Rotation rotation)
137 {
138     int i;
139
140     if ((rotation & 0xf) == 0)
141         return "normal";
142     for (i = 0; i < 4; i++)
143         if (rotation & (1 << i))
144             return direction[i];
145     return "invalid rotation";
146 }
147
148 static char *
149 reflection_name (Rotation rotation)
150 {
151     rotation &= (RR_Reflect_X|RR_Reflect_Y);
152     switch (rotation) {
153     case 0:
154         return "none";
155     case RR_Reflect_X:
156         return "X axis";
157     case RR_Reflect_Y:
158         return "Y axis";
159     case RR_Reflect_X|RR_Reflect_Y:
160         return "X and Y axis";
161     }
162 }
163
164 #if HAS_RANDR_1_2
165 typedef enum _policy {
166     clone, extend
167 } policy_t;
168
169 typedef enum _relation {
170     left_of, right_of, above, below
171 } relation_t;
172
173 typedef enum _changes {
174     changes_none = 0,
175     changes_crtc = (1 << 0),
176     changes_mode = (1 << 1),
177     changes_relation = (1 << 2),
178     changes_position = (1 << 3),
179     changes_rotation = (1 << 4),
180     changes_reflection = (1 << 5),
181     changes_automatic = (1 << 6),
182     changes_refresh = (1 << 7),
183 } changes_t;
184
185 typedef enum _name_kind {
186     name_none = 0,
187     name_string = (1 << 0),
188     name_xid = (1 << 1),
189     name_index = (1 << 2),
190     name_preferred = (1 << 3),
191 } name_kind_t;
192
193 typedef struct {
194     name_kind_t     kind;
195     char            *string;
196     XID             xid;
197     int             index;
198 } name_t;
199
200 typedef struct _crtc crtc_t;
201 typedef struct _output  output_t;
202
203 struct _crtc {
204     name_t          crtc;
205     Bool            changing;
206     XRRCrtcInfo     *crtc_info;
207
208     XRRModeInfo     *mode_info;
209     int             x;
210     int             y;
211     Rotation        rotation;
212     output_t        **outputs;
213     int             noutput;
214 };
215
216 struct _output {
217     struct _output   *next;
218     
219     changes_t       changes;
220     
221     name_t          output;
222     XRROutputInfo   *output_info;
223     
224     name_t          crtc;
225     crtc_t          *crtc_info;
226     
227     name_t          mode;
228     float           refresh;
229     XRRModeInfo     *mode_info;
230     
231     relation_t      relation;
232     char            *relative_to;
233
234     int             x, y;
235     Rotation        rotation;
236     
237     Bool            automatic;
238 };
239
240 static char *connection[3] = {
241     "connected",
242     "disconnected",
243     "unknown connection"};
244
245 #define OUTPUT_NAME 1
246
247 #define CRTC_OFF    2
248 #define CRTC_UNSET  3
249 #define CRTC_INDEX  0x40000000
250
251 #define MODE_NAME   1
252 #define MODE_OFF    2
253 #define MODE_UNSET  3
254 #define MODE_PREF   4
255
256 #define POS_UNSET   -1
257
258 static output_t *outputs = NULL;
259 static output_t **outputs_tail = &outputs;
260 static crtc_t   *crtcs;
261 static int      num_crtcs;
262 static XRRScreenResources  *res;
263 static int      fb_width = 0, fb_height = 0;
264 static int      fb_width_mm = 0, fb_height_mm = 0;
265 static float    dpi = 0;
266 static char     *dpi_output = NULL;
267 static Bool     dryrun = False;
268 static int      minWidth, maxWidth, minHeight, maxHeight;
269 static Bool     has_1_2 = False;
270
271 static int
272 mode_height (XRRModeInfo *mode_info, Rotation rotation)
273 {
274     switch (rotation & 0xf) {
275     case RR_Rotate_0:
276     case RR_Rotate_180:
277         return mode_info->height;
278     case RR_Rotate_90:
279     case RR_Rotate_270:
280         return mode_info->width;
281     default:
282         return 0;
283     }
284 }
285
286 static int
287 mode_width (XRRModeInfo *mode_info, Rotation rotation)
288 {
289     switch (rotation & 0xf) {
290     case RR_Rotate_0:
291     case RR_Rotate_180:
292         return mode_info->width;
293     case RR_Rotate_90:
294     case RR_Rotate_270:
295         return mode_info->height;
296     default:
297         return 0;
298     }
299 }
300
301 /* v refresh frequency in Hz */
302 static float
303 mode_refresh (XRRModeInfo *mode_info)
304 {
305     float rate;
306     
307     if (mode_info->hTotal && mode_info->vTotal)
308         rate = ((float) mode_info->dotClock / 
309                 ((float) mode_info->hTotal * (float) mode_info->vTotal));
310     else
311         rate = 0;
312     return rate;
313 }
314
315 /* h sync frequency in Hz */
316 static float
317 mode_hsync (XRRModeInfo *mode_info)
318 {
319     float rate;
320     
321     if (mode_info->hTotal)
322         rate = (float) mode_info->dotClock / (float) mode_info->hTotal;
323     else
324         rate = 0;
325     return rate;
326 }
327
328 static void
329 init_name (name_t *name)
330 {
331     name->kind = name_none;
332 }
333
334 static void
335 set_name_string (name_t *name, char *string)
336 {
337     name->kind |= name_string;
338     name->string = string;
339 }
340
341 static void
342 set_name_xid (name_t *name, XID xid)
343 {
344     name->kind |= name_xid;
345     name->xid = xid;
346 }
347
348 static void
349 set_name_index (name_t *name, int index)
350 {
351     name->kind |= name_index;
352     name->index = index;
353 }
354
355 static void
356 set_name_preferred (name_t *name)
357 {
358     name->kind |= name_preferred;
359 }
360
361 static void
362 set_name_all (name_t *name, name_t *old)
363 {
364     if (old->kind & name_xid)
365         name->xid = old->xid;
366     if (old->kind & name_string)
367         name->string = old->string;
368     if (old->kind & name_index)
369         name->index = old->index;
370     name->kind |= old->kind;
371 }
372
373 static void
374 set_name (name_t *name, char *string, name_kind_t valid)
375 {
376     XID xid;
377     int index;
378
379     if ((valid & name_xid) && sscanf (string, "0x%x", &xid) == 1)
380         set_name_xid (name, xid);
381     else if ((valid & name_index) && sscanf (string, "%d", &index) == 1)
382         set_name_index (name, index);
383     else if (valid & name_string)
384         set_name_string (name, string);
385     else
386         usage ();
387 }
388
389 static output_t *
390 add_output (void)
391 {
392     output_t *output = calloc (1, sizeof (output_t));
393
394     if (!output)
395         fatal ("out of memory");
396     output->next = NULL;
397     *outputs_tail = output;
398     outputs_tail = &output->next;
399     return output;
400 }
401
402 static output_t *
403 find_output (name_t *name)
404 {
405     output_t *output;
406
407     for (output = outputs; output; output = output->next)
408     {
409         name_kind_t common = name->kind & output->output.kind;
410         
411         if ((common & name_xid) && name->xid == output->output.xid)
412             break;
413         if ((common & name_string) && !strcmp (name->string, output->output.string))
414             break;
415         if ((common & name_index) & name->index == output->output.index)
416             break;
417     }
418     return output;
419 }
420
421 static output_t *
422 find_output_by_xid (RROutput output)
423 {
424     name_t  output_name;
425
426     init_name (&output_name);
427     set_name_xid (&output_name, output);
428     return find_output (&output_name);
429 }
430
431 static output_t *
432 find_output_by_name (char *name)
433 {
434     name_t  output_name;
435
436     init_name (&output_name);
437     set_name_string (&output_name, name);
438     return find_output (&output_name);
439 }
440
441 static crtc_t *
442 find_crtc (name_t *name)
443 {
444     int     c;
445     crtc_t  *crtc = NULL;
446
447     for (c = 0; c < num_crtcs; c++)
448     {
449         name_kind_t common;
450         
451         crtc = &crtcs[c];
452         common = name->kind & crtc->crtc.kind;
453         
454         if ((common & name_xid) && name->xid == crtc->crtc.xid)
455             break;
456         if ((common & name_string) && !strcmp (name->string, crtc->crtc.string))
457             break;
458         if ((common & name_index) & name->index == crtc->crtc.index)
459             break;
460         crtc = NULL;
461     }
462     return crtc;
463 }
464
465 static crtc_t *
466 find_crtc_by_xid (RRCrtc crtc)
467 {
468     name_t  crtc_name;
469
470     init_name (&crtc_name);
471     set_name_xid (&crtc_name, crtc);
472     return find_crtc (&crtc_name);
473 }
474
475 static XRRModeInfo *
476 find_mode (name_t *name, float refresh)
477 {
478     int         m;
479     XRRModeInfo *best = NULL;
480     float       bestDist = 0;
481
482     for (m = 0; m < res->nmode; m++)
483     {
484         XRRModeInfo *mode = &res->modes[m];
485         if ((name->kind & name_xid) && name->xid == mode->id)
486         {
487             best = mode;
488             break;
489         }
490         if ((name->kind & name_string) && !strcmp (name->string, mode->name))
491         {
492             float   dist;
493             
494             if (refresh)
495                 dist = fabs (mode_refresh (mode) - refresh);
496             else
497                 dist = 0;
498             if (!best || dist < bestDist)
499             {
500                 bestDist = dist;
501                 best = mode;
502             }
503             break;
504         }
505     }
506     return best;
507 }
508
509 static XRRModeInfo *
510 find_mode_by_xid (RRMode mode)
511 {
512     name_t  mode_name;
513
514     init_name (&mode_name);
515     set_name_xid (&mode_name, mode);
516     return find_mode (&mode_name, 0);
517 }
518
519 static
520 XRRModeInfo *
521 find_mode_for_output (output_t *output, name_t *name)
522 {
523     XRROutputInfo   *output_info = output->output_info;
524     int             m;
525     XRRModeInfo     *best = NULL;
526     float           bestDist = 0;
527
528     for (m = 0; m < output_info->nmode; m++)
529     {
530         XRRModeInfo         *mode;
531         
532         mode = find_mode_by_xid (output_info->modes[m]);
533         if (!mode) continue;
534         if ((name->kind & name_xid) && name->xid == mode->id)
535         {
536             best = mode;
537             break;
538         }
539         if ((name->kind & name_string) && !strcmp (name->string, mode->name))
540         {
541             float   dist;
542             
543             if (output->refresh)
544                 dist = fabs (mode_refresh (mode) - output->refresh);
545             else
546                 dist = 0;
547             if (!best || dist < bestDist)
548             {
549                 bestDist = dist;
550                 best = mode;
551             }
552         }
553     }
554     return best;
555 }
556
557 XRRModeInfo *
558 preferred_mode (output_t *output)
559 {
560     XRROutputInfo   *output_info = output->output_info;
561     int             m;
562     XRRModeInfo     *best;
563     int             bestDist;
564     
565     best = NULL;
566     bestDist = 0;
567     for (m = 0; m < output_info->nmode; m++)
568     {
569         XRRModeInfo *mode_info = find_mode_by_xid (output_info->modes[m]);
570         int         dist;
571         
572         if (m < output_info->npreferred)
573             dist = 0;
574         else if (output_info->mm_height)
575             dist = (1000 * DisplayHeight(dpy, screen) / DisplayHeightMM(dpy, screen) -
576                     1000 * mode_info->height / output_info->mm_height);
577         else
578             dist = DisplayHeight(dpy, screen) - mode_info->height;
579
580         if (dist < 0) dist = -dist;
581         if (!best || dist < bestDist)
582         {
583             best = mode_info;
584             bestDist = dist;
585         }
586     }
587     return best;
588 }
589
590 static Bool
591 output_can_use_crtc (output_t *output, crtc_t *crtc)
592 {
593     XRROutputInfo   *output_info = output->output_info;
594     int             c;
595
596     for (c = 0; c < output_info->ncrtc; c++)
597         if (output_info->crtcs[c] == crtc->crtc.xid)
598             return True;
599     return False;
600 }
601
602 static Bool
603 output_can_use_mode (output_t *output, XRRModeInfo *mode)
604 {
605     XRROutputInfo   *output_info = output->output_info;
606     int             m;
607
608     for (m = 0; m < output_info->nmode; m++)
609         if (output_info->modes[m] == mode->id)
610             return True;
611     return False;
612 }
613
614 static Bool
615 crtc_can_use_rotation (crtc_t *crtc, Rotation rotation)
616 {
617     Rotation    rotations = crtc->crtc_info->rotations;
618     Rotation    dir = rotation & (RR_Rotate_0|RR_Rotate_90|RR_Rotate_180|RR_Rotate_270);
619     Rotation    reflect = rotation & (RR_Reflect_X|RR_Reflect_Y);
620     if (((rotations & dir) != 0) && ((rotations & reflect) == reflect))
621         return True;
622     return False;
623 }
624
625 /*
626  * Report only rotations that are supported by all crtcs
627  */
628 static Rotation
629 output_rotations (output_t *output)
630 {
631     Bool            found = False;
632     Rotation        rotation = RR_Rotate_0;
633     XRROutputInfo   *output_info = output->output_info;
634     int             c;
635     
636     for (c = 0; c < output_info->ncrtc; c++)
637     {
638         crtc_t  *crtc = find_crtc_by_xid (output_info->crtcs[c]);
639         if (crtc)
640         {
641             if (!found) {
642                 rotation = crtc->crtc_info->rotations;
643                 found = True;
644             } else
645                 rotation &= crtc->crtc_info->rotations;
646         }
647     }
648     return rotation;
649 }
650
651 static Bool
652 output_can_use_rotation (output_t *output, Rotation rotation)
653 {
654     XRROutputInfo   *output_info = output->output_info;
655     int             c;
656
657     /* make sure all of the crtcs can use this rotation.
658      * yes, this is not strictly necessary, but it is 
659      * simpler,and we expect most drivers to either
660      * support rotation everywhere or nowhere
661      */
662     for (c = 0; c < output_info->ncrtc; c++)
663     {
664         crtc_t  *crtc = find_crtc_by_xid (output_info->crtcs[c]);
665         if (crtc && !crtc_can_use_rotation (crtc, rotation))
666             return False;
667     }
668     return True;
669 }
670
671 static void
672 set_output_info (output_t *output, RROutput xid, XRROutputInfo *output_info)
673 {
674     /* sanity check output info */
675     if (output_info->connection != RR_Disconnected && !output_info->nmode)
676         fatal ("Output %s is not disconnected but has no modes\n",
677                output_info->name);
678     
679     /* set output name and info */
680     if (!(output->output.kind & name_xid))
681         set_name_xid (&output->output, xid);
682     if (!(output->output.kind & name_string))
683         set_name_string (&output->output, output_info->name);
684     output->output_info = output_info;
685     
686     /* set crtc name and info */
687     if (!(output->changes & changes_crtc))
688         set_name_xid (&output->crtc, output_info->crtc);
689     
690     if (output->crtc.kind == name_xid && output->crtc.xid == None)
691         output->crtc_info = NULL;
692     else
693     {
694         output->crtc_info = find_crtc (&output->crtc);
695         if (!output->crtc_info)
696         {
697             if (output->crtc.kind & name_xid)
698                 fatal ("cannot find crtc 0x%x\n", output->crtc.xid);
699             if (output->crtc.kind & name_index)
700                 fatal ("cannot find crtc %d\n", output->crtc.index);
701         }
702         if (!output_can_use_crtc (output, output->crtc_info))
703             fatal ("output %s cannot use crtc 0x%x\n", output->output.string,
704                    output->crtc_info->crtc.xid);
705     }
706
707     /* set mode name and info */
708     if (!(output->changes & changes_mode))
709     {
710         if (output->crtc_info)
711             set_name_xid (&output->mode, output->crtc_info->crtc_info->mode);
712         else
713             set_name_xid (&output->mode, None);
714         if (output->mode.xid)
715         {
716             output->mode_info = find_mode_by_xid (output->mode.xid);
717             if (!output->mode_info)
718                 fatal ("server did not report mode 0x%x for output %s\n",
719                        output->mode.xid, output->output.string);
720         }
721         else
722             output->mode_info = NULL;
723     }
724     else if (output->mode.kind == name_xid && output->mode.xid == None)
725         output->mode_info = NULL;
726     else
727     {
728         if (output->mode.kind == name_preferred)
729             output->mode_info = preferred_mode (output);
730         else
731             output->mode_info = find_mode_for_output (output, &output->mode);
732         if (!output->mode_info)
733         {
734             if (output->mode.kind & name_preferred)
735                 fatal ("cannot find preferred mode\n");
736             if (output->mode.kind & name_string)
737                 fatal ("cannot find mode %s\n", output->mode.string);
738             if (output->mode.kind & name_xid)
739                 fatal ("cannot find mode 0x%x\n", output->mode.xid);
740         }
741         if (!output_can_use_mode (output, output->mode_info))
742             fatal ("output %s cannot use mode %s\n", output->output.string,
743                    output->mode_info->name);
744     }
745
746     /* set position */
747     if (!(output->changes & changes_position))
748     {
749         if (output->crtc_info)
750         {
751             output->x = output->crtc_info->crtc_info->x;
752             output->y = output->crtc_info->crtc_info->y;
753         }
754         else
755         {
756             output->x = 0;
757             output->y = 0;
758         }
759     }
760
761     /* set rotation */
762     if (!(output->changes & changes_rotation))
763     {
764         output->rotation &= ~0xf;
765         if (output->crtc_info)
766             output->rotation |= (output->crtc_info->crtc_info->rotation & 0xf);
767         else
768             output->rotation = RR_Rotate_0;
769     }
770     if (!(output->changes & changes_reflection))
771     {
772         output->rotation &= ~(RR_Reflect_X|RR_Reflect_Y);
773         if (output->crtc_info)
774             output->rotation |= (output->crtc_info->crtc_info->rotation &
775                                  (RR_Reflect_X|RR_Reflect_Y));
776     }
777     if (!output_can_use_rotation (output, output->rotation))
778         fatal ("output %s cannot use rotation \"%s\" reflection \"%s\"\n",
779                output->output.string,
780                rotation_name (output->rotation),
781                reflection_name (output->rotation));
782 }
783     
784 static void
785 get_screen (void)
786 {
787     if (!has_1_2)
788         fatal ("Server RandR version before 1.2\n");
789     
790     XRRGetScreenSizeRange (dpy, root, &minWidth, &minHeight,
791                            &maxWidth, &maxHeight);
792     
793     res = XRRGetScreenResources (dpy, root);
794     if (!res) fatal ("could not get screen resources");
795 }
796
797 static void
798 get_crtcs (void)
799 {
800     int         c;
801
802     num_crtcs = res->ncrtc;
803     crtcs = calloc (num_crtcs, sizeof (crtc_t));
804     if (!crtcs) fatal ("out of memory");
805     
806     for (c = 0; c < res->ncrtc; c++)
807     {
808         XRRCrtcInfo *crtc_info = XRRGetCrtcInfo (dpy, res, res->crtcs[c]);
809         set_name_xid (&crtcs[c].crtc, res->crtcs[c]);
810         set_name_index (&crtcs[c].crtc, c);
811         if (!crtc_info) fatal ("could not get crtc 0x%x information", res->crtcs[c]);
812         crtcs[c].crtc_info = crtc_info;
813         if (crtc_info->mode == None)
814         {
815             crtcs[c].mode_info = NULL;
816             crtcs[c].x = 0;
817             crtcs[c].y = 0;
818             crtcs[c].rotation = RR_Rotate_0;
819         }
820     }
821 }
822
823 static void
824 crtc_add_output (crtc_t *crtc, output_t *output)
825 {
826     if (crtc->outputs)
827         crtc->outputs = realloc (crtc->outputs, (crtc->noutput + 1) * sizeof (output_t *));
828     else
829     {
830         crtc->outputs = malloc (sizeof (output_t *));
831         crtc->x = output->x;
832         crtc->y = output->y;
833         crtc->rotation = output->rotation;
834         crtc->mode_info = output->mode_info;
835     }
836     if (!crtc->outputs) fatal ("out of memory");
837     crtc->outputs[crtc->noutput++] = output;
838 }
839
840 static void
841 set_crtcs (void)
842 {
843     output_t    *output;
844
845     for (output = outputs; output; output = output->next)
846     {
847         if (!output->mode_info) continue;
848         crtc_add_output (output->crtc_info, output);
849     }
850 }
851
852 static Status
853 crtc_disable (crtc_t *crtc)
854 {
855     XRRCrtcInfo *crtc_info = crtc->crtc_info;
856     
857     if (verbose)
858         printf ("crtc %d: disable\n", crtc->crtc.index);
859         
860     if (dryrun)
861         return RRSetConfigSuccess;
862     return XRRSetCrtcConfig (dpy, res, crtc->crtc.xid, CurrentTime,
863                              0, 0, None, RR_Rotate_0, NULL, 0);
864 }
865
866 static Status
867 crtc_revert (crtc_t *crtc)
868 {
869     XRRCrtcInfo *crtc_info = crtc->crtc_info;
870     
871     if (verbose)
872         printf ("crtc %d: revert\n", crtc->crtc.index);
873         
874     if (dryrun)
875         return RRSetConfigSuccess;
876     return XRRSetCrtcConfig (dpy, res, crtc->crtc.xid, CurrentTime,
877                             crtc_info->x, crtc_info->y,
878                             crtc_info->mode, crtc_info->rotation,
879                             crtc_info->outputs, crtc_info->noutput);
880 }
881
882 static Status
883 crtc_apply (crtc_t *crtc)
884 {
885     RROutput    *rr_outputs;
886     int         o;
887     Status      s;
888     RRMode      mode = None;
889
890     if (!crtc->changing || !crtc->mode_info)
891         return RRSetConfigSuccess;
892
893     rr_outputs = calloc (crtc->noutput, sizeof (RROutput));
894     if (!rr_outputs)
895         return BadAlloc;
896     for (o = 0; o < crtc->noutput; o++)
897         rr_outputs[o] = crtc->outputs[o]->output.xid;
898     mode = crtc->mode_info->id;
899     if (verbose) {
900         printf ("crtc %d: %12s %6.1f +%d+%d", crtc->crtc.index,
901                 crtc->mode_info->name, mode_refresh (crtc->mode_info),
902                 crtc->x, crtc->y);
903         for (o = 0; o < crtc->noutput; o++)
904             printf (" \"%s\"", crtc->outputs[o]->output.string);
905         printf ("\n");
906     }
907     
908     if (dryrun)
909         s = RRSetConfigSuccess;
910     else
911         s = XRRSetCrtcConfig (dpy, res, crtc->crtc.xid, CurrentTime,
912                               crtc->x, crtc->y, mode, crtc->rotation,
913                               rr_outputs, crtc->noutput);
914     free (rr_outputs);
915     return s;
916 }
917
918 static void
919 screen_revert (void)
920 {
921     if (verbose)
922         printf ("screen %d: revert\n");
923
924     if (dryrun)
925         return;
926     XRRSetScreenSize (dpy, root,
927                       DisplayWidth (dpy, screen),
928                       DisplayHeight (dpy, screen),
929                       DisplayWidthMM (dpy, screen),
930                       DisplayHeightMM (dpy, screen));
931 }
932
933 static void
934 screen_apply (void)
935 {
936     if (fb_width == DisplayWidth (dpy, screen) &&
937         fb_height == DisplayHeight (dpy, screen) &&
938         fb_width_mm == DisplayWidthMM (dpy, screen) &&
939         fb_height_mm == DisplayHeightMM (dpy, screen))
940     {
941         return;
942     }
943     if (verbose)
944         printf ("screen %d: %dx%d %dx%d mm %6.2fdpi\n", screen,
945                 fb_width, fb_height, fb_width_mm, fb_height_mm, dpi);
946     if (dryrun)
947         return;
948     XRRSetScreenSize (dpy, root, fb_width, fb_height,
949                       fb_width_mm, fb_height_mm);
950 }
951
952 static void
953 revert (void)
954 {
955     int c;
956
957     /* first disable all crtcs */
958     for (c = 0; c < res->ncrtc; c++)
959         crtc_disable (&crtcs[c]);
960     /* next reset screen size */
961     screen_revert ();
962     /* now restore all crtcs */
963     for (c = 0; c < res->ncrtc; c++)
964         crtc_revert (&crtcs[c]);
965 }
966
967 /*
968  * uh-oh, something bad happened in the middle of changing
969  * the configuration. Revert to the previous configuration
970  * and bail
971  */
972 static void
973 panic (Status s, crtc_t *crtc)
974 {
975     int     c = crtc->crtc.index;
976     char    *message;
977     
978     switch (s) {
979     case RRSetConfigSuccess:            message = "succeeded";              break;
980     case BadAlloc:                      message = "out of memory";          break;
981     case RRSetConfigFailed:             message = "failed";                 break;
982     case RRSetConfigInvalidConfigTime:  message = "invalid config time";    break;
983     case RRSetConfigInvalidTime:        message = "invalid time";           break;
984     default:                            message = "unknown failure";        break;
985     }
986     
987     fprintf (stderr, "%s: Configure crtc %d %s\n", program_name, c, message);
988     revert ();
989     exit (1);
990 }
991
992 void
993 apply (void)
994 {
995     Status  s;
996     int     c;
997     
998     /*
999      * Turn off any crtcs which are to be disabled or which are
1000      * larger than the target size
1001      */
1002     for (c = 0; c < res->ncrtc; c++)
1003     {
1004         crtc_t      *crtc = &crtcs[c];
1005         XRRCrtcInfo *crtc_info = crtc->crtc_info;
1006
1007         /* if this crtc is already disabled, skip it */
1008         if (crtc_info->mode == None) 
1009             continue;
1010         
1011         /* 
1012          * If this crtc is to be left enabled, make
1013          * sure the old size fits then new screen
1014          */
1015         if (crtc->mode_info) 
1016         {
1017             XRRModeInfo *old_mode = find_mode_by_xid (crtc_info->mode);
1018             int x, y, w, h;
1019
1020             if (!old_mode) 
1021                 panic (RRSetConfigFailed, crtc);
1022             
1023             /* old position and size information */
1024             x = crtc_info->x;
1025             y = crtc_info->y;
1026             w = mode_width (old_mode, crtc_info->rotation);
1027             h = mode_height (old_mode, crtc_info->rotation);
1028             
1029             /* if it fits, skip it */
1030             if (x + w <= fb_width && y + h <= fb_height) 
1031                 continue;
1032             crtc->changing = True;
1033         }
1034         s = crtc_disable (crtc);
1035         if (s != RRSetConfigSuccess)
1036             panic (s, crtc);
1037     }
1038
1039     /*
1040      * Hold the server grabbed while messing with
1041      * the screen so that apps which notice the resize
1042      * event and ask for xinerama information from the server
1043      * receive up-to-date information
1044      */
1045     XGrabServer (dpy);
1046     
1047     /*
1048      * Set the screen size
1049      */
1050     screen_apply ();
1051     
1052     /*
1053      * Set crtcs
1054      */
1055
1056     for (c = 0; c < res->ncrtc; c++)
1057     {
1058         crtc_t  *crtc = &crtcs[c];
1059         
1060         s = crtc_apply (crtc);
1061         if (s != RRSetConfigSuccess)
1062             panic (s, crtc);
1063     }
1064     /*
1065      * Release the server grab and let all clients
1066      * respond to the updated state
1067      */
1068     XUngrabServer (dpy);
1069 }
1070
1071 /*
1072  * Use current output state to complete the output list
1073  */
1074 void
1075 get_outputs (void)
1076 {
1077     int         o;
1078     
1079     for (o = 0; o < res->noutput; o++)
1080     {
1081         XRROutputInfo   *output_info = XRRGetOutputInfo (dpy, res, res->outputs[o]);
1082         output_t        *output;
1083         name_t          output_name;
1084         if (!output_info) fatal ("could not get output 0x%x information", res->outputs[o]);
1085         set_name_xid (&output_name, res->outputs[o]);
1086         set_name_index (&output_name, o);
1087         set_name_string (&output_name, output_info->name);
1088         output = find_output (&output_name);
1089         if (!output)
1090         {
1091             output = add_output ();
1092             set_name_all (&output->output, &output_name);
1093             /*
1094              * When global --automatic mode is set, turn on connected but off
1095              * outputs, turn off disconnected but on outputs
1096              */
1097             if (automatic)
1098             {
1099                 switch (output_info->connection) {
1100                 case RR_Connected:
1101                     if (!output_info->crtc) {
1102                         output->changes |= changes_automatic;
1103                         output->automatic = True;
1104                     }
1105                     break;
1106                 case RR_Disconnected:
1107                     if (output_info->crtc)
1108                     {
1109                         output->changes |= changes_automatic;
1110                         output->automatic = True;
1111                     }
1112                     break;
1113                 }
1114             }
1115         }
1116
1117         /*
1118          * Automatic mode -- track connection state and enable/disable outputs
1119          * as necessary
1120          */
1121         if (output->automatic)
1122         {
1123             switch (output_info->connection) {
1124             case RR_Connected:
1125             case RR_UnknownConnection:
1126                 if ((!(output->changes & changes_mode)))
1127                 {
1128                     set_name_preferred (&output->mode);
1129                     output->changes |= changes_mode;
1130                 }
1131                 break;
1132             case RR_Disconnected:
1133                 if ((!(output->changes & changes_mode)))
1134                 {
1135                     set_name_xid (&output->mode, None);
1136                     set_name_xid (&output->crtc, None);
1137                     output->changes |= changes_mode;
1138                     output->changes |= changes_crtc;
1139                 }
1140                 break;
1141             }
1142         }
1143
1144         set_output_info (output, res->outputs[o], output_info);
1145     }
1146 }
1147
1148 void
1149 mark_changing_crtcs (void)
1150 {
1151     int c;
1152
1153     for (c = 0; c < num_crtcs; c++)
1154     {
1155         crtc_t      *crtc = &crtcs[c];
1156         int         o;
1157         output_t    *output;
1158
1159         /* walk old output list (to catch disables) */
1160         for (o = 0; o < crtc->crtc_info->noutput; o++)
1161         {
1162             output = find_output_by_xid (crtc->crtc_info->outputs[o]);
1163             if (!output) fatal ("cannot find output 0x%x\n",
1164                                 crtc->crtc_info->outputs[o]);
1165             if (output->changes)
1166                 crtc->changing = True;
1167         }
1168         /* walk new output list */
1169         for (o = 0; o < crtc->noutput; o++)
1170         {
1171             output = crtc->outputs[o];
1172             if (output->changes)
1173                 crtc->changing = True;
1174         }
1175     }
1176 }
1177
1178 crtc_t *
1179 find_crtc_for_output (output_t *output)
1180 {
1181     int     c;
1182
1183     for (c = 0; c < output->output_info->ncrtc; c++)
1184     {
1185         crtc_t  *crtc;
1186         int     l, o;
1187
1188         crtc = find_crtc_by_xid (output->output_info->crtcs[c]);
1189         if (!crtc) fatal ("cannot find crtc 0x%x\n", output->output_info->crtcs[c]);
1190
1191         /* make sure all of the outputs currently connected can share */
1192         for (o = 0; o < crtc->noutput; o++)
1193         {
1194             for (l = 0; l < output->output_info->nclone; l++)
1195                 if (output->output_info->clones[l] == crtc->outputs[o]->output.xid)
1196                     break;
1197             if (l != output->output_info->nclone) break;
1198         }
1199         if (o != crtc->noutput) continue;
1200
1201         if (crtc->noutput)
1202         {
1203             /* make sure the state matches */
1204             if (crtc->mode_info != output->mode_info) continue;
1205             if (crtc->x != output->x) continue;
1206             if (crtc->y != output->y) continue;
1207             if (crtc->rotation != output->rotation) continue;
1208         }
1209         return crtc;
1210     }
1211     return NULL;
1212 }
1213
1214 static void
1215 set_positions (void)
1216 {
1217     output_t    *output;
1218     Bool        keep_going;
1219     Bool        any_set;
1220     int         min_x, min_y;
1221
1222     for (;;)
1223     {
1224         any_set = False;
1225         keep_going = False;
1226         for (output = outputs; output; output = output->next)
1227         {
1228             output_t    *relation;
1229             name_t      relation_name;
1230
1231             if (!(output->changes & changes_relation)) continue;
1232             
1233             init_name (&relation_name);
1234             set_name_string (&relation_name, output->relative_to);
1235             relation = find_output (&relation_name);
1236             if (!relation) fatal ("cannot find output \"%s\"\n", output->relative_to);
1237             
1238             if (relation->mode_info == NULL) 
1239             {
1240                 output->x = 0;
1241                 output->y = 0;
1242                 output->changes |= changes_position;
1243                 any_set = True;
1244                 continue;
1245             }
1246             /*
1247              * Make sure the dependent object has been set in place
1248              */
1249             if ((relation->changes & changes_relation) && 
1250                 !(relation->changes & changes_position))
1251             {
1252                 keep_going = True;
1253                 continue;
1254             }
1255             
1256             switch (output->relation) {
1257             case left_of:
1258                 output->y = relation->y;
1259                 output->x = relation->x - mode_width (output->mode_info, output->rotation);
1260                 break;
1261             case right_of:
1262                 output->y = relation->y;
1263                 output->x = relation->x + mode_width (relation->mode_info, relation->rotation);
1264                 break;
1265             case above:
1266                 output->x = relation->x;
1267                 output->y = relation->y - mode_height (output->mode_info, output->rotation);
1268                 break;
1269             case below:
1270                 output->x = relation->x;
1271                 output->y = relation->y + mode_height (relation->mode_info, relation->rotation);
1272                 break;
1273             }
1274             output->changes |= changes_position;
1275             any_set = True;
1276         }
1277         if (!keep_going)
1278             break;
1279         if (!any_set)
1280             fatal ("loop in relative position specifications\n");
1281     }
1282
1283     /*
1284      * Now normalize positions so the upper left corner of all outputs is at 0,0
1285      */
1286     min_x = 32768;
1287     min_y = 32768;
1288     for (output = outputs; output; output = output->next)
1289     {
1290         if (output->mode_info == NULL) continue;
1291         
1292         if (output->x < min_x) min_x = output->x;
1293         if (output->y < min_y) min_y = output->y;
1294     }
1295     if (min_x || min_y)
1296     {
1297         /* move all outputs */
1298         for (output = outputs; output; output = output->next)
1299         {
1300             if (output->mode_info == NULL) continue;
1301
1302             output->x -= min_x;
1303             output->y -= min_y;
1304             output->changes |= changes_position;
1305         }
1306     }
1307 }
1308
1309 static void
1310 set_screen_size (void)
1311 {
1312     output_t    *output;
1313     Bool        fb_specified = fb_width != 0 && fb_height != 0;
1314     
1315     for (output = outputs; output; output = output->next)
1316     {
1317         XRRModeInfo *mode_info = output->mode_info;
1318         int         x, y, w, h;
1319         
1320         if (!mode_info) continue;
1321         
1322         x = output->x;
1323         y = output->y;
1324         w = mode_width (mode_info, output->rotation);
1325         h = mode_height (mode_info, output->rotation);
1326         /* make sure output fits in specified size */
1327         if (fb_specified)
1328         {
1329             if (x + w > fb_width || y + h > fb_height)
1330                 fatal ("specified screen %dx%d not large enough for output %s (%dx%d+%d+%d)\n",
1331                        fb_width, fb_height, output->output.string, w, h, x, y);
1332         }
1333         /* fit fb to output */
1334         else
1335         {
1336             if (x + w > fb_width) fb_width = x + w;
1337             if (y + h > fb_height) fb_height = y + h;
1338         }
1339     }   
1340
1341     if (fb_width > maxWidth || fb_height > maxHeight)
1342         fatal ("screen cannot be larger than %dx%d (desired size %dx%d)\n",
1343                maxWidth, maxHeight, fb_width, fb_height);
1344     if (fb_specified)
1345     {
1346         if (fb_width < minWidth || fb_height < minHeight)
1347             fatal ("screen must be at least %dx%d\n", minWidth, minHeight);
1348     }
1349     else
1350     {
1351         if (fb_width < minWidth) fb_width = minWidth;
1352         if (fb_height < minHeight) fb_height = minHeight;
1353     }
1354 }
1355     
1356 #endif
1357     
1358 int
1359 main (int argc, char **argv)
1360 {
1361     XRRScreenSize *sizes;
1362     XRRScreenConfiguration *sc;
1363     int         nsize;
1364     int         nrate;
1365     short               *rates;
1366     Status      status = RRSetConfigFailed;
1367     int         rot = -1;
1368     int         query = 0;
1369     Rotation    rotation, current_rotation, rotations;
1370     XEvent      event;
1371     XRRScreenChangeNotifyEvent *sce;    
1372     char          *display_name = NULL;
1373     int                 i, j;
1374     SizeID      current_size;
1375     short       current_rate;
1376     float       rate = -1;
1377     int         size = -1;
1378     int         dirind = 0;
1379     Bool        setit = False;
1380     Bool        version = False;
1381     int         event_base, error_base;
1382     int         reflection = 0;
1383     int         width = 0, height = 0;
1384     Bool        have_pixel_size = False;
1385     int         ret = 0;
1386 #if HAS_RANDR_1_2
1387     output_t    *output = NULL;
1388     char        *crtc;
1389     policy_t    policy = clone;
1390     Bool        setit_1_2 = False;
1391     Bool        query_1_2 = False;
1392     Bool        query_1 = False;
1393     int         major, minor;
1394 #endif
1395
1396     program_name = argv[0];
1397     if (argc == 1) query = True;
1398     for (i = 1; i < argc; i++) {
1399         if (!strcmp ("-display", argv[i]) || !strcmp ("-d", argv[i])) {
1400             if (++i>=argc) usage ();
1401             display_name = argv[i];
1402             continue;
1403         }
1404         if (!strcmp("-help", argv[i])) {
1405             usage();
1406             continue;
1407         }
1408         if (!strcmp ("--verbose", argv[i])) {
1409             verbose = True;
1410             continue;
1411         }
1412         if (!strcmp ("--dryrun", argv[i])) {
1413             dryrun = True;
1414             verbose = True;
1415             continue;
1416         }
1417
1418         if (!strcmp ("-s", argv[i]) || !strcmp ("--size", argv[i])) {
1419             if (++i>=argc) usage ();
1420             if (sscanf (argv[i], "%dx%d", &width, &height) == 2)
1421                 have_pixel_size = True;
1422             else {
1423                 size = atoi (argv[i]);
1424                 if (size < 0) usage();
1425             }
1426             setit = True;
1427             continue;
1428         }
1429
1430         if (!strcmp ("-r", argv[i]) ||
1431             !strcmp ("--rate", argv[i]) ||
1432             !strcmp ("--refresh", argv[i]))
1433         {
1434             if (++i>=argc) usage ();
1435             if (sscanf (argv[i], "%f", &rate) != 1)
1436                 usage ();
1437             setit = True;
1438 #if HAS_RANDR_1_2
1439             if (output)
1440             {
1441                 output->refresh = rate;
1442                 output->changes |= changes_refresh;
1443                 setit_1_2 = True;
1444             }
1445 #endif
1446             continue;
1447         }
1448
1449         if (!strcmp ("-v", argv[i]) || !strcmp ("--version", argv[i])) {
1450             version = True;
1451             continue;
1452         }
1453
1454         if (!strcmp ("-x", argv[i])) {
1455             reflection |= RR_Reflect_X;
1456             setit = True;
1457             continue;
1458         }
1459         if (!strcmp ("-y", argv[i])) {
1460             reflection |= RR_Reflect_Y;
1461             setit = True;
1462             continue;
1463         }
1464         if (!strcmp ("--screen", argv[i])) {
1465             if (++i>=argc) usage ();
1466             screen = atoi (argv[i]);
1467             if (screen < 0) usage();
1468             continue;
1469         }
1470         if (!strcmp ("-q", argv[i]) || !strcmp ("--query", argv[i])) {
1471             query = True;
1472             continue;
1473         }
1474         if (!strcmp ("-o", argv[i]) || !strcmp ("--orientation", argv[i])) {
1475             char *endptr;
1476             if (++i>=argc) usage ();
1477             dirind = strtol(argv[i], &endptr, 0);
1478             if (*endptr != '\0') {
1479                 for (dirind = 0; dirind < 4; dirind++) {
1480                     if (strcmp (direction[dirind], argv[i]) == 0) break;
1481                 }
1482                 if ((dirind < 0) || (dirind > 3))  usage();
1483             }
1484             rot = dirind;
1485             setit = True;
1486             continue;
1487         }
1488 #if HAS_RANDR_1_2
1489         if (!strcmp ("--prop", argv[i]) || !strcmp ("--properties", argv[i]))
1490         {
1491             query_1_2 = True;
1492             properties = True;
1493             continue;
1494         }
1495         if (!strcmp ("--output", argv[i])) {
1496             if (++i >= argc) usage();
1497             output = add_output ();
1498
1499             set_name (&output->output, argv[i], name_string|name_xid);
1500             
1501             setit_1_2 = True;
1502             continue;
1503         }
1504         if (!strcmp ("--crtc", argv[i])) {
1505             if (++i >= argc) usage();
1506             if (!output) usage();
1507             set_name (&output->crtc, argv[i], name_xid|name_index);
1508             output->changes |= changes_crtc;
1509             continue;
1510         }
1511         if (!strcmp ("--mode", argv[i])) {
1512             if (++i >= argc) usage();
1513             if (!output) usage();
1514             set_name (&output->mode, argv[i], name_string|name_xid);
1515             output->changes |= changes_mode;
1516             continue;
1517         }
1518         if (!strcmp ("--preferred", argv[i])) {
1519             if (!output) usage();
1520             set_name_preferred (&output->mode);
1521             output->changes |= changes_mode;
1522             continue;
1523         }
1524         if (!strcmp ("--pos", argv[i])) {
1525             if (++i>=argc) usage ();
1526             if (!output) usage();
1527             if (sscanf (argv[i], "%dx%d",
1528                         &output->x, &output->y) != 2)
1529                 usage ();
1530             output->changes |= changes_position;
1531             continue;
1532         }
1533         if (!strcmp ("--rotation", argv[i]) || !strcmp ("--rotate", argv[i])) {
1534             if (++i>=argc) usage ();
1535             if (!output) usage();
1536             for (dirind = 0; dirind < 4; dirind++) {
1537                 if (strcmp (direction[dirind], argv[i]) == 0) break;
1538             }
1539             if (dirind == 4)
1540                 usage ();
1541             output->rotation &= ~0xf;
1542             output->rotation |= 1 << dirind;
1543             output->changes |= changes_rotation;
1544             continue;
1545         }
1546         if (!strcmp ("--reflect", argv[i]) || !strcmp ("--reflection", argv[i])) {
1547             if (++i>=argc) usage ();
1548             if (!output) usage();
1549             for (dirind = 0; dirind < 4; dirind++) {
1550                 if (strcmp (reflections[dirind], argv[i]) == 0) break;
1551             }
1552             if (dirind == 4)
1553                 usage ();
1554             output->rotation &= ~(RR_Reflect_X|RR_Reflect_Y);
1555             output->rotation |= dirind * RR_Reflect_X;
1556             output->changes |= changes_reflection;
1557             continue;
1558         }
1559         if (!strcmp ("--left-of", argv[i])) {
1560             if (++i>=argc) usage ();
1561             if (!output) usage();
1562             output->relation = left_of;
1563             output->relative_to = argv[i];
1564             output->changes |= changes_relation;
1565             continue;
1566         }
1567         if (!strcmp ("--right-of", argv[i])) {
1568             if (++i>=argc) usage ();
1569             if (!output) usage();
1570             output->relation = right_of;
1571             output->relative_to = argv[i];
1572             output->changes |= changes_relation;
1573             continue;
1574         }
1575         if (!strcmp ("--above", argv[i])) {
1576             if (++i>=argc) usage ();
1577             if (!output) usage();
1578             output->relation = above;
1579             output->relative_to = argv[i];
1580             output->changes |= changes_relation;
1581             continue;
1582         }
1583         if (!strcmp ("--below", argv[i])) {
1584             if (++i>=argc) usage ();
1585             if (!output) usage();
1586             output->relation = below;
1587             output->relative_to = argv[i];
1588             output->changes |= changes_relation;
1589             continue;
1590         }
1591         if (!strcmp ("--off", argv[i])) {
1592             if (!output) usage();
1593             set_name_xid (&output->mode, None);
1594             set_name_xid (&output->crtc, None);
1595             output->changes |= changes_mode;
1596             continue;
1597         }
1598         if (!strcmp ("--fb", argv[i])) {
1599             if (++i>=argc) usage ();
1600             if (sscanf (argv[i], "%dx%d",
1601                         &fb_width, &fb_height) != 2)
1602                 usage ();
1603             setit_1_2 = True;
1604             continue;
1605         }
1606         if (!strcmp ("--fbmm", argv[i])) {
1607             if (++i>=argc) usage ();
1608             if (sscanf (argv[i], "%dx%d",
1609                         &fb_width_mm, &fb_height_mm) != 2)
1610                 usage ();
1611             setit_1_2 = True;
1612             continue;
1613         }
1614         if (!strcmp ("--dpi", argv[i])) {
1615             if (++i>=argc) usage ();
1616             if (sscanf (argv[i], "%f", &dpi) != 1)
1617             {
1618                 dpi = 0.0;
1619                 dpi_output = argv[i];
1620             }
1621             setit_1_2 = True;
1622             continue;
1623         }
1624         if (!strcmp ("--clone", argv[i])) {
1625             policy = clone;
1626             setit_1_2 = True;
1627             continue;
1628         }
1629         if (!strcmp ("--extend", argv[i])) {
1630             policy = extend;
1631             setit_1_2 = True;
1632             continue;
1633         }
1634         if (!strcmp ("--auto", argv[i])) {
1635             if (output)
1636             {
1637                 output->automatic = True;
1638                 output->changes |= changes_automatic;
1639             }
1640             automatic = True;
1641             setit_1_2 = True;
1642             continue;
1643         }
1644         if (!strcmp ("--q12", argv[i]))
1645         {
1646             query_1_2 = True;
1647             continue;
1648         }
1649         if (!strcmp ("--q1", argv[i]))
1650         {
1651             query_1 = True;
1652             continue;
1653         }
1654 #endif
1655         usage();
1656     }
1657     if (verbose) query = True;
1658
1659     dpy = XOpenDisplay (display_name);
1660
1661     if (dpy == NULL) {
1662         fprintf (stderr, "Can't open display %s\n", XDisplayName(display_name));
1663         exit (1);
1664     }
1665     if (screen < 0)
1666         screen = DefaultScreen (dpy);
1667     if (screen >= ScreenCount (dpy)) {
1668         fprintf (stderr, "Invalid screen number %d (display has %d)\n",
1669                  screen, ScreenCount (dpy));
1670         exit (1);
1671     }
1672
1673     root = RootWindow (dpy, screen);
1674
1675 #if HAS_RANDR_1_2
1676     if (!XRRQueryVersion (dpy, &major, &minor))
1677     {
1678         fprintf (stderr, "RandR extension missing\n");
1679         exit (1);
1680     }
1681     if (major > 1 || (major == 1 && minor >= 2))
1682         has_1_2 = True;
1683         
1684     if (setit_1_2)
1685     {
1686         XRROutputInfo       *output_info;
1687         XRRCrtcInfo         *crtc_info;
1688         XRRCrtcInfo         *crtc_cur;
1689         XRRModeInfo         *mode_info;
1690         RROutput            *crtc_outputs;
1691         int                 n_crtc_output;
1692         int                 c, o, m;
1693         int                 om, sm;
1694
1695         get_screen ();
1696         get_crtcs ();
1697         get_outputs ();
1698         set_positions ();
1699         set_screen_size ();
1700
1701         /*
1702          * Pick crtcs for any changing outputs that don't have one
1703          */
1704         for (output = outputs; output; output = output->next)
1705         {
1706             if (output->changes && output->mode_info && !output->crtc_info)
1707             {
1708                 output->crtc_info = find_crtc_for_output (output);
1709                 if (!output->crtc_info)
1710                     fatal ("cannot find crtc for output %s\n", output->output.string);
1711             }
1712         }
1713
1714         /*
1715          * Assign outputs to crtcs
1716          */
1717         set_crtcs ();
1718         
1719         /*
1720          * Mark changing crtcs
1721          */
1722         mark_changing_crtcs ();
1723
1724         /*
1725          * If an output was specified to track dpi, use it
1726          */
1727         if (dpi_output)
1728         {
1729             output_t    *output = find_output_by_name (dpi_output);
1730             XRROutputInfo       *output_info;
1731             XRRModeInfo *mode_info;
1732             if (!output)
1733                 fatal ("Cannot find output %s\n", dpi_output);
1734             output_info = output->output_info;
1735             mode_info = output->mode_info;
1736             if (output_info && mode_info && output_info->mm_height)
1737             {
1738                 /*
1739                  * When this output covers the whole screen, just use
1740                  * the known physical size
1741                  */
1742                 if (fb_width == mode_info->width &&
1743                     fb_height == mode_info->height)
1744                 {
1745                     fb_width_mm = output_info->mm_width;
1746                     fb_height_mm = output_info->mm_height;
1747                 }
1748                 else
1749                 {
1750                     dpi = (25.4 * mode_info->height) / output_info->mm_height;
1751                 }
1752             }
1753         }
1754
1755         /*
1756          * Compute physical screen size
1757          */
1758         if (fb_width_mm == 0 || fb_height_mm == 0)
1759         {
1760             if (fb_width != DisplayWidth (dpy, screen) ||
1761                 fb_height != DisplayHeight (dpy, screen) || dpi != 0.0)
1762             {
1763                 if (dpi <= 0)
1764                     dpi = (25.4 * DisplayHeight (dpy, screen)) / DisplayHeightMM(dpy, screen);
1765
1766                 fb_width_mm = (25.4 * fb_width) / dpi;
1767                 fb_height_mm = (25.4 * fb_height) / dpi;
1768             }
1769             else
1770             {
1771                 fb_width_mm = DisplayWidthMM (dpy, screen);
1772                 fb_height_mm = DisplayHeightMM (dpy, screen);
1773             }
1774         }
1775         
1776         /*
1777          * Now apply all of the changes
1778          */
1779         apply ();
1780         
1781         XSync (dpy, False);
1782         exit (0);
1783     }
1784     if (query_1_2 || (query && has_1_2 && !query_1))
1785     {
1786         output_t    *output;
1787         
1788         get_screen ();
1789         get_crtcs ();
1790         get_outputs ();
1791
1792         printf ("Screen %d: minimum %d x %d, current %d x %d, maximum %d x %d\n",
1793                 screen, minWidth, minHeight,
1794                 DisplayWidth (dpy, screen), DisplayHeight(dpy, screen),
1795                 maxWidth, maxHeight);
1796
1797         for (output = outputs; output; output = output->next)
1798         {
1799             XRROutputInfo   *output_info = output->output_info;
1800             XRRModeInfo     *mode = output->mode_info;
1801             Atom            *props;
1802             int             j, k, nprop;
1803             Bool            *mode_shown;
1804             Rotation        rotations = output_rotations (output);
1805
1806             printf ("%s %s", output_info->name, connection[output_info->connection]);
1807             if (mode)
1808             {
1809                 printf (" %dx%d+%d+%d",
1810                         mode_width (mode, output->rotation),
1811                         mode_height (mode, output->rotation),
1812                         output->x, output->y);
1813                 if (output->rotation != RR_Rotate_0 || verbose)
1814                 {
1815                     printf (" %s", 
1816                             rotation_name (output->rotation));
1817                     if (output->rotation & (RR_Reflect_X|RR_Reflect_Y))
1818                         printf (" %s", reflection_name (output->rotation));
1819                 }
1820             }
1821             if (rotations != RR_Rotate_0 || verbose)
1822             {
1823                 Bool    first = True;
1824                 printf (" (");
1825                 for (i = 0; i < 4; i ++) {
1826                     if ((rotations >> i) & 1) {
1827                         if (!first) printf (" "); first = False;
1828                         printf("%s", direction[i]);
1829                         first = False;
1830                     }
1831                 }
1832                 if (rotations & RR_Reflect_X)
1833                 {
1834                     if (!first) printf (" "); first = False;
1835                     printf ("x axis");
1836                 }
1837                 if (rotations & RR_Reflect_Y)
1838                 {
1839                     if (!first) printf (" "); first = False;
1840                     printf ("y axis");
1841                 }
1842                 printf (")");
1843             }
1844
1845             if (mode)
1846             {
1847                 printf (" %dmm x %dmm",
1848                         output_info->mm_width, output_info->mm_height);
1849             }
1850             printf ("\n");
1851
1852             if (verbose)
1853             {
1854                 printf ("\tIdentifier: 0x%x\n", output->output.xid);
1855                 printf ("\tTimestamp:  %d\n", output_info->timestamp);
1856                 printf ("\tSubpixel:   %s\n", order[output_info->subpixel_order]);
1857                 printf ("\tClones:     ");
1858                 for (j = 0; j < output_info->nclone; j++)
1859                 {
1860                     output_t    *clone = find_output_by_xid (output_info->clones[j]);
1861
1862                     if (clone) printf (" %s", clone->output.string);
1863                 }
1864                 printf ("\n");
1865                 if (output->crtc_info)
1866                     printf ("\tCRTC:       %d\n", output->crtc_info->crtc.index);
1867             }
1868             if (verbose || properties)
1869             {
1870                 props = XRRListOutputProperties (dpy, output->output.xid,
1871                                                  &nprop);
1872                 for (j = 0; j < nprop; j++) {
1873                     unsigned char *prop;
1874                     int actual_format;
1875                     unsigned long nitems, bytes_after;
1876                     Atom actual_type;
1877                     XRRPropertyInfo *propinfo;
1878     
1879                     XRRGetOutputProperty (dpy, output->output.xid, props[j],
1880                                           0, 100, False, False,
1881                                           AnyPropertyType,
1882                                           &actual_type, &actual_format,
1883                                           &nitems, &bytes_after, &prop);
1884
1885                     propinfo = XRRQueryOutputProperty(dpy, output->output.xid,
1886                                                       props[j]);
1887
1888                     if (actual_type == XA_INTEGER && actual_format == 8) {
1889                         int k;
1890     
1891                         printf("\t%s:\n", XGetAtomName (dpy, props[j]));
1892                         for (k = 0; k < nitems; k++) {
1893                             if (k % 16 == 0)
1894                                 printf ("\t\t");
1895                             printf("%02x", (unsigned char)prop[k]);
1896                             if (k % 16 == 15)
1897                                 printf("\n");
1898                         }
1899                     } else if (actual_type == XA_INTEGER &&
1900                                actual_format == 32)
1901                     {
1902                         printf("\t%s: %d (0x%08x)",
1903                                XGetAtomName (dpy, props[j]),
1904                                *(INT32 *)prop);
1905
1906                         if (propinfo->range && propinfo->num_values > 0) {
1907                             printf(" range%s: ",
1908                                    (propinfo->num_values == 2) ? "" : "s");
1909
1910                             for (k = 0; k < propinfo->num_values / 2; k++)
1911                                 printf(" (%d,%d)", propinfo->values[k * 2],
1912                                        propinfo->values[k * 2 + 1]);
1913                         }
1914
1915                         printf("\n");
1916                     } else if (actual_format == 8) {
1917                         printf ("\t\t%s: %s%s\n", XGetAtomName (dpy, props[j]),
1918                                 prop, bytes_after ? "..." : "");
1919                     } else {
1920                         printf ("\t\t%s: ????\n", XGetAtomName (dpy, props[j]));
1921                     }
1922
1923                     free(propinfo);
1924                 }
1925             }
1926             
1927             if (verbose)
1928             {
1929                 for (j = 0; j < output_info->nmode; j++)
1930                 {
1931                     XRRModeInfo *mode = find_mode_by_xid (output_info->modes[j]);
1932                     
1933                     printf ("  %s (0x%x) %6.1fMHz\n",
1934                             mode->name, mode->id,
1935                             (float)mode->dotClock / 1000000.0);
1936                     printf ("        h: width  %4d start %4d end %4d total %4d skew %4d clock %6.1fKHz\n",
1937                             mode->width, mode->hSyncStart, mode->hSyncEnd,
1938                             mode->hTotal, mode->hSkew, mode_hsync (mode) / 1000);
1939                     printf ("        v: height %4d start %4d end %4d total %4d           clock %6.1fHz\n",
1940                             mode->height, mode->vSyncStart, mode->vSyncEnd, mode->vTotal,
1941                             mode_refresh (mode));
1942                 }
1943             }
1944             else
1945             {
1946                 mode_shown = calloc (output_info->nmode, sizeof (Bool));
1947                 if (!mode_shown) fatal ("out of memory\n");
1948                 for (j = 0; j < output_info->nmode; j++)
1949                 {
1950                     XRRModeInfo *jmode, *kmode;
1951                     
1952                     if (mode_shown[j]) continue;
1953     
1954                     jmode = find_mode_by_xid (output_info->modes[j]);
1955                     printf (" ");
1956                     printf ("  %-12s", jmode->name);
1957                     for (k = j; k < output_info->nmode; k++)
1958                     {
1959                         if (mode_shown[k]) continue;
1960                         kmode = find_mode_by_xid (output_info->modes[k]);
1961                         if (strcmp (jmode->name, kmode->name) != 0) continue;
1962                         mode_shown[k] = True;
1963                         printf (" %6.1f", mode_refresh (kmode));
1964                         if (kmode == output->mode_info)
1965                             printf ("*");
1966                         else
1967                             printf (" ");
1968                         if (k < output_info->npreferred)
1969                             printf ("+");
1970                         else
1971                             printf (" ");
1972                     }
1973                     printf ("\n");
1974                 }
1975                 free (mode_shown);
1976             }
1977         }
1978         exit (0);
1979     }
1980 #endif
1981     
1982     sc = XRRGetScreenInfo (dpy, root);
1983
1984     if (sc == NULL) 
1985         exit (1);
1986
1987     current_size = XRRConfigCurrentConfiguration (sc, &current_rotation);
1988
1989     sizes = XRRConfigSizes(sc, &nsize);
1990
1991     if (have_pixel_size) {
1992         for (size = 0; size < nsize; size++)
1993         {
1994             if (sizes[size].width == width && sizes[size].height == height)
1995                 break;
1996         }
1997         if (size >= nsize) {
1998             fprintf (stderr,
1999                      "Size %dx%d not found in available modes\n", width, height);
2000             exit (1);
2001         }
2002     }
2003     else if (size < 0)
2004         size = current_size;
2005
2006     if (rot < 0)
2007     {
2008         for (rot = 0; rot < 4; rot++)
2009             if (1 << rot == (current_rotation & 0xf))
2010                 break;
2011     }
2012
2013     current_rate = XRRConfigCurrentRate (sc);
2014
2015     if (rate < 0)
2016     {
2017         if (size == current_size)
2018             rate = current_rate;
2019         else
2020             rate = 0;
2021     }
2022     else
2023     {
2024         rates = XRRConfigRates (sc, size, &nrate);
2025         for (i = 0; i < nrate; i++)
2026             if (rate == rates[i])
2027                 break;
2028         if (i == nrate) {
2029             fprintf (stderr, "Rate %d not available for this size\n", rate);
2030             exit (1);
2031         }
2032     }
2033
2034     if (version) {
2035         int major_version, minor_version;
2036         XRRQueryVersion (dpy, &major_version, &minor_version);
2037         printf("Server reports RandR version %d.%d\n", 
2038                major_version, minor_version);
2039     }
2040
2041     if (query) {
2042         printf(" SZ:    Pixels          Physical       Refresh\n");
2043         for (i = 0; i < nsize; i++) {
2044             printf ("%c%-2d %5d x %-5d  (%4dmm x%4dmm )",
2045                     i == current_size ? '*' : ' ',
2046                     i, sizes[i].width, sizes[i].height,
2047                     sizes[i].mwidth, sizes[i].mheight);
2048             rates = XRRConfigRates (sc, i, &nrate);
2049             if (nrate) printf ("  ");
2050             for (j = 0; j < nrate; j++)
2051                 printf ("%c%-4d",
2052                         i == current_size && rates[j] == current_rate ? '*' : ' ',
2053                         rates[j]);
2054             printf ("\n");
2055         }
2056     }
2057
2058     rotations = XRRConfigRotations(sc, &current_rotation);
2059
2060     rotation = 1 << rot ;
2061     if (query) {
2062         printf("Current rotation - %s\n",
2063                rotation_name (current_rotation));
2064
2065         printf("Current reflection - %s\n",
2066                reflection_name (current_rotation));
2067
2068         printf ("Rotations possible - ");
2069         for (i = 0; i < 4; i ++) {
2070             if ((rotations >> i) & 1)  printf("%s ", direction[i]);
2071         }
2072         printf ("\n");
2073
2074         printf ("Reflections possible - ");
2075         if (rotations & (RR_Reflect_X|RR_Reflect_Y))
2076         {
2077             if (rotations & RR_Reflect_X) printf ("X Axis ");
2078             if (rotations & RR_Reflect_Y) printf ("Y Axis");
2079         }
2080         else
2081             printf ("none");
2082         printf ("\n");
2083     }
2084
2085     if (verbose) { 
2086         printf("Setting size to %d, rotation to %s\n",  size, direction[rot]);
2087
2088         printf ("Setting reflection on ");
2089         if (reflection)
2090         {
2091             if (reflection & RR_Reflect_X) printf ("X Axis ");
2092             if (reflection & RR_Reflect_Y) printf ("Y Axis");
2093         }
2094         else
2095             printf ("neither axis");
2096         printf ("\n");
2097
2098         if (reflection & RR_Reflect_X) printf("Setting reflection on X axis\n");
2099
2100         if (reflection & RR_Reflect_Y) printf("Setting reflection on Y axis\n");
2101     }
2102
2103     /* we should test configureNotify on the root window */
2104     XSelectInput (dpy, root, StructureNotifyMask);
2105
2106     if (setit && !dryrun) XRRSelectInput (dpy, root,
2107                                RRScreenChangeNotifyMask);
2108     if (setit && !dryrun) status = XRRSetScreenConfigAndRate (dpy, sc,
2109                                                    DefaultRootWindow (dpy), 
2110                                                    (SizeID) size, (Rotation) (rotation | reflection), rate, CurrentTime);
2111
2112     XRRQueryExtension(dpy, &event_base, &error_base);
2113
2114     if (setit && !dryrun && status == RRSetConfigFailed) {
2115         printf ("Failed to change the screen configuration!\n");
2116         ret = 1;
2117     }
2118
2119     if (verbose && setit && !dryrun) {
2120         if (status == RRSetConfigSuccess)
2121         {
2122             while (1) {
2123                 int spo;
2124                 XNextEvent(dpy, (XEvent *) &event);
2125
2126                 printf ("Event received, type = %d\n", event.type);
2127                 /* update Xlib's knowledge of the event */
2128                 XRRUpdateConfiguration (&event);
2129                 if (event.type == ConfigureNotify)
2130                     printf("Received ConfigureNotify Event!\n");
2131
2132                 switch (event.type - event_base) {
2133                 case RRScreenChangeNotify:
2134                     sce = (XRRScreenChangeNotifyEvent *) &event;
2135
2136                     printf("Got a screen change notify event!\n");
2137                     printf(" window = %d\n root = %d\n size_index = %d\n rotation %d\n", 
2138                            (int) sce->window, (int) sce->root, 
2139                            sce->size_index,  sce->rotation);
2140                     printf(" timestamp = %ld, config_timestamp = %ld\n",
2141                            sce->timestamp, sce->config_timestamp);
2142                     printf(" Rotation = %x\n", sce->rotation);
2143                     printf(" %d X %d pixels, %d X %d mm\n",
2144                            sce->width, sce->height, sce->mwidth, sce->mheight);
2145                     printf("Display width   %d, height   %d\n",
2146                            DisplayWidth(dpy, screen), DisplayHeight(dpy, screen));
2147                     printf("Display widthmm %d, heightmm %d\n", 
2148                            DisplayWidthMM(dpy, screen), DisplayHeightMM(dpy, screen));
2149                     spo = sce->subpixel_order;
2150                     if ((spo < 0) || (spo > 5))
2151                         printf ("Unknown subpixel order, value = %d\n", spo);
2152                     else printf ("new Subpixel rendering model is %s\n", order[spo]);
2153                     break;
2154                 default:
2155                     if (event.type != ConfigureNotify) 
2156                         printf("unknown event received, type = %d!\n", event.type);
2157                 }
2158             }
2159         }
2160     }
2161     XRRFreeScreenConfigInfo(sc);
2162     return(ret);
2163 }