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