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