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