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