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