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