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