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