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