Add xrandr test suite.
[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 const struct {
76     char            *string;
77     unsigned long   flag;
78 } mode_flags[] = {
79     { "+HSync", RR_HSyncPositive },
80     { "-HSync", RR_HSyncNegative },
81     { "+VSync", RR_VSyncPositive },
82     { "-VSync", RR_VSyncNegative },
83     { "Interlace", RR_Interlace },
84     { "DoubleScan", RR_DoubleScan },
85     { "CSync",      RR_CSync },
86     { "+CSync",     RR_CSyncPositive },
87     { "-CSync",     RR_CSyncNegative },
88     { NULL,         0 }
89 };
90
91 static void
92 usage(void)
93 {
94     fprintf(stderr, "usage: %s [options]\n", program_name);
95     fprintf(stderr, "  where options are:\n");
96     fprintf(stderr, "  -display <display> or -d <display>\n");
97     fprintf(stderr, "  -help\n");
98     fprintf(stderr, "  -o <normal,inverted,left,right,0,1,2,3>\n");
99     fprintf(stderr, "            or --orientation <normal,inverted,left,right,0,1,2,3>\n");
100     fprintf(stderr, "  -q        or --query\n");
101     fprintf(stderr, "  -s <size>/<width>x<height> or --size <size>/<width>x<height>\n");
102     fprintf(stderr, "  -r <rate> or --rate <rate> or --refresh <rate>\n");
103     fprintf(stderr, "  -v        or --version\n");
104     fprintf(stderr, "  -x        (reflect in x)\n");
105     fprintf(stderr, "  -y        (reflect in y)\n");
106     fprintf(stderr, "  --screen <screen>\n");
107     fprintf(stderr, "  --verbose\n");
108     fprintf(stderr, "  --dryrun\n");
109 #if HAS_RANDR_1_2
110     fprintf(stderr, "  --prop or --properties\n");
111     fprintf(stderr, "  --fb <width>x<height>\n");
112     fprintf(stderr, "  --fbmm <width>x<height>\n");
113     fprintf(stderr, "  --dpi <dpi>/<output>\n");
114 #if 0
115     fprintf(stderr, "  --clone\n");
116     fprintf(stderr, "  --extend\n");
117 #endif
118     fprintf(stderr, "  --output <output>\n");
119     fprintf(stderr, "      --auto\n");
120     fprintf(stderr, "      --mode <mode>\n");
121     fprintf(stderr, "      --preferred\n");
122     fprintf(stderr, "      --pos <x>x<y>\n");
123     fprintf(stderr, "      --rate <rate> or --refresh <rate>\n");
124     fprintf(stderr, "      --reflect normal,x,y,xy\n");
125     fprintf(stderr, "      --rotate normal,inverted,left,right\n");
126     fprintf(stderr, "      --left-of <output>\n");
127     fprintf(stderr, "      --right-of <output>\n");
128     fprintf(stderr, "      --above <output>\n");
129     fprintf(stderr, "      --below <output>\n");
130     fprintf(stderr, "      --same-as <output>\n");
131     fprintf(stderr, "      --set <property> <value>\n");
132     fprintf(stderr, "      --off\n");
133     fprintf(stderr, "      --crtc <crtc>\n");
134     fprintf(stderr, "  --newmode <name> <clock MHz>\n");
135     fprintf(stderr, "            <hdisp> <hsync-start> <hsync-end> <htotal>\n");
136     fprintf(stderr, "            <vdisp> <vsync-start> <vsync-end> <vtotal>\n");
137     fprintf(stderr, "            [+HSync] [-HSync] [+VSync] [-VSync]\n");
138     fprintf(stderr, "  --rmmode <name>\n");
139     fprintf(stderr, "  --addmode <output> <name>\n");
140     fprintf(stderr, "  --delmode <output> <name>\n");
141 #endif
142
143     exit(1);
144     /*NOTREACHED*/
145 }
146
147 static void
148 fatal (const char *format, ...)
149 {
150     va_list ap;
151     
152     va_start (ap, format);
153     fprintf (stderr, "%s: ", program_name);
154     vfprintf (stderr, format, ap);
155     va_end (ap);
156     exit (1);
157     /*NOTREACHED*/
158 }
159
160 static char *
161 rotation_name (Rotation rotation)
162 {
163     int i;
164
165     if ((rotation & 0xf) == 0)
166         return "normal";
167     for (i = 0; i < 4; i++)
168         if (rotation & (1 << i))
169             return direction[i];
170     return "invalid rotation";
171 }
172
173 static char *
174 reflection_name (Rotation rotation)
175 {
176     rotation &= (RR_Reflect_X|RR_Reflect_Y);
177     switch (rotation) {
178     case 0:
179         return "none";
180     case RR_Reflect_X:
181         return "X axis";
182     case RR_Reflect_Y:
183         return "Y axis";
184     case RR_Reflect_X|RR_Reflect_Y:
185         return "X and Y axis";
186     }
187     return "invalid reflection";
188 }
189
190 #if HAS_RANDR_1_2
191 typedef enum _policy {
192     clone, extend
193 } policy_t;
194
195 typedef enum _relation {
196     left_of, right_of, above, below, same_as,
197 } relation_t;
198
199 typedef enum _changes {
200     changes_none = 0,
201     changes_crtc = (1 << 0),
202     changes_mode = (1 << 1),
203     changes_relation = (1 << 2),
204     changes_position = (1 << 3),
205     changes_rotation = (1 << 4),
206     changes_reflection = (1 << 5),
207     changes_automatic = (1 << 6),
208     changes_refresh = (1 << 7),
209     changes_property = (1 << 8),
210 } changes_t;
211
212 typedef enum _name_kind {
213     name_none = 0,
214     name_string = (1 << 0),
215     name_xid = (1 << 1),
216     name_index = (1 << 2),
217     name_preferred = (1 << 3),
218 } name_kind_t;
219
220 typedef struct {
221     name_kind_t     kind;
222     char            *string;
223     XID             xid;
224     int             index;
225 } name_t;
226
227 typedef struct _crtc crtc_t;
228 typedef struct _output  output_t;
229 typedef struct _umode   umode_t;
230 typedef struct _output_prop output_prop_t;
231
232 struct _crtc {
233     name_t          crtc;
234     Bool            changing;
235     XRRCrtcInfo     *crtc_info;
236
237     XRRModeInfo     *mode_info;
238     int             x;
239     int             y;
240     Rotation        rotation;
241     output_t        **outputs;
242     int             noutput;
243 };
244
245 struct _output_prop {
246     struct _output_prop *next;
247     char                *name;
248     char                *value;
249 };
250
251 struct _output {
252     struct _output   *next;
253     
254     changes_t       changes;
255     
256     output_prop_t   *props;
257
258     name_t          output;
259     XRROutputInfo   *output_info;
260     
261     name_t          crtc;
262     crtc_t          *crtc_info;
263     crtc_t          *current_crtc_info;
264     
265     name_t          mode;
266     float           refresh;
267     XRRModeInfo     *mode_info;
268     
269     name_t          addmode;
270
271     relation_t      relation;
272     char            *relative_to;
273
274     int             x, y;
275     Rotation        rotation;
276     
277     Bool            automatic;
278 };
279
280 typedef enum _umode_action {
281     umode_create, umode_destroy, umode_add, umode_delete
282 } umode_action_t;
283
284
285 struct _umode {
286     struct _umode   *next;
287     
288     umode_action_t  action;
289     XRRModeInfo     mode;
290     name_t          output;
291     name_t          name;
292 };
293
294 static char *connection[3] = {
295     "connected",
296     "disconnected",
297     "unknown connection"};
298
299 #define OUTPUT_NAME 1
300
301 #define CRTC_OFF    2
302 #define CRTC_UNSET  3
303 #define CRTC_INDEX  0x40000000
304
305 #define MODE_NAME   1
306 #define MODE_OFF    2
307 #define MODE_UNSET  3
308 #define MODE_PREF   4
309
310 #define POS_UNSET   -1
311
312 static output_t *outputs = NULL;
313 static output_t **outputs_tail = &outputs;
314 static crtc_t   *crtcs;
315 static umode_t  *umodes;
316 static int      num_crtcs;
317 static XRRScreenResources  *res;
318 static int      fb_width = 0, fb_height = 0;
319 static int      fb_width_mm = 0, fb_height_mm = 0;
320 static float    dpi = 0;
321 static char     *dpi_output = NULL;
322 static Bool     dryrun = False;
323 static int      minWidth, maxWidth, minHeight, maxHeight;
324 static Bool     has_1_2 = False;
325
326 static int
327 mode_height (XRRModeInfo *mode_info, Rotation rotation)
328 {
329     switch (rotation & 0xf) {
330     case RR_Rotate_0:
331     case RR_Rotate_180:
332         return mode_info->height;
333     case RR_Rotate_90:
334     case RR_Rotate_270:
335         return mode_info->width;
336     default:
337         return 0;
338     }
339 }
340
341 static int
342 mode_width (XRRModeInfo *mode_info, Rotation rotation)
343 {
344     switch (rotation & 0xf) {
345     case RR_Rotate_0:
346     case RR_Rotate_180:
347         return mode_info->width;
348     case RR_Rotate_90:
349     case RR_Rotate_270:
350         return mode_info->height;
351     default:
352         return 0;
353     }
354 }
355
356 /* v refresh frequency in Hz */
357 static float
358 mode_refresh (XRRModeInfo *mode_info)
359 {
360     float rate;
361     
362     if (mode_info->hTotal && mode_info->vTotal)
363         rate = ((float) mode_info->dotClock / 
364                 ((float) mode_info->hTotal * (float) mode_info->vTotal));
365     else
366         rate = 0;
367     return rate;
368 }
369
370 /* h sync frequency in Hz */
371 static float
372 mode_hsync (XRRModeInfo *mode_info)
373 {
374     float rate;
375     
376     if (mode_info->hTotal)
377         rate = (float) mode_info->dotClock / (float) mode_info->hTotal;
378     else
379         rate = 0;
380     return rate;
381 }
382
383 static void
384 init_name (name_t *name)
385 {
386     name->kind = name_none;
387 }
388
389 static void
390 set_name_string (name_t *name, char *string)
391 {
392     name->kind |= name_string;
393     name->string = string;
394 }
395
396 static void
397 set_name_xid (name_t *name, XID xid)
398 {
399     name->kind |= name_xid;
400     name->xid = xid;
401 }
402
403 static void
404 set_name_index (name_t *name, int index)
405 {
406     name->kind |= name_index;
407     name->index = index;
408 }
409
410 static void
411 set_name_preferred (name_t *name)
412 {
413     name->kind |= name_preferred;
414 }
415
416 static void
417 set_name_all (name_t *name, name_t *old)
418 {
419     if (old->kind & name_xid)
420         name->xid = old->xid;
421     if (old->kind & name_string)
422         name->string = old->string;
423     if (old->kind & name_index)
424         name->index = old->index;
425     name->kind |= old->kind;
426 }
427
428 static void
429 set_name (name_t *name, char *string, name_kind_t valid)
430 {
431     XID xid;
432     int index;
433
434     if ((valid & name_xid) && sscanf (string, "0x%x", &xid) == 1)
435         set_name_xid (name, xid);
436     else if ((valid & name_index) && sscanf (string, "%d", &index) == 1)
437         set_name_index (name, index);
438     else if (valid & name_string)
439         set_name_string (name, string);
440     else
441         usage ();
442 }
443
444 static output_t *
445 add_output (void)
446 {
447     output_t *output = calloc (1, sizeof (output_t));
448
449     if (!output)
450         fatal ("out of memory");
451     output->next = NULL;
452     *outputs_tail = output;
453     outputs_tail = &output->next;
454     return output;
455 }
456
457 static output_t *
458 find_output (name_t *name)
459 {
460     output_t *output;
461
462     for (output = outputs; output; output = output->next)
463     {
464         name_kind_t common = name->kind & output->output.kind;
465         
466         if ((common & name_xid) && name->xid == output->output.xid)
467             break;
468         if ((common & name_string) && !strcmp (name->string, output->output.string))
469             break;
470         if ((common & name_index) && name->index == output->output.index)
471             break;
472     }
473     return output;
474 }
475
476 static output_t *
477 find_output_by_xid (RROutput output)
478 {
479     name_t  output_name;
480
481     init_name (&output_name);
482     set_name_xid (&output_name, output);
483     return find_output (&output_name);
484 }
485
486 static output_t *
487 find_output_by_name (char *name)
488 {
489     name_t  output_name;
490
491     init_name (&output_name);
492     set_name_string (&output_name, name);
493     return find_output (&output_name);
494 }
495
496 static crtc_t *
497 find_crtc (name_t *name)
498 {
499     int     c;
500     crtc_t  *crtc = NULL;
501
502     for (c = 0; c < num_crtcs; c++)
503     {
504         name_kind_t common;
505         
506         crtc = &crtcs[c];
507         common = name->kind & crtc->crtc.kind;
508         
509         if ((common & name_xid) && name->xid == crtc->crtc.xid)
510             break;
511         if ((common & name_string) && !strcmp (name->string, crtc->crtc.string))
512             break;
513         if ((common & name_index) && name->index == crtc->crtc.index)
514             break;
515         crtc = NULL;
516     }
517     return crtc;
518 }
519
520 static crtc_t *
521 find_crtc_by_xid (RRCrtc crtc)
522 {
523     name_t  crtc_name;
524
525     init_name (&crtc_name);
526     set_name_xid (&crtc_name, crtc);
527     return find_crtc (&crtc_name);
528 }
529
530 static XRRModeInfo *
531 find_mode (name_t *name, float refresh)
532 {
533     int         m;
534     XRRModeInfo *best = NULL;
535     float       bestDist = 0;
536
537     for (m = 0; m < res->nmode; m++)
538     {
539         XRRModeInfo *mode = &res->modes[m];
540         if ((name->kind & name_xid) && name->xid == mode->id)
541         {
542             best = mode;
543             break;
544         }
545         if ((name->kind & name_string) && !strcmp (name->string, mode->name))
546         {
547             float   dist;
548             
549             if (refresh)
550                 dist = fabs (mode_refresh (mode) - refresh);
551             else
552                 dist = 0;
553             if (!best || dist < bestDist)
554             {
555                 bestDist = dist;
556                 best = mode;
557             }
558             break;
559         }
560     }
561     return best;
562 }
563
564 static XRRModeInfo *
565 find_mode_by_xid (RRMode mode)
566 {
567     name_t  mode_name;
568
569     init_name (&mode_name);
570     set_name_xid (&mode_name, mode);
571     return find_mode (&mode_name, 0);
572 }
573
574 static XRRModeInfo *
575 find_mode_by_name (char *name)
576 {
577     name_t  mode_name;
578     init_name (&mode_name);
579     set_name_string (&mode_name, name);
580     return find_mode (&mode_name, 0);
581 }
582
583 static
584 XRRModeInfo *
585 find_mode_for_output (output_t *output, name_t *name)
586 {
587     XRROutputInfo   *output_info = output->output_info;
588     int             m;
589     XRRModeInfo     *best = NULL;
590     float           bestDist = 0;
591
592     for (m = 0; m < output_info->nmode; m++)
593     {
594         XRRModeInfo         *mode;
595         
596         mode = find_mode_by_xid (output_info->modes[m]);
597         if (!mode) continue;
598         if ((name->kind & name_xid) && name->xid == mode->id)
599         {
600             best = mode;
601             break;
602         }
603         if ((name->kind & name_string) && !strcmp (name->string, mode->name))
604         {
605             float   dist;
606             
607             if (output->refresh)
608                 dist = fabs (mode_refresh (mode) - output->refresh);
609             else
610                 dist = 0;
611             if (!best || dist < bestDist)
612             {
613                 bestDist = dist;
614                 best = mode;
615             }
616         }
617     }
618     return best;
619 }
620
621 XRRModeInfo *
622 preferred_mode (output_t *output)
623 {
624     XRROutputInfo   *output_info = output->output_info;
625     int             m;
626     XRRModeInfo     *best;
627     int             bestDist;
628     
629     best = NULL;
630     bestDist = 0;
631     for (m = 0; m < output_info->nmode; m++)
632     {
633         XRRModeInfo *mode_info = find_mode_by_xid (output_info->modes[m]);
634         int         dist;
635         
636         if (m < output_info->npreferred)
637             dist = 0;
638         else if (output_info->mm_height)
639             dist = (1000 * DisplayHeight(dpy, screen) / DisplayHeightMM(dpy, screen) -
640                     1000 * mode_info->height / output_info->mm_height);
641         else
642             dist = DisplayHeight(dpy, screen) - mode_info->height;
643
644         if (dist < 0) dist = -dist;
645         if (!best || dist < bestDist)
646         {
647             best = mode_info;
648             bestDist = dist;
649         }
650     }
651     return best;
652 }
653
654 static Bool
655 output_can_use_crtc (output_t *output, crtc_t *crtc)
656 {
657     XRROutputInfo   *output_info = output->output_info;
658     int             c;
659
660     for (c = 0; c < output_info->ncrtc; c++)
661         if (output_info->crtcs[c] == crtc->crtc.xid)
662             return True;
663     return False;
664 }
665
666 static Bool
667 output_can_use_mode (output_t *output, XRRModeInfo *mode)
668 {
669     XRROutputInfo   *output_info = output->output_info;
670     int             m;
671
672     for (m = 0; m < output_info->nmode; m++)
673         if (output_info->modes[m] == mode->id)
674             return True;
675     return False;
676 }
677
678 static Bool
679 crtc_can_use_rotation (crtc_t *crtc, Rotation rotation)
680 {
681     Rotation    rotations = crtc->crtc_info->rotations;
682     Rotation    dir = rotation & (RR_Rotate_0|RR_Rotate_90|RR_Rotate_180|RR_Rotate_270);
683     Rotation    reflect = rotation & (RR_Reflect_X|RR_Reflect_Y);
684     if (((rotations & dir) != 0) && ((rotations & reflect) == reflect))
685         return True;
686     return False;
687 }
688
689 /*
690  * Report only rotations that are supported by all crtcs
691  */
692 static Rotation
693 output_rotations (output_t *output)
694 {
695     Bool            found = False;
696     Rotation        rotation = RR_Rotate_0;
697     XRROutputInfo   *output_info = output->output_info;
698     int             c;
699     
700     for (c = 0; c < output_info->ncrtc; c++)
701     {
702         crtc_t  *crtc = find_crtc_by_xid (output_info->crtcs[c]);
703         if (crtc)
704         {
705             if (!found) {
706                 rotation = crtc->crtc_info->rotations;
707                 found = True;
708             } else
709                 rotation &= crtc->crtc_info->rotations;
710         }
711     }
712     return rotation;
713 }
714
715 static Bool
716 output_can_use_rotation (output_t *output, Rotation rotation)
717 {
718     XRROutputInfo   *output_info = output->output_info;
719     int             c;
720
721     /* make sure all of the crtcs can use this rotation.
722      * yes, this is not strictly necessary, but it is 
723      * simpler,and we expect most drivers to either
724      * support rotation everywhere or nowhere
725      */
726     for (c = 0; c < output_info->ncrtc; c++)
727     {
728         crtc_t  *crtc = find_crtc_by_xid (output_info->crtcs[c]);
729         if (crtc && !crtc_can_use_rotation (crtc, rotation))
730             return False;
731     }
732     return True;
733 }
734
735 static void
736 set_output_info (output_t *output, RROutput xid, XRROutputInfo *output_info)
737 {
738     /* sanity check output info */
739     if (output_info->connection != RR_Disconnected && !output_info->nmode)
740         fatal ("Output %s is not disconnected but has no modes\n",
741                output_info->name);
742     
743     /* set output name and info */
744     if (!(output->output.kind & name_xid))
745         set_name_xid (&output->output, xid);
746     if (!(output->output.kind & name_string))
747         set_name_string (&output->output, output_info->name);
748     output->output_info = output_info;
749     
750     /* set crtc name and info */
751     if (!(output->changes & changes_crtc))
752         set_name_xid (&output->crtc, output_info->crtc);
753     
754     if (output->crtc.kind == name_xid && output->crtc.xid == None)
755         output->crtc_info = NULL;
756     else
757     {
758         output->crtc_info = find_crtc (&output->crtc);
759         if (!output->crtc_info)
760         {
761             if (output->crtc.kind & name_xid)
762                 fatal ("cannot find crtc 0x%x\n", output->crtc.xid);
763             if (output->crtc.kind & name_index)
764                 fatal ("cannot find crtc %d\n", output->crtc.index);
765         }
766         if (!output_can_use_crtc (output, output->crtc_info))
767             fatal ("output %s cannot use crtc 0x%x\n", output->output.string,
768                    output->crtc_info->crtc.xid);
769     }
770
771     /* set mode name and info */
772     if (!(output->changes & changes_mode))
773     {
774         if (output->crtc_info)
775             set_name_xid (&output->mode, output->crtc_info->crtc_info->mode);
776         else
777             set_name_xid (&output->mode, None);
778         if (output->mode.xid)
779         {
780             output->mode_info = find_mode_by_xid (output->mode.xid);
781             if (!output->mode_info)
782                 fatal ("server did not report mode 0x%x for output %s\n",
783                        output->mode.xid, output->output.string);
784         }
785         else
786             output->mode_info = NULL;
787     }
788     else if (output->mode.kind == name_xid && output->mode.xid == None)
789         output->mode_info = NULL;
790     else
791     {
792         if (output->mode.kind == name_preferred)
793             output->mode_info = preferred_mode (output);
794         else
795             output->mode_info = find_mode_for_output (output, &output->mode);
796         if (!output->mode_info)
797         {
798             if (output->mode.kind & name_preferred)
799                 fatal ("cannot find preferred mode\n");
800             if (output->mode.kind & name_string)
801                 fatal ("cannot find mode %s\n", output->mode.string);
802             if (output->mode.kind & name_xid)
803                 fatal ("cannot find mode 0x%x\n", output->mode.xid);
804         }
805         if (!output_can_use_mode (output, output->mode_info))
806             fatal ("output %s cannot use mode %s\n", output->output.string,
807                    output->mode_info->name);
808     }
809
810     /* set position */
811     if (!(output->changes & changes_position))
812     {
813         if (output->crtc_info)
814         {
815             output->x = output->crtc_info->crtc_info->x;
816             output->y = output->crtc_info->crtc_info->y;
817         }
818         else
819         {
820             output->x = 0;
821             output->y = 0;
822         }
823     }
824
825     /* set rotation */
826     if (!(output->changes & changes_rotation))
827     {
828         output->rotation &= ~0xf;
829         if (output->crtc_info)
830             output->rotation |= (output->crtc_info->crtc_info->rotation & 0xf);
831         else
832             output->rotation = RR_Rotate_0;
833     }
834     if (!(output->changes & changes_reflection))
835     {
836         output->rotation &= ~(RR_Reflect_X|RR_Reflect_Y);
837         if (output->crtc_info)
838             output->rotation |= (output->crtc_info->crtc_info->rotation &
839                                  (RR_Reflect_X|RR_Reflect_Y));
840     }
841     if (!output_can_use_rotation (output, output->rotation))
842         fatal ("output %s cannot use rotation \"%s\" reflection \"%s\"\n",
843                output->output.string,
844                rotation_name (output->rotation),
845                reflection_name (output->rotation));
846 }
847     
848 static void
849 get_screen (void)
850 {
851     if (!has_1_2)
852         fatal ("Server RandR version before 1.2\n");
853     
854     XRRGetScreenSizeRange (dpy, root, &minWidth, &minHeight,
855                            &maxWidth, &maxHeight);
856     
857     res = XRRGetScreenResources (dpy, root);
858     if (!res) fatal ("could not get screen resources");
859 }
860
861 static void
862 get_crtcs (void)
863 {
864     int         c;
865
866     num_crtcs = res->ncrtc;
867     crtcs = calloc (num_crtcs, sizeof (crtc_t));
868     if (!crtcs) fatal ("out of memory");
869     
870     for (c = 0; c < res->ncrtc; c++)
871     {
872         XRRCrtcInfo *crtc_info = XRRGetCrtcInfo (dpy, res, res->crtcs[c]);
873         set_name_xid (&crtcs[c].crtc, res->crtcs[c]);
874         set_name_index (&crtcs[c].crtc, c);
875         if (!crtc_info) fatal ("could not get crtc 0x%x information", res->crtcs[c]);
876         crtcs[c].crtc_info = crtc_info;
877         if (crtc_info->mode == None)
878         {
879             crtcs[c].mode_info = NULL;
880             crtcs[c].x = 0;
881             crtcs[c].y = 0;
882             crtcs[c].rotation = RR_Rotate_0;
883         }
884     }
885 }
886
887 static void
888 crtc_add_output (crtc_t *crtc, output_t *output)
889 {
890     if (crtc->outputs)
891         crtc->outputs = realloc (crtc->outputs, (crtc->noutput + 1) * sizeof (output_t *));
892     else
893     {
894         crtc->outputs = malloc (sizeof (output_t *));
895         crtc->x = output->x;
896         crtc->y = output->y;
897         crtc->rotation = output->rotation;
898         crtc->mode_info = output->mode_info;
899     }
900     if (!crtc->outputs) fatal ("out of memory");
901     crtc->outputs[crtc->noutput++] = output;
902 }
903
904 static void
905 set_crtcs (void)
906 {
907     output_t    *output;
908
909     for (output = outputs; output; output = output->next)
910     {
911         if (!output->mode_info) continue;
912         crtc_add_output (output->crtc_info, output);
913     }
914 }
915
916 static Status
917 crtc_disable (crtc_t *crtc)
918 {
919     if (verbose)
920         printf ("crtc %d: disable\n", crtc->crtc.index);
921         
922     if (dryrun)
923         return RRSetConfigSuccess;
924     return XRRSetCrtcConfig (dpy, res, crtc->crtc.xid, CurrentTime,
925                              0, 0, None, RR_Rotate_0, NULL, 0);
926 }
927
928 static Status
929 crtc_revert (crtc_t *crtc)
930 {
931     XRRCrtcInfo *crtc_info = crtc->crtc_info;
932     
933     if (verbose)
934         printf ("crtc %d: revert\n", crtc->crtc.index);
935         
936     if (dryrun)
937         return RRSetConfigSuccess;
938     return XRRSetCrtcConfig (dpy, res, crtc->crtc.xid, CurrentTime,
939                             crtc_info->x, crtc_info->y,
940                             crtc_info->mode, crtc_info->rotation,
941                             crtc_info->outputs, crtc_info->noutput);
942 }
943
944 static Status
945 crtc_apply (crtc_t *crtc)
946 {
947     RROutput    *rr_outputs;
948     int         o;
949     Status      s;
950     RRMode      mode = None;
951
952     if (!crtc->changing || !crtc->mode_info)
953         return RRSetConfigSuccess;
954
955     rr_outputs = calloc (crtc->noutput, sizeof (RROutput));
956     if (!rr_outputs)
957         return BadAlloc;
958     for (o = 0; o < crtc->noutput; o++)
959         rr_outputs[o] = crtc->outputs[o]->output.xid;
960     mode = crtc->mode_info->id;
961     if (verbose) {
962         printf ("crtc %d: %12s %6.1f +%d+%d", crtc->crtc.index,
963                 crtc->mode_info->name, mode_refresh (crtc->mode_info),
964                 crtc->x, crtc->y);
965         for (o = 0; o < crtc->noutput; o++)
966             printf (" \"%s\"", crtc->outputs[o]->output.string);
967         printf ("\n");
968     }
969     
970     if (dryrun)
971         s = RRSetConfigSuccess;
972     else
973         s = XRRSetCrtcConfig (dpy, res, crtc->crtc.xid, CurrentTime,
974                               crtc->x, crtc->y, mode, crtc->rotation,
975                               rr_outputs, crtc->noutput);
976     free (rr_outputs);
977     return s;
978 }
979
980 static void
981 screen_revert (void)
982 {
983     if (verbose)
984         printf ("screen %d: revert\n", screen);
985
986     if (dryrun)
987         return;
988     XRRSetScreenSize (dpy, root,
989                       DisplayWidth (dpy, screen),
990                       DisplayHeight (dpy, screen),
991                       DisplayWidthMM (dpy, screen),
992                       DisplayHeightMM (dpy, screen));
993 }
994
995 static void
996 screen_apply (void)
997 {
998     if (fb_width == DisplayWidth (dpy, screen) &&
999         fb_height == DisplayHeight (dpy, screen) &&
1000         fb_width_mm == DisplayWidthMM (dpy, screen) &&
1001         fb_height_mm == DisplayHeightMM (dpy, screen))
1002     {
1003         return;
1004     }
1005     if (verbose)
1006         printf ("screen %d: %dx%d %dx%d mm %6.2fdpi\n", screen,
1007                 fb_width, fb_height, fb_width_mm, fb_height_mm, dpi);
1008     if (dryrun)
1009         return;
1010     XRRSetScreenSize (dpy, root, fb_width, fb_height,
1011                       fb_width_mm, fb_height_mm);
1012 }
1013
1014 static void
1015 revert (void)
1016 {
1017     int c;
1018
1019     /* first disable all crtcs */
1020     for (c = 0; c < res->ncrtc; c++)
1021         crtc_disable (&crtcs[c]);
1022     /* next reset screen size */
1023     screen_revert ();
1024     /* now restore all crtcs */
1025     for (c = 0; c < res->ncrtc; c++)
1026         crtc_revert (&crtcs[c]);
1027 }
1028
1029 /*
1030  * uh-oh, something bad happened in the middle of changing
1031  * the configuration. Revert to the previous configuration
1032  * and bail
1033  */
1034 static void
1035 panic (Status s, crtc_t *crtc)
1036 {
1037     int     c = crtc->crtc.index;
1038     char    *message;
1039     
1040     switch (s) {
1041     case RRSetConfigSuccess:            message = "succeeded";              break;
1042     case BadAlloc:                      message = "out of memory";          break;
1043     case RRSetConfigFailed:             message = "failed";                 break;
1044     case RRSetConfigInvalidConfigTime:  message = "invalid config time";    break;
1045     case RRSetConfigInvalidTime:        message = "invalid time";           break;
1046     default:                            message = "unknown failure";        break;
1047     }
1048     
1049     fprintf (stderr, "%s: Configure crtc %d %s\n", program_name, c, message);
1050     revert ();
1051     exit (1);
1052 }
1053
1054 void
1055 apply (void)
1056 {
1057     Status  s;
1058     int     c;
1059     
1060     /*
1061      * Turn off any crtcs which are to be disabled or which are
1062      * larger than the target size
1063      */
1064     for (c = 0; c < res->ncrtc; c++)
1065     {
1066         crtc_t      *crtc = &crtcs[c];
1067         XRRCrtcInfo *crtc_info = crtc->crtc_info;
1068
1069         /* if this crtc is already disabled, skip it */
1070         if (crtc_info->mode == None) 
1071             continue;
1072         
1073         /* 
1074          * If this crtc is to be left enabled, make
1075          * sure the old size fits then new screen
1076          */
1077         if (crtc->mode_info) 
1078         {
1079             XRRModeInfo *old_mode = find_mode_by_xid (crtc_info->mode);
1080             int x, y, w, h;
1081
1082             if (!old_mode) 
1083                 panic (RRSetConfigFailed, crtc);
1084             
1085             /* old position and size information */
1086             x = crtc_info->x;
1087             y = crtc_info->y;
1088             w = mode_width (old_mode, crtc_info->rotation);
1089             h = mode_height (old_mode, crtc_info->rotation);
1090             
1091             /* if it fits, skip it */
1092             if (x + w <= fb_width && y + h <= fb_height) 
1093                 continue;
1094             crtc->changing = True;
1095         }
1096         s = crtc_disable (crtc);
1097         if (s != RRSetConfigSuccess)
1098             panic (s, crtc);
1099     }
1100
1101     /*
1102      * Hold the server grabbed while messing with
1103      * the screen so that apps which notice the resize
1104      * event and ask for xinerama information from the server
1105      * receive up-to-date information
1106      */
1107     XGrabServer (dpy);
1108     
1109     /*
1110      * Set the screen size
1111      */
1112     screen_apply ();
1113     
1114     /*
1115      * Set crtcs
1116      */
1117
1118     for (c = 0; c < res->ncrtc; c++)
1119     {
1120         crtc_t  *crtc = &crtcs[c];
1121         
1122         s = crtc_apply (crtc);
1123         if (s != RRSetConfigSuccess)
1124             panic (s, crtc);
1125     }
1126     /*
1127      * Release the server grab and let all clients
1128      * respond to the updated state
1129      */
1130     XUngrabServer (dpy);
1131 }
1132
1133 /*
1134  * Use current output state to complete the output list
1135  */
1136 void
1137 get_outputs (void)
1138 {
1139     int         o;
1140     
1141     for (o = 0; o < res->noutput; o++)
1142     {
1143         XRROutputInfo   *output_info = XRRGetOutputInfo (dpy, res, res->outputs[o]);
1144         output_t        *output;
1145         name_t          output_name;
1146         if (!output_info) fatal ("could not get output 0x%x information", res->outputs[o]);
1147         set_name_xid (&output_name, res->outputs[o]);
1148         set_name_index (&output_name, o);
1149         set_name_string (&output_name, output_info->name);
1150         output = find_output (&output_name);
1151         if (!output)
1152         {
1153             output = add_output ();
1154             set_name_all (&output->output, &output_name);
1155             /*
1156              * When global --automatic mode is set, turn on connected but off
1157              * outputs, turn off disconnected but on outputs
1158              */
1159             if (automatic)
1160             {
1161                 switch (output_info->connection) {
1162                 case RR_Connected:
1163                     if (!output_info->crtc) {
1164                         output->changes |= changes_automatic;
1165                         output->automatic = True;
1166                     }
1167                     break;
1168                 case RR_Disconnected:
1169                     if (output_info->crtc)
1170                     {
1171                         output->changes |= changes_automatic;
1172                         output->automatic = True;
1173                     }
1174                     break;
1175                 }
1176             }
1177         }
1178
1179         /*
1180          * Automatic mode -- track connection state and enable/disable outputs
1181          * as necessary
1182          */
1183         if (output->automatic)
1184         {
1185             switch (output_info->connection) {
1186             case RR_Connected:
1187             case RR_UnknownConnection:
1188                 if ((!(output->changes & changes_mode)))
1189                 {
1190                     set_name_preferred (&output->mode);
1191                     output->changes |= changes_mode;
1192                 }
1193                 break;
1194             case RR_Disconnected:
1195                 if ((!(output->changes & changes_mode)))
1196                 {
1197                     set_name_xid (&output->mode, None);
1198                     set_name_xid (&output->crtc, None);
1199                     output->changes |= changes_mode;
1200                     output->changes |= changes_crtc;
1201                 }
1202                 break;
1203             }
1204         }
1205
1206         set_output_info (output, res->outputs[o], output_info);
1207     }
1208 }
1209
1210 void
1211 mark_changing_crtcs (void)
1212 {
1213     int c;
1214
1215     for (c = 0; c < num_crtcs; c++)
1216     {
1217         crtc_t      *crtc = &crtcs[c];
1218         int         o;
1219         output_t    *output;
1220
1221         /* walk old output list (to catch disables) */
1222         for (o = 0; o < crtc->crtc_info->noutput; o++)
1223         {
1224             output = find_output_by_xid (crtc->crtc_info->outputs[o]);
1225             if (!output) fatal ("cannot find output 0x%x\n",
1226                                 crtc->crtc_info->outputs[o]);
1227             if (output->changes)
1228                 crtc->changing = True;
1229         }
1230         /* walk new output list */
1231         for (o = 0; o < crtc->noutput; o++)
1232         {
1233             output = crtc->outputs[o];
1234             if (output->changes)
1235                 crtc->changing = True;
1236         }
1237     }
1238 }
1239
1240 /*
1241  * Test whether 'crtc' can be used for 'output'
1242  */
1243 Bool
1244 check_crtc_for_output (crtc_t *crtc, output_t *output)
1245 {
1246     int         c;
1247     int         l;
1248     output_t    *other;
1249     
1250     for (c = 0; c < output->output_info->ncrtc; c++)
1251         if (output->output_info->crtcs[c] == crtc->crtc.xid)
1252             break;
1253     if (c == output->output_info->ncrtc)
1254         return False;
1255     for (other = outputs; other; other = other->next)
1256     {
1257         if (other == output)
1258             continue;
1259
1260         if (other->mode_info == NULL)
1261             continue;
1262
1263         if (other->crtc_info != crtc)
1264             continue;
1265
1266         /* see if the output connected to the crtc can clone to this output */
1267         for (l = 0; l < output->output_info->nclone; l++)
1268             if (output->output_info->clones[l] == other->output.xid)
1269                 break;
1270         /* not on the list, can't clone */
1271         if (l == output->output_info->nclone) 
1272             return False;
1273     }
1274
1275     if (crtc->noutput)
1276     {
1277         /* make sure the state matches */
1278         if (crtc->mode_info != output->mode_info)
1279             return False;
1280         if (crtc->x != output->x)
1281             return False;
1282         if (crtc->y != output->y)
1283             return False;
1284         if (crtc->rotation != output->rotation)
1285             return False;
1286     }
1287     else if (crtc->crtc_info->noutput)
1288     {
1289         /* make sure the state matches the already used state */
1290         XRRModeInfo *mode = find_mode_by_xid (crtc->crtc_info->mode);
1291
1292         if (mode != output->mode_info)
1293             return False;
1294         if (crtc->crtc_info->x != output->x)
1295             return False;
1296         if (crtc->crtc_info->y != output->y)
1297             return False;
1298         if (crtc->crtc_info->rotation != output->rotation)
1299             return False;
1300     }
1301     return True;
1302 }
1303
1304 crtc_t *
1305 find_crtc_for_output (output_t *output)
1306 {
1307     int     c;
1308
1309     for (c = 0; c < output->output_info->ncrtc; c++)
1310     {
1311         crtc_t      *crtc;
1312
1313         crtc = find_crtc_by_xid (output->output_info->crtcs[c]);
1314         if (!crtc) fatal ("cannot find crtc 0x%x\n", output->output_info->crtcs[c]);
1315
1316         if (check_crtc_for_output (crtc, output))
1317             return crtc;
1318     }
1319     return NULL;
1320 }
1321
1322 static void
1323 set_positions (void)
1324 {
1325     output_t    *output;
1326     Bool        keep_going;
1327     Bool        any_set;
1328     int         min_x, min_y;
1329
1330     for (;;)
1331     {
1332         any_set = False;
1333         keep_going = False;
1334         for (output = outputs; output; output = output->next)
1335         {
1336             output_t    *relation;
1337             name_t      relation_name;
1338
1339             if (!(output->changes & changes_relation)) continue;
1340             
1341             if (output->mode_info == NULL) continue;
1342
1343             init_name (&relation_name);
1344             set_name_string (&relation_name, output->relative_to);
1345             relation = find_output (&relation_name);
1346             if (!relation) fatal ("cannot find output \"%s\"\n", output->relative_to);
1347             
1348             if (relation->mode_info == NULL) 
1349             {
1350                 output->x = 0;
1351                 output->y = 0;
1352                 output->changes |= changes_position;
1353                 any_set = True;
1354                 continue;
1355             }
1356             /*
1357              * Make sure the dependent object has been set in place
1358              */
1359             if ((relation->changes & changes_relation) && 
1360                 !(relation->changes & changes_position))
1361             {
1362                 keep_going = True;
1363                 continue;
1364             }
1365             
1366             switch (output->relation) {
1367             case left_of:
1368                 output->y = relation->y;
1369                 output->x = relation->x - mode_width (output->mode_info, output->rotation);
1370                 break;
1371             case right_of:
1372                 output->y = relation->y;
1373                 output->x = relation->x + mode_width (relation->mode_info, relation->rotation);
1374                 break;
1375             case above:
1376                 output->x = relation->x;
1377                 output->y = relation->y - mode_height (output->mode_info, output->rotation);
1378                 break;
1379             case below:
1380                 output->x = relation->x;
1381                 output->y = relation->y + mode_height (relation->mode_info, relation->rotation);
1382                 break;
1383             case same_as:
1384                 output->x = relation->x;
1385                 output->y = relation->y;
1386             }
1387             output->changes |= changes_position;
1388             any_set = True;
1389         }
1390         if (!keep_going)
1391             break;
1392         if (!any_set)
1393             fatal ("loop in relative position specifications\n");
1394     }
1395
1396     /*
1397      * Now normalize positions so the upper left corner of all outputs is at 0,0
1398      */
1399     min_x = 32768;
1400     min_y = 32768;
1401     for (output = outputs; output; output = output->next)
1402     {
1403         if (output->mode_info == NULL) continue;
1404         
1405         if (output->x < min_x) min_x = output->x;
1406         if (output->y < min_y) min_y = output->y;
1407     }
1408     if (min_x || min_y)
1409     {
1410         /* move all outputs */
1411         for (output = outputs; output; output = output->next)
1412         {
1413             if (output->mode_info == NULL) continue;
1414
1415             output->x -= min_x;
1416             output->y -= min_y;
1417             output->changes |= changes_position;
1418         }
1419     }
1420 }
1421
1422 static void
1423 set_screen_size (void)
1424 {
1425     output_t    *output;
1426     Bool        fb_specified = fb_width != 0 && fb_height != 0;
1427     
1428     for (output = outputs; output; output = output->next)
1429     {
1430         XRRModeInfo *mode_info = output->mode_info;
1431         int         x, y, w, h;
1432         
1433         if (!mode_info) continue;
1434         
1435         x = output->x;
1436         y = output->y;
1437         w = mode_width (mode_info, output->rotation);
1438         h = mode_height (mode_info, output->rotation);
1439         /* make sure output fits in specified size */
1440         if (fb_specified)
1441         {
1442             if (x + w > fb_width || y + h > fb_height)
1443                 fatal ("specified screen %dx%d not large enough for output %s (%dx%d+%d+%d)\n",
1444                        fb_width, fb_height, output->output.string, w, h, x, y);
1445         }
1446         /* fit fb to output */
1447         else
1448         {
1449             if (x + w > fb_width) fb_width = x + w;
1450             if (y + h > fb_height) fb_height = y + h;
1451         }
1452     }   
1453
1454     if (fb_width > maxWidth || fb_height > maxHeight)
1455         fatal ("screen cannot be larger than %dx%d (desired size %dx%d)\n",
1456                maxWidth, maxHeight, fb_width, fb_height);
1457     if (fb_specified)
1458     {
1459         if (fb_width < minWidth || fb_height < minHeight)
1460             fatal ("screen must be at least %dx%d\n", minWidth, minHeight);
1461     }
1462     else
1463     {
1464         if (fb_width < minWidth) fb_width = minWidth;
1465         if (fb_height < minHeight) fb_height = minHeight;
1466     }
1467 }
1468     
1469 #endif
1470     
1471 void
1472 disable_outputs (output_t *outputs)
1473 {
1474     while (outputs)
1475     {
1476         outputs->crtc_info = NULL;
1477         outputs = outputs->next;
1478     }
1479 }
1480
1481 /*
1482  * find the best mapping from output to crtc available
1483  */
1484 int
1485 pick_crtcs_score (output_t *outputs)
1486 {
1487     output_t    *output;
1488     int         best_score;
1489     int         my_score;
1490     int         score;
1491     crtc_t      *best_crtc;
1492     int         c;
1493     
1494     if (!outputs)
1495         return 0;
1496     
1497     output = outputs;
1498     outputs = outputs->next;
1499     /*
1500      * Score with this output disabled
1501      */
1502     output->crtc_info = NULL;
1503     best_score = pick_crtcs_score (outputs);
1504     if (output->mode_info == NULL)
1505         return best_score;
1506
1507     best_crtc = NULL;
1508     /* 
1509      * Now score with this output any valid crtc
1510      */
1511     for (c = 0; c < output->output_info->ncrtc; c++)
1512     {
1513         crtc_t      *crtc;
1514
1515         crtc = find_crtc_by_xid (output->output_info->crtcs[c]);
1516         if (!crtc)
1517             fatal ("cannot find crtc 0x%x\n", output->output_info->crtcs[c]);
1518         
1519         /* reset crtc allocation for following outputs */
1520         disable_outputs (outputs);
1521         if (!check_crtc_for_output (crtc, output))
1522             continue;
1523         
1524         my_score = 1000;
1525         /* slight preference for existing connections */
1526         if (crtc == output->current_crtc_info)
1527             my_score++;
1528
1529         output->crtc_info = crtc;
1530         score = my_score + pick_crtcs_score (outputs);
1531         if (score > best_score)
1532         {
1533             best_crtc = crtc;
1534             best_score = score;
1535         }
1536     }
1537     if (output->crtc_info != best_crtc)
1538         output->crtc_info = best_crtc;
1539     /*
1540      * Reset other outputs based on this one using the best crtc
1541      */
1542     (void) pick_crtcs_score (outputs);
1543
1544     return best_score;
1545 }
1546
1547 /*
1548  * Pick crtcs for any changing outputs that don't have one
1549  */
1550 void
1551 pick_crtcs (void)
1552 {
1553     output_t    *output;
1554
1555     /*
1556      * First try to match up newly enabled outputs with spare crtcs
1557      */
1558     for (output = outputs; output; output = output->next)
1559     {
1560         if (output->changes && output->mode_info)
1561         {
1562             if (output->crtc_info) {
1563                 if (output->crtc_info->crtc_info->noutput > 0 &&
1564                     (output->crtc_info->crtc_info->noutput > 1 ||
1565                      output != find_output_by_xid (output->crtc_info->crtc_info->outputs[0])))
1566                     break;
1567             } else {
1568                 output->crtc_info = find_crtc_for_output (output);
1569                 if (!output->crtc_info)
1570                     break;
1571             }
1572         }
1573     }
1574     /*
1575      * Everyone is happy
1576      */
1577     if (!output)
1578         return;
1579     /*
1580      * When the simple way fails, see if there is a way
1581      * to swap crtcs around and make things work
1582      */
1583     for (output = outputs; output; output = output->next)
1584         output->current_crtc_info = output->crtc_info;
1585     pick_crtcs_score (outputs);
1586     for (output = outputs; output; output = output->next)
1587     {
1588         if (output->mode_info && !output->crtc_info)
1589             fatal ("cannot find crtc for output %s\n", output->output.string);
1590         if (!output->changes && output->crtc_info != output->current_crtc_info)
1591             output->changes |= changes_crtc;
1592     }
1593 }
1594
1595 int
1596 main (int argc, char **argv)
1597 {
1598     XRRScreenSize *sizes;
1599     XRRScreenConfiguration *sc;
1600     int         nsize;
1601     int         nrate;
1602     short               *rates;
1603     Status      status = RRSetConfigFailed;
1604     int         rot = -1;
1605     int         query = 0;
1606     Rotation    rotation, current_rotation, rotations;
1607     XEvent      event;
1608     XRRScreenChangeNotifyEvent *sce;    
1609     char          *display_name = NULL;
1610     int                 i, j;
1611     SizeID      current_size;
1612     short       current_rate;
1613     float       rate = -1;
1614     int         size = -1;
1615     int         dirind = 0;
1616     Bool        setit = False;
1617     Bool        version = False;
1618     int         event_base, error_base;
1619     int         reflection = 0;
1620     int         width = 0, height = 0;
1621     Bool        have_pixel_size = False;
1622     int         ret = 0;
1623 #if HAS_RANDR_1_2
1624     output_t    *output = NULL;
1625     policy_t    policy = clone;
1626     Bool        setit_1_2 = False;
1627     Bool        query_1_2 = False;
1628     Bool        modeit = False;
1629     Bool        propit = False;
1630     Bool        query_1 = False;
1631     int         major, minor;
1632 #endif
1633
1634     program_name = argv[0];
1635     if (argc == 1) query = True;
1636     for (i = 1; i < argc; i++) {
1637         if (!strcmp ("-display", argv[i]) || !strcmp ("-d", argv[i])) {
1638             if (++i>=argc) usage ();
1639             display_name = argv[i];
1640             continue;
1641         }
1642         if (!strcmp("-help", argv[i])) {
1643             usage();
1644             continue;
1645         }
1646         if (!strcmp ("--verbose", argv[i])) {
1647             verbose = True;
1648             continue;
1649         }
1650         if (!strcmp ("--dryrun", argv[i])) {
1651             dryrun = True;
1652             verbose = True;
1653             continue;
1654         }
1655
1656         if (!strcmp ("-s", argv[i]) || !strcmp ("--size", argv[i])) {
1657             if (++i>=argc) usage ();
1658             if (sscanf (argv[i], "%dx%d", &width, &height) == 2)
1659                 have_pixel_size = True;
1660             else {
1661                 size = atoi (argv[i]);
1662                 if (size < 0) usage();
1663             }
1664             setit = True;
1665             continue;
1666         }
1667
1668         if (!strcmp ("-r", argv[i]) ||
1669             !strcmp ("--rate", argv[i]) ||
1670             !strcmp ("--refresh", argv[i]))
1671         {
1672             if (++i>=argc) usage ();
1673             if (sscanf (argv[i], "%f", &rate) != 1)
1674                 usage ();
1675             setit = True;
1676 #if HAS_RANDR_1_2
1677             if (output)
1678             {
1679                 output->refresh = rate;
1680                 output->changes |= changes_refresh;
1681                 setit_1_2 = True;
1682             }
1683 #endif
1684             continue;
1685         }
1686
1687         if (!strcmp ("-v", argv[i]) || !strcmp ("--version", argv[i])) {
1688             version = True;
1689             continue;
1690         }
1691
1692         if (!strcmp ("-x", argv[i])) {
1693             reflection |= RR_Reflect_X;
1694             setit = True;
1695             continue;
1696         }
1697         if (!strcmp ("-y", argv[i])) {
1698             reflection |= RR_Reflect_Y;
1699             setit = True;
1700             continue;
1701         }
1702         if (!strcmp ("--screen", argv[i])) {
1703             if (++i>=argc) usage ();
1704             screen = atoi (argv[i]);
1705             if (screen < 0) usage();
1706             continue;
1707         }
1708         if (!strcmp ("-q", argv[i]) || !strcmp ("--query", argv[i])) {
1709             query = True;
1710             continue;
1711         }
1712         if (!strcmp ("-o", argv[i]) || !strcmp ("--orientation", argv[i])) {
1713             char *endptr;
1714             if (++i>=argc) usage ();
1715             dirind = strtol(argv[i], &endptr, 0);
1716             if (*endptr != '\0') {
1717                 for (dirind = 0; dirind < 4; dirind++) {
1718                     if (strcmp (direction[dirind], argv[i]) == 0) break;
1719                 }
1720                 if ((dirind < 0) || (dirind > 3))  usage();
1721             }
1722             rot = dirind;
1723             setit = True;
1724             continue;
1725         }
1726 #if HAS_RANDR_1_2
1727         if (!strcmp ("--prop", argv[i]) || !strcmp ("--properties", argv[i]))
1728         {
1729             query_1_2 = True;
1730             properties = True;
1731             continue;
1732         }
1733         if (!strcmp ("--output", argv[i])) {
1734             if (++i >= argc) usage();
1735             output = add_output ();
1736
1737             set_name (&output->output, argv[i], name_string|name_xid);
1738             
1739             setit_1_2 = True;
1740             continue;
1741         }
1742         if (!strcmp ("--crtc", argv[i])) {
1743             if (++i >= argc) usage();
1744             if (!output) usage();
1745             set_name (&output->crtc, argv[i], name_xid|name_index);
1746             output->changes |= changes_crtc;
1747             continue;
1748         }
1749         if (!strcmp ("--mode", argv[i])) {
1750             if (++i >= argc) usage();
1751             if (!output) usage();
1752             set_name (&output->mode, argv[i], name_string|name_xid);
1753             output->changes |= changes_mode;
1754             continue;
1755         }
1756         if (!strcmp ("--preferred", argv[i])) {
1757             if (!output) usage();
1758             set_name_preferred (&output->mode);
1759             output->changes |= changes_mode;
1760             continue;
1761         }
1762         if (!strcmp ("--pos", argv[i])) {
1763             if (++i>=argc) usage ();
1764             if (!output) usage();
1765             if (sscanf (argv[i], "%dx%d",
1766                         &output->x, &output->y) != 2)
1767                 usage ();
1768             output->changes |= changes_position;
1769             continue;
1770         }
1771         if (!strcmp ("--rotation", argv[i]) || !strcmp ("--rotate", argv[i])) {
1772             if (++i>=argc) usage ();
1773             if (!output) usage();
1774             for (dirind = 0; dirind < 4; dirind++) {
1775                 if (strcmp (direction[dirind], argv[i]) == 0) break;
1776             }
1777             if (dirind == 4)
1778                 usage ();
1779             output->rotation &= ~0xf;
1780             output->rotation |= 1 << dirind;
1781             output->changes |= changes_rotation;
1782             continue;
1783         }
1784         if (!strcmp ("--reflect", argv[i]) || !strcmp ("--reflection", argv[i])) {
1785             if (++i>=argc) usage ();
1786             if (!output) usage();
1787             for (dirind = 0; dirind < 4; dirind++) {
1788                 if (strcmp (reflections[dirind], argv[i]) == 0) break;
1789             }
1790             if (dirind == 4)
1791                 usage ();
1792             output->rotation &= ~(RR_Reflect_X|RR_Reflect_Y);
1793             output->rotation |= dirind * RR_Reflect_X;
1794             output->changes |= changes_reflection;
1795             continue;
1796         }
1797         if (!strcmp ("--left-of", argv[i])) {
1798             if (++i>=argc) usage ();
1799             if (!output) usage();
1800             output->relation = left_of;
1801             output->relative_to = argv[i];
1802             output->changes |= changes_relation;
1803             continue;
1804         }
1805         if (!strcmp ("--right-of", argv[i])) {
1806             if (++i>=argc) usage ();
1807             if (!output) usage();
1808             output->relation = right_of;
1809             output->relative_to = argv[i];
1810             output->changes |= changes_relation;
1811             continue;
1812         }
1813         if (!strcmp ("--above", argv[i])) {
1814             if (++i>=argc) usage ();
1815             if (!output) usage();
1816             output->relation = above;
1817             output->relative_to = argv[i];
1818             output->changes |= changes_relation;
1819             continue;
1820         }
1821         if (!strcmp ("--below", argv[i])) {
1822             if (++i>=argc) usage ();
1823             if (!output) usage();
1824             output->relation = below;
1825             output->relative_to = argv[i];
1826             output->changes |= changes_relation;
1827             continue;
1828         }
1829         if (!strcmp ("--same-as", argv[i])) {
1830             if (++i>=argc) usage ();
1831             if (!output) usage();
1832             output->relation = same_as;
1833             output->relative_to = argv[i];
1834             output->changes |= changes_relation;
1835             continue;
1836         }
1837         if (!strcmp ("--set", argv[i])) {
1838             output_prop_t   *prop;
1839             if (!output) usage();
1840             prop = malloc (sizeof (output_prop_t));
1841             prop->next = output->props;
1842             output->props = prop;
1843             if (++i>=argc) usage ();
1844             prop->name = argv[i];
1845             if (++i>=argc) usage ();
1846             prop->value = argv[i];
1847             propit = True;
1848             output->changes |= changes_property;
1849             setit_1_2 = True;
1850             continue;
1851         }
1852         if (!strcmp ("--off", argv[i])) {
1853             if (!output) usage();
1854             set_name_xid (&output->mode, None);
1855             set_name_xid (&output->crtc, None);
1856             output->changes |= changes_mode;
1857             continue;
1858         }
1859         if (!strcmp ("--fb", argv[i])) {
1860             if (++i>=argc) usage ();
1861             if (sscanf (argv[i], "%dx%d",
1862                         &fb_width, &fb_height) != 2)
1863                 usage ();
1864             setit_1_2 = True;
1865             continue;
1866         }
1867         if (!strcmp ("--fbmm", argv[i])) {
1868             if (++i>=argc) usage ();
1869             if (sscanf (argv[i], "%dx%d",
1870                         &fb_width_mm, &fb_height_mm) != 2)
1871                 usage ();
1872             setit_1_2 = True;
1873             continue;
1874         }
1875         if (!strcmp ("--dpi", argv[i])) {
1876             if (++i>=argc) usage ();
1877             if (sscanf (argv[i], "%f", &dpi) != 1)
1878             {
1879                 dpi = 0.0;
1880                 dpi_output = argv[i];
1881             }
1882             setit_1_2 = True;
1883             continue;
1884         }
1885         if (!strcmp ("--clone", argv[i])) {
1886             policy = clone;
1887             setit_1_2 = True;
1888             continue;
1889         }
1890         if (!strcmp ("--extend", argv[i])) {
1891             policy = extend;
1892             setit_1_2 = True;
1893             continue;
1894         }
1895         if (!strcmp ("--auto", argv[i])) {
1896             if (output)
1897             {
1898                 output->automatic = True;
1899                 output->changes |= changes_automatic;
1900             }
1901             else
1902                 automatic = True;
1903             setit_1_2 = True;
1904             continue;
1905         }
1906         if (!strcmp ("--q12", argv[i]))
1907         {
1908             query_1_2 = True;
1909             continue;
1910         }
1911         if (!strcmp ("--q1", argv[i]))
1912         {
1913             query_1 = True;
1914             continue;
1915         }
1916         if (!strcmp ("--newmode", argv[i]))
1917         {
1918             umode_t  *m = malloc (sizeof (umode_t));
1919             float   clock;
1920             
1921             ++i;
1922             if (i + 9 >= argc) usage ();
1923             m->mode.name = argv[i];
1924             m->mode.nameLength = strlen (argv[i]);
1925             i++;
1926             if (sscanf (argv[i++], "%f", &clock) != 1)
1927                 usage ();
1928             m->mode.dotClock = clock * 1e6;
1929
1930             if (sscanf (argv[i++], "%d", &m->mode.width) != 1) usage();
1931             if (sscanf (argv[i++], "%d", &m->mode.hSyncStart) != 1) usage();
1932             if (sscanf (argv[i++], "%d", &m->mode.hSyncEnd) != 1) usage();
1933             if (sscanf (argv[i++], "%d", &m->mode.hTotal) != 1) usage();
1934             if (sscanf (argv[i++], "%d", &m->mode.height) != 1) usage();
1935             if (sscanf (argv[i++], "%d", &m->mode.vSyncStart) != 1) usage();
1936             if (sscanf (argv[i++], "%d", &m->mode.vSyncEnd) != 1) usage();
1937             if (sscanf (argv[i++], "%d", &m->mode.vTotal) != 1) usage();
1938             m->mode.modeFlags = 0;
1939             while (i < argc) {
1940                 int f;
1941                 
1942                 for (f = 0; mode_flags[f].string; f++)
1943                     if (!strcasecmp (mode_flags[f].string, argv[i]))
1944                         break;
1945                 
1946                 if (!mode_flags[f].string)
1947                     break;
1948                 m->mode.modeFlags |= mode_flags[f].flag;
1949                 i++;
1950             }
1951             m->next = umodes;
1952             m->action = umode_create;
1953             umodes = m;
1954             modeit = True;
1955             continue;
1956         }
1957         if (!strcmp ("--rmmode", argv[i]))
1958         {
1959             umode_t  *m = malloc (sizeof (umode_t));
1960
1961             if (++i>=argc) usage ();
1962             set_name (&m->name, argv[i], name_string|name_xid);
1963             m->action = umode_destroy;
1964             m->next = umodes;
1965             umodes = m;
1966             modeit = True;
1967             continue;
1968         }
1969         if (!strcmp ("--addmode", argv[i]))
1970         {
1971             umode_t  *m = malloc (sizeof (umode_t));
1972
1973             if (++i>=argc) usage ();
1974             set_name (&m->output, argv[i], name_string|name_xid);
1975             if (++i>=argc) usage();
1976             set_name (&m->name, argv[i], name_string|name_xid);
1977             m->action = umode_add;
1978             m->next = umodes;
1979             umodes = m;
1980             modeit = True;
1981             continue;
1982         }
1983         if (!strcmp ("--delmode", argv[i]))
1984         {
1985             umode_t  *m = malloc (sizeof (umode_t));
1986
1987             if (++i>=argc) usage ();
1988             set_name (&m->output, argv[i], name_string|name_xid);
1989             if (++i>=argc) usage();
1990             set_name (&m->name, argv[i], name_string|name_xid);
1991             m->action = umode_delete;
1992             m->next = umodes;
1993             umodes = m;
1994             modeit = True;
1995             continue;
1996         }
1997 #endif
1998         usage();
1999     }
2000     if (verbose) 
2001     {
2002         query = True;
2003         if (setit && !setit_1_2)
2004             query_1 = True;
2005     }
2006
2007     dpy = XOpenDisplay (display_name);
2008
2009     if (dpy == NULL) {
2010         fprintf (stderr, "Can't open display %s\n", XDisplayName(display_name));
2011         exit (1);
2012     }
2013     if (screen < 0)
2014         screen = DefaultScreen (dpy);
2015     if (screen >= ScreenCount (dpy)) {
2016         fprintf (stderr, "Invalid screen number %d (display has %d)\n",
2017                  screen, ScreenCount (dpy));
2018         exit (1);
2019     }
2020
2021     root = RootWindow (dpy, screen);
2022
2023 #if HAS_RANDR_1_2
2024     if (!XRRQueryVersion (dpy, &major, &minor))
2025     {
2026         fprintf (stderr, "RandR extension missing\n");
2027         exit (1);
2028     }
2029     if (major > 1 || (major == 1 && minor >= 2))
2030         has_1_2 = True;
2031         
2032     if (has_1_2 && modeit)
2033     {
2034         umode_t *m;
2035
2036         get_screen ();
2037         get_crtcs();
2038         get_outputs();
2039         
2040         for (m = umodes; m; m = m->next)
2041         {
2042             XRRModeInfo *e;
2043             output_t    *o;
2044             
2045             switch (m->action) {
2046             case umode_create:
2047                 XRRCreateMode (dpy, root, &m->mode);
2048                 break;
2049             case umode_destroy:
2050                 e = find_mode (&m->name, 0);
2051                 if (!e)
2052                     fatal ("cannot find mode \"%s\"\n", m->name.string);
2053                 XRRDestroyMode (dpy, e->id);
2054                 break;
2055             case umode_add:
2056                 o = find_output (&m->output);
2057                 if (!o)
2058                     fatal ("cannot find output \"%s\"\n", m->output.string);
2059                 e = find_mode (&m->name, 0);
2060                 if (!e)
2061                     fatal ("cannot find mode \"%s\"\n", m->name.string);
2062                 XRRAddOutputMode (dpy, o->output.xid, e->id);
2063                 break;
2064             case umode_delete:
2065                 o = find_output (&m->output);
2066                 if (!o)
2067                     fatal ("cannot find output \"%s\"\n", m->output.string);
2068                 e = find_mode (&m->name, 0);
2069                 if (!e)
2070                     fatal ("cannot find mode \"%s\"\n", m->name.string);
2071                 XRRDeleteOutputMode (dpy, o->output.xid, e->id);
2072                 break;
2073             }
2074         }
2075         if (!setit_1_2)
2076         {
2077             XSync (dpy, False);
2078             exit (0);
2079         }
2080     }
2081     if (has_1_2 && propit)
2082     {
2083         
2084         get_screen ();
2085         get_crtcs();
2086         get_outputs();
2087         
2088         for (output = outputs; output; output = output->next)
2089         {
2090             output_prop_t   *prop;
2091
2092             for (prop = output->props; prop; prop = prop->next)
2093             {
2094                 Atom            name = XInternAtom (dpy, prop->name, False);
2095                 Atom            type;
2096                 int             format;
2097                 unsigned char   *data;
2098                 int             nelements;
2099                 int             int_value;
2100                 unsigned long   ulong_value;
2101                 unsigned char   *prop_data;
2102                 int             actual_format;
2103                 unsigned long   nitems, bytes_after;
2104                 Atom            actual_type;
2105                 XRRPropertyInfo *propinfo;
2106
2107                 type = AnyPropertyType;
2108                 format=0;
2109                 
2110                 if (XRRGetOutputProperty (dpy, output->output.xid, name,
2111                                           0, 100, False, False,
2112                                           AnyPropertyType,
2113                                           &actual_type, &actual_format,
2114                                           &nitems, &bytes_after, &prop_data) == Success &&
2115
2116                     (propinfo = XRRQueryOutputProperty(dpy, output->output.xid,
2117                                                       name)))
2118                 {
2119                     type = actual_type;
2120                     format = actual_format;
2121                 }
2122                 
2123                 if ((type == XA_INTEGER || type == AnyPropertyType) &&
2124                     (sscanf (prop->value, "%d", &int_value) == 1 ||
2125                      sscanf (prop->value, "0x%x", &int_value) == 1))
2126                 {
2127                     type = XA_INTEGER;
2128                     ulong_value = int_value;
2129                     data = (unsigned char *) &ulong_value;
2130                     nelements = 1;
2131                     format = 32;
2132                 }
2133                 else if ((type == XA_ATOM))
2134                 {
2135                     ulong_value = XInternAtom (dpy, prop->value, False);
2136                     data = (unsigned char *) &ulong_value;
2137                     nelements = 1;
2138                     format = 32;
2139                 }
2140                 else if ((type == XA_STRING || type == AnyPropertyType))
2141                 {
2142                     type = XA_STRING;
2143                     data = (unsigned char *) prop->value;
2144                     nelements = strlen (prop->value);
2145                     format = 8;
2146                 }
2147                 XRRChangeOutputProperty (dpy, output->output.xid,
2148                                          name, type, format, PropModeReplace,
2149                                          data, nelements);
2150             }
2151         }
2152         if (!setit_1_2)
2153         {
2154             XSync (dpy, False);
2155             exit (0);
2156         }
2157     }
2158     if (setit_1_2)
2159     {
2160         get_screen ();
2161         get_crtcs ();
2162         get_outputs ();
2163         set_positions ();
2164         set_screen_size ();
2165
2166         pick_crtcs ();
2167
2168         /*
2169          * Assign outputs to crtcs
2170          */
2171         set_crtcs ();
2172         
2173         /*
2174          * Mark changing crtcs
2175          */
2176         mark_changing_crtcs ();
2177
2178         /*
2179          * If an output was specified to track dpi, use it
2180          */
2181         if (dpi_output)
2182         {
2183             output_t    *output = find_output_by_name (dpi_output);
2184             XRROutputInfo       *output_info;
2185             XRRModeInfo *mode_info;
2186             if (!output)
2187                 fatal ("Cannot find output %s\n", dpi_output);
2188             output_info = output->output_info;
2189             mode_info = output->mode_info;
2190             if (output_info && mode_info && output_info->mm_height)
2191             {
2192                 /*
2193                  * When this output covers the whole screen, just use
2194                  * the known physical size
2195                  */
2196                 if (fb_width == mode_info->width &&
2197                     fb_height == mode_info->height)
2198                 {
2199                     fb_width_mm = output_info->mm_width;
2200                     fb_height_mm = output_info->mm_height;
2201                 }
2202                 else
2203                 {
2204                     dpi = (25.4 * mode_info->height) / output_info->mm_height;
2205                 }
2206             }
2207         }
2208
2209         /*
2210          * Compute physical screen size
2211          */
2212         if (fb_width_mm == 0 || fb_height_mm == 0)
2213         {
2214             if (fb_width != DisplayWidth (dpy, screen) ||
2215                 fb_height != DisplayHeight (dpy, screen) || dpi != 0.0)
2216             {
2217                 if (dpi <= 0)
2218                     dpi = (25.4 * DisplayHeight (dpy, screen)) / DisplayHeightMM(dpy, screen);
2219
2220                 fb_width_mm = (25.4 * fb_width) / dpi;
2221                 fb_height_mm = (25.4 * fb_height) / dpi;
2222             }
2223             else
2224             {
2225                 fb_width_mm = DisplayWidthMM (dpy, screen);
2226                 fb_height_mm = DisplayHeightMM (dpy, screen);
2227             }
2228         }
2229         
2230         /*
2231          * Now apply all of the changes
2232          */
2233         apply ();
2234         
2235         XSync (dpy, False);
2236         exit (0);
2237     }
2238     if (query_1_2 || (query && has_1_2 && !query_1))
2239     {
2240         output_t    *output;
2241         int         m;
2242         
2243 #define ModeShown   0x80000000
2244         
2245         get_screen ();
2246         get_crtcs ();
2247         get_outputs ();
2248
2249         printf ("Screen %d: minimum %d x %d, current %d x %d, maximum %d x %d\n",
2250                 screen, minWidth, minHeight,
2251                 DisplayWidth (dpy, screen), DisplayHeight(dpy, screen),
2252                 maxWidth, maxHeight);
2253
2254         for (output = outputs; output; output = output->next)
2255         {
2256             XRROutputInfo   *output_info = output->output_info;
2257             XRRModeInfo     *mode = output->mode_info;
2258             Atom            *props;
2259             int             j, k, nprop;
2260             Bool            *mode_shown;
2261             Rotation        rotations = output_rotations (output);
2262
2263             printf ("%s %s", output_info->name, connection[output_info->connection]);
2264             if (mode)
2265             {
2266                 printf (" %dx%d+%d+%d",
2267                         mode_width (mode, output->rotation),
2268                         mode_height (mode, output->rotation),
2269                         output->x, output->y);
2270                 if (verbose)
2271                     printf (" (0x%x)", mode->id);
2272                 if (output->rotation != RR_Rotate_0 || verbose)
2273                 {
2274                     printf (" %s", 
2275                             rotation_name (output->rotation));
2276                     if (output->rotation & (RR_Reflect_X|RR_Reflect_Y))
2277                         printf (" %s", reflection_name (output->rotation));
2278                 }
2279             }
2280             if (rotations != RR_Rotate_0 || verbose)
2281             {
2282                 Bool    first = True;
2283                 printf (" (");
2284                 for (i = 0; i < 4; i ++) {
2285                     if ((rotations >> i) & 1) {
2286                         if (!first) printf (" "); first = False;
2287                         printf("%s", direction[i]);
2288                         first = False;
2289                     }
2290                 }
2291                 if (rotations & RR_Reflect_X)
2292                 {
2293                     if (!first) printf (" "); first = False;
2294                     printf ("x axis");
2295                 }
2296                 if (rotations & RR_Reflect_Y)
2297                 {
2298                     if (!first) printf (" "); first = False;
2299                     printf ("y axis");
2300                 }
2301                 printf (")");
2302             }
2303
2304             if (mode)
2305             {
2306                 printf (" %dmm x %dmm",
2307                         output_info->mm_width, output_info->mm_height);
2308             }
2309             printf ("\n");
2310
2311             if (verbose)
2312             {
2313                 printf ("\tIdentifier: 0x%x\n", output->output.xid);
2314                 printf ("\tTimestamp:  %d\n", output_info->timestamp);
2315                 printf ("\tSubpixel:   %s\n", order[output_info->subpixel_order]);
2316                 printf ("\tClones:    ");
2317                 for (j = 0; j < output_info->nclone; j++)
2318                 {
2319                     output_t    *clone = find_output_by_xid (output_info->clones[j]);
2320
2321                     if (clone) printf (" %s", clone->output.string);
2322                 }
2323                 printf ("\n");
2324                 if (output->crtc_info)
2325                     printf ("\tCRTC:       %d\n", output->crtc_info->crtc.index);
2326                 printf ("\tCRTCs:     ");
2327                 for (j = 0; j < output_info->ncrtc; j++)
2328                 {
2329                     crtc_t      *crtc = find_crtc_by_xid (output_info->crtcs[j]);
2330                     if (crtc)
2331                         printf (" %d", crtc->crtc.index);
2332                 }
2333                 printf ("\n");
2334             }
2335             if (verbose || properties)
2336             {
2337                 props = XRRListOutputProperties (dpy, output->output.xid,
2338                                                  &nprop);
2339                 for (j = 0; j < nprop; j++) {
2340                     unsigned char *prop;
2341                     int actual_format;
2342                     unsigned long nitems, bytes_after;
2343                     Atom actual_type;
2344                     XRRPropertyInfo *propinfo;
2345     
2346                     XRRGetOutputProperty (dpy, output->output.xid, props[j],
2347                                           0, 100, False, False,
2348                                           AnyPropertyType,
2349                                           &actual_type, &actual_format,
2350                                           &nitems, &bytes_after, &prop);
2351
2352                     propinfo = XRRQueryOutputProperty(dpy, output->output.xid,
2353                                                       props[j]);
2354
2355                     if (actual_type == XA_INTEGER && actual_format == 8) {
2356                         int k;
2357     
2358                         printf("\t%s:\n", XGetAtomName (dpy, props[j]));
2359                         for (k = 0; k < nitems; k++) {
2360                             if (k % 16 == 0)
2361                                 printf ("\t\t");
2362                             printf("%02x", (unsigned char)prop[k]);
2363                             if (k % 16 == 15)
2364                                 printf("\n");
2365                         }
2366                     } else if (actual_type == XA_INTEGER &&
2367                                actual_format == 32)
2368                     {
2369                         printf("\t%s: %d (0x%08x)",
2370                                XGetAtomName (dpy, props[j]),
2371                                *(INT32 *)prop, *(INT32 *)prop);
2372
2373                         if (propinfo->range && propinfo->num_values > 0) {
2374                             printf(" range%s: ",
2375                                    (propinfo->num_values == 2) ? "" : "s");
2376
2377                             for (k = 0; k < propinfo->num_values / 2; k++)
2378                                 printf(" (%d,%d)", propinfo->values[k * 2],
2379                                        propinfo->values[k * 2 + 1]);
2380                         }
2381
2382                         printf("\n");
2383                     } else if (actual_type == XA_ATOM &&
2384                                actual_format == 32)
2385                     {
2386                         printf("\t%s: %s",
2387                                XGetAtomName (dpy, props[j]),
2388                                XGetAtomName (dpy, *(Atom *)prop));
2389
2390                         if (!propinfo->range && propinfo->num_values > 0) {
2391                             printf("\n\t\tsupported:");
2392
2393                             for (k = 0; k < propinfo->num_values; k++)
2394                             {
2395                                 printf(" %-12.12s", XGetAtomName (dpy,
2396                                                             propinfo->values[k]));
2397                                 if (k % 4 == 3 && k < propinfo->num_values - 1)
2398                                     printf ("\n\t\t          ");
2399                             }
2400                         }
2401                         printf("\n");
2402                         
2403                     } else if (actual_format == 8) {
2404                         printf ("\t\t%s: %s%s\n", XGetAtomName (dpy, props[j]),
2405                                 prop, bytes_after ? "..." : "");
2406                     } else {
2407                         printf ("\t\t%s: ????\n", XGetAtomName (dpy, props[j]));
2408                     }
2409
2410                     free(propinfo);
2411                 }
2412             }
2413             
2414             if (verbose)
2415             {
2416                 for (j = 0; j < output_info->nmode; j++)
2417                 {
2418                     XRRModeInfo *mode = find_mode_by_xid (output_info->modes[j]);
2419                     int         f;
2420                     
2421                     printf ("  %s (0x%x) %6.1fMHz",
2422                             mode->name, mode->id,
2423                             (float)mode->dotClock / 1000000.0);
2424                     for (f = 0; mode_flags[f].flag; f++)
2425                         if (mode->modeFlags & mode_flags[f].flag)
2426                             printf (" %s", mode_flags[f].string);
2427                     if (mode == output->mode_info)
2428                         printf (" *current");
2429                     if (j < output_info->npreferred)
2430                         printf (" +preferred");
2431                     printf ("\n");
2432                     printf ("        h: width  %4d start %4d end %4d total %4d skew %4d clock %6.1fKHz\n",
2433                             mode->width, mode->hSyncStart, mode->hSyncEnd,
2434                             mode->hTotal, mode->hSkew, mode_hsync (mode) / 1000);
2435                     printf ("        v: height %4d start %4d end %4d total %4d           clock %6.1fHz\n",
2436                             mode->height, mode->vSyncStart, mode->vSyncEnd, mode->vTotal,
2437                             mode_refresh (mode));
2438                     mode->modeFlags |= ModeShown;
2439                 }
2440             }
2441             else
2442             {
2443                 mode_shown = calloc (output_info->nmode, sizeof (Bool));
2444                 if (!mode_shown) fatal ("out of memory\n");
2445                 for (j = 0; j < output_info->nmode; j++)
2446                 {
2447                     XRRModeInfo *jmode, *kmode;
2448                     
2449                     if (mode_shown[j]) continue;
2450     
2451                     jmode = find_mode_by_xid (output_info->modes[j]);
2452                     printf (" ");
2453                     printf ("  %-12s", jmode->name);
2454                     for (k = j; k < output_info->nmode; k++)
2455                     {
2456                         if (mode_shown[k]) continue;
2457                         kmode = find_mode_by_xid (output_info->modes[k]);
2458                         if (strcmp (jmode->name, kmode->name) != 0) continue;
2459                         mode_shown[k] = True;
2460                         kmode->modeFlags |= ModeShown;
2461                         printf (" %6.1f", mode_refresh (kmode));
2462                         if (kmode == output->mode_info)
2463                             printf ("*");
2464                         else
2465                             printf (" ");
2466                         if (k < output_info->npreferred)
2467                             printf ("+");
2468                         else
2469                             printf (" ");
2470                     }
2471                     printf ("\n");
2472                 }
2473                 free (mode_shown);
2474             }
2475         }
2476         for (m = 0; m < res->nmode; m++)
2477         {
2478             XRRModeInfo *mode = &res->modes[m];
2479
2480             if (!(mode->modeFlags & ModeShown))
2481             {
2482                 printf ("  %s (0x%x) %6.1fMHz\n",
2483                         mode->name, mode->id,
2484                         (float)mode->dotClock / 1000000.0);
2485                 printf ("        h: width  %4d start %4d end %4d total %4d skew %4d clock %6.1fKHz\n",
2486                         mode->width, mode->hSyncStart, mode->hSyncEnd,
2487                         mode->hTotal, mode->hSkew, mode_hsync (mode) / 1000);
2488                 printf ("        v: height %4d start %4d end %4d total %4d           clock %6.1fHz\n",
2489                         mode->height, mode->vSyncStart, mode->vSyncEnd, mode->vTotal,
2490                         mode_refresh (mode));
2491             }
2492         }
2493         exit (0);
2494     }
2495 #endif
2496     
2497     sc = XRRGetScreenInfo (dpy, root);
2498
2499     if (sc == NULL) 
2500         exit (1);
2501
2502     current_size = XRRConfigCurrentConfiguration (sc, &current_rotation);
2503
2504     sizes = XRRConfigSizes(sc, &nsize);
2505
2506     if (have_pixel_size) {
2507         for (size = 0; size < nsize; size++)
2508         {
2509             if (sizes[size].width == width && sizes[size].height == height)
2510                 break;
2511         }
2512         if (size >= nsize) {
2513             fprintf (stderr,
2514                      "Size %dx%d not found in available modes\n", width, height);
2515             exit (1);
2516         }
2517     }
2518     else if (size < 0)
2519         size = current_size;
2520     else if (size >= nsize) {
2521         fprintf (stderr,
2522                  "Size index %d is too large, there are only %d sizes\n",
2523                  size, nsize);
2524         exit (1);
2525     }
2526
2527     if (rot < 0)
2528     {
2529         for (rot = 0; rot < 4; rot++)
2530             if (1 << rot == (current_rotation & 0xf))
2531                 break;
2532     }
2533
2534     current_rate = XRRConfigCurrentRate (sc);
2535
2536     if (rate < 0)
2537     {
2538         if (size == current_size)
2539             rate = current_rate;
2540         else
2541             rate = 0;
2542     }
2543     else
2544     {
2545         rates = XRRConfigRates (sc, size, &nrate);
2546         for (i = 0; i < nrate; i++)
2547             if (rate == rates[i])
2548                 break;
2549         if (i == nrate) {
2550             fprintf (stderr, "Rate %.1f Hz not available for this size\n", rate);
2551             exit (1);
2552         }
2553     }
2554
2555     if (version) {
2556         int major_version, minor_version;
2557         XRRQueryVersion (dpy, &major_version, &minor_version);
2558         printf("Server reports RandR version %d.%d\n", 
2559                major_version, minor_version);
2560     }
2561
2562     if (query || query_1) {
2563         printf(" SZ:    Pixels          Physical       Refresh\n");
2564         for (i = 0; i < nsize; i++) {
2565             printf ("%c%-2d %5d x %-5d  (%4dmm x%4dmm )",
2566                     i == current_size ? '*' : ' ',
2567                     i, sizes[i].width, sizes[i].height,
2568                     sizes[i].mwidth, sizes[i].mheight);
2569             rates = XRRConfigRates (sc, i, &nrate);
2570             if (nrate) printf ("  ");
2571             for (j = 0; j < nrate; j++)
2572                 printf ("%c%-4d",
2573                         i == current_size && rates[j] == current_rate ? '*' : ' ',
2574                         rates[j]);
2575             printf ("\n");
2576         }
2577     }
2578
2579     rotations = XRRConfigRotations(sc, &current_rotation);
2580
2581     rotation = 1 << rot ;
2582     if (query) {
2583         printf("Current rotation - %s\n",
2584                rotation_name (current_rotation));
2585
2586         printf("Current reflection - %s\n",
2587                reflection_name (current_rotation));
2588
2589         printf ("Rotations possible - ");
2590         for (i = 0; i < 4; i ++) {
2591             if ((rotations >> i) & 1)  printf("%s ", direction[i]);
2592         }
2593         printf ("\n");
2594
2595         printf ("Reflections possible - ");
2596         if (rotations & (RR_Reflect_X|RR_Reflect_Y))
2597         {
2598             if (rotations & RR_Reflect_X) printf ("X Axis ");
2599             if (rotations & RR_Reflect_Y) printf ("Y Axis");
2600         }
2601         else
2602             printf ("none");
2603         printf ("\n");
2604     }
2605
2606     if (verbose) { 
2607         printf("Setting size to %d, rotation to %s\n",  size, direction[rot]);
2608
2609         printf ("Setting reflection on ");
2610         if (reflection)
2611         {
2612             if (reflection & RR_Reflect_X) printf ("X Axis ");
2613             if (reflection & RR_Reflect_Y) printf ("Y Axis");
2614         }
2615         else
2616             printf ("neither axis");
2617         printf ("\n");
2618
2619         if (reflection & RR_Reflect_X) printf("Setting reflection on X axis\n");
2620
2621         if (reflection & RR_Reflect_Y) printf("Setting reflection on Y axis\n");
2622     }
2623
2624     /* we should test configureNotify on the root window */
2625     XSelectInput (dpy, root, StructureNotifyMask);
2626
2627     if (setit && !dryrun) XRRSelectInput (dpy, root,
2628                                RRScreenChangeNotifyMask);
2629     if (setit && !dryrun) status = XRRSetScreenConfigAndRate (dpy, sc,
2630                                                    DefaultRootWindow (dpy), 
2631                                                    (SizeID) size, (Rotation) (rotation | reflection), rate, CurrentTime);
2632
2633     XRRQueryExtension(dpy, &event_base, &error_base);
2634
2635     if (setit && !dryrun && status == RRSetConfigFailed) {
2636         printf ("Failed to change the screen configuration!\n");
2637         ret = 1;
2638     }
2639
2640     if (verbose && setit && !dryrun && size != current_size) {
2641         if (status == RRSetConfigSuccess)
2642         {
2643             Bool    seen_screen = False;
2644             while (!seen_screen) {
2645                 int spo;
2646                 XNextEvent(dpy, (XEvent *) &event);
2647
2648                 printf ("Event received, type = %d\n", event.type);
2649                 /* update Xlib's knowledge of the event */
2650                 XRRUpdateConfiguration (&event);
2651                 if (event.type == ConfigureNotify)
2652                     printf("Received ConfigureNotify Event!\n");
2653
2654                 switch (event.type - event_base) {
2655                 case RRScreenChangeNotify:
2656                     sce = (XRRScreenChangeNotifyEvent *) &event;
2657
2658                     printf("Got a screen change notify event!\n");
2659                     printf(" window = %d\n root = %d\n size_index = %d\n rotation %d\n", 
2660                            (int) sce->window, (int) sce->root, 
2661                            sce->size_index,  sce->rotation);
2662                     printf(" timestamp = %ld, config_timestamp = %ld\n",
2663                            sce->timestamp, sce->config_timestamp);
2664                     printf(" Rotation = %x\n", sce->rotation);
2665                     printf(" %d X %d pixels, %d X %d mm\n",
2666                            sce->width, sce->height, sce->mwidth, sce->mheight);
2667                     printf("Display width   %d, height   %d\n",
2668                            DisplayWidth(dpy, screen), DisplayHeight(dpy, screen));
2669                     printf("Display widthmm %d, heightmm %d\n", 
2670                            DisplayWidthMM(dpy, screen), DisplayHeightMM(dpy, screen));
2671                     spo = sce->subpixel_order;
2672                     if ((spo < 0) || (spo > 5))
2673                         printf ("Unknown subpixel order, value = %d\n", spo);
2674                     else printf ("new Subpixel rendering model is %s\n", order[spo]);
2675                     seen_screen = True;
2676                     break;
2677                 default:
2678                     if (event.type != ConfigureNotify) 
2679                         printf("unknown event received, type = %d!\n", event.type);
2680                 }
2681             }
2682         }
2683     }
2684     XRRFreeScreenConfigInfo(sc);
2685     return(ret);
2686 }