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