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