Bug #14118: print usage() to stdout, proper errors for bad arguments
[xorg/xrandr] / xrandr.c
1 /* 
2  * Copyright © 2001 Keith Packard, member of The XFree86 Project, Inc.
3  * Copyright © 2002 Hewlett Packard Company, Inc.
4  * Copyright © 2006 Intel Corporation
5  * Copyright © 2013 NVIDIA Corporation
6  *
7  * Permission to use, copy, modify, distribute, and sell this software and its
8  * documentation for any purpose is hereby granted without fee, provided that
9  * the above copyright notice appear in all copies and that both that copyright
10  * notice and this permission notice appear in supporting documentation, and
11  * that the name of the copyright holders not be used in advertising or
12  * publicity pertaining to distribution of the software without specific,
13  * written prior permission.  The copyright holders make no representations
14  * about the suitability of this software for any purpose.  It is provided "as
15  * is" without express or implied warranty.
16  *
17  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
18  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
19  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
20  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
22  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
23  * OF THIS SOFTWARE.
24  *
25  * Thanks to Jim Gettys who wrote most of the client side code,
26  * and part of the server code for randr.
27  */
28
29 #include <stdio.h>
30 #include <X11/Xlib.h>
31 #include <X11/Xlibint.h>
32 #include <X11/Xproto.h>
33 #include <X11/Xatom.h>
34 #include <X11/extensions/Xrandr.h>
35 #include <X11/extensions/Xrender.h>     /* we share subpixel information */
36 #include <strings.h>
37 #include <string.h>
38 #include <stdlib.h>
39 #include <stdint.h>
40 #include <inttypes.h>
41 #include <stdarg.h>
42 #include <math.h>
43
44 #include "config.h"
45
46 static char     *program_name;
47 static Display  *dpy;
48 static Window   root;
49 static int      screen = -1;
50 static Bool     verbose = False;
51 static Bool     automatic = False;
52 static Bool     properties = False;
53 static Bool     grab_server = True;
54 static Bool     no_primary = False;
55
56 static const char *direction[5] = {
57     "normal", 
58     "left", 
59     "inverted", 
60     "right",
61     "\n"};
62
63 static const char *reflections[5] = {
64     "normal", 
65     "x", 
66     "y", 
67     "xy",
68     "\n"};
69
70 /* subpixel order */
71 static const char *order[6] = {
72     "unknown",
73     "horizontal rgb",
74     "horizontal bgr",
75     "vertical rgb",
76     "vertical bgr",
77     "no subpixels"};
78
79 static const struct {
80     const char      *string;
81     unsigned long   flag;
82 } mode_flags[] = {
83     { "+HSync", RR_HSyncPositive },
84     { "-HSync", RR_HSyncNegative },
85     { "+VSync", RR_VSyncPositive },
86     { "-VSync", RR_VSyncNegative },
87     { "Interlace", RR_Interlace },
88     { "DoubleScan", RR_DoubleScan },
89     { "CSync",      RR_CSync },
90     { "+CSync",     RR_CSyncPositive },
91     { "-CSync",     RR_CSyncNegative },
92     { NULL,         0 }
93 };
94
95 static void
96 usage(void)
97 {
98     printf("usage: %s [options]\n", program_name);
99     printf("  where options are:\n");
100     printf("  -display <display> or -d <display>\n");
101     printf("  --help\n");
102     printf("  -o <normal,inverted,left,right,0,1,2,3>\n");
103     printf("            or --orientation <normal,inverted,left,right,0,1,2,3>\n");
104     printf("  -q        or --query\n");
105     printf("  -s <size>/<width>x<height> or --size <size>/<width>x<height>\n");
106     printf("  -r <rate> or --rate <rate> or --refresh <rate>\n");
107     printf("  -v        or --version\n");
108     printf("  -x        (reflect in x)\n");
109     printf("  -y        (reflect in y)\n");
110     printf("  --screen <screen>\n");
111     printf("  --verbose\n");
112     printf("  --current\n");
113     printf("  --dryrun\n");
114     printf("  --nograb\n");
115     printf("  --prop or --properties\n");
116     printf("  --fb <width>x<height>\n");
117     printf("  --fbmm <width>x<height>\n");
118     printf("  --dpi <dpi>/<output>\n");
119     printf("  --output <output>\n");
120     printf("      --auto\n");
121     printf("      --mode <mode>\n");
122     printf("      --preferred\n");
123     printf("      --pos <x>x<y>\n");
124     printf("      --rate <rate> or --refresh <rate>\n");
125     printf("      --reflect normal,x,y,xy\n");
126     printf("      --rotate normal,inverted,left,right\n");
127     printf("      --left-of <output>\n");
128     printf("      --right-of <output>\n");
129     printf("      --above <output>\n");
130     printf("      --below <output>\n");
131     printf("      --same-as <output>\n");
132     printf("      --set <property> <value>\n");
133     printf("      --scale <x>x<y>\n");
134     printf("      --scale-from <w>x<h>\n");
135     printf("      --transform <a>,<b>,<c>,<d>,<e>,<f>,<g>,<h>,<i>\n");
136     printf("      --off\n");
137     printf("      --crtc <crtc>\n");
138     printf("      --panning <w>x<h>[+<x>+<y>[/<track:w>x<h>+<x>+<y>[/<border:l>/<t>/<r>/<b>]]]\n");
139     printf("      --gamma <r>:<g>:<b>\n");
140     printf("      --primary\n");
141     printf("  --noprimary\n");
142     printf("  --newmode <name> <clock MHz>\n");
143     printf("            <hdisp> <hsync-start> <hsync-end> <htotal>\n");
144     printf("            <vdisp> <vsync-start> <vsync-end> <vtotal>\n");
145     printf("            [flags...]\n");
146     printf("            Valid flags: +HSync -HSync +VSync -VSync\n");
147     printf("                         +CSync -CSync CSync Interlace DoubleScan\n");
148     printf("  --rmmode <name>\n");
149     printf("  --addmode <output> <name>\n");
150     printf("  --delmode <output> <name>\n");
151     printf("  --listproviders\n");
152     printf("  --setprovideroutputsource <prov-xid> <source-xid>\n");
153     printf("  --setprovideroffloadsink <prov-xid> <sink-xid>\n");
154 }
155
156 static void _X_NORETURN _X_ATTRIBUTE_PRINTF(1,2)
157 fatal (const char *format, ...)
158 {
159     va_list ap;
160     
161     va_start (ap, format);
162     fprintf (stderr, "%s: ", program_name);
163     vfprintf (stderr, format, ap);
164     va_end (ap);
165     exit (1);
166     /*NOTREACHED*/
167 }
168
169 static void _X_ATTRIBUTE_PRINTF(1,2)
170 warning (const char *format, ...)
171 {
172     va_list ap;
173     
174     va_start (ap, format);
175     fprintf (stderr, "%s: ", program_name);
176     vfprintf (stderr, format, ap);
177     va_end (ap);
178 }
179
180 static void _X_NORETURN _X_ATTRIBUTE_PRINTF(1,2)
181 argerr (const char *format, ...)
182 {
183     va_list ap;
184
185     va_start (ap, format);
186     fprintf (stderr, "%s: ", program_name);
187     vfprintf (stderr, format, ap);
188     fprintf (stderr, "Try '%s --help' for more information.\n", program_name);
189     va_end (ap);
190     exit (1);
191     /*NOTREACHED*/
192 }
193
194 /* Because fmin requires C99 suppport */
195 static inline double dmin (double x, double y)
196 {
197     return x < y ? x : y;
198 }
199
200 static const char *
201 rotation_name (Rotation rotation)
202 {
203     int i;
204
205     if ((rotation & 0xf) == 0)
206         return "normal";
207     for (i = 0; i < 4; i++)
208         if (rotation & (1 << i))
209             return direction[i];
210     return "invalid rotation";
211 }
212
213 static const char *
214 reflection_name (Rotation rotation)
215 {
216     rotation &= (RR_Reflect_X|RR_Reflect_Y);
217     switch (rotation) {
218     case 0:
219         return "none";
220     case RR_Reflect_X:
221         return "X axis";
222     case RR_Reflect_Y:
223         return "Y axis";
224     case RR_Reflect_X|RR_Reflect_Y:
225         return "X and Y axis";
226     }
227     return "invalid reflection";
228 }
229
230 static char *
231 capability_name (int cap_bit)
232 {
233     switch (cap_bit) {
234     case RR_Capability_SourceOutput:
235         return "Source Output";
236     case RR_Capability_SinkOutput:
237         return "Sink Output";
238     case RR_Capability_SourceOffload:
239         return "Source Offload";
240     case RR_Capability_SinkOffload:
241         return "Sink Offload";
242     }
243     return "invalid capability";
244 }
245
246 typedef enum _relation {
247     relation_left_of,
248     relation_right_of,
249     relation_above,
250     relation_below,
251     relation_same_as,
252 } relation_t;
253
254 typedef struct {
255     int     x, y, width, height;
256 } rectangle_t;
257
258 typedef struct {
259     int     x1, y1, x2, y2;
260 } box_t;
261
262 typedef struct {
263     int     x, y;
264 } point_t;
265
266 typedef enum _changes {
267     changes_none = 0,
268     changes_crtc = (1 << 0),
269     changes_mode = (1 << 1),
270     changes_relation = (1 << 2),
271     changes_position = (1 << 3),
272     changes_rotation = (1 << 4),
273     changes_reflection = (1 << 5),
274     changes_automatic = (1 << 6),
275     changes_refresh = (1 << 7),
276     changes_property = (1 << 8),
277     changes_transform = (1 << 9),
278     changes_panning = (1 << 10),
279     changes_gamma = (1 << 11),
280     changes_primary = (1 << 12),
281 } changes_t;
282
283 typedef enum _name_kind {
284     name_none = 0,
285     name_string = (1 << 0),
286     name_xid = (1 << 1),
287     name_index = (1 << 2),
288     name_preferred = (1 << 3),
289 } name_kind_t;
290
291 typedef struct {
292     name_kind_t     kind;
293     char            *string;
294     XID             xid;
295     int             index;
296 } name_t;
297
298 typedef struct _crtc crtc_t;
299 typedef struct _output  output_t;
300 typedef struct _transform transform_t;
301 typedef struct _umode   umode_t;
302 typedef struct _output_prop output_prop_t;
303 typedef struct _provider provider_t;
304
305 struct _transform {
306     XTransform      transform;
307     const char      *filter;
308     int             nparams;
309     XFixed          *params;
310 };
311
312 struct _crtc {
313     name_t          crtc;
314     Bool            changing;
315     XRRCrtcInfo     *crtc_info;
316
317     XRRModeInfo     *mode_info;
318     XRRPanning      *panning_info;
319     int             x;
320     int             y;
321     Rotation        rotation;
322     output_t        **outputs;
323     int             noutput;
324     transform_t     current_transform, pending_transform;
325 };
326
327 struct _output_prop {
328     struct _output_prop *next;
329     char                *name;
330     char                *value;
331 };
332
333 struct _output {
334     struct _output   *next;
335     
336     changes_t       changes;
337     
338     output_prop_t   *props;
339
340     name_t          output;
341     XRROutputInfo   *output_info;
342     
343     name_t          crtc;
344     crtc_t          *crtc_info;
345     crtc_t          *current_crtc_info;
346     
347     name_t          mode;
348     double          refresh;
349     XRRModeInfo     *mode_info;
350     
351     name_t          addmode;
352
353     relation_t      relation;
354     char            *relative_to;
355
356     int             x, y;
357     Rotation        rotation;
358
359     XRRPanning      panning;
360
361     Bool            automatic;
362     int             scale_from_w, scale_from_h;
363     transform_t     transform;
364
365     struct {
366         float red;
367         float green;
368         float blue;
369     } gamma;
370
371     float           brightness;
372
373     Bool            primary;
374
375     Bool            found;
376 };
377
378 typedef enum _umode_action {
379     umode_create, umode_destroy, umode_add, umode_delete
380 } umode_action_t;
381
382
383 struct _umode {
384     struct _umode   *next;
385     
386     umode_action_t  action;
387     XRRModeInfo     mode;
388     name_t          output;
389     name_t          name;
390 };
391
392 struct _provider {
393     name_t              provider;
394     XRRProviderInfo     *info;
395 };
396
397 static const char *connection[3] = {
398     "connected",
399     "disconnected",
400     "unknown connection"};
401
402 #define OUTPUT_NAME 1
403
404 #define CRTC_OFF    2
405 #define CRTC_UNSET  3
406 #define CRTC_INDEX  0x40000000
407
408 #define MODE_NAME   1
409 #define MODE_OFF    2
410 #define MODE_UNSET  3
411 #define MODE_PREF   4
412
413 #define POS_UNSET   -1
414
415 static output_t *outputs = NULL;
416 static output_t **outputs_tail = &outputs;
417 static crtc_t   *crtcs;
418 static provider_t       *providers;
419 static umode_t  *umodes;
420 static int      num_crtcs, num_providers;
421 static XRRScreenResources  *res;
422 static int      fb_width = 0, fb_height = 0;
423 static int      fb_width_mm = 0, fb_height_mm = 0;
424 static double   dpi = 0;
425 static char     *dpi_output = NULL;
426 static Bool     dryrun = False;
427 static int      minWidth, maxWidth, minHeight, maxHeight;
428 static Bool     has_1_2 = False;
429 static Bool     has_1_3 = False;
430 static Bool     has_1_4 = False;
431 static name_t   provider_name, output_source_provider_name, offload_sink_provider_name;
432
433 static int
434 mode_height (XRRModeInfo *mode_info, Rotation rotation)
435 {
436     switch (rotation & 0xf) {
437     case RR_Rotate_0:
438     case RR_Rotate_180:
439         return mode_info->height;
440     case RR_Rotate_90:
441     case RR_Rotate_270:
442         return mode_info->width;
443     default:
444         return 0;
445     }
446 }
447
448 static int
449 mode_width (XRRModeInfo *mode_info, Rotation rotation)
450 {
451     switch (rotation & 0xf) {
452     case RR_Rotate_0:
453     case RR_Rotate_180:
454         return mode_info->width;
455     case RR_Rotate_90:
456     case RR_Rotate_270:
457         return mode_info->height;
458     default:
459         return 0;
460     }
461 }
462
463 static Bool
464 transform_point (XTransform *transform, double *xp, double *yp)
465 {
466     double  vector[3];
467     double  result[3];
468     int     i, j;
469     double  v;
470
471     vector[0] = *xp;
472     vector[1] = *yp;
473     vector[2] = 1;
474     for (j = 0; j < 3; j++)
475     {
476         v = 0;
477         for (i = 0; i < 3; i++)
478             v += (XFixedToDouble (transform->matrix[j][i]) * vector[i]);
479         result[j] = v;
480     }
481     if (!result[2])
482         return False;
483     for (j = 0; j < 2; j++) {
484         vector[j] = result[j] / result[2];
485         if (vector[j] > 32767 || vector[j] < -32767)
486             return False;
487     }
488     *xp = vector[0];
489     *yp = vector[1];
490     return True;
491 }
492
493 static void
494 path_bounds (XTransform *transform, point_t *points, int npoints, box_t *box)
495 {
496     int     i;
497     box_t   point;
498
499     for (i = 0; i < npoints; i++) {
500         double  x, y;
501         x = points[i].x;
502         y = points[i].y;
503         transform_point (transform, &x, &y);
504         point.x1 = floor (x);
505         point.y1 = floor (y);
506         point.x2 = ceil (x);
507         point.y2 = ceil (y);
508         if (i == 0)
509             *box = point;
510         else {
511             if (point.x1 < box->x1) box->x1 = point.x1;
512             if (point.y1 < box->y1) box->y1 = point.y1;
513             if (point.x2 > box->x2) box->x2 = point.x2;
514             if (point.y2 > box->y2) box->y2 = point.y2;
515         }
516     }
517 }
518
519 static void
520 mode_geometry (XRRModeInfo *mode_info, Rotation rotation,
521                XTransform *transform,
522                box_t *bounds)
523 {
524     point_t rect[4];
525     int width = mode_width (mode_info, rotation);
526     int height = mode_height (mode_info, rotation);
527
528     rect[0].x = 0;
529     rect[0].y = 0;
530     rect[1].x = width;
531     rect[1].y = 0;
532     rect[2].x = width;
533     rect[2].y = height;
534     rect[3].x = 0;
535     rect[3].y = height;
536     path_bounds (transform, rect, 4, bounds);
537 }
538
539 /* v refresh frequency in Hz */
540 static double
541 mode_refresh (XRRModeInfo *mode_info)
542 {
543     double rate;
544     
545     if (mode_info->hTotal && mode_info->vTotal)
546         rate = ((double) mode_info->dotClock /
547                 ((double) mode_info->hTotal * (double) mode_info->vTotal));
548     else
549         rate = 0;
550     return rate;
551 }
552
553 /* h sync frequency in Hz */
554 static double
555 mode_hsync (XRRModeInfo *mode_info)
556 {
557     double rate;
558     
559     if (mode_info->hTotal)
560         rate = (double) mode_info->dotClock / (double) mode_info->hTotal;
561     else
562         rate = 0;
563     return rate;
564 }
565
566 static void
567 init_name (name_t *name)
568 {
569     name->kind = name_none;
570 }
571
572 static void
573 set_name_string (name_t *name, char *string)
574 {
575     name->kind |= name_string;
576     name->string = string;
577 }
578
579 static void
580 set_name_xid (name_t *name, XID xid)
581 {
582     name->kind |= name_xid;
583     name->xid = xid;
584 }
585
586 static void
587 set_name_index (name_t *name, int index)
588 {
589     name->kind |= name_index;
590     name->index = index;
591 }
592
593 static void
594 set_name_preferred (name_t *name)
595 {
596     name->kind |= name_preferred;
597 }
598
599 static void
600 set_name_all (name_t *name, name_t *old)
601 {
602     if (old->kind & name_xid)
603         name->xid = old->xid;
604     if (old->kind & name_string)
605         name->string = old->string;
606     if (old->kind & name_index)
607         name->index = old->index;
608     name->kind |= old->kind;
609 }
610
611 static void
612 set_name (name_t *name, char *string, name_kind_t valid)
613 {
614     unsigned int xid; /* don't make it XID (which is unsigned long):
615                          scanf() takes unsigned int */
616     int index;
617
618     if ((valid & name_xid) && sscanf (string, "0x%x", &xid) == 1)
619         set_name_xid (name, xid);
620     else if ((valid & name_index) && sscanf (string, "%d", &index) == 1)
621         set_name_index (name, index);
622     else if (valid & name_string)
623         set_name_string (name, string);
624     else
625         argerr ("invalid name '%s'\n", string);
626 }
627
628 static int
629 print_name (const name_t *name)
630 {
631     name_kind_t kind = name->kind;
632
633     if ((kind & name_xid))         return printf("XID 0x%x", name->xid);
634     else if ((kind & name_string)) return printf("name %s", name->string);
635     else if ((kind & name_index))  return printf("index %d", name->index);
636     else                           return printf("unknown name");
637 }
638
639 static void
640 init_transform (transform_t *transform)
641 {
642     int x;
643     memset (&transform->transform, '\0', sizeof (transform->transform));
644     for (x = 0; x < 3; x++)
645         transform->transform.matrix[x][x] = XDoubleToFixed (1.0);
646     transform->filter = "";
647     transform->nparams = 0;
648     transform->params = NULL;
649 }
650
651 static void
652 set_transform (transform_t  *dest,
653                XTransform   *transform,
654                const char   *filter,
655                XFixed       *params,
656                int          nparams)
657 {
658     dest->transform = *transform;
659     /* note: this string is leaked */
660     dest->filter = strdup (filter);
661     dest->nparams = nparams;
662     dest->params = malloc (nparams * sizeof (XFixed));
663     memcpy (dest->params, params, nparams * sizeof (XFixed));
664 }
665
666 static void
667 copy_transform (transform_t *dest, transform_t *src)
668 {
669     set_transform (dest, &src->transform,
670                    src->filter, src->params, src->nparams);
671 }
672
673 static Bool
674 equal_transform (transform_t *a, transform_t *b)
675 {
676     if (memcmp (&a->transform, &b->transform, sizeof (XTransform)) != 0)
677         return False;
678     if (strcmp (a->filter, b->filter) != 0)
679         return False;
680     if (a->nparams != b->nparams)
681         return False;
682     if (memcmp (a->params, b->params, a->nparams * sizeof (XFixed)) != 0)
683         return False;
684     return True;
685 }
686
687 static output_t *
688 add_output (void)
689 {
690     output_t *output = calloc (1, sizeof (output_t));
691
692     if (!output)
693         fatal ("out of memory\n");
694     output->next = NULL;
695     output->found = False;
696     output->brightness = 1.0;
697     *outputs_tail = output;
698     outputs_tail = &output->next;
699     return output;
700 }
701
702 static output_t *
703 find_output (name_t *name)
704 {
705     output_t *output;
706
707     for (output = outputs; output; output = output->next)
708     {
709         name_kind_t common = name->kind & output->output.kind;
710         
711         if ((common & name_xid) && name->xid == output->output.xid)
712             break;
713         if ((common & name_string) && !strcmp (name->string, output->output.string))
714             break;
715         if ((common & name_index) && name->index == output->output.index)
716             break;
717     }
718     return output;
719 }
720
721 static output_t *
722 find_output_by_xid (RROutput output)
723 {
724     name_t  output_name;
725
726     init_name (&output_name);
727     set_name_xid (&output_name, output);
728     return find_output (&output_name);
729 }
730
731 static output_t *
732 find_output_by_name (char *name)
733 {
734     name_t  output_name;
735
736     init_name (&output_name);
737     set_name_string (&output_name, name);
738     return find_output (&output_name);
739 }
740
741 static crtc_t *
742 find_crtc (name_t *name)
743 {
744     int     c;
745     crtc_t  *crtc = NULL;
746
747     for (c = 0; c < num_crtcs; c++)
748     {
749         name_kind_t common;
750         
751         crtc = &crtcs[c];
752         common = name->kind & crtc->crtc.kind;
753         
754         if ((common & name_xid) && name->xid == crtc->crtc.xid)
755             break;
756         if ((common & name_string) && !strcmp (name->string, crtc->crtc.string))
757             break;
758         if ((common & name_index) && name->index == crtc->crtc.index)
759             break;
760         crtc = NULL;
761     }
762     return crtc;
763 }
764
765 static crtc_t *
766 find_crtc_by_xid (RRCrtc crtc)
767 {
768     name_t  crtc_name;
769
770     init_name (&crtc_name);
771     set_name_xid (&crtc_name, crtc);
772     return find_crtc (&crtc_name);
773 }
774
775 static XRRModeInfo *
776 find_mode (name_t *name, double refresh)
777 {
778     int         m;
779     XRRModeInfo *best = NULL;
780     double      bestDist = 0;
781
782     for (m = 0; m < res->nmode; m++)
783     {
784         XRRModeInfo *mode = &res->modes[m];
785         if ((name->kind & name_xid) && name->xid == mode->id)
786         {
787             best = mode;
788             break;
789         }
790         if ((name->kind & name_string) && !strcmp (name->string, mode->name))
791         {
792             double   dist;
793             
794             if (refresh)
795                 dist = fabs (mode_refresh (mode) - refresh);
796             else
797                 dist = 0;
798             if (!best || dist < bestDist)
799             {
800                 bestDist = dist;
801                 best = mode;
802             }
803         }
804     }
805     return best;
806 }
807
808 static XRRModeInfo *
809 find_mode_by_xid (RRMode mode)
810 {
811     name_t  mode_name;
812
813     init_name (&mode_name);
814     set_name_xid (&mode_name, mode);
815     return find_mode (&mode_name, 0);
816 }
817
818 #if 0
819 static XRRModeInfo *
820 find_mode_by_name (char *name)
821 {
822     name_t  mode_name;
823     init_name (&mode_name);
824     set_name_string (&mode_name, name);
825     return find_mode (&mode_name, 0);
826 }
827 #endif
828
829 static
830 XRRModeInfo *
831 find_mode_for_output (output_t *output, name_t *name)
832 {
833     XRROutputInfo   *output_info = output->output_info;
834     int             m;
835     XRRModeInfo     *best = NULL;
836     double          bestDist = 0;
837
838     for (m = 0; m < output_info->nmode; m++)
839     {
840         XRRModeInfo         *mode;
841
842         mode = find_mode_by_xid (output_info->modes[m]);
843         if (!mode) continue;
844         if ((name->kind & name_xid) && name->xid == mode->id)
845         {
846             best = mode;
847             break;
848         }
849         if ((name->kind & name_string) && !strcmp (name->string, mode->name))
850         {
851             double   dist;
852
853             /* Stay away from doublescan modes unless refresh rate is specified. */
854             if (!output->refresh && (mode->modeFlags & RR_DoubleScan))
855                 continue;
856
857             if (output->refresh)
858                 dist = fabs (mode_refresh (mode) - output->refresh);
859             else
860                 dist = 0;
861             if (!best || dist < bestDist)
862             {
863                 bestDist = dist;
864                 best = mode;
865             }
866         }
867     }
868     return best;
869 }
870
871 static XRRModeInfo *
872 preferred_mode (output_t *output)
873 {
874     XRROutputInfo   *output_info = output->output_info;
875     int             m;
876     XRRModeInfo     *best;
877     int             bestDist;
878     
879     best = NULL;
880     bestDist = 0;
881     for (m = 0; m < output_info->nmode; m++)
882     {
883         XRRModeInfo *mode_info = find_mode_by_xid (output_info->modes[m]);
884         int         dist;
885         
886         if (m < output_info->npreferred)
887             dist = 0;
888         else if (output_info->mm_height)
889             dist = (1000 * DisplayHeight(dpy, screen) / DisplayHeightMM(dpy, screen) -
890                     1000 * mode_info->height / output_info->mm_height);
891         else
892             dist = DisplayHeight(dpy, screen) - mode_info->height;
893
894         if (dist < 0) dist = -dist;
895         if (!best || dist < bestDist)
896         {
897             best = mode_info;
898             bestDist = dist;
899         }
900     }
901     return best;
902 }
903
904 static Bool
905 output_can_use_crtc (output_t *output, crtc_t *crtc)
906 {
907     XRROutputInfo   *output_info = output->output_info;
908     int             c;
909
910     for (c = 0; c < output_info->ncrtc; c++)
911         if (output_info->crtcs[c] == crtc->crtc.xid)
912             return True;
913     return False;
914 }
915
916 static Bool
917 output_can_use_mode (output_t *output, XRRModeInfo *mode)
918 {
919     XRROutputInfo   *output_info = output->output_info;
920     int             m;
921
922     for (m = 0; m < output_info->nmode; m++)
923         if (output_info->modes[m] == mode->id)
924             return True;
925     return False;
926 }
927
928 static Bool
929 crtc_can_use_rotation (crtc_t *crtc, Rotation rotation)
930 {
931     Rotation    rotations = crtc->crtc_info->rotations;
932     Rotation    dir = rotation & (RR_Rotate_0|RR_Rotate_90|RR_Rotate_180|RR_Rotate_270);
933     Rotation    reflect = rotation & (RR_Reflect_X|RR_Reflect_Y);
934     if (((rotations & dir) != 0) && ((rotations & reflect) == reflect))
935         return True;
936     return False;
937 }
938
939 #if 0
940 static Bool
941 crtc_can_use_transform (crtc_t *crtc, XTransform *transform)
942 {
943     int major, minor;
944
945     XRRQueryVersion (dpy, &major, &minor);
946     if (major > 1 || (major == 1 && minor >= 3))
947         return True;
948     return False;
949 }
950 #endif
951
952 /*
953  * Report only rotations that are supported by all crtcs
954  */
955 static Rotation
956 output_rotations (output_t *output)
957 {
958     Bool            found = False;
959     Rotation        rotation = RR_Rotate_0;
960     XRROutputInfo   *output_info = output->output_info;
961     int             c;
962     
963     for (c = 0; c < output_info->ncrtc; c++)
964     {
965         crtc_t  *crtc = find_crtc_by_xid (output_info->crtcs[c]);
966         if (crtc)
967         {
968             if (!found) {
969                 rotation = crtc->crtc_info->rotations;
970                 found = True;
971             } else
972                 rotation &= crtc->crtc_info->rotations;
973         }
974     }
975     return rotation;
976 }
977
978 static Bool
979 output_can_use_rotation (output_t *output, Rotation rotation)
980 {
981     XRROutputInfo   *output_info = output->output_info;
982     int             c;
983
984     /* make sure all of the crtcs can use this rotation.
985      * yes, this is not strictly necessary, but it is 
986      * simpler,and we expect most drivers to either
987      * support rotation everywhere or nowhere
988      */
989     for (c = 0; c < output_info->ncrtc; c++)
990     {
991         crtc_t  *crtc = find_crtc_by_xid (output_info->crtcs[c]);
992         if (crtc && !crtc_can_use_rotation (crtc, rotation))
993             return False;
994     }
995     return True;
996 }
997
998 static Bool
999 output_is_primary(output_t *output)
1000 {
1001     if (has_1_3)
1002             return XRRGetOutputPrimary(dpy, root) == output->output.xid;
1003     return False;
1004 }
1005
1006 /* Returns the index of the last value in an array < 0xffff */
1007 static int
1008 find_last_non_clamped(CARD16 array[], int size) {
1009     int i;
1010     for (i = size - 1; i > 0; i--) {
1011         if (array[i] < 0xffff)
1012             return i;
1013     }
1014     return 0;
1015 }
1016
1017 static void
1018 set_gamma_info(output_t *output)
1019 {
1020     XRRCrtcGamma *gamma;
1021     double i1, v1, i2, v2;
1022     int size, middle, last_best, last_red, last_green, last_blue;
1023     CARD16 *best_array;
1024
1025     if (!output->crtc_info)
1026         return;
1027
1028     size = XRRGetCrtcGammaSize(dpy, output->crtc_info->crtc.xid);
1029     if (!size) {
1030         warning("Failed to get size of gamma for output %s\n", output->output.string);
1031         return;
1032     }
1033
1034     gamma = XRRGetCrtcGamma(dpy, output->crtc_info->crtc.xid);
1035     if (!gamma) {
1036         warning("Failed to get gamma for output %s\n", output->output.string);
1037         return;
1038     }
1039
1040     /*
1041      * Here is a bit tricky because gamma is a whole curve for each
1042      * color.  So, typically, we need to represent 3 * 256 values as 3 + 1
1043      * values.  Therefore, we approximate the gamma curve (v) by supposing
1044      * it always follows the way we set it: a power function (i^g)
1045      * multiplied by a brightness (b).
1046      * v = i^g * b
1047      * so g = (ln(v) - ln(b))/ln(i)
1048      * and b can be found using two points (v1,i1) and (v2, i2):
1049      * b = e^((ln(v2)*ln(i1) - ln(v1)*ln(i2))/ln(i1/i2))
1050      * For the best resolution, we select i2 at the highest place not
1051      * clamped and i1 at i2/2. Note that if i2 = 1 (as in most normal
1052      * cases), then b = v2.
1053      */
1054     last_red = find_last_non_clamped(gamma->red, size);
1055     last_green = find_last_non_clamped(gamma->green, size);
1056     last_blue = find_last_non_clamped(gamma->blue, size);
1057     best_array = gamma->red;
1058     last_best = last_red;
1059     if (last_green > last_best) {
1060         last_best = last_green;
1061         best_array = gamma->green;
1062     }
1063     if (last_blue > last_best) {
1064         last_best = last_blue;
1065         best_array = gamma->blue;
1066     }
1067     if (last_best == 0)
1068         last_best = 1;
1069
1070     middle = last_best / 2;
1071     i1 = (double)(middle + 1) / size;
1072     v1 = (double)(best_array[middle]) / 65535;
1073     i2 = (double)(last_best + 1) / size;
1074     v2 = (double)(best_array[last_best]) / 65535;
1075     if (v2 < 0.0001) { /* The screen is black */
1076         output->brightness = 0;
1077         output->gamma.red = 1;
1078         output->gamma.green = 1;
1079         output->gamma.blue = 1;
1080     } else {
1081         if ((last_best + 1) == size)
1082             output->brightness = v2;
1083         else
1084             output->brightness = exp((log(v2)*log(i1) - log(v1)*log(i2))/log(i1/i2));
1085         output->gamma.red = log((double)(gamma->red[last_red / 2]) / output->brightness
1086                                 / 65535) / log((double)((last_red / 2) + 1) / size);
1087         output->gamma.green = log((double)(gamma->green[last_green / 2]) / output->brightness
1088                                   / 65535) / log((double)((last_green / 2) + 1) / size);
1089         output->gamma.blue = log((double)(gamma->blue[last_blue / 2]) / output->brightness
1090                                  / 65535) / log((double)((last_blue / 2) + 1) / size);
1091     }
1092
1093     XRRFreeGamma(gamma);
1094 }
1095
1096 static void
1097 set_output_info (output_t *output, RROutput xid, XRROutputInfo *output_info)
1098 {
1099     /* sanity check output info */
1100     if (output_info->connection != RR_Disconnected && !output_info->nmode)
1101         warning ("Output %s is not disconnected but has no modes\n",
1102                  output_info->name);
1103     
1104     /* set output name and info */
1105     if (!(output->output.kind & name_xid))
1106         set_name_xid (&output->output, xid);
1107     if (!(output->output.kind & name_string))
1108         set_name_string (&output->output, output_info->name);
1109     output->output_info = output_info;
1110     
1111     /* set crtc name and info */
1112     if (!(output->changes & changes_crtc))
1113         set_name_xid (&output->crtc, output_info->crtc);
1114     
1115     if (output->crtc.kind == name_xid && output->crtc.xid == None)
1116         output->crtc_info = NULL;
1117     else
1118     {
1119         output->crtc_info = find_crtc (&output->crtc);
1120         if (!output->crtc_info)
1121         {
1122             if (output->crtc.kind & name_xid)
1123                 fatal ("cannot find crtc 0x%lx\n", output->crtc.xid);
1124             if (output->crtc.kind & name_index)
1125                 fatal ("cannot find crtc %d\n", output->crtc.index);
1126         }
1127         if (!output_can_use_crtc (output, output->crtc_info))
1128             fatal ("output %s cannot use crtc 0x%lx\n", output->output.string,
1129                    output->crtc_info->crtc.xid);
1130     }
1131
1132     /* set mode name and info */
1133     if (!(output->changes & changes_mode))
1134     {
1135         crtc_t  *crtc = NULL;
1136         
1137         if (output_info->crtc)
1138             crtc = find_crtc_by_xid(output_info->crtc);
1139         if (crtc && crtc->crtc_info)
1140             set_name_xid (&output->mode, crtc->crtc_info->mode);
1141         else if (output->crtc_info)
1142             set_name_xid (&output->mode, output->crtc_info->crtc_info->mode);
1143         else
1144             set_name_xid (&output->mode, None);
1145         if (output->mode.xid)
1146         {
1147             output->mode_info = find_mode_by_xid (output->mode.xid);
1148             if (!output->mode_info)
1149                 fatal ("server did not report mode 0x%lx for output %s\n",
1150                        output->mode.xid, output->output.string);
1151         }
1152         else
1153             output->mode_info = NULL;
1154     }
1155     else if (output->mode.kind == name_xid && output->mode.xid == None)
1156         output->mode_info = NULL;
1157     else
1158     {
1159         if (output->mode.kind == name_preferred)
1160             output->mode_info = preferred_mode (output);
1161         else
1162             output->mode_info = find_mode_for_output (output, &output->mode);
1163         if (!output->mode_info)
1164         {
1165             if (output->mode.kind & name_preferred)
1166                 fatal ("cannot find preferred mode\n");
1167             if (output->mode.kind & name_string)
1168                 fatal ("cannot find mode %s\n", output->mode.string);
1169             if (output->mode.kind & name_xid)
1170                 fatal ("cannot find mode 0x%lx\n", output->mode.xid);
1171         }
1172         if (!output_can_use_mode (output, output->mode_info))
1173             fatal ("output %s cannot use mode %s\n", output->output.string,
1174                    output->mode_info->name);
1175     }
1176
1177     /* set position */
1178     if (!(output->changes & changes_position))
1179     {
1180         if (output->crtc_info)
1181         {
1182             output->x = output->crtc_info->crtc_info->x;
1183             output->y = output->crtc_info->crtc_info->y;
1184         }
1185         else
1186         {
1187             output->x = 0;
1188             output->y = 0;
1189         }
1190     }
1191
1192     /* set rotation */
1193     if (!(output->changes & changes_rotation))
1194     {
1195         output->rotation &= ~0xf;
1196         if (output->crtc_info)
1197             output->rotation |= (output->crtc_info->crtc_info->rotation & 0xf);
1198         else
1199             output->rotation = RR_Rotate_0;
1200     }
1201     if (!(output->changes & changes_reflection))
1202     {
1203         output->rotation &= ~(RR_Reflect_X|RR_Reflect_Y);
1204         if (output->crtc_info)
1205             output->rotation |= (output->crtc_info->crtc_info->rotation &
1206                                  (RR_Reflect_X|RR_Reflect_Y));
1207     }
1208     if (!output_can_use_rotation (output, output->rotation))
1209         fatal ("output %s cannot use rotation \"%s\" reflection \"%s\"\n",
1210                output->output.string,
1211                rotation_name (output->rotation),
1212                reflection_name (output->rotation));
1213
1214     /* set gamma */
1215     if (!(output->changes & changes_gamma))
1216             set_gamma_info(output);
1217
1218     /* set transformation */
1219     if (!(output->changes & changes_transform))
1220     {
1221         if (output->crtc_info)
1222             copy_transform (&output->transform, &output->crtc_info->current_transform);
1223         else
1224             init_transform (&output->transform);
1225     } else {
1226         /* transform was already set for --scale or --transform */
1227
1228         /* for --scale-from, figure out the mode size and compute the transform
1229          * for the target framebuffer area */
1230         if (output->scale_from_w > 0 && output->mode_info) {
1231             double sx = (double)output->scale_from_w /
1232                                 output->mode_info->width;
1233             double sy = (double)output->scale_from_h /
1234                                 output->mode_info->height;
1235             if (verbose)
1236                 printf("scaling %s by %lfx%lf\n", output->output.string, sx,
1237                        sy);
1238             init_transform (&output->transform);
1239             output->transform.transform.matrix[0][0] = XDoubleToFixed (sx);
1240             output->transform.transform.matrix[1][1] = XDoubleToFixed (sy);
1241             output->transform.transform.matrix[2][2] = XDoubleToFixed (1.0);
1242             if (sx != 1 || sy != 1)
1243                 output->transform.filter = "bilinear";
1244             else
1245                 output->transform.filter = "nearest";
1246             output->transform.nparams = 0;
1247             output->transform.params = NULL;
1248         }
1249     }
1250
1251     /* set primary */
1252     if (!(output->changes & changes_primary))
1253         output->primary = output_is_primary(output);
1254 }
1255     
1256 static void
1257 get_screen (Bool current)
1258 {
1259     if (!has_1_2)
1260         fatal ("Server RandR version before 1.2\n");
1261
1262     if (res)
1263         return;
1264
1265     XRRGetScreenSizeRange (dpy, root, &minWidth, &minHeight,
1266                            &maxWidth, &maxHeight);
1267     
1268     if (current)
1269         res = XRRGetScreenResourcesCurrent (dpy, root);
1270     else
1271         res = XRRGetScreenResources (dpy, root);
1272     if (!res) fatal ("could not get screen resources");
1273 }
1274
1275 static void
1276 get_crtcs (void)
1277 {
1278     int         c;
1279
1280     num_crtcs = res->ncrtc;
1281     crtcs = calloc (num_crtcs, sizeof (crtc_t));
1282     if (!crtcs) fatal ("out of memory\n");
1283     
1284     for (c = 0; c < res->ncrtc; c++)
1285     {
1286         XRRCrtcInfo *crtc_info = XRRGetCrtcInfo (dpy, res, res->crtcs[c]);
1287         XRRCrtcTransformAttributes  *attr;
1288         XRRPanning  *panning_info = NULL;
1289
1290         if (has_1_3) {
1291             XRRPanning zero;
1292             memset(&zero, 0, sizeof(zero));
1293             panning_info = XRRGetPanning  (dpy, res, res->crtcs[c]);
1294             zero.timestamp = panning_info->timestamp;
1295             if (!memcmp(panning_info, &zero, sizeof(zero))) {
1296                 Xfree(panning_info);
1297                 panning_info = NULL;
1298             }
1299         }
1300
1301         set_name_xid (&crtcs[c].crtc, res->crtcs[c]);
1302         set_name_index (&crtcs[c].crtc, c);
1303         if (!crtc_info) fatal ("could not get crtc 0x%lx information\n", res->crtcs[c]);
1304         crtcs[c].crtc_info = crtc_info;
1305         crtcs[c].panning_info = panning_info;
1306         if (crtc_info->mode == None)
1307         {
1308             crtcs[c].mode_info = NULL;
1309             crtcs[c].x = 0;
1310             crtcs[c].y = 0;
1311             crtcs[c].rotation = RR_Rotate_0;
1312         }
1313         if (XRRGetCrtcTransform (dpy, res->crtcs[c], &attr) && attr) {
1314             set_transform (&crtcs[c].current_transform,
1315                            &attr->currentTransform,
1316                            attr->currentFilter,
1317                            attr->currentParams,
1318                            attr->currentNparams);
1319             XFree (attr);
1320         }
1321         else
1322         {
1323             init_transform (&crtcs[c].current_transform);
1324         }
1325         copy_transform (&crtcs[c].pending_transform, &crtcs[c].current_transform);
1326    }
1327 }
1328
1329 static void
1330 crtc_add_output (crtc_t *crtc, output_t *output)
1331 {
1332     if (crtc->outputs)
1333         crtc->outputs = realloc (crtc->outputs, (crtc->noutput + 1) * sizeof (output_t *));
1334     else
1335     {
1336         crtc->outputs = malloc (sizeof (output_t *));
1337         crtc->x = output->x;
1338         crtc->y = output->y;
1339         crtc->rotation = output->rotation;
1340         crtc->mode_info = output->mode_info;
1341         copy_transform (&crtc->pending_transform, &output->transform);
1342    }
1343     if (!crtc->outputs) fatal ("out of memory\n");
1344     crtc->outputs[crtc->noutput++] = output;
1345 }
1346
1347 static void
1348 set_crtcs (void)
1349 {
1350     output_t    *output;
1351
1352     for (output = outputs; output; output = output->next)
1353     {
1354         if (!output->mode_info) continue;
1355         crtc_add_output (output->crtc_info, output);
1356     }
1357 }
1358
1359 static void
1360 set_panning (void)
1361 {
1362     output_t    *output;
1363
1364     for (output = outputs; output; output = output->next)
1365     {
1366         if (! output->crtc_info)
1367             continue;
1368         if (! (output->changes & changes_panning))
1369             continue;
1370         if (! output->crtc_info->panning_info)
1371             output->crtc_info->panning_info = malloc (sizeof(XRRPanning));
1372         memcpy (output->crtc_info->panning_info, &output->panning, sizeof(XRRPanning));
1373         output->crtc_info->changing = 1;
1374     }
1375 }
1376
1377 static void
1378 set_gamma(void)
1379 {
1380     output_t    *output;
1381
1382     for (output = outputs; output; output = output->next) {
1383         int i, size, shift;
1384         crtc_t *crtc;
1385         XRRCrtcGamma *gamma;
1386         float gammaRed;
1387         float gammaGreen;
1388         float gammaBlue;
1389
1390         if (!(output->changes & changes_gamma))
1391             continue;
1392
1393         if (!output->crtc_info) {
1394             fatal("Need crtc to set gamma on.\n");
1395             continue;
1396         }
1397
1398         crtc = output->crtc_info;
1399
1400         size = XRRGetCrtcGammaSize(dpy, crtc->crtc.xid);
1401
1402         if (!size) {
1403             fatal("Gamma size is 0.\n");
1404             continue;
1405         }
1406
1407         /*
1408          * The gamma-correction lookup table managed through XRR[GS]etCrtcGamma
1409          * is 2^n in size, where 'n' is the number of significant bits in
1410          * the X Color.  Because an X Color is 16 bits, size cannot be larger
1411          * than 2^16.
1412          */
1413         if (size > 65536) {
1414             fatal("Gamma correction table is impossibly large.\n");
1415             continue;
1416         }
1417
1418         /*
1419          * The hardware color lookup table has a number of significant
1420          * bits equal to ffs(size) - 1; compute all values so that
1421          * they are in the range [0,size) then shift the values so
1422          * that they occupy the MSBs of the 16-bit X Color.
1423          */
1424         shift = 16 - (ffs(size) - 1);
1425
1426         gamma = XRRAllocGamma(size);
1427         if (!gamma) {
1428             fatal("Gamma allocation failed.\n");
1429             continue;
1430         }
1431
1432         if (output->gamma.red == 0.0)
1433             output->gamma.red = 1.0;
1434         if (output->gamma.green == 0.0)
1435             output->gamma.green = 1.0;
1436         if (output->gamma.blue == 0.0)
1437             output->gamma.blue = 1.0;
1438
1439         gammaRed = 1.0 / output->gamma.red;
1440         gammaGreen = 1.0 / output->gamma.green;
1441         gammaBlue = 1.0 / output->gamma.blue;
1442
1443         for (i = 0; i < size; i++) {
1444             if (gammaRed == 1.0 && output->brightness == 1.0)
1445                 gamma->red[i] = i;
1446             else
1447                 gamma->red[i] = dmin(pow((double)i/(double)(size - 1),
1448                                          gammaRed) * output->brightness,
1449                                      1.0) * (double)(size - 1);
1450             gamma->red[i] <<= shift;
1451
1452             if (gammaGreen == 1.0 && output->brightness == 1.0)
1453                 gamma->green[i] = i;
1454             else
1455                 gamma->green[i] = dmin(pow((double)i/(double)(size - 1),
1456                                            gammaGreen) * output->brightness,
1457                                        1.0) * (double)(size - 1);
1458             gamma->green[i] <<= shift;
1459
1460             if (gammaBlue == 1.0 && output->brightness == 1.0)
1461                 gamma->blue[i] = i;
1462             else
1463                 gamma->blue[i] = dmin(pow((double)i/(double)(size - 1),
1464                                           gammaBlue) * output->brightness,
1465                                       1.0) * (double)(size - 1);
1466             gamma->blue[i] <<= shift;
1467         }
1468
1469         XRRSetCrtcGamma(dpy, crtc->crtc.xid, gamma);
1470
1471         free(gamma);
1472     }
1473 }
1474
1475 static void
1476 set_primary(void)
1477 {
1478     output_t *output;
1479
1480     if (no_primary) {
1481         XRRSetOutputPrimary(dpy, root, None);
1482     } else {
1483         for (output = outputs; output; output = output->next) {
1484             if (!(output->changes & changes_primary))
1485                 continue;
1486             if (output->primary)
1487                 XRRSetOutputPrimary(dpy, root, output->output.xid);
1488         }
1489     }
1490 }
1491
1492 static Status
1493 crtc_disable (crtc_t *crtc)
1494 {
1495     if (verbose)
1496         printf ("crtc %d: disable\n", crtc->crtc.index);
1497         
1498     if (dryrun)
1499         return RRSetConfigSuccess;
1500     return XRRSetCrtcConfig (dpy, res, crtc->crtc.xid, CurrentTime,
1501                              0, 0, None, RR_Rotate_0, NULL, 0);
1502 }
1503
1504 static void
1505 crtc_set_transform (crtc_t *crtc, transform_t *transform)
1506 {
1507     int major, minor;
1508
1509     XRRQueryVersion (dpy, &major, &minor);
1510     if (major > 1 || (major == 1 && minor >= 3))
1511         XRRSetCrtcTransform (dpy, crtc->crtc.xid,
1512                              &transform->transform,
1513                              transform->filter,
1514                              transform->params,
1515                              transform->nparams);
1516 }
1517
1518 static Status
1519 crtc_revert (crtc_t *crtc)
1520 {
1521     XRRCrtcInfo *crtc_info = crtc->crtc_info;
1522     
1523     if (verbose)
1524         printf ("crtc %d: revert\n", crtc->crtc.index);
1525         
1526     if (dryrun)
1527         return RRSetConfigSuccess;
1528
1529     if (!equal_transform (&crtc->current_transform, &crtc->pending_transform))
1530         crtc_set_transform (crtc, &crtc->current_transform);
1531     return XRRSetCrtcConfig (dpy, res, crtc->crtc.xid, CurrentTime,
1532                             crtc_info->x, crtc_info->y,
1533                             crtc_info->mode, crtc_info->rotation,
1534                             crtc_info->outputs, crtc_info->noutput);
1535 }
1536
1537 static Status
1538 crtc_apply (crtc_t *crtc)
1539 {
1540     RROutput    *rr_outputs;
1541     int         o;
1542     Status      s;
1543     RRMode      mode = None;
1544
1545     if (!crtc->changing || !crtc->mode_info)
1546         return RRSetConfigSuccess;
1547
1548     rr_outputs = calloc (crtc->noutput, sizeof (RROutput));
1549     if (!rr_outputs)
1550         return BadAlloc;
1551     for (o = 0; o < crtc->noutput; o++)
1552         rr_outputs[o] = crtc->outputs[o]->output.xid;
1553     mode = crtc->mode_info->id;
1554     if (verbose) {
1555         printf ("crtc %d: %12s %6.1f +%d+%d", crtc->crtc.index,
1556                 crtc->mode_info->name, mode_refresh (crtc->mode_info),
1557                 crtc->x, crtc->y);
1558         for (o = 0; o < crtc->noutput; o++)
1559             printf (" \"%s\"", crtc->outputs[o]->output.string);
1560         printf ("\n");
1561     }
1562     
1563     if (dryrun)
1564         s = RRSetConfigSuccess;
1565     else
1566     {
1567         if (!equal_transform (&crtc->current_transform, &crtc->pending_transform))
1568             crtc_set_transform (crtc, &crtc->pending_transform);
1569         s = XRRSetCrtcConfig (dpy, res, crtc->crtc.xid, CurrentTime,
1570                               crtc->x, crtc->y, mode, crtc->rotation,
1571                               rr_outputs, crtc->noutput);
1572         if (s == RRSetConfigSuccess && crtc->panning_info) {
1573             if (has_1_3)
1574                 s = XRRSetPanning (dpy, res, crtc->crtc.xid, crtc->panning_info);
1575             else
1576                 fatal ("panning needs RandR 1.3\n");
1577         }
1578     }
1579     free (rr_outputs);
1580     return s;
1581 }
1582
1583 static void
1584 screen_revert (void)
1585 {
1586     if (verbose)
1587         printf ("screen %d: revert\n", screen);
1588
1589     if (dryrun)
1590         return;
1591     XRRSetScreenSize (dpy, root,
1592                       DisplayWidth (dpy, screen),
1593                       DisplayHeight (dpy, screen),
1594                       DisplayWidthMM (dpy, screen),
1595                       DisplayHeightMM (dpy, screen));
1596 }
1597
1598 static void
1599 screen_apply (void)
1600 {
1601     if (fb_width == DisplayWidth (dpy, screen) &&
1602         fb_height == DisplayHeight (dpy, screen) &&
1603         fb_width_mm == DisplayWidthMM (dpy, screen) &&
1604         fb_height_mm == DisplayHeightMM (dpy, screen))
1605     {
1606         return;
1607     }
1608     if (verbose)
1609         printf ("screen %d: %dx%d %dx%d mm %6.2fdpi\n", screen,
1610                 fb_width, fb_height, fb_width_mm, fb_height_mm, dpi);
1611     if (dryrun)
1612         return;
1613     XRRSetScreenSize (dpy, root, fb_width, fb_height,
1614                       fb_width_mm, fb_height_mm);
1615 }
1616
1617 static void
1618 revert (void)
1619 {
1620     int c;
1621
1622     /* first disable all crtcs */
1623     for (c = 0; c < res->ncrtc; c++)
1624         crtc_disable (&crtcs[c]);
1625     /* next reset screen size */
1626     screen_revert ();
1627     /* now restore all crtcs */
1628     for (c = 0; c < res->ncrtc; c++)
1629         crtc_revert (&crtcs[c]);
1630 }
1631
1632 /*
1633  * uh-oh, something bad happened in the middle of changing
1634  * the configuration. Revert to the previous configuration
1635  * and bail
1636  */
1637 static void _X_NORETURN
1638 panic (Status s, crtc_t *crtc)
1639 {
1640     int     c = crtc->crtc.index;
1641     const char *message;
1642     
1643     switch (s) {
1644     case RRSetConfigSuccess:            message = "succeeded";              break;
1645     case BadAlloc:                      message = "out of memory";          break;
1646     case RRSetConfigFailed:             message = "failed";                 break;
1647     case RRSetConfigInvalidConfigTime:  message = "invalid config time";    break;
1648     case RRSetConfigInvalidTime:        message = "invalid time";           break;
1649     default:                            message = "unknown failure";        break;
1650     }
1651     
1652     fprintf (stderr, "%s: Configure crtc %d %s\n", program_name, c, message);
1653     revert ();
1654     exit (1);
1655 }
1656
1657 static void
1658 apply (void)
1659 {
1660     Status  s;
1661     int     c;
1662     
1663     /*
1664      * Hold the server grabbed while messing with
1665      * the screen so that apps which notice the resize
1666      * event and ask for xinerama information from the server
1667      * receive up-to-date information
1668      */
1669     if (grab_server)
1670         XGrabServer (dpy);
1671     
1672     /*
1673      * Turn off any crtcs which are to be disabled or which are
1674      * larger than the target size
1675      */
1676     for (c = 0; c < res->ncrtc; c++)
1677     {
1678         crtc_t      *crtc = &crtcs[c];
1679         XRRCrtcInfo *crtc_info = crtc->crtc_info;
1680
1681         /* if this crtc is already disabled, skip it */
1682         if (crtc_info->mode == None) 
1683             continue;
1684         
1685         /* 
1686          * If this crtc is to be left enabled, make
1687          * sure the old size fits then new screen
1688          */
1689         if (crtc->mode_info) 
1690         {
1691             XRRModeInfo *old_mode = find_mode_by_xid (crtc_info->mode);
1692             int x, y, w, h;
1693             box_t bounds;
1694
1695             if (!old_mode) 
1696                 panic (RRSetConfigFailed, crtc);
1697             
1698             /* old position and size information */
1699             mode_geometry (old_mode, crtc_info->rotation,
1700                            &crtc->current_transform.transform,
1701                            &bounds);
1702
1703             x = crtc_info->x + bounds.x1;
1704             y = crtc_info->y + bounds.y1;
1705             w = bounds.x2 - bounds.x1;
1706             h = bounds.y2 - bounds.y1;
1707
1708             /* if it fits, skip it */
1709             if (x + w <= fb_width && y + h <= fb_height) 
1710                 continue;
1711             crtc->changing = True;
1712         }
1713         s = crtc_disable (crtc);
1714         if (s != RRSetConfigSuccess)
1715             panic (s, crtc);
1716     }
1717
1718     /*
1719      * Set the screen size
1720      */
1721     screen_apply ();
1722     
1723     /*
1724      * Set crtcs
1725      */
1726
1727     for (c = 0; c < res->ncrtc; c++)
1728     {
1729         crtc_t  *crtc = &crtcs[c];
1730         
1731         s = crtc_apply (crtc);
1732         if (s != RRSetConfigSuccess)
1733             panic (s, crtc);
1734     }
1735
1736     set_primary ();
1737
1738     /*
1739      * Release the server grab and let all clients
1740      * respond to the updated state
1741      */
1742     if (grab_server)
1743         XUngrabServer (dpy);
1744 }
1745
1746 /*
1747  * Use current output state to complete the output list
1748  */
1749 static void
1750 get_outputs (void)
1751 {
1752     int         o;
1753     output_t    *q;
1754     
1755     for (o = 0; o < res->noutput; o++)
1756     {
1757         XRROutputInfo   *output_info = XRRGetOutputInfo (dpy, res, res->outputs[o]);
1758         output_t        *output;
1759         name_t          output_name;
1760         if (!output_info) fatal ("could not get output 0x%lx information\n", res->outputs[o]);
1761         set_name_xid (&output_name, res->outputs[o]);
1762         set_name_index (&output_name, o);
1763         set_name_string (&output_name, output_info->name);
1764         output = find_output (&output_name);
1765         if (!output)
1766         {
1767             output = add_output ();
1768             set_name_all (&output->output, &output_name);
1769             /*
1770              * When global --automatic mode is set, turn on connected but off
1771              * outputs, turn off disconnected but on outputs
1772              */
1773             if (automatic)
1774             {
1775                 switch (output_info->connection) {
1776                 case RR_Connected:
1777                     if (!output_info->crtc) {
1778                         output->changes |= changes_automatic;
1779                         output->automatic = True;
1780                     }
1781                     break;
1782                 case RR_Disconnected:
1783                     if (output_info->crtc)
1784                     {
1785                         output->changes |= changes_automatic;
1786                         output->automatic = True;
1787                     }
1788                     break;
1789                 }
1790             }
1791         }
1792         output->found = True;
1793
1794         /*
1795          * Automatic mode -- track connection state and enable/disable outputs
1796          * as necessary
1797          */
1798         if (output->automatic)
1799         {
1800             switch (output_info->connection) {
1801             case RR_Connected:
1802             case RR_UnknownConnection:
1803                 if ((!(output->changes & changes_mode)))
1804                 {
1805                     set_name_preferred (&output->mode);
1806                     output->changes |= changes_mode;
1807                 }
1808                 break;
1809             case RR_Disconnected:
1810                 if ((!(output->changes & changes_mode)))
1811                 {
1812                     set_name_xid (&output->mode, None);
1813                     set_name_xid (&output->crtc, None);
1814                     output->changes |= changes_mode;
1815                     output->changes |= changes_crtc;
1816                 }
1817                 break;
1818             }
1819         }
1820
1821         set_output_info (output, res->outputs[o], output_info);
1822     }
1823     for (q = outputs; q; q = q->next)
1824     {
1825         if (!q->found)
1826         {
1827             fprintf(stderr, "warning: output %s not found; ignoring\n",
1828                     q->output.string);
1829         }
1830     }
1831 }
1832
1833 static void
1834 mark_changing_crtcs (void)
1835 {
1836     int c;
1837
1838     for (c = 0; c < num_crtcs; c++)
1839     {
1840         crtc_t      *crtc = &crtcs[c];
1841         int         o;
1842         output_t    *output;
1843
1844         /* walk old output list (to catch disables) */
1845         for (o = 0; o < crtc->crtc_info->noutput; o++)
1846         {
1847             output = find_output_by_xid (crtc->crtc_info->outputs[o]);
1848             if (!output) fatal ("cannot find output 0x%lx\n",
1849                                 crtc->crtc_info->outputs[o]);
1850             if (output->changes)
1851                 crtc->changing = True;
1852         }
1853         /* walk new output list */
1854         for (o = 0; o < crtc->noutput; o++)
1855         {
1856             output = crtc->outputs[o];
1857             if (output->changes)
1858                 crtc->changing = True;
1859         }
1860     }
1861 }
1862
1863 /*
1864  * Test whether 'crtc' can be used for 'output'
1865  */
1866 static Bool
1867 check_crtc_for_output (crtc_t *crtc, output_t *output)
1868 {
1869     int         c;
1870     int         l;
1871     output_t    *other;
1872     
1873     for (c = 0; c < output->output_info->ncrtc; c++)
1874         if (output->output_info->crtcs[c] == crtc->crtc.xid)
1875             break;
1876     if (c == output->output_info->ncrtc)
1877         return False;
1878     for (other = outputs; other; other = other->next)
1879     {
1880         if (other == output)
1881             continue;
1882
1883         if (other->mode_info == NULL)
1884             continue;
1885
1886         if (other->crtc_info != crtc)
1887             continue;
1888
1889         /* see if the output connected to the crtc can clone to this output */
1890         for (l = 0; l < output->output_info->nclone; l++)
1891             if (output->output_info->clones[l] == other->output.xid)
1892                 break;
1893         /* not on the list, can't clone */
1894         if (l == output->output_info->nclone) 
1895             return False;
1896     }
1897
1898     if (crtc->noutput)
1899     {
1900         /* make sure the state matches */
1901         if (crtc->mode_info != output->mode_info)
1902             return False;
1903         if (crtc->x != output->x)
1904             return False;
1905         if (crtc->y != output->y)
1906             return False;
1907         if (crtc->rotation != output->rotation)
1908             return False;
1909         if (!equal_transform (&crtc->current_transform, &output->transform))
1910             return False;
1911     }
1912     else if (crtc->crtc_info->noutput)
1913     {
1914         /* make sure the state matches the already used state */
1915         XRRModeInfo *mode = find_mode_by_xid (crtc->crtc_info->mode);
1916
1917         if (mode != output->mode_info)
1918             return False;
1919         if (crtc->crtc_info->x != output->x)
1920             return False;
1921         if (crtc->crtc_info->y != output->y)
1922             return False;
1923         if (crtc->crtc_info->rotation != output->rotation)
1924             return False;
1925     }
1926     return True;
1927 }
1928
1929 static crtc_t *
1930 find_crtc_for_output (output_t *output)
1931 {
1932     int     c;
1933
1934     for (c = 0; c < output->output_info->ncrtc; c++)
1935     {
1936         crtc_t      *crtc;
1937
1938         crtc = find_crtc_by_xid (output->output_info->crtcs[c]);
1939         if (!crtc) fatal ("cannot find crtc 0x%lx\n", output->output_info->crtcs[c]);
1940
1941         if (check_crtc_for_output (crtc, output))
1942             return crtc;
1943     }
1944     return NULL;
1945 }
1946
1947 static void
1948 set_positions (void)
1949 {
1950     output_t    *output;
1951     Bool        keep_going;
1952     Bool        any_set;
1953     int         min_x, min_y;
1954
1955     for (;;)
1956     {
1957         any_set = False;
1958         keep_going = False;
1959         for (output = outputs; output; output = output->next)
1960         {
1961             output_t    *relation;
1962             name_t      relation_name;
1963
1964             if (!(output->changes & changes_relation)) continue;
1965             
1966             if (output->mode_info == NULL) continue;
1967
1968             init_name (&relation_name);
1969             set_name_string (&relation_name, output->relative_to);
1970             relation = find_output (&relation_name);
1971             if (!relation) fatal ("cannot find output \"%s\"\n", output->relative_to);
1972             
1973             if (relation->mode_info == NULL) 
1974             {
1975                 output->x = 0;
1976                 output->y = 0;
1977                 output->changes |= changes_position;
1978                 any_set = True;
1979                 continue;
1980             }
1981             /*
1982              * Make sure the dependent object has been set in place
1983              */
1984             if ((relation->changes & changes_relation) && 
1985                 !(relation->changes & changes_position))
1986             {
1987                 keep_going = True;
1988                 continue;
1989             }
1990             
1991             switch (output->relation) {
1992             case relation_left_of:
1993                 output->y = relation->y;
1994                 output->x = relation->x - mode_width (output->mode_info, output->rotation);
1995                 break;
1996             case relation_right_of:
1997                 output->y = relation->y;
1998                 output->x = relation->x + mode_width (relation->mode_info, relation->rotation);
1999                 break;
2000             case relation_above:
2001                 output->x = relation->x;
2002                 output->y = relation->y - mode_height (output->mode_info, output->rotation);
2003                 break;
2004             case relation_below:
2005                 output->x = relation->x;
2006                 output->y = relation->y + mode_height (relation->mode_info, relation->rotation);
2007                 break;
2008             case relation_same_as:
2009                 output->x = relation->x;
2010                 output->y = relation->y;
2011             }
2012             output->changes |= changes_position;
2013             any_set = True;
2014         }
2015         if (!keep_going)
2016             break;
2017         if (!any_set)
2018             fatal ("loop in relative position specifications\n");
2019     }
2020
2021     /*
2022      * Now normalize positions so the upper left corner of all outputs is at 0,0
2023      */
2024     min_x = 32768;
2025     min_y = 32768;
2026     for (output = outputs; output; output = output->next)
2027     {
2028         if (output->mode_info == NULL) continue;
2029         
2030         if (output->x < min_x) min_x = output->x;
2031         if (output->y < min_y) min_y = output->y;
2032     }
2033     if (min_x || min_y)
2034     {
2035         /* move all outputs */
2036         for (output = outputs; output; output = output->next)
2037         {
2038             if (output->mode_info == NULL) continue;
2039
2040             output->x -= min_x;
2041             output->y -= min_y;
2042             output->changes |= changes_position;
2043         }
2044     }
2045 }
2046
2047 static void
2048 set_screen_size (void)
2049 {
2050     output_t    *output;
2051     Bool        fb_specified = fb_width != 0 && fb_height != 0;
2052     
2053     for (output = outputs; output; output = output->next)
2054     {
2055         XRRModeInfo *mode_info = output->mode_info;
2056         int         x, y, w, h;
2057         box_t       bounds;
2058         
2059         if (!mode_info) continue;
2060         
2061         mode_geometry (mode_info, output->rotation,
2062                        &output->transform.transform,
2063                        &bounds);
2064         x = output->x + bounds.x1;
2065         y = output->y + bounds.y1;
2066         w = bounds.x2 - bounds.x1;
2067         h = bounds.y2 - bounds.y1;
2068         /* make sure output fits in specified size */
2069         if (fb_specified)
2070         {
2071             if (x + w > fb_width || y + h > fb_height)
2072                 warning ("specified screen %dx%d not large enough for output %s (%dx%d+%d+%d)\n",
2073                          fb_width, fb_height, output->output.string, w, h, x, y);
2074         }
2075         /* fit fb to output */
2076         else
2077         {
2078             XRRPanning *pan;
2079             if (x + w > fb_width)
2080                 fb_width = x + w;
2081             if (y + h > fb_height)
2082                 fb_height = y + h;
2083             if (output->changes & changes_panning)
2084                 pan = &output->panning;
2085             else
2086                 pan = output->crtc_info ? output->crtc_info->panning_info : NULL;
2087             if (pan && pan->left + pan->width > fb_width)
2088                 fb_width = pan->left + pan->width;
2089             if (pan && pan->top + pan->height > fb_height)
2090                 fb_height = pan->top + pan->height;
2091         }
2092     }   
2093
2094     if (fb_width > maxWidth || fb_height > maxHeight)
2095         fatal ("screen cannot be larger than %dx%d (desired size %dx%d)\n",
2096                maxWidth, maxHeight, fb_width, fb_height);
2097     if (fb_specified)
2098     {
2099         if (fb_width < minWidth || fb_height < minHeight)
2100             fatal ("screen must be at least %dx%d\n", minWidth, minHeight);
2101     }
2102     else
2103     {
2104         if (fb_width < minWidth) fb_width = minWidth;
2105         if (fb_height < minHeight) fb_height = minHeight;
2106     }
2107 }
2108     
2109
2110 static void
2111 disable_outputs (output_t *outputs)
2112 {
2113     while (outputs)
2114     {
2115         outputs->crtc_info = NULL;
2116         outputs = outputs->next;
2117     }
2118 }
2119
2120 /*
2121  * find the best mapping from output to crtc available
2122  */
2123 static int
2124 pick_crtcs_score (output_t *outputs)
2125 {
2126     output_t    *output;
2127     int         best_score;
2128     int         my_score;
2129     int         score;
2130     crtc_t      *best_crtc;
2131     int         c;
2132     
2133     if (!outputs)
2134         return 0;
2135     
2136     output = outputs;
2137     outputs = outputs->next;
2138     /*
2139      * Score with this output disabled
2140      */
2141     output->crtc_info = NULL;
2142     best_score = pick_crtcs_score (outputs);
2143     if (output->mode_info == NULL)
2144         return best_score;
2145
2146     best_crtc = NULL;
2147     /* 
2148      * Now score with this output any valid crtc
2149      */
2150     for (c = 0; c < output->output_info->ncrtc; c++)
2151     {
2152         crtc_t      *crtc;
2153
2154         crtc = find_crtc_by_xid (output->output_info->crtcs[c]);
2155         if (!crtc)
2156             fatal ("cannot find crtc 0x%lx\n", output->output_info->crtcs[c]);
2157         
2158         /* reset crtc allocation for following outputs */
2159         disable_outputs (outputs);
2160         if (!check_crtc_for_output (crtc, output))
2161             continue;
2162         
2163         my_score = 1000;
2164         /* slight preference for existing connections */
2165         if (crtc == output->current_crtc_info)
2166             my_score++;
2167
2168         output->crtc_info = crtc;
2169         score = my_score + pick_crtcs_score (outputs);
2170         if (score > best_score)
2171         {
2172             best_crtc = crtc;
2173             best_score = score;
2174         }
2175     }
2176     if (output->crtc_info != best_crtc)
2177         output->crtc_info = best_crtc;
2178     /*
2179      * Reset other outputs based on this one using the best crtc
2180      */
2181     (void) pick_crtcs_score (outputs);
2182
2183     return best_score;
2184 }
2185
2186 /*
2187  * Pick crtcs for any changing outputs that don't have one
2188  */
2189 static void
2190 pick_crtcs (void)
2191 {
2192     output_t    *output;
2193
2194     /*
2195      * First try to match up newly enabled outputs with spare crtcs
2196      */
2197     for (output = outputs; output; output = output->next)
2198     {
2199         if (output->changes && output->mode_info)
2200         {
2201             if (output->crtc_info) {
2202                 if (output->crtc_info->crtc_info->noutput > 0 &&
2203                     (output->crtc_info->crtc_info->noutput > 1 ||
2204                      output != find_output_by_xid (output->crtc_info->crtc_info->outputs[0])))
2205                     break;
2206             } else {
2207                 output->crtc_info = find_crtc_for_output (output);
2208                 if (!output->crtc_info)
2209                     break;
2210             }
2211         }
2212     }
2213     /*
2214      * Everyone is happy
2215      */
2216     if (!output)
2217         return;
2218     /*
2219      * When the simple way fails, see if there is a way
2220      * to swap crtcs around and make things work
2221      */
2222     for (output = outputs; output; output = output->next)
2223         output->current_crtc_info = output->crtc_info;
2224     pick_crtcs_score (outputs);
2225     for (output = outputs; output; output = output->next)
2226     {
2227         if (output->mode_info && !output->crtc_info)
2228             fatal ("cannot find crtc for output %s\n", output->output.string);
2229         if (!output->changes && output->crtc_info != output->current_crtc_info)
2230             output->changes |= changes_crtc;
2231     }
2232 }
2233
2234 static int
2235 check_strtol(char *s)
2236 {
2237     char *endptr;
2238     int result = strtol(s, &endptr, 10);
2239     if (s == endptr)
2240         argerr ("failed to parse '%s' as a number\n", s);
2241     return result;
2242 }
2243
2244 static double
2245 check_strtod(char *s)
2246 {
2247     char *endptr;
2248     double result = strtod(s, &endptr);
2249     if (s == endptr)
2250         argerr ("failed to parse '%s' as a number\n", s);
2251     return result;
2252 }
2253
2254
2255 static void *
2256 property_values_from_string(const char *str, const Atom type, const int format,
2257                             int *returned_nitems)
2258 {
2259     char *token, *tmp;
2260     void *returned_bytes = NULL;
2261     int nitems = 0, bytes_per_item = format / 8;
2262
2263     if ((type != XA_INTEGER && type != XA_CARDINAL) ||
2264         (format != 8 && format != 16 && format != 32))
2265     {
2266         return NULL;
2267     }
2268
2269     tmp = strdup (str);
2270
2271     for (token = strtok (tmp, ","); token; token = strtok (NULL, ","))
2272     {
2273         char *endptr;
2274         long int val = strtol (token, &endptr, 0);
2275
2276         if (token == endptr || *endptr != '\0')
2277         {
2278             argerr ("failed to parse '%s' as a number\n", token);
2279         }
2280
2281         returned_bytes = realloc (returned_bytes, (nitems + 1) * bytes_per_item);
2282
2283         if (type == XA_INTEGER && format == 8)
2284         {
2285             int8_t *ptr = returned_bytes;
2286             ptr[nitems] = (int8_t) val;
2287         }
2288         else if (type == XA_INTEGER && format == 16)
2289         {
2290             int16_t *ptr = returned_bytes;
2291             ptr[nitems] = (int16_t) val;
2292         }
2293         else if (type == XA_INTEGER && format == 32)
2294         {
2295             int32_t *ptr = returned_bytes;
2296             ptr[nitems] = (int32_t) val;
2297         }
2298         else if (type == XA_CARDINAL && format == 8)
2299         {
2300             uint8_t *ptr = returned_bytes;
2301             ptr[nitems] = (uint8_t) val;
2302         }
2303         else if (type == XA_CARDINAL && format == 16)
2304         {
2305             uint16_t *ptr = returned_bytes;
2306             ptr[nitems] = (uint16_t) val;
2307         }
2308         else if (type == XA_CARDINAL && format == 32)
2309         {
2310             uint32_t *ptr = returned_bytes;
2311             ptr[nitems] = (uint32_t) val;
2312         }
2313         else
2314         {
2315             free (tmp);
2316             free (returned_bytes);
2317             return NULL;
2318         }
2319
2320         nitems++;
2321     }
2322
2323     free (tmp);
2324
2325     *returned_nitems = nitems;
2326     return returned_bytes;
2327 }
2328
2329
2330 static void
2331 print_output_property_value(Bool is_edid,
2332                             int value_format, /* 8, 16, 32 */
2333                             Atom value_type,  /* XA_{ATOM,INTEGER,CARDINAL} */
2334                             const void *value_bytes)
2335 {
2336     /* special-case the EDID */
2337     if (is_edid && value_format == 8)
2338     {
2339         const uint8_t *val = value_bytes;
2340         printf ("%02" PRIx8, *val);
2341         return;
2342     }
2343
2344     if (value_type == XA_ATOM && value_format == 32)
2345     {
2346         const Atom *val = value_bytes;
2347         char *str = XGetAtomName (dpy, *val);
2348         if (str != NULL)
2349         {
2350             printf ("%s", str);
2351             XFree (str);
2352             return;
2353         }
2354     }
2355
2356     if (value_type == XA_INTEGER)
2357     {
2358         if (value_format == 8)
2359         {
2360             const int8_t *val = value_bytes;
2361             printf ("%" PRId8, *val);
2362             return;
2363         }
2364         if (value_format == 16)
2365         {
2366             const int16_t *val = value_bytes;
2367             printf ("%" PRId16, *val);
2368             return;
2369         }
2370         if (value_format == 32)
2371         {
2372             const int32_t *val = value_bytes;
2373             printf ("%" PRId32, *val);
2374             return;
2375         }
2376     }
2377
2378     if (value_type == XA_CARDINAL)
2379     {
2380         if (value_format == 8)
2381         {
2382             const uint8_t *val = value_bytes;
2383             printf ("%" PRIu8, *val);
2384             return;
2385         }
2386         if (value_format == 16)
2387         {
2388             const uint16_t *val = value_bytes;
2389             printf ("%" PRIu16, *val);
2390             return;
2391         }
2392         if (value_format == 32)
2393         {
2394             const uint32_t *val = value_bytes;
2395             printf ("%" PRIu32, *val);
2396             return;
2397         }
2398     }
2399
2400     printf ("?");
2401 }
2402
2403 static void
2404 get_providers (void)
2405 {
2406     XRRProviderResources *pr;
2407     int i;
2408
2409     if (!has_1_4 || providers)
2410         return;
2411
2412     pr = XRRGetProviderResources(dpy, root);
2413     num_providers = pr->nproviders;
2414     providers = calloc (num_providers, sizeof (provider_t));
2415     if (!providers)
2416         fatal ("out of memory\n");
2417
2418     for (i = 0; i < num_providers; i++) {
2419         provider_t *provider = &providers[i];
2420         name_t *name = &provider->provider;
2421         XRRProviderInfo *info = XRRGetProviderInfo(dpy, res, pr->providers[i]);
2422
2423         provider->info = info;
2424         set_name_xid (name, pr->providers[i]);
2425         set_name_index (name, i);
2426         set_name_string (name, info->name);
2427    }
2428
2429    XRRFreeProviderResources(pr);
2430 }
2431
2432 static provider_t *
2433 find_provider (name_t *name)
2434 {
2435     int i;
2436
2437     for (i = 0; i < num_providers; i++) {
2438         provider_t *p = &providers[i];
2439         name_kind_t common = name->kind & p->provider.kind;
2440
2441         if ((common & name_xid) && name->xid == p->provider.xid)
2442             return p;
2443         if ((common & name_string) && !strcmp (name->string, p->provider.string))
2444             return p;
2445         if ((common & name_index) && name->index == p->provider.index)
2446             return p;
2447     }
2448
2449     printf ("Could not find provider with ");
2450     print_name (name);
2451     printf ("\n");
2452     exit (1);
2453 }
2454
2455
2456 int
2457 main (int argc, char **argv)
2458 {
2459     XRRScreenSize *sizes;
2460     XRRScreenConfiguration *sc;
2461     int         nsize;
2462     int         nrate;
2463     short               *rates;
2464     Status      status = RRSetConfigFailed;
2465     int         rot = -1;
2466     int         query = False;
2467     int         action_requested = False;
2468     Rotation    rotation, current_rotation, rotations;
2469     XEvent      event;
2470     XRRScreenChangeNotifyEvent *sce;    
2471     char          *display_name = NULL;
2472     int                 i, j;
2473     SizeID      current_size;
2474     short       current_rate;
2475     double      rate = -1;
2476     int         size = -1;
2477     int         dirind = 0;
2478     Bool        setit = False;
2479     Bool        version = False;
2480     int         event_base, error_base;
2481     int         reflection = 0;
2482     int         width = 0, height = 0;
2483     Bool        have_pixel_size = False;
2484     int         ret = 0;
2485     output_t    *output = NULL;
2486     Bool        setit_1_2 = False;
2487     Bool        query_1_2 = False;
2488     Bool        modeit = False;
2489     Bool        propit = False;
2490     Bool        query_1 = False;
2491     Bool        list_providers = False;
2492     Bool        provsetoutsource = False;
2493     Bool        provsetoffsink = False;
2494     int         major, minor;
2495     Bool        current = False;
2496
2497     program_name = argv[0];
2498     for (i = 1; i < argc; i++) {
2499         if (!strcmp ("-display", argv[i]) || !strcmp ("-d", argv[i])) {
2500             if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]);
2501             display_name = argv[i];
2502             continue;
2503         }
2504         if (!strcmp("-help", argv[i]) || !strcmp("--help", argv[i])) {
2505             usage();
2506             exit(0);
2507         }
2508         if (!strcmp ("--verbose", argv[i])) {
2509             verbose = True;
2510             continue;
2511         }
2512         if (!strcmp ("--dryrun", argv[i])) {
2513             dryrun = True;
2514             verbose = True;
2515             continue;
2516         }
2517         if (!strcmp ("--nograb", argv[i])) {
2518             grab_server = False;
2519             continue;
2520         }
2521         if (!strcmp("--current", argv[i])) {
2522             current = True;
2523             continue;
2524         }
2525
2526         if (!strcmp ("-s", argv[i]) || !strcmp ("--size", argv[i])) {
2527             if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]);
2528             if (sscanf (argv[i], "%dx%d", &width, &height) == 2) {
2529                 have_pixel_size = True;
2530             } else {
2531                 size = check_strtol(argv[i]);
2532                 if (size < 0) argerr ("--size argument must be nonnegative\n");
2533             }
2534             setit = True;
2535             action_requested = True;
2536             continue;
2537         }
2538
2539         if (!strcmp ("-r", argv[i]) ||
2540             !strcmp ("--rate", argv[i]) ||
2541             !strcmp ("--refresh", argv[i]))
2542         {
2543             if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]);
2544             rate = check_strtod(argv[i]);
2545             setit = True;
2546             if (output)
2547             {
2548                 output->refresh = rate;
2549                 output->changes |= changes_refresh;
2550                 setit_1_2 = True;
2551             }
2552             action_requested = True;
2553             continue;
2554         }
2555
2556         if (!strcmp ("-v", argv[i]) || !strcmp ("--version", argv[i])) {
2557             version = True;
2558             action_requested = True;
2559             continue;
2560         }
2561
2562         if (!strcmp ("-x", argv[i])) {
2563             reflection |= RR_Reflect_X;
2564             setit = True;
2565             action_requested = True;
2566             continue;
2567         }
2568         if (!strcmp ("-y", argv[i])) {
2569             reflection |= RR_Reflect_Y;
2570             setit = True;
2571             action_requested = True;
2572             continue;
2573         }
2574         if (!strcmp ("--screen", argv[i])) {
2575             if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]);
2576             screen = check_strtol(argv[i]);
2577             if (screen < 0) argerr ("--screen argument must be nonnegative\n");
2578             continue;
2579         }
2580         if (!strcmp ("-q", argv[i]) || !strcmp ("--query", argv[i])) {
2581             query = True;
2582             continue;
2583         }
2584         if (!strcmp ("-o", argv[i]) || !strcmp ("--orientation", argv[i])) {
2585             char *endptr;
2586             if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]);
2587             dirind = strtol(argv[i], &endptr, 10);
2588             if (argv[i] == endptr) {
2589                 for (dirind = 0; dirind < 4; dirind++) {
2590                     if (strcmp (direction[dirind], argv[i]) == 0) break;
2591                 }
2592             }
2593             if ((dirind < 0) || (dirind > 3))
2594                 argerr ("%s: invalid argument '%s'\n", argv[i-1], argv[i]);
2595             rot = dirind;
2596             setit = True;
2597             action_requested = True;
2598             continue;
2599         }
2600         if (!strcmp ("--prop", argv[i]) ||
2601             !strcmp ("--props", argv[i]) ||
2602             !strcmp ("--madprops", argv[i]) ||
2603             !strcmp ("--properties", argv[i]))
2604         {
2605             query_1_2 = True;
2606             properties = True;
2607             action_requested = True;
2608             continue;
2609         }
2610         if (!strcmp ("--output", argv[i])) {
2611             if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]);
2612
2613             output = find_output_by_name (argv[i]);
2614             if (!output) {
2615                 output = add_output ();
2616                 set_name (&output->output, argv[i], name_string|name_xid);
2617             }
2618             
2619             setit_1_2 = True;
2620             action_requested = True;
2621             continue;
2622         }
2623         if (!strcmp ("--crtc", argv[i])) {
2624             if (!output) argerr ("%s must be used after --output\n", argv[i]);
2625             if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]);
2626             set_name (&output->crtc, argv[i], name_xid|name_index);
2627             output->changes |= changes_crtc;
2628             continue;
2629         }
2630         if (!strcmp ("--mode", argv[i])) {
2631             if (!output) argerr ("%s must be used after --output\n", argv[i]);
2632             if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]);
2633             set_name (&output->mode, argv[i], name_string|name_xid);
2634             output->changes |= changes_mode;
2635             continue;
2636         }
2637         if (!strcmp ("--preferred", argv[i])) {
2638             if (!output) argerr ("%s must be used after --output\n", argv[i]);
2639             set_name_preferred (&output->mode);
2640             output->changes |= changes_mode;
2641             continue;
2642         }
2643         if (!strcmp ("--pos", argv[i])) {
2644             if (!output) argerr ("%s must be used after --output\n", argv[i]);
2645             if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]);
2646             if (sscanf (argv[i], "%dx%d",
2647                         &output->x, &output->y) != 2)
2648                 argerr ("failed to parse '%s' as a position\n", argv[i]);
2649             output->changes |= changes_position;
2650             continue;
2651         }
2652         if (!strcmp ("--rotation", argv[i]) || !strcmp ("--rotate", argv[i])) {
2653             if (!output) argerr ("%s must be used after --output\n", argv[i]);
2654             if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]);
2655             for (dirind = 0; dirind < 4; dirind++) {
2656                 if (strcmp (direction[dirind], argv[i]) == 0) break;
2657             }
2658             if (dirind == 4)
2659                 argerr ("%s: invalid argument '%s'\n", argv[i-1], argv[i]);
2660             output->rotation &= ~0xf;
2661             output->rotation |= 1 << dirind;
2662             output->changes |= changes_rotation;
2663             continue;
2664         }
2665         if (!strcmp ("--reflect", argv[i]) || !strcmp ("--reflection", argv[i])) {
2666             if (!output) argerr ("%s must be used after --output\n", argv[i]);
2667             if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]);
2668             for (dirind = 0; dirind < 4; dirind++) {
2669                 if (strcmp (reflections[dirind], argv[i]) == 0) break;
2670             }
2671             if (dirind == 4)
2672                 argerr ("%s: invalid argument '%s'\n", argv[i-1], argv[i]);
2673             output->rotation &= ~(RR_Reflect_X|RR_Reflect_Y);
2674             output->rotation |= dirind * RR_Reflect_X;
2675             output->changes |= changes_reflection;
2676             continue;
2677         }
2678         if (!strcmp ("--left-of", argv[i])) {
2679             if (!output) argerr ("%s must be used after --output\n", argv[i]);
2680             if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]);
2681             output->relation = relation_left_of;
2682             output->relative_to = argv[i];
2683             output->changes |= changes_relation;
2684             continue;
2685         }
2686         if (!strcmp ("--right-of", argv[i])) {
2687             if (!output) argerr ("%s must be used after --output\n", argv[i]);
2688             if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]);
2689             output->relation = relation_right_of;
2690             output->relative_to = argv[i];
2691             output->changes |= changes_relation;
2692             continue;
2693         }
2694         if (!strcmp ("--above", argv[i])) {
2695             if (!output) argerr ("%s must be used after --output\n", argv[i]);
2696             if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]);
2697             output->relation = relation_above;
2698             output->relative_to = argv[i];
2699             output->changes |= changes_relation;
2700             continue;
2701         }
2702         if (!strcmp ("--below", argv[i])) {
2703             if (!output) argerr ("%s must be used after --output\n", argv[i]);
2704             if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]);
2705             output->relation = relation_below;
2706             output->relative_to = argv[i];
2707             output->changes |= changes_relation;
2708             continue;
2709         }
2710         if (!strcmp ("--same-as", argv[i])) {
2711             if (!output) argerr ("%s must be used after --output\n", argv[i]);
2712             if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]);
2713             output->relation = relation_same_as;
2714             output->relative_to = argv[i];
2715             output->changes |= changes_relation;
2716             continue;
2717         }
2718         if (!strcmp ("--panning", argv[i])) {
2719             XRRPanning *pan;
2720             if (!output) argerr ("%s must be used after --output\n", argv[i]);
2721             if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]);
2722             pan = &output->panning;
2723             switch (sscanf (argv[i], "%dx%d+%d+%d/%dx%d+%d+%d/%d/%d/%d/%d",
2724                             &pan->width, &pan->height, &pan->left, &pan->top,
2725                             &pan->track_width, &pan->track_height,
2726                             &pan->track_left, &pan->track_top,
2727                             &pan->border_left, &pan->border_top,
2728                             &pan->border_right, &pan->border_bottom)) {
2729             case 2:
2730                 pan->left = pan->top = 0;
2731                 /* fall through */
2732             case 4:
2733                 pan->track_left = pan->track_top =
2734                     pan->track_width = pan->track_height = 0;
2735                 /* fall through */
2736             case 8:
2737                 pan->border_left = pan->border_top =
2738                     pan->border_right = pan->border_bottom = 0;
2739                 /* fall through */
2740             case 12:
2741                 break;
2742             default:
2743                 argerr ("%s: invalid argument '%s'\n", argv[i-1], argv[i]);
2744             }
2745             output->changes |= changes_panning;
2746             continue;
2747         }
2748         if (!strcmp ("--gamma", argv[i])) {
2749             if (!output) argerr ("%s must be used after --output\n", argv[i]);
2750             if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]);
2751             if (sscanf(argv[i], "%f:%f:%f", &output->gamma.red, 
2752                     &output->gamma.green, &output->gamma.blue) != 3)
2753                 argerr ("%s: invalid argument '%s'\n", argv[i-1], argv[i]);
2754             output->changes |= changes_gamma;
2755             setit_1_2 = True;
2756             continue;
2757         }
2758         if (!strcmp ("--brightness", argv[i])) {
2759             if (!output) argerr ("%s must be used after --output\n", argv[i]);
2760             if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]);
2761             if (sscanf(argv[i], "%f", &output->brightness) != 1)
2762                 argerr ("%s: invalid argument '%s'\n", argv[i-1], argv[i]);
2763             output->changes |= changes_gamma;
2764             setit_1_2 = True;
2765             continue;
2766         }
2767         if (!strcmp ("--primary", argv[i])) {
2768             if (!output) argerr ("%s must be used after --output\n", argv[i]);
2769             output->changes |= changes_primary;
2770             output->primary = True;
2771             setit_1_2 = True;
2772             continue;
2773         }
2774         if (!strcmp ("--noprimary", argv[i])) {
2775             no_primary = True;
2776             setit_1_2 = True;
2777             continue;
2778         }
2779         if (!strcmp ("--set", argv[i])) {
2780             output_prop_t   *prop;
2781             if (!output) argerr ("%s must be used after --output\n", argv[i]);
2782             if (i+2 >= argc) argerr ("%s requires two arguments\n", argv[i]);
2783             prop = malloc (sizeof (output_prop_t));
2784             prop->next = output->props;
2785             output->props = prop;
2786             prop->name = argv[++i];
2787             prop->value = argv[++i];
2788             propit = True;
2789             output->changes |= changes_property;
2790             setit_1_2 = True;
2791             continue;
2792         }
2793         if (!strcmp ("--scale", argv[i]))
2794         {
2795             double  sx, sy;
2796             if (!output) argerr ("%s must be used after --output\n", argv[i]);
2797             if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]);
2798             if (sscanf (argv[i], "%lfx%lf", &sx, &sy) != 2)
2799                 argerr ("failed to parse '%s' as a scaling factor\n", argv[i]);
2800             init_transform (&output->transform);
2801             output->transform.transform.matrix[0][0] = XDoubleToFixed (sx);
2802             output->transform.transform.matrix[1][1] = XDoubleToFixed (sy);
2803             output->transform.transform.matrix[2][2] = XDoubleToFixed (1.0);
2804             if (sx != 1 || sy != 1)
2805                 output->transform.filter = "bilinear";
2806             else
2807                 output->transform.filter = "nearest";
2808             output->transform.nparams = 0;
2809             output->transform.params = NULL;
2810             output->changes |= changes_transform;
2811             continue;
2812         }
2813         if (!strcmp ("--scale-from", argv[i]))
2814         {
2815             int w, h;
2816             if (!output) argerr ("%s must be used after --output\n", argv[i]);
2817             if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]);
2818             if (sscanf (argv[i], "%dx%d", &w, &h) != 2)
2819                 argerr ("failed to parse '%s' as a scale-from size\n", argv[i]);
2820             if (w <=0 || h <= 0)
2821                 argerr ("--scale-from dimensions must be nonnegative\n");
2822             output->scale_from_w = w;
2823             output->scale_from_h = h;
2824             output->changes |= changes_transform;
2825             continue;
2826         }
2827         if (!strcmp ("--transform", argv[i])) {
2828             double  transform[3][3];
2829             int     k, l;
2830             if (!output) argerr ("%s must be used after --output\n", argv[i]);
2831             if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]);
2832             init_transform (&output->transform);
2833             if (strcmp (argv[i], "none") != 0)
2834             {
2835                 if (sscanf(argv[i], "%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf",
2836                            &transform[0][0],&transform[0][1],&transform[0][2],
2837                            &transform[1][0],&transform[1][1],&transform[1][2],
2838                            &transform[2][0],&transform[2][1],&transform[2][2])
2839                     != 9)
2840                     argerr ("failed to parse '%s' as a transformation\n", argv[i]);
2841                 init_transform (&output->transform);
2842                 for (k = 0; k < 3; k++)
2843                     for (l = 0; l < 3; l++) {
2844                         output->transform.transform.matrix[k][l] = XDoubleToFixed (transform[k][l]);
2845                     }
2846                 output->transform.filter = "bilinear";
2847                 output->transform.nparams = 0;
2848                 output->transform.params = NULL;
2849             }
2850             output->changes |= changes_transform;
2851             continue;
2852         }
2853         if (!strcmp ("--off", argv[i])) {
2854             if (!output) argerr ("%s must be used after --output\n", argv[i]);
2855             set_name_xid (&output->mode, None);
2856             set_name_xid (&output->crtc, None);
2857             output->changes |= changes_mode;
2858             continue;
2859         }
2860         if (!strcmp ("--fb", argv[i])) {
2861             if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]);
2862             if (sscanf (argv[i], "%dx%d",
2863                         &fb_width, &fb_height) != 2)
2864                 argerr ("failed to parse '%s' as a framebuffer size\n", argv[i]);
2865             setit_1_2 = True;
2866             action_requested = True;
2867             continue;
2868         }
2869         if (!strcmp ("--fbmm", argv[i])) {
2870             if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]);
2871             if (sscanf (argv[i], "%dx%d",
2872                         &fb_width_mm, &fb_height_mm) != 2)
2873                 argerr ("failed to parse '%s' as a physical size\n", argv[i]);
2874             setit_1_2 = True;
2875             action_requested = True;
2876             continue;
2877         }
2878         if (!strcmp ("--dpi", argv[i])) {
2879             char *strtod_error;
2880             if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]);
2881             dpi = strtod(argv[i], &strtod_error);
2882             if (argv[i] == strtod_error)
2883             {
2884                 dpi = 0.0;
2885                 dpi_output = argv[i];
2886             }
2887             setit_1_2 = True;
2888             action_requested = True;
2889             continue;
2890         }
2891         if (!strcmp ("--auto", argv[i])) {
2892             if (output)
2893             {
2894                 output->automatic = True;
2895                 output->changes |= changes_automatic;
2896             }
2897             else
2898                 automatic = True;
2899             setit_1_2 = True;
2900             action_requested = True;
2901             continue;
2902         }
2903         if (!strcmp ("--q12", argv[i]))
2904         {
2905             query_1_2 = True;
2906             continue;
2907         }
2908         if (!strcmp ("--q1", argv[i]))
2909         {
2910             query_1 = True;
2911             continue;
2912         }
2913         if (!strcmp ("--newmode", argv[i]))
2914         {
2915             umode_t  *m = malloc (sizeof (umode_t));
2916             double    clock;
2917             
2918             ++i;
2919             if (i + 9 >= argc)
2920                 argerr ("failed to parse '%s' as a mode specification\n", argv[i]);
2921             m->mode.name = argv[i];
2922             m->mode.nameLength = strlen (argv[i]);
2923             i++;
2924             clock = check_strtod(argv[i++]);
2925             m->mode.dotClock = clock * 1e6;
2926
2927             m->mode.width = check_strtol(argv[i++]);
2928             m->mode.hSyncStart = check_strtol(argv[i++]);
2929             m->mode.hSyncEnd = check_strtol(argv[i++]);
2930             m->mode.hTotal = check_strtol(argv[i++]);
2931             m->mode.height = check_strtol(argv[i++]);
2932             m->mode.vSyncStart = check_strtol(argv[i++]);
2933             m->mode.vSyncEnd = check_strtol(argv[i++]);
2934             m->mode.vTotal = check_strtol(argv[i++]);
2935             m->mode.modeFlags = 0;
2936             while (i < argc) {
2937                 int f;
2938                 
2939                 for (f = 0; mode_flags[f].string; f++)
2940                     if (!strcasecmp (mode_flags[f].string, argv[i]))
2941                         break;
2942                 
2943                 if (!mode_flags[f].string)
2944                     break;
2945                 m->mode.modeFlags |= mode_flags[f].flag;
2946                 i++;
2947             }
2948             m->next = umodes;
2949             m->action = umode_create;
2950             umodes = m;
2951             modeit = True;
2952             action_requested = True;
2953             continue;
2954         }
2955         if (!strcmp ("--rmmode", argv[i]))
2956         {
2957             umode_t  *m = malloc (sizeof (umode_t));
2958
2959             if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]);
2960             set_name (&m->name, argv[i], name_string|name_xid);
2961             m->action = umode_destroy;
2962             m->next = umodes;
2963             umodes = m;
2964             modeit = True;
2965             action_requested = True;
2966             continue;
2967         }
2968         if (!strcmp ("--addmode", argv[i]))
2969         {
2970             umode_t  *m = malloc (sizeof (umode_t));
2971
2972             if (i+2 >= argc) argerr ("%s requires two arguments\n", argv[i]);
2973             set_name (&m->output, argv[++i], name_string|name_xid);
2974             set_name (&m->name, argv[++i], name_string|name_xid);
2975             m->action = umode_add;
2976             m->next = umodes;
2977             umodes = m;
2978             modeit = True;
2979             action_requested = True;
2980             continue;
2981         }
2982         if (!strcmp ("--delmode", argv[i]))
2983         {
2984             umode_t  *m = malloc (sizeof (umode_t));
2985
2986             if (i+2 >= argc) argerr ("%s requires two arguments\n", argv[i]);
2987             set_name (&m->output, argv[++i], name_string|name_xid);
2988             set_name (&m->name, argv[++i], name_string|name_xid);
2989             m->action = umode_delete;
2990             m->next = umodes;
2991             umodes = m;
2992             modeit = True;
2993             action_requested = True;
2994             continue;
2995         }
2996         if (!strcmp ("--listproviders", argv[i]))
2997         {
2998             list_providers = True;
2999             action_requested = True;
3000             continue;
3001         }
3002         if (!strcmp("--setprovideroutputsource", argv[i]))
3003         { 
3004             if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]);
3005             set_name (&provider_name, argv[i], name_string|name_xid|name_index);
3006             if (++i>=argc) 
3007                 set_name_xid (&output_source_provider_name, 0);
3008             else
3009                 set_name (&output_source_provider_name, argv[i], name_string|name_xid|name_index);
3010             action_requested = True;
3011             provsetoutsource = True;
3012             continue;
3013         }
3014         if (!strcmp("--setprovideroffloadsink", argv[i]))
3015         { 
3016             if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]);
3017             set_name (&provider_name, argv[i], name_string|name_xid|name_index);
3018             if (++i>=argc) 
3019                 set_name_xid (&offload_sink_provider_name, 0);
3020             else
3021                 set_name (&offload_sink_provider_name, argv[i], name_string|name_xid|name_index);
3022             action_requested = True;
3023             provsetoffsink = True;
3024             continue;
3025         }
3026
3027         argerr ("unrecognized option '%s'\n", argv[i]);
3028     }
3029     if (!action_requested)
3030             query = True;
3031     if (verbose) 
3032     {
3033         query = True;
3034         if (setit && !setit_1_2)
3035             query_1 = True;
3036     }
3037     if (version)
3038         printf("xrandr program version       " VERSION "\n");
3039
3040     dpy = XOpenDisplay (display_name);
3041
3042     if (dpy == NULL) {
3043         fprintf (stderr, "Can't open display %s\n", XDisplayName(display_name));
3044         exit (1);
3045     }
3046     if (screen < 0)
3047         screen = DefaultScreen (dpy);
3048     if (screen >= ScreenCount (dpy)) {
3049         fprintf (stderr, "Invalid screen number %d (display has %d)\n",
3050                  screen, ScreenCount (dpy));
3051         exit (1);
3052     }
3053
3054     root = RootWindow (dpy, screen);
3055
3056     if (!XRRQueryExtension (dpy, &event_base, &error_base) ||
3057         !XRRQueryVersion (dpy, &major, &minor))
3058     {
3059         fprintf (stderr, "RandR extension missing\n");
3060         exit (1);
3061     }
3062     if (major > 1 || (major == 1 && minor >= 2))
3063         has_1_2 = True;
3064     if (major > 1 || (major == 1 && minor >= 3))
3065         has_1_3 = True;
3066     if (major > 1 || (major == 1 && minor >= 4))
3067         has_1_4 = True;
3068         
3069     if (has_1_2 && modeit)
3070     {
3071         umode_t *m;
3072
3073         get_screen (current);
3074         get_crtcs();
3075         get_outputs();
3076         
3077         for (m = umodes; m; m = m->next)
3078         {
3079             XRRModeInfo *e;
3080             output_t    *o;
3081             
3082             switch (m->action) {
3083             case umode_create:
3084                 XRRCreateMode (dpy, root, &m->mode);
3085                 break;
3086             case umode_destroy:
3087                 e = find_mode (&m->name, 0);
3088                 if (!e)
3089                     fatal ("cannot find mode \"%s\"\n", m->name.string);
3090                 XRRDestroyMode (dpy, e->id);
3091                 break;
3092             case umode_add:
3093                 o = find_output (&m->output);
3094                 if (!o)
3095                     fatal ("cannot find output \"%s\"\n", m->output.string);
3096                 e = find_mode (&m->name, 0);
3097                 if (!e)
3098                     fatal ("cannot find mode \"%s\"\n", m->name.string);
3099                 XRRAddOutputMode (dpy, o->output.xid, e->id);
3100                 break;
3101             case umode_delete:
3102                 o = find_output (&m->output);
3103                 if (!o)
3104                     fatal ("cannot find output \"%s\"\n", m->output.string);
3105                 e = find_mode (&m->name, 0);
3106                 if (!e)
3107                     fatal ("cannot find mode \"%s\"\n", m->name.string);
3108                 XRRDeleteOutputMode (dpy, o->output.xid, e->id);
3109                 break;
3110             }
3111         }
3112         if (!setit_1_2)
3113         {
3114             XSync (dpy, False);
3115             exit (0);
3116         }
3117     }
3118     if (has_1_2 && propit)
3119     {
3120         
3121         get_screen (current);
3122         get_crtcs();
3123         get_outputs();
3124         
3125         for (output = outputs; output; output = output->next)
3126         {
3127             output_prop_t   *prop;
3128
3129             for (prop = output->props; prop; prop = prop->next)
3130             {
3131                 Atom            name = XInternAtom (dpy, prop->name, False);
3132                 Atom            type;
3133                 int             format = 0;
3134                 unsigned char   *data, *malloced_data = NULL;
3135                 int             nelements;
3136                 int             int_value;
3137                 unsigned long   ulong_value;
3138                 unsigned char   *prop_data;
3139                 int             actual_format;
3140                 unsigned long   nitems, bytes_after;
3141                 Atom            actual_type;
3142                 XRRPropertyInfo *propinfo;
3143
3144                 type = AnyPropertyType;
3145                 
3146                 if (XRRGetOutputProperty (dpy, output->output.xid, name,
3147                                           0, 100, False, False,
3148                                           AnyPropertyType,
3149                                           &actual_type, &actual_format,
3150                                           &nitems, &bytes_after, &prop_data) == Success &&
3151
3152                     (propinfo = XRRQueryOutputProperty(dpy, output->output.xid,
3153                                                       name)))
3154                 {
3155                     type = actual_type;
3156                     format = actual_format;
3157                 }
3158
3159                 malloced_data = property_values_from_string
3160                     (prop->value, type, actual_format, &nelements);
3161
3162                 if (malloced_data)
3163                 {
3164                     data = malloced_data;
3165                     type = actual_type;
3166                     format = actual_format;
3167                 }
3168                 else if (type == AnyPropertyType &&
3169                     (sscanf (prop->value, "%d", &int_value) == 1 ||
3170                      sscanf (prop->value, "0x%x", &int_value) == 1))
3171                 {
3172                     type = XA_INTEGER;
3173                     ulong_value = int_value;
3174                     data = (unsigned char *) &ulong_value;
3175                     nelements = 1;
3176                     format = 32;
3177                 }
3178                 else if ((type == XA_ATOM))
3179                 {
3180                     ulong_value = XInternAtom (dpy, prop->value, False);
3181                     data = (unsigned char *) &ulong_value;
3182                     nelements = 1;
3183                 }
3184                 else if ((type == XA_STRING || type == AnyPropertyType))
3185                 {
3186                     type = XA_STRING;
3187                     data = (unsigned char *) prop->value;
3188                     nelements = strlen (prop->value);
3189                     format = 8;
3190                 }
3191                 else
3192                     continue;
3193                 XRRChangeOutputProperty (dpy, output->output.xid,
3194                                          name, type, format, PropModeReplace,
3195                                          data, nelements);
3196                 free (malloced_data);
3197             }
3198         }
3199         if (!setit_1_2)
3200         {
3201             XSync (dpy, False);
3202             exit (0);
3203         }
3204     }
3205     if (provsetoutsource)
3206     {
3207         provider_t *provider, *source;
3208
3209         if (!has_1_4)
3210             fatal ("--setprovideroutputsource requires RandR 1.4\n");
3211
3212         get_screen (current);
3213         get_providers ();
3214
3215         provider = find_provider (&provider_name);
3216         source = find_provider(&output_source_provider_name);
3217
3218         XRRSetProviderOutputSource(dpy, provider->provider.xid, source->provider.xid);
3219     }
3220     if (provsetoffsink)
3221     {
3222         provider_t *provider, *sink;
3223
3224         if (!has_1_4)
3225             fatal ("--setprovideroffloadsink requires RandR 1.4\n");
3226
3227         get_screen (current);
3228         get_providers ();
3229
3230         provider = find_provider (&provider_name);
3231         sink = find_provider(&offload_sink_provider_name);
3232
3233         XRRSetProviderOffloadSink(dpy, provider->provider.xid, sink->provider.xid);
3234     }
3235     if (setit_1_2)
3236     {
3237         get_screen (current);
3238         get_crtcs ();
3239         get_outputs ();
3240         set_positions ();
3241         set_screen_size ();
3242
3243         pick_crtcs ();
3244
3245         /*
3246          * Assign outputs to crtcs
3247          */
3248         set_crtcs ();
3249         
3250         /*
3251          * Mark changing crtcs
3252          */
3253         mark_changing_crtcs ();
3254
3255         /*
3256          * If an output was specified to track dpi, use it
3257          */
3258         if (dpi_output)
3259         {
3260             output_t    *output = find_output_by_name (dpi_output);
3261             XRROutputInfo       *output_info;
3262             XRRModeInfo *mode_info;
3263             if (!output)
3264                 fatal ("Cannot find output %s\n", dpi_output);
3265             output_info = output->output_info;
3266             mode_info = output->mode_info;
3267             if (output_info && mode_info && output_info->mm_height)
3268             {
3269                 /*
3270                  * When this output covers the whole screen, just use
3271                  * the known physical size
3272                  */
3273                 if (fb_width == mode_info->width &&
3274                     fb_height == mode_info->height)
3275                 {
3276                     fb_width_mm = output_info->mm_width;
3277                     fb_height_mm = output_info->mm_height;
3278                 }
3279                 else
3280                 {
3281                     dpi = (25.4 * mode_info->height) / output_info->mm_height;
3282                 }
3283             }
3284         }
3285
3286         /*
3287          * Compute physical screen size
3288          */
3289         if (fb_width_mm == 0 || fb_height_mm == 0)
3290         {
3291             if (fb_width != DisplayWidth (dpy, screen) ||
3292                 fb_height != DisplayHeight (dpy, screen) || dpi != 0.0)
3293             {
3294                 if (dpi <= 0)
3295                     dpi = (25.4 * DisplayHeight (dpy, screen)) / DisplayHeightMM(dpy, screen);
3296
3297                 fb_width_mm = (25.4 * fb_width) / dpi;
3298                 fb_height_mm = (25.4 * fb_height) / dpi;
3299             }
3300             else
3301             {
3302                 fb_width_mm = DisplayWidthMM (dpy, screen);
3303                 fb_height_mm = DisplayHeightMM (dpy, screen);
3304             }
3305         }
3306         
3307         /*
3308          * Set panning
3309          */
3310         set_panning ();
3311
3312         /* 
3313          * Set gamma on crtc's that belong to the outputs.
3314          */
3315         set_gamma ();
3316
3317         /*
3318          * Now apply all of the changes
3319          */
3320         apply ();
3321         
3322         XSync (dpy, False);
3323         exit (0);
3324     }
3325     if (query_1_2 || (query && has_1_2 && !query_1))
3326     {
3327         output_t    *output;
3328         int         m;
3329         
3330 #define ModeShown   0x80000000
3331         
3332         get_screen (current);
3333         get_crtcs ();
3334         get_outputs ();
3335
3336         printf ("Screen %d: minimum %d x %d, current %d x %d, maximum %d x %d\n",
3337                 screen, minWidth, minHeight,
3338                 DisplayWidth (dpy, screen), DisplayHeight(dpy, screen),
3339                 maxWidth, maxHeight);
3340
3341         for (output = outputs; output; output = output->next)
3342         {
3343             XRROutputInfo   *output_info = output->output_info;
3344             crtc_t          *crtc = output->crtc_info;
3345             XRRCrtcInfo     *crtc_info = crtc ? crtc->crtc_info : NULL;
3346             XRRModeInfo     *mode = output->mode_info;
3347             Atom            *props;
3348             int             j, k, nprop;
3349             Bool            *mode_shown;
3350             Rotation        rotations = output_rotations (output);
3351
3352             printf ("%s %s", output_info->name, connection[output_info->connection]);
3353             if (output->primary) {
3354                 printf(" primary");
3355             }
3356             if (mode)
3357             {
3358                 if (crtc_info) {
3359                     printf (" %dx%d+%d+%d",
3360                             crtc_info->width, crtc_info->height,
3361                             crtc_info->x, crtc_info->y);
3362                 } else {
3363                     printf (" %dx%d+%d+%d",
3364                             mode->width, mode->height, output->x, output->y);
3365                 }
3366                 if (verbose)
3367                     printf (" (0x%x)", (int)mode->id);
3368                 if (output->rotation != RR_Rotate_0 || verbose)
3369                 {
3370                     printf (" %s", 
3371                             rotation_name (output->rotation));
3372                     if (output->rotation & (RR_Reflect_X|RR_Reflect_Y))
3373                         printf (" %s", reflection_name (output->rotation));
3374                 }
3375             }
3376             if (rotations != RR_Rotate_0 || verbose)
3377             {
3378                 Bool    first = True;
3379                 printf (" (");
3380                 for (i = 0; i < 4; i ++) {
3381                     if ((rotations >> i) & 1) {
3382                         if (!first) printf (" "); first = False;
3383                         printf("%s", direction[i]);
3384                     }
3385                 }
3386                 if (rotations & RR_Reflect_X)
3387                 {
3388                     if (!first) printf (" "); first = False;
3389                     printf ("x axis");
3390                 }
3391                 if (rotations & RR_Reflect_Y)
3392                 {
3393                     if (!first) printf (" ");
3394                     printf ("y axis");
3395                 }
3396                 printf (")");
3397             }
3398
3399             if (mode)
3400             {
3401                 printf (" %dmm x %dmm",
3402                         (int)output_info->mm_width, (int)output_info->mm_height);
3403             }
3404
3405             if (crtc && crtc->panning_info && crtc->panning_info->width > 0)
3406             {
3407                 XRRPanning *pan = crtc->panning_info;
3408                 printf (" panning %dx%d+%d+%d",
3409                         pan->width, pan->height, pan->left, pan->top);
3410                 if ((pan->track_width    != 0 &&
3411                      (pan->track_left    != pan->left           ||
3412                       pan->track_width   != pan->width          ||
3413                       pan->border_left   != 0                   ||
3414                       pan->border_right  != 0))                 ||
3415                     (pan->track_height   != 0 &&
3416                      (pan->track_top     != pan->top            ||
3417                       pan->track_height  != pan->height         ||
3418                       pan->border_top    != 0                   ||
3419                       pan->border_bottom != 0)))
3420                     printf (" tracking %dx%d+%d+%d border %d/%d/%d/%d",
3421                             pan->track_width,  pan->track_height,
3422                             pan->track_left,   pan->track_top,
3423                             pan->border_left,  pan->border_top,
3424                             pan->border_right, pan->border_bottom);
3425             }
3426             printf ("\n");
3427
3428             if (verbose)
3429             {
3430                 printf ("\tIdentifier: 0x%x\n", (int)output->output.xid);
3431                 printf ("\tTimestamp:  %d\n", (int)output_info->timestamp);
3432                 printf ("\tSubpixel:   %s\n", order[output_info->subpixel_order]);
3433                 if (output->gamma.red != 0.0 && output->gamma.green != 0.0 && output->gamma.blue != 0.0) {
3434                     printf ("\tGamma:      %#.2g:%#.2g:%#.2g\n",
3435                             output->gamma.red, output->gamma.green, output->gamma.blue);
3436                     printf ("\tBrightness: %#.2g\n", output->brightness);
3437                 }
3438                 printf ("\tClones:    ");
3439                 for (j = 0; j < output_info->nclone; j++)
3440                 {
3441                     output_t    *clone = find_output_by_xid (output_info->clones[j]);
3442
3443                     if (clone) printf (" %s", clone->output.string);
3444                 }
3445                 printf ("\n");
3446                 if (output->crtc_info)
3447                     printf ("\tCRTC:       %d\n", output->crtc_info->crtc.index);
3448                 printf ("\tCRTCs:     ");
3449                 for (j = 0; j < output_info->ncrtc; j++)
3450                 {
3451                     crtc_t      *crtc = find_crtc_by_xid (output_info->crtcs[j]);
3452                     if (crtc)
3453                         printf (" %d", crtc->crtc.index);
3454                 }
3455                 printf ("\n");
3456                 if (output->crtc_info && output->crtc_info->panning_info) {
3457                     XRRPanning *pan = output->crtc_info->panning_info;
3458                     printf ("\tPanning:    %dx%d+%d+%d\n",
3459                             pan->width, pan->height, pan->left, pan->top);
3460                     printf ("\tTracking:   %dx%d+%d+%d\n",
3461                             pan->track_width,  pan->track_height,
3462                             pan->track_left,   pan->track_top);
3463                     printf ("\tBorder:     %d/%d/%d/%d\n",
3464                             pan->border_left,  pan->border_top,
3465                             pan->border_right, pan->border_bottom);
3466                 }
3467             }
3468             if (verbose)
3469             {
3470                 int x, y;
3471
3472                 printf ("\tTransform: ");
3473                 for (y = 0; y < 3; y++)
3474                 {
3475                     for (x = 0; x < 3; x++)
3476                         printf (" %f", XFixedToDouble (output->transform.transform.matrix[y][x]));
3477                     if (y < 2)
3478                         printf ("\n\t           ");
3479                 }
3480                 if (output->transform.filter)
3481                     printf ("\n\t           filter: %s", output->transform.filter);
3482                 printf ("\n");
3483             }
3484             if (verbose || properties)
3485             {
3486                 props = XRRListOutputProperties (dpy, output->output.xid,
3487                                                  &nprop);
3488                 for (j = 0; j < nprop; j++) {
3489                     unsigned char *prop;
3490                     int actual_format;
3491                     unsigned long nitems, bytes_after;
3492                     Atom actual_type;
3493                     XRRPropertyInfo *propinfo;
3494                     char *atom_name = XGetAtomName (dpy, props[j]);
3495                     Bool is_edid = strcmp (atom_name, "EDID") == 0;
3496                     int bytes_per_item;
3497
3498                     XRRGetOutputProperty (dpy, output->output.xid, props[j],
3499                                           0, 100, False, False,
3500                                           AnyPropertyType,
3501                                           &actual_type, &actual_format,
3502                                           &nitems, &bytes_after, &prop);
3503
3504                     propinfo = XRRQueryOutputProperty(dpy, output->output.xid,
3505                                                       props[j]);
3506
3507                     bytes_per_item = actual_format / 8;
3508
3509                     printf ("\t%s: ", atom_name);
3510
3511                     if (is_edid)
3512                     {
3513                         printf ("\n\t\t");
3514                     }
3515
3516                     for (k = 0; k < nitems; k++)
3517                     {
3518                         if (k != 0)
3519                         {
3520                             if ((k % 16) == 0)
3521                             {
3522                                 printf ("\n\t\t");
3523                             }
3524                         }
3525                         print_output_property_value (is_edid, actual_format,
3526                                                      actual_type,
3527                                                      prop + (k * bytes_per_item));
3528                         if (!is_edid)
3529                         {
3530                             printf (" ");
3531                         }
3532                     }
3533                     printf ("\n");
3534
3535                     if (propinfo->range && propinfo->num_values > 0)
3536                     {
3537                         printf ("\t\trange%s: ",
3538                                 (propinfo->num_values == 2) ? "" : "s");
3539                         for (k = 0; k < propinfo->num_values / 2; k++)
3540                         {
3541                             printf ("(");
3542                             print_output_property_value (False, 32, actual_type,
3543                                                          (unsigned char *) &(propinfo->values[k * 2]));
3544                             printf (", ");
3545                             print_output_property_value (False, 32, actual_type,
3546                                                          (unsigned char *) &(propinfo->values[k * 2 + 1]));
3547                             printf (")");
3548                         }
3549                         printf ("\n");
3550                     }
3551                     if (!propinfo->range && propinfo->num_values > 0)
3552                     {
3553                         printf ("\t\tsupported: ");
3554                         for (k = 0; k < propinfo->num_values; k++)
3555                         {
3556                             print_output_property_value (False, 32, actual_type,
3557                                                          (unsigned char *) &(propinfo->values[k]));
3558                         }
3559                         printf ("\n");
3560                     }
3561
3562                     free(propinfo);
3563                 }
3564             }
3565
3566             if (verbose)
3567             {
3568                 for (j = 0; j < output_info->nmode; j++)
3569                 {
3570                     XRRModeInfo *mode = find_mode_by_xid (output_info->modes[j]);
3571                     int         f;
3572                     
3573                     printf ("  %s (0x%x) %6.1fMHz",
3574                             mode->name, (int)mode->id,
3575                             (double)mode->dotClock / 1000000.0);
3576                     for (f = 0; mode_flags[f].flag; f++)
3577                         if (mode->modeFlags & mode_flags[f].flag)
3578                             printf (" %s", mode_flags[f].string);
3579                     if (mode == output->mode_info)
3580                         printf (" *current");
3581                     if (j < output_info->npreferred)
3582                         printf (" +preferred");
3583                     printf ("\n");
3584                     printf ("        h: width  %4d start %4d end %4d total %4d skew %4d clock %6.1fKHz\n",
3585                             mode->width, mode->hSyncStart, mode->hSyncEnd,
3586                             mode->hTotal, mode->hSkew, mode_hsync (mode) / 1000);
3587                     printf ("        v: height %4d start %4d end %4d total %4d           clock %6.1fHz\n",
3588                             mode->height, mode->vSyncStart, mode->vSyncEnd, mode->vTotal,
3589                             mode_refresh (mode));
3590                     mode->modeFlags |= ModeShown;
3591                 }
3592             }
3593             else
3594             {
3595                 mode_shown = calloc (output_info->nmode, sizeof (Bool));
3596                 if (!mode_shown) fatal ("out of memory\n");
3597                 for (j = 0; j < output_info->nmode; j++)
3598                 {
3599                     XRRModeInfo *jmode, *kmode;
3600                     
3601                     if (mode_shown[j]) continue;
3602     
3603                     jmode = find_mode_by_xid (output_info->modes[j]);
3604                     printf (" ");
3605                     printf ("  %-12s", jmode->name);
3606                     for (k = j; k < output_info->nmode; k++)
3607                     {
3608                         if (mode_shown[k]) continue;
3609                         kmode = find_mode_by_xid (output_info->modes[k]);
3610                         if (strcmp (jmode->name, kmode->name) != 0) continue;
3611                         mode_shown[k] = True;
3612                         kmode->modeFlags |= ModeShown;
3613                         printf (" %6.1f", mode_refresh (kmode));
3614                         if (kmode == output->mode_info)
3615                             printf ("*");
3616                         else
3617                             printf (" ");
3618                         if (k < output_info->npreferred)
3619                             printf ("+");
3620                         else
3621                             printf (" ");
3622                     }
3623                     printf ("\n");
3624                 }
3625                 free (mode_shown);
3626             }
3627         }
3628         for (m = 0; m < res->nmode; m++)
3629         {
3630             XRRModeInfo *mode = &res->modes[m];
3631
3632             if (!(mode->modeFlags & ModeShown))
3633             {
3634                 printf ("  %s (0x%x) %6.1fMHz\n",
3635                         mode->name, (int)mode->id,
3636                         (double)mode->dotClock / 1000000.0);
3637                 printf ("        h: width  %4d start %4d end %4d total %4d skew %4d clock %6.1fKHz\n",
3638                         mode->width, mode->hSyncStart, mode->hSyncEnd,
3639                         mode->hTotal, mode->hSkew, mode_hsync (mode) / 1000);
3640                 printf ("        v: height %4d start %4d end %4d total %4d           clock %6.1fHz\n",
3641                         mode->height, mode->vSyncStart, mode->vSyncEnd, mode->vTotal,
3642                         mode_refresh (mode));
3643             }
3644         }
3645         exit (0);
3646     }
3647     if (list_providers) {
3648         int k;
3649
3650         if (!has_1_4) {
3651             printf ("RandR 1.4 not supported\n");
3652             exit (0);
3653         }
3654
3655         get_screen (current);
3656         get_providers ();
3657
3658         if (providers) {
3659             printf("Providers: number : %d\n", num_providers);
3660
3661             for (j = 0; j < num_providers; j++) {
3662                 provider_t *provider = &providers[j];
3663                 XRRProviderInfo *info = provider->info;
3664
3665                 printf("Provider %d: id: 0x%x cap: 0x%x", j, (int)provider->provider.xid, info->capabilities);
3666                 for (k = 0; k < 4; k++)
3667                         if (info->capabilities & (1 << k))
3668                                 printf(", %s", capability_name(1<<k));
3669
3670                 printf(" crtcs: %d outputs: %d associated providers: %d name:%s\n", info->ncrtcs, info->noutputs, info->nassociatedproviders, info->name);
3671             }
3672         }
3673     }
3674
3675     sc = XRRGetScreenInfo (dpy, root);
3676
3677     if (sc == NULL) 
3678         exit (1);
3679
3680     current_size = XRRConfigCurrentConfiguration (sc, &current_rotation);
3681
3682     sizes = XRRConfigSizes(sc, &nsize);
3683
3684     if (have_pixel_size) {
3685         for (size = 0; size < nsize; size++)
3686         {
3687             if (sizes[size].width == width && sizes[size].height == height)
3688                 break;
3689         }
3690         if (size >= nsize) {
3691             fprintf (stderr,
3692                      "Size %dx%d not found in available modes\n", width, height);
3693             exit (1);
3694         }
3695     }
3696     else if (size < 0)
3697         size = current_size;
3698     else if (size >= nsize) {
3699         fprintf (stderr,
3700                  "Size index %d is too large, there are only %d sizes\n",
3701                  size, nsize);
3702         exit (1);
3703     }
3704
3705     if (rot < 0)
3706     {
3707         for (rot = 0; rot < 4; rot++)
3708             if (1 << rot == (current_rotation & 0xf))
3709                 break;
3710     }
3711
3712     current_rate = XRRConfigCurrentRate (sc);
3713
3714     if (rate < 0)
3715     {
3716         if (size == current_size)
3717             rate = current_rate;
3718         else
3719             rate = 0;
3720     }
3721     else
3722     {
3723         rates = XRRConfigRates (sc, size, &nrate);
3724         for (i = 0; i < nrate; i++)
3725             if (rate == rates[i])
3726                 break;
3727         if (i == nrate) {
3728             fprintf (stderr, "Rate %.1f Hz not available for this size\n", rate);
3729             exit (1);
3730         }
3731     }
3732
3733     if (version) {
3734         int major_version, minor_version;
3735         XRRQueryVersion (dpy, &major_version, &minor_version);
3736         printf("Server reports RandR version %d.%d\n", 
3737                major_version, minor_version);
3738     }
3739
3740     if (query || query_1) {
3741         printf(" SZ:    Pixels          Physical       Refresh\n");
3742         for (i = 0; i < nsize; i++) {
3743             printf ("%c%-2d %5d x %-5d  (%4dmm x%4dmm )",
3744                     i == current_size ? '*' : ' ',
3745                     i, sizes[i].width, sizes[i].height,
3746                     sizes[i].mwidth, sizes[i].mheight);
3747             rates = XRRConfigRates (sc, i, &nrate);
3748             if (nrate) printf ("  ");
3749             for (j = 0; j < nrate; j++)
3750                 printf ("%c%-4d",
3751                         i == current_size && rates[j] == current_rate ? '*' : ' ',
3752                         rates[j]);
3753             printf ("\n");
3754         }
3755     }
3756
3757     rotations = XRRConfigRotations(sc, &current_rotation);
3758
3759     rotation = 1 << rot ;
3760     if (query) {
3761         printf("Current rotation - %s\n",
3762                rotation_name (current_rotation));
3763
3764         printf("Current reflection - %s\n",
3765                reflection_name (current_rotation));
3766
3767         printf ("Rotations possible - ");
3768         for (i = 0; i < 4; i ++) {
3769             if ((rotations >> i) & 1)  printf("%s ", direction[i]);
3770         }
3771         printf ("\n");
3772
3773         printf ("Reflections possible - ");
3774         if (rotations & (RR_Reflect_X|RR_Reflect_Y))
3775         {
3776             if (rotations & RR_Reflect_X) printf ("X Axis ");
3777             if (rotations & RR_Reflect_Y) printf ("Y Axis");
3778         }
3779         else
3780             printf ("none");
3781         printf ("\n");
3782     }
3783
3784     if (verbose) { 
3785         printf("Setting size to %d, rotation to %s\n",  size, direction[rot]);
3786
3787         printf ("Setting reflection on ");
3788         if (reflection)
3789         {
3790             if (reflection & RR_Reflect_X) printf ("X Axis ");
3791             if (reflection & RR_Reflect_Y) printf ("Y Axis");
3792         }
3793         else
3794             printf ("neither axis");
3795         printf ("\n");
3796
3797         if (reflection & RR_Reflect_X) printf("Setting reflection on X axis\n");
3798
3799         if (reflection & RR_Reflect_Y) printf("Setting reflection on Y axis\n");
3800     }
3801
3802     /* we should test configureNotify on the root window */
3803     XSelectInput (dpy, root, StructureNotifyMask);
3804
3805     if (setit && !dryrun) XRRSelectInput (dpy, root,
3806                                RRScreenChangeNotifyMask);
3807     if (setit && !dryrun) status = XRRSetScreenConfigAndRate (dpy, sc,
3808                                                    root,
3809                                                    (SizeID) size, (Rotation) (rotation | reflection), rate, CurrentTime);
3810
3811     if (setit && !dryrun && status == RRSetConfigFailed) {
3812         printf ("Failed to change the screen configuration!\n");
3813         ret = 1;
3814     }
3815
3816     if (verbose && setit && !dryrun && size != current_size) {
3817         if (status == RRSetConfigSuccess)
3818         {
3819             Bool    seen_screen = False;
3820             while (!seen_screen) {
3821                 int spo;
3822                 XNextEvent(dpy, (XEvent *) &event);
3823
3824                 printf ("Event received, type = %d\n", event.type);
3825                 /* update Xlib's knowledge of the event */
3826                 XRRUpdateConfiguration (&event);
3827                 if (event.type == ConfigureNotify)
3828                     printf("Received ConfigureNotify Event!\n");
3829
3830                 switch (event.type - event_base) {
3831                 case RRScreenChangeNotify:
3832                     sce = (XRRScreenChangeNotifyEvent *) &event;
3833
3834                     printf("Got a screen change notify event!\n");
3835                     printf(" window = %d\n root = %d\n size_index = %d\n rotation %d\n", 
3836                            (int) sce->window, (int) sce->root, 
3837                            sce->size_index,  sce->rotation);
3838                     printf(" timestamp = %ld, config_timestamp = %ld\n",
3839                            sce->timestamp, sce->config_timestamp);
3840                     printf(" Rotation = %x\n", sce->rotation);
3841                     printf(" %d X %d pixels, %d X %d mm\n",
3842                            sce->width, sce->height, sce->mwidth, sce->mheight);
3843                     printf("Display width   %d, height   %d\n",
3844                            DisplayWidth(dpy, screen), DisplayHeight(dpy, screen));
3845                     printf("Display widthmm %d, heightmm %d\n", 
3846                            DisplayWidthMM(dpy, screen), DisplayHeightMM(dpy, screen));
3847                     spo = sce->subpixel_order;
3848                     if ((spo < 0) || (spo > 5))
3849                         printf ("Unknown subpixel order, value = %d\n", spo);
3850                     else printf ("new Subpixel rendering model is %s\n", order[spo]);
3851                     seen_screen = True;
3852                     break;
3853                 default:
3854                     if (event.type != ConfigureNotify) 
3855                         printf("unknown event received, type = %d!\n", event.type);
3856                 }
3857             }
3858         }
3859     }
3860     XRRFreeScreenConfigInfo(sc);
3861     return(ret);
3862 }