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