xrandr.c revision a0d3b6ea
1a0d3b6eaSmrg/*
2a0d3b6eaSmrg * Copyright © 2001 Keith Packard, member of The XFree86 Project, Inc.
3a0d3b6eaSmrg * Copyright © 2002 Hewlett Packard Company, Inc.
4a0d3b6eaSmrg * Copyright © 2006 Intel Corporation
5a0d3b6eaSmrg *
6a0d3b6eaSmrg * Permission to use, copy, modify, distribute, and sell this software and its
7a0d3b6eaSmrg * documentation for any purpose is hereby granted without fee, provided that
8a0d3b6eaSmrg * the above copyright notice appear in all copies and that both that copyright
9a0d3b6eaSmrg * notice and this permission notice appear in supporting documentation, and
10a0d3b6eaSmrg * that the name of the copyright holders not be used in advertising or
11a0d3b6eaSmrg * publicity pertaining to distribution of the software without specific,
12a0d3b6eaSmrg * written prior permission.  The copyright holders make no representations
13a0d3b6eaSmrg * about the suitability of this software for any purpose.  It is provided "as
14a0d3b6eaSmrg * is" without express or implied warranty.
15a0d3b6eaSmrg *
16a0d3b6eaSmrg * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17a0d3b6eaSmrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18a0d3b6eaSmrg * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
19a0d3b6eaSmrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
20a0d3b6eaSmrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
21a0d3b6eaSmrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
22a0d3b6eaSmrg * OF THIS SOFTWARE.
23a0d3b6eaSmrg *
24a0d3b6eaSmrg * Thanks to Jim Gettys who wrote most of the client side code,
25a0d3b6eaSmrg * and part of the server code for randr.
26a0d3b6eaSmrg */
27a0d3b6eaSmrg
28a0d3b6eaSmrg#include <stdio.h>
29a0d3b6eaSmrg#include <X11/Xlib.h>
30a0d3b6eaSmrg#include <X11/Xlibint.h>
31a0d3b6eaSmrg#include <X11/Xproto.h>
32a0d3b6eaSmrg#include <X11/Xatom.h>
33a0d3b6eaSmrg#include <X11/extensions/Xrandr.h>
34a0d3b6eaSmrg#include <X11/extensions/Xrender.h>	/* we share subpixel information */
35a0d3b6eaSmrg#include <string.h>
36a0d3b6eaSmrg#include <stdlib.h>
37a0d3b6eaSmrg#include <stdarg.h>
38a0d3b6eaSmrg#include <math.h>
39a0d3b6eaSmrg
40a0d3b6eaSmrg#if RANDR_MAJOR > 1 || (RANDR_MAJOR == 1 && RANDR_MINOR >= 2)
41a0d3b6eaSmrg#define HAS_RANDR_1_2 1
42a0d3b6eaSmrg#endif
43a0d3b6eaSmrg
44a0d3b6eaSmrgstatic char	*program_name;
45a0d3b6eaSmrgstatic Display	*dpy;
46a0d3b6eaSmrgstatic Window	root;
47a0d3b6eaSmrgstatic int	screen = -1;
48a0d3b6eaSmrgstatic Bool	verbose = False;
49a0d3b6eaSmrgstatic Bool	automatic = False;
50a0d3b6eaSmrgstatic Bool	properties = False;
51a0d3b6eaSmrg
52a0d3b6eaSmrgstatic char *direction[5] = {
53a0d3b6eaSmrg    "normal",
54a0d3b6eaSmrg    "left",
55a0d3b6eaSmrg    "inverted",
56a0d3b6eaSmrg    "right",
57a0d3b6eaSmrg    "\n"};
58a0d3b6eaSmrg
59a0d3b6eaSmrgstatic char *reflections[5] = {
60a0d3b6eaSmrg    "normal",
61a0d3b6eaSmrg    "x",
62a0d3b6eaSmrg    "y",
63a0d3b6eaSmrg    "xy",
64a0d3b6eaSmrg    "\n"};
65a0d3b6eaSmrg
66a0d3b6eaSmrg/* subpixel order */
67a0d3b6eaSmrgstatic char *order[6] = {
68a0d3b6eaSmrg    "unknown",
69a0d3b6eaSmrg    "horizontal rgb",
70a0d3b6eaSmrg    "horizontal bgr",
71a0d3b6eaSmrg    "vertical rgb",
72a0d3b6eaSmrg    "vertical bgr",
73a0d3b6eaSmrg    "no subpixels"};
74a0d3b6eaSmrg
75a0d3b6eaSmrgstatic const struct {
76a0d3b6eaSmrg    char	    *string;
77a0d3b6eaSmrg    unsigned long   flag;
78a0d3b6eaSmrg} mode_flags[] = {
79a0d3b6eaSmrg    { "+HSync", RR_HSyncPositive },
80a0d3b6eaSmrg    { "-HSync", RR_HSyncNegative },
81a0d3b6eaSmrg    { "+VSync", RR_VSyncPositive },
82a0d3b6eaSmrg    { "-VSync", RR_VSyncNegative },
83a0d3b6eaSmrg    { "Interlace", RR_Interlace },
84a0d3b6eaSmrg    { "DoubleScan", RR_DoubleScan },
85a0d3b6eaSmrg    { "CSync",	    RR_CSync },
86a0d3b6eaSmrg    { "+CSync",	    RR_CSyncPositive },
87a0d3b6eaSmrg    { "-CSync",	    RR_CSyncNegative },
88a0d3b6eaSmrg    { NULL,	    0 }
89a0d3b6eaSmrg};
90a0d3b6eaSmrg
91a0d3b6eaSmrgstatic void
92a0d3b6eaSmrgusage(void)
93a0d3b6eaSmrg{
94a0d3b6eaSmrg    fprintf(stderr, "usage: %s [options]\n", program_name);
95a0d3b6eaSmrg    fprintf(stderr, "  where options are:\n");
96a0d3b6eaSmrg    fprintf(stderr, "  -display <display> or -d <display>\n");
97a0d3b6eaSmrg    fprintf(stderr, "  -help\n");
98a0d3b6eaSmrg    fprintf(stderr, "  -o <normal,inverted,left,right,0,1,2,3>\n");
99a0d3b6eaSmrg    fprintf(stderr, "            or --orientation <normal,inverted,left,right,0,1,2,3>\n");
100a0d3b6eaSmrg    fprintf(stderr, "  -q        or --query\n");
101a0d3b6eaSmrg    fprintf(stderr, "  -s <size>/<width>x<height> or --size <size>/<width>x<height>\n");
102a0d3b6eaSmrg    fprintf(stderr, "  -r <rate> or --rate <rate> or --refresh <rate>\n");
103a0d3b6eaSmrg    fprintf(stderr, "  -v        or --version\n");
104a0d3b6eaSmrg    fprintf(stderr, "  -x        (reflect in x)\n");
105a0d3b6eaSmrg    fprintf(stderr, "  -y        (reflect in y)\n");
106a0d3b6eaSmrg    fprintf(stderr, "  --screen <screen>\n");
107a0d3b6eaSmrg    fprintf(stderr, "  --verbose\n");
108a0d3b6eaSmrg    fprintf(stderr, "  --dryrun\n");
109a0d3b6eaSmrg#if HAS_RANDR_1_2
110a0d3b6eaSmrg    fprintf(stderr, "  --prop or --properties\n");
111a0d3b6eaSmrg    fprintf(stderr, "  --fb <width>x<height>\n");
112a0d3b6eaSmrg    fprintf(stderr, "  --fbmm <width>x<height>\n");
113a0d3b6eaSmrg    fprintf(stderr, "  --dpi <dpi>/<output>\n");
114a0d3b6eaSmrg#if 0
115a0d3b6eaSmrg    fprintf(stderr, "  --clone\n");
116a0d3b6eaSmrg    fprintf(stderr, "  --extend\n");
117a0d3b6eaSmrg#endif
118a0d3b6eaSmrg    fprintf(stderr, "  --output <output>\n");
119a0d3b6eaSmrg    fprintf(stderr, "      --auto\n");
120a0d3b6eaSmrg    fprintf(stderr, "      --mode <mode>\n");
121a0d3b6eaSmrg    fprintf(stderr, "      --preferred\n");
122a0d3b6eaSmrg    fprintf(stderr, "      --pos <x>x<y>\n");
123a0d3b6eaSmrg    fprintf(stderr, "      --rate <rate> or --refresh <rate>\n");
124a0d3b6eaSmrg    fprintf(stderr, "      --reflect normal,x,y,xy\n");
125a0d3b6eaSmrg    fprintf(stderr, "      --rotate normal,inverted,left,right\n");
126a0d3b6eaSmrg    fprintf(stderr, "      --left-of <output>\n");
127a0d3b6eaSmrg    fprintf(stderr, "      --right-of <output>\n");
128a0d3b6eaSmrg    fprintf(stderr, "      --above <output>\n");
129a0d3b6eaSmrg    fprintf(stderr, "      --below <output>\n");
130a0d3b6eaSmrg    fprintf(stderr, "      --same-as <output>\n");
131a0d3b6eaSmrg    fprintf(stderr, "      --set <property> <value>\n");
132a0d3b6eaSmrg    fprintf(stderr, "      --off\n");
133a0d3b6eaSmrg    fprintf(stderr, "      --crtc <crtc>\n");
134a0d3b6eaSmrg    fprintf(stderr, "  --newmode <name> <clock MHz>\n");
135a0d3b6eaSmrg    fprintf(stderr, "            <hdisp> <hsync-start> <hsync-end> <htotal>\n");
136a0d3b6eaSmrg    fprintf(stderr, "            <vdisp> <vsync-start> <vsync-end> <vtotal>\n");
137a0d3b6eaSmrg    fprintf(stderr, "            [+HSync] [-HSync] [+VSync] [-VSync]\n");
138a0d3b6eaSmrg    fprintf(stderr, "  --rmmode <name>\n");
139a0d3b6eaSmrg    fprintf(stderr, "  --addmode <output> <name>\n");
140a0d3b6eaSmrg    fprintf(stderr, "  --delmode <output> <name>\n");
141a0d3b6eaSmrg#endif
142a0d3b6eaSmrg
143a0d3b6eaSmrg    exit(1);
144a0d3b6eaSmrg    /*NOTREACHED*/
145a0d3b6eaSmrg}
146a0d3b6eaSmrg
147a0d3b6eaSmrgstatic void
148a0d3b6eaSmrgfatal (const char *format, ...)
149a0d3b6eaSmrg{
150a0d3b6eaSmrg    va_list ap;
151a0d3b6eaSmrg
152a0d3b6eaSmrg    va_start (ap, format);
153a0d3b6eaSmrg    fprintf (stderr, "%s: ", program_name);
154a0d3b6eaSmrg    vfprintf (stderr, format, ap);
155a0d3b6eaSmrg    va_end (ap);
156a0d3b6eaSmrg    exit (1);
157a0d3b6eaSmrg    /*NOTREACHED*/
158a0d3b6eaSmrg}
159a0d3b6eaSmrg
160a0d3b6eaSmrgstatic char *
161a0d3b6eaSmrgrotation_name (Rotation rotation)
162a0d3b6eaSmrg{
163a0d3b6eaSmrg    int	i;
164a0d3b6eaSmrg
165a0d3b6eaSmrg    if ((rotation & 0xf) == 0)
166a0d3b6eaSmrg	return "normal";
167a0d3b6eaSmrg    for (i = 0; i < 4; i++)
168a0d3b6eaSmrg	if (rotation & (1 << i))
169a0d3b6eaSmrg	    return direction[i];
170a0d3b6eaSmrg    return "invalid rotation";
171a0d3b6eaSmrg}
172a0d3b6eaSmrg
173a0d3b6eaSmrgstatic char *
174a0d3b6eaSmrgreflection_name (Rotation rotation)
175a0d3b6eaSmrg{
176a0d3b6eaSmrg    rotation &= (RR_Reflect_X|RR_Reflect_Y);
177a0d3b6eaSmrg    switch (rotation) {
178a0d3b6eaSmrg    case 0:
179a0d3b6eaSmrg	return "none";
180a0d3b6eaSmrg    case RR_Reflect_X:
181a0d3b6eaSmrg	return "X axis";
182a0d3b6eaSmrg    case RR_Reflect_Y:
183a0d3b6eaSmrg	return "Y axis";
184a0d3b6eaSmrg    case RR_Reflect_X|RR_Reflect_Y:
185a0d3b6eaSmrg	return "X and Y axis";
186a0d3b6eaSmrg    }
187a0d3b6eaSmrg    return "invalid reflection";
188a0d3b6eaSmrg}
189a0d3b6eaSmrg
190a0d3b6eaSmrg#if HAS_RANDR_1_2
191a0d3b6eaSmrgtypedef enum _policy {
192a0d3b6eaSmrg    clone, extend
193a0d3b6eaSmrg} policy_t;
194a0d3b6eaSmrg
195a0d3b6eaSmrgtypedef enum _relation {
196a0d3b6eaSmrg    left_of, right_of, above, below, same_as,
197a0d3b6eaSmrg} relation_t;
198a0d3b6eaSmrg
199a0d3b6eaSmrgtypedef enum _changes {
200a0d3b6eaSmrg    changes_none = 0,
201a0d3b6eaSmrg    changes_crtc = (1 << 0),
202a0d3b6eaSmrg    changes_mode = (1 << 1),
203a0d3b6eaSmrg    changes_relation = (1 << 2),
204a0d3b6eaSmrg    changes_position = (1 << 3),
205a0d3b6eaSmrg    changes_rotation = (1 << 4),
206a0d3b6eaSmrg    changes_reflection = (1 << 5),
207a0d3b6eaSmrg    changes_automatic = (1 << 6),
208a0d3b6eaSmrg    changes_refresh = (1 << 7),
209a0d3b6eaSmrg    changes_property = (1 << 8),
210a0d3b6eaSmrg} changes_t;
211a0d3b6eaSmrg
212a0d3b6eaSmrgtypedef enum _name_kind {
213a0d3b6eaSmrg    name_none = 0,
214a0d3b6eaSmrg    name_string = (1 << 0),
215a0d3b6eaSmrg    name_xid = (1 << 1),
216a0d3b6eaSmrg    name_index = (1 << 2),
217a0d3b6eaSmrg    name_preferred = (1 << 3),
218a0d3b6eaSmrg} name_kind_t;
219a0d3b6eaSmrg
220a0d3b6eaSmrgtypedef struct {
221a0d3b6eaSmrg    name_kind_t	    kind;
222a0d3b6eaSmrg    char    	    *string;
223a0d3b6eaSmrg    XID	    	    xid;
224a0d3b6eaSmrg    int		    index;
225a0d3b6eaSmrg} name_t;
226a0d3b6eaSmrg
227a0d3b6eaSmrgtypedef struct _crtc crtc_t;
228a0d3b6eaSmrgtypedef struct _output	output_t;
229a0d3b6eaSmrgtypedef struct _umode	umode_t;
230a0d3b6eaSmrgtypedef struct _output_prop output_prop_t;
231a0d3b6eaSmrg
232a0d3b6eaSmrgstruct _crtc {
233a0d3b6eaSmrg    name_t	    crtc;
234a0d3b6eaSmrg    Bool	    changing;
235a0d3b6eaSmrg    XRRCrtcInfo	    *crtc_info;
236a0d3b6eaSmrg
237a0d3b6eaSmrg    XRRModeInfo	    *mode_info;
238a0d3b6eaSmrg    int		    x;
239a0d3b6eaSmrg    int		    y;
240a0d3b6eaSmrg    Rotation	    rotation;
241a0d3b6eaSmrg    output_t	    **outputs;
242a0d3b6eaSmrg    int		    noutput;
243a0d3b6eaSmrg};
244a0d3b6eaSmrg
245a0d3b6eaSmrgstruct _output_prop {
246a0d3b6eaSmrg    struct _output_prop	*next;
247a0d3b6eaSmrg    char		*name;
248a0d3b6eaSmrg    char		*value;
249a0d3b6eaSmrg};
250a0d3b6eaSmrg
251a0d3b6eaSmrgstruct _output {
252a0d3b6eaSmrg    struct _output   *next;
253a0d3b6eaSmrg
254a0d3b6eaSmrg    changes_t	    changes;
255a0d3b6eaSmrg
256a0d3b6eaSmrg    output_prop_t   *props;
257a0d3b6eaSmrg
258a0d3b6eaSmrg    name_t	    output;
259a0d3b6eaSmrg    XRROutputInfo   *output_info;
260a0d3b6eaSmrg
261a0d3b6eaSmrg    name_t	    crtc;
262a0d3b6eaSmrg    crtc_t	    *crtc_info;
263a0d3b6eaSmrg    crtc_t	    *current_crtc_info;
264a0d3b6eaSmrg
265a0d3b6eaSmrg    name_t	    mode;
266a0d3b6eaSmrg    float	    refresh;
267a0d3b6eaSmrg    XRRModeInfo	    *mode_info;
268a0d3b6eaSmrg
269a0d3b6eaSmrg    name_t	    addmode;
270a0d3b6eaSmrg
271a0d3b6eaSmrg    relation_t	    relation;
272a0d3b6eaSmrg    char	    *relative_to;
273a0d3b6eaSmrg
274a0d3b6eaSmrg    int		    x, y;
275a0d3b6eaSmrg    Rotation	    rotation;
276a0d3b6eaSmrg
277a0d3b6eaSmrg    Bool    	    automatic;
278a0d3b6eaSmrg};
279a0d3b6eaSmrg
280a0d3b6eaSmrgtypedef enum _umode_action {
281a0d3b6eaSmrg    umode_create, umode_destroy, umode_add, umode_delete
282a0d3b6eaSmrg} umode_action_t;
283a0d3b6eaSmrg
284a0d3b6eaSmrg
285a0d3b6eaSmrgstruct _umode {
286a0d3b6eaSmrg    struct _umode   *next;
287a0d3b6eaSmrg
288a0d3b6eaSmrg    umode_action_t  action;
289a0d3b6eaSmrg    XRRModeInfo	    mode;
290a0d3b6eaSmrg    name_t	    output;
291a0d3b6eaSmrg    name_t	    name;
292a0d3b6eaSmrg};
293a0d3b6eaSmrg
294a0d3b6eaSmrgstatic char *connection[3] = {
295a0d3b6eaSmrg    "connected",
296a0d3b6eaSmrg    "disconnected",
297a0d3b6eaSmrg    "unknown connection"};
298a0d3b6eaSmrg
299a0d3b6eaSmrg#define OUTPUT_NAME 1
300a0d3b6eaSmrg
301a0d3b6eaSmrg#define CRTC_OFF    2
302a0d3b6eaSmrg#define CRTC_UNSET  3
303a0d3b6eaSmrg#define CRTC_INDEX  0x40000000
304a0d3b6eaSmrg
305a0d3b6eaSmrg#define MODE_NAME   1
306a0d3b6eaSmrg#define MODE_OFF    2
307a0d3b6eaSmrg#define MODE_UNSET  3
308a0d3b6eaSmrg#define MODE_PREF   4
309a0d3b6eaSmrg
310a0d3b6eaSmrg#define POS_UNSET   -1
311a0d3b6eaSmrg
312a0d3b6eaSmrgstatic output_t	*outputs = NULL;
313a0d3b6eaSmrgstatic output_t	**outputs_tail = &outputs;
314a0d3b6eaSmrgstatic crtc_t	*crtcs;
315a0d3b6eaSmrgstatic umode_t	*umodes;
316a0d3b6eaSmrgstatic int	num_crtcs;
317a0d3b6eaSmrgstatic XRRScreenResources  *res;
318a0d3b6eaSmrgstatic int	fb_width = 0, fb_height = 0;
319a0d3b6eaSmrgstatic int	fb_width_mm = 0, fb_height_mm = 0;
320a0d3b6eaSmrgstatic float	dpi = 0;
321a0d3b6eaSmrgstatic char	*dpi_output = NULL;
322a0d3b6eaSmrgstatic Bool	dryrun = False;
323a0d3b6eaSmrgstatic int	minWidth, maxWidth, minHeight, maxHeight;
324a0d3b6eaSmrgstatic Bool    	has_1_2 = False;
325a0d3b6eaSmrg
326a0d3b6eaSmrgstatic int
327a0d3b6eaSmrgmode_height (XRRModeInfo *mode_info, Rotation rotation)
328a0d3b6eaSmrg{
329a0d3b6eaSmrg    switch (rotation & 0xf) {
330a0d3b6eaSmrg    case RR_Rotate_0:
331a0d3b6eaSmrg    case RR_Rotate_180:
332a0d3b6eaSmrg	return mode_info->height;
333a0d3b6eaSmrg    case RR_Rotate_90:
334a0d3b6eaSmrg    case RR_Rotate_270:
335a0d3b6eaSmrg	return mode_info->width;
336a0d3b6eaSmrg    default:
337a0d3b6eaSmrg	return 0;
338a0d3b6eaSmrg    }
339a0d3b6eaSmrg}
340a0d3b6eaSmrg
341a0d3b6eaSmrgstatic int
342a0d3b6eaSmrgmode_width (XRRModeInfo *mode_info, Rotation rotation)
343a0d3b6eaSmrg{
344a0d3b6eaSmrg    switch (rotation & 0xf) {
345a0d3b6eaSmrg    case RR_Rotate_0:
346a0d3b6eaSmrg    case RR_Rotate_180:
347a0d3b6eaSmrg	return mode_info->width;
348a0d3b6eaSmrg    case RR_Rotate_90:
349a0d3b6eaSmrg    case RR_Rotate_270:
350a0d3b6eaSmrg	return mode_info->height;
351a0d3b6eaSmrg    default:
352a0d3b6eaSmrg	return 0;
353a0d3b6eaSmrg    }
354a0d3b6eaSmrg}
355a0d3b6eaSmrg
356a0d3b6eaSmrg/* v refresh frequency in Hz */
357a0d3b6eaSmrgstatic float
358a0d3b6eaSmrgmode_refresh (XRRModeInfo *mode_info)
359a0d3b6eaSmrg{
360a0d3b6eaSmrg    float rate;
361a0d3b6eaSmrg
362a0d3b6eaSmrg    if (mode_info->hTotal && mode_info->vTotal)
363a0d3b6eaSmrg	rate = ((float) mode_info->dotClock /
364a0d3b6eaSmrg		((float) mode_info->hTotal * (float) mode_info->vTotal));
365a0d3b6eaSmrg    else
366a0d3b6eaSmrg    	rate = 0;
367a0d3b6eaSmrg    return rate;
368a0d3b6eaSmrg}
369a0d3b6eaSmrg
370a0d3b6eaSmrg/* h sync frequency in Hz */
371a0d3b6eaSmrgstatic float
372a0d3b6eaSmrgmode_hsync (XRRModeInfo *mode_info)
373a0d3b6eaSmrg{
374a0d3b6eaSmrg    float rate;
375a0d3b6eaSmrg
376a0d3b6eaSmrg    if (mode_info->hTotal)
377a0d3b6eaSmrg	rate = (float) mode_info->dotClock / (float) mode_info->hTotal;
378a0d3b6eaSmrg    else
379a0d3b6eaSmrg    	rate = 0;
380a0d3b6eaSmrg    return rate;
381a0d3b6eaSmrg}
382a0d3b6eaSmrg
383a0d3b6eaSmrgstatic void
384a0d3b6eaSmrginit_name (name_t *name)
385a0d3b6eaSmrg{
386a0d3b6eaSmrg    name->kind = name_none;
387a0d3b6eaSmrg}
388a0d3b6eaSmrg
389a0d3b6eaSmrgstatic void
390a0d3b6eaSmrgset_name_string (name_t *name, char *string)
391a0d3b6eaSmrg{
392a0d3b6eaSmrg    name->kind |= name_string;
393a0d3b6eaSmrg    name->string = string;
394a0d3b6eaSmrg}
395a0d3b6eaSmrg
396a0d3b6eaSmrgstatic void
397a0d3b6eaSmrgset_name_xid (name_t *name, XID xid)
398a0d3b6eaSmrg{
399a0d3b6eaSmrg    name->kind |= name_xid;
400a0d3b6eaSmrg    name->xid = xid;
401a0d3b6eaSmrg}
402a0d3b6eaSmrg
403a0d3b6eaSmrgstatic void
404a0d3b6eaSmrgset_name_index (name_t *name, int index)
405a0d3b6eaSmrg{
406a0d3b6eaSmrg    name->kind |= name_index;
407a0d3b6eaSmrg    name->index = index;
408a0d3b6eaSmrg}
409a0d3b6eaSmrg
410a0d3b6eaSmrgstatic void
411a0d3b6eaSmrgset_name_preferred (name_t *name)
412a0d3b6eaSmrg{
413a0d3b6eaSmrg    name->kind |= name_preferred;
414a0d3b6eaSmrg}
415a0d3b6eaSmrg
416a0d3b6eaSmrgstatic void
417a0d3b6eaSmrgset_name_all (name_t *name, name_t *old)
418a0d3b6eaSmrg{
419a0d3b6eaSmrg    if (old->kind & name_xid)
420a0d3b6eaSmrg	name->xid = old->xid;
421a0d3b6eaSmrg    if (old->kind & name_string)
422a0d3b6eaSmrg	name->string = old->string;
423a0d3b6eaSmrg    if (old->kind & name_index)
424a0d3b6eaSmrg	name->index = old->index;
425a0d3b6eaSmrg    name->kind |= old->kind;
426a0d3b6eaSmrg}
427a0d3b6eaSmrg
428a0d3b6eaSmrgstatic void
429a0d3b6eaSmrgset_name (name_t *name, char *string, name_kind_t valid)
430a0d3b6eaSmrg{
431a0d3b6eaSmrg    XID	xid;
432a0d3b6eaSmrg    int index;
433a0d3b6eaSmrg
434a0d3b6eaSmrg    if ((valid & name_xid) && sscanf (string, "0x%x", &xid) == 1)
435a0d3b6eaSmrg	set_name_xid (name, xid);
436a0d3b6eaSmrg    else if ((valid & name_index) && sscanf (string, "%d", &index) == 1)
437a0d3b6eaSmrg	set_name_index (name, index);
438a0d3b6eaSmrg    else if (valid & name_string)
439a0d3b6eaSmrg	set_name_string (name, string);
440a0d3b6eaSmrg    else
441a0d3b6eaSmrg	usage ();
442a0d3b6eaSmrg}
443a0d3b6eaSmrg
444a0d3b6eaSmrgstatic output_t *
445a0d3b6eaSmrgadd_output (void)
446a0d3b6eaSmrg{
447a0d3b6eaSmrg    output_t *output = calloc (1, sizeof (output_t));
448a0d3b6eaSmrg
449a0d3b6eaSmrg    if (!output)
450a0d3b6eaSmrg	fatal ("out of memory");
451a0d3b6eaSmrg    output->next = NULL;
452a0d3b6eaSmrg    *outputs_tail = output;
453a0d3b6eaSmrg    outputs_tail = &output->next;
454a0d3b6eaSmrg    return output;
455a0d3b6eaSmrg}
456a0d3b6eaSmrg
457a0d3b6eaSmrgstatic output_t *
458a0d3b6eaSmrgfind_output (name_t *name)
459a0d3b6eaSmrg{
460a0d3b6eaSmrg    output_t *output;
461a0d3b6eaSmrg
462a0d3b6eaSmrg    for (output = outputs; output; output = output->next)
463a0d3b6eaSmrg    {
464a0d3b6eaSmrg	name_kind_t common = name->kind & output->output.kind;
465a0d3b6eaSmrg
466a0d3b6eaSmrg	if ((common & name_xid) && name->xid == output->output.xid)
467a0d3b6eaSmrg	    break;
468a0d3b6eaSmrg	if ((common & name_string) && !strcmp (name->string, output->output.string))
469a0d3b6eaSmrg	    break;
470a0d3b6eaSmrg	if ((common & name_index) && name->index == output->output.index)
471a0d3b6eaSmrg	    break;
472a0d3b6eaSmrg    }
473a0d3b6eaSmrg    return output;
474a0d3b6eaSmrg}
475a0d3b6eaSmrg
476a0d3b6eaSmrgstatic output_t *
477a0d3b6eaSmrgfind_output_by_xid (RROutput output)
478a0d3b6eaSmrg{
479a0d3b6eaSmrg    name_t  output_name;
480a0d3b6eaSmrg
481a0d3b6eaSmrg    init_name (&output_name);
482a0d3b6eaSmrg    set_name_xid (&output_name, output);
483a0d3b6eaSmrg    return find_output (&output_name);
484a0d3b6eaSmrg}
485a0d3b6eaSmrg
486a0d3b6eaSmrgstatic output_t *
487a0d3b6eaSmrgfind_output_by_name (char *name)
488a0d3b6eaSmrg{
489a0d3b6eaSmrg    name_t  output_name;
490a0d3b6eaSmrg
491a0d3b6eaSmrg    init_name (&output_name);
492a0d3b6eaSmrg    set_name_string (&output_name, name);
493a0d3b6eaSmrg    return find_output (&output_name);
494a0d3b6eaSmrg}
495a0d3b6eaSmrg
496a0d3b6eaSmrgstatic crtc_t *
497a0d3b6eaSmrgfind_crtc (name_t *name)
498a0d3b6eaSmrg{
499a0d3b6eaSmrg    int	    c;
500a0d3b6eaSmrg    crtc_t  *crtc = NULL;
501a0d3b6eaSmrg
502a0d3b6eaSmrg    for (c = 0; c < num_crtcs; c++)
503a0d3b6eaSmrg    {
504a0d3b6eaSmrg	name_kind_t common;
505a0d3b6eaSmrg
506a0d3b6eaSmrg	crtc = &crtcs[c];
507a0d3b6eaSmrg	common = name->kind & crtc->crtc.kind;
508a0d3b6eaSmrg
509a0d3b6eaSmrg	if ((common & name_xid) && name->xid == crtc->crtc.xid)
510a0d3b6eaSmrg	    break;
511a0d3b6eaSmrg	if ((common & name_string) && !strcmp (name->string, crtc->crtc.string))
512a0d3b6eaSmrg	    break;
513a0d3b6eaSmrg	if ((common & name_index) && name->index == crtc->crtc.index)
514a0d3b6eaSmrg	    break;
515a0d3b6eaSmrg	crtc = NULL;
516a0d3b6eaSmrg    }
517a0d3b6eaSmrg    return crtc;
518a0d3b6eaSmrg}
519a0d3b6eaSmrg
520a0d3b6eaSmrgstatic crtc_t *
521a0d3b6eaSmrgfind_crtc_by_xid (RRCrtc crtc)
522a0d3b6eaSmrg{
523a0d3b6eaSmrg    name_t  crtc_name;
524a0d3b6eaSmrg
525a0d3b6eaSmrg    init_name (&crtc_name);
526a0d3b6eaSmrg    set_name_xid (&crtc_name, crtc);
527a0d3b6eaSmrg    return find_crtc (&crtc_name);
528a0d3b6eaSmrg}
529a0d3b6eaSmrg
530a0d3b6eaSmrgstatic XRRModeInfo *
531a0d3b6eaSmrgfind_mode (name_t *name, float refresh)
532a0d3b6eaSmrg{
533a0d3b6eaSmrg    int		m;
534a0d3b6eaSmrg    XRRModeInfo	*best = NULL;
535a0d3b6eaSmrg    float	bestDist = 0;
536a0d3b6eaSmrg
537a0d3b6eaSmrg    for (m = 0; m < res->nmode; m++)
538a0d3b6eaSmrg    {
539a0d3b6eaSmrg	XRRModeInfo *mode = &res->modes[m];
540a0d3b6eaSmrg	if ((name->kind & name_xid) && name->xid == mode->id)
541a0d3b6eaSmrg	{
542a0d3b6eaSmrg	    best = mode;
543a0d3b6eaSmrg	    break;
544a0d3b6eaSmrg	}
545a0d3b6eaSmrg	if ((name->kind & name_string) && !strcmp (name->string, mode->name))
546a0d3b6eaSmrg	{
547a0d3b6eaSmrg	    float   dist;
548a0d3b6eaSmrg
549a0d3b6eaSmrg	    if (refresh)
550a0d3b6eaSmrg		dist = fabs (mode_refresh (mode) - refresh);
551a0d3b6eaSmrg	    else
552a0d3b6eaSmrg		dist = 0;
553a0d3b6eaSmrg	    if (!best || dist < bestDist)
554a0d3b6eaSmrg	    {
555a0d3b6eaSmrg		bestDist = dist;
556a0d3b6eaSmrg		best = mode;
557a0d3b6eaSmrg	    }
558a0d3b6eaSmrg	    break;
559a0d3b6eaSmrg	}
560a0d3b6eaSmrg    }
561a0d3b6eaSmrg    return best;
562a0d3b6eaSmrg}
563a0d3b6eaSmrg
564a0d3b6eaSmrgstatic XRRModeInfo *
565a0d3b6eaSmrgfind_mode_by_xid (RRMode mode)
566a0d3b6eaSmrg{
567a0d3b6eaSmrg    name_t  mode_name;
568a0d3b6eaSmrg
569a0d3b6eaSmrg    init_name (&mode_name);
570a0d3b6eaSmrg    set_name_xid (&mode_name, mode);
571a0d3b6eaSmrg    return find_mode (&mode_name, 0);
572a0d3b6eaSmrg}
573a0d3b6eaSmrg
574a0d3b6eaSmrgstatic XRRModeInfo *
575a0d3b6eaSmrgfind_mode_by_name (char *name)
576a0d3b6eaSmrg{
577a0d3b6eaSmrg    name_t  mode_name;
578a0d3b6eaSmrg    init_name (&mode_name);
579a0d3b6eaSmrg    set_name_string (&mode_name, name);
580a0d3b6eaSmrg    return find_mode (&mode_name, 0);
581a0d3b6eaSmrg}
582a0d3b6eaSmrg
583a0d3b6eaSmrgstatic
584a0d3b6eaSmrgXRRModeInfo *
585a0d3b6eaSmrgfind_mode_for_output (output_t *output, name_t *name)
586a0d3b6eaSmrg{
587a0d3b6eaSmrg    XRROutputInfo   *output_info = output->output_info;
588a0d3b6eaSmrg    int		    m;
589a0d3b6eaSmrg    XRRModeInfo	    *best = NULL;
590a0d3b6eaSmrg    float	    bestDist = 0;
591a0d3b6eaSmrg
592a0d3b6eaSmrg    for (m = 0; m < output_info->nmode; m++)
593a0d3b6eaSmrg    {
594a0d3b6eaSmrg	XRRModeInfo	    *mode;
595a0d3b6eaSmrg
596a0d3b6eaSmrg	mode = find_mode_by_xid (output_info->modes[m]);
597a0d3b6eaSmrg	if (!mode) continue;
598a0d3b6eaSmrg	if ((name->kind & name_xid) && name->xid == mode->id)
599a0d3b6eaSmrg	{
600a0d3b6eaSmrg	    best = mode;
601a0d3b6eaSmrg	    break;
602a0d3b6eaSmrg	}
603a0d3b6eaSmrg	if ((name->kind & name_string) && !strcmp (name->string, mode->name))
604a0d3b6eaSmrg	{
605a0d3b6eaSmrg	    float   dist;
606a0d3b6eaSmrg
607a0d3b6eaSmrg	    if (output->refresh)
608a0d3b6eaSmrg		dist = fabs (mode_refresh (mode) - output->refresh);
609a0d3b6eaSmrg	    else
610a0d3b6eaSmrg		dist = 0;
611a0d3b6eaSmrg	    if (!best || dist < bestDist)
612a0d3b6eaSmrg	    {
613a0d3b6eaSmrg		bestDist = dist;
614a0d3b6eaSmrg		best = mode;
615a0d3b6eaSmrg	    }
616a0d3b6eaSmrg	}
617a0d3b6eaSmrg    }
618a0d3b6eaSmrg    return best;
619a0d3b6eaSmrg}
620a0d3b6eaSmrg
621a0d3b6eaSmrgXRRModeInfo *
622a0d3b6eaSmrgpreferred_mode (output_t *output)
623a0d3b6eaSmrg{
624a0d3b6eaSmrg    XRROutputInfo   *output_info = output->output_info;
625a0d3b6eaSmrg    int		    m;
626a0d3b6eaSmrg    XRRModeInfo	    *best;
627a0d3b6eaSmrg    int		    bestDist;
628a0d3b6eaSmrg
629a0d3b6eaSmrg    best = NULL;
630a0d3b6eaSmrg    bestDist = 0;
631a0d3b6eaSmrg    for (m = 0; m < output_info->nmode; m++)
632a0d3b6eaSmrg    {
633a0d3b6eaSmrg	XRRModeInfo *mode_info = find_mode_by_xid (output_info->modes[m]);
634a0d3b6eaSmrg	int	    dist;
635a0d3b6eaSmrg
636a0d3b6eaSmrg	if (m < output_info->npreferred)
637a0d3b6eaSmrg	    dist = 0;
638a0d3b6eaSmrg	else if (output_info->mm_height)
639a0d3b6eaSmrg	    dist = (1000 * DisplayHeight(dpy, screen) / DisplayHeightMM(dpy, screen) -
640a0d3b6eaSmrg		    1000 * mode_info->height / output_info->mm_height);
641a0d3b6eaSmrg	else
642a0d3b6eaSmrg	    dist = DisplayHeight(dpy, screen) - mode_info->height;
643a0d3b6eaSmrg
644a0d3b6eaSmrg        if (dist < 0) dist = -dist;
645a0d3b6eaSmrg	if (!best || dist < bestDist)
646a0d3b6eaSmrg	{
647a0d3b6eaSmrg	    best = mode_info;
648a0d3b6eaSmrg	    bestDist = dist;
649a0d3b6eaSmrg	}
650a0d3b6eaSmrg    }
651a0d3b6eaSmrg    return best;
652a0d3b6eaSmrg}
653a0d3b6eaSmrg
654a0d3b6eaSmrgstatic Bool
655a0d3b6eaSmrgoutput_can_use_crtc (output_t *output, crtc_t *crtc)
656a0d3b6eaSmrg{
657a0d3b6eaSmrg    XRROutputInfo   *output_info = output->output_info;
658a0d3b6eaSmrg    int		    c;
659a0d3b6eaSmrg
660a0d3b6eaSmrg    for (c = 0; c < output_info->ncrtc; c++)
661a0d3b6eaSmrg	if (output_info->crtcs[c] == crtc->crtc.xid)
662a0d3b6eaSmrg	    return True;
663a0d3b6eaSmrg    return False;
664a0d3b6eaSmrg}
665a0d3b6eaSmrg
666a0d3b6eaSmrgstatic Bool
667a0d3b6eaSmrgoutput_can_use_mode (output_t *output, XRRModeInfo *mode)
668a0d3b6eaSmrg{
669a0d3b6eaSmrg    XRROutputInfo   *output_info = output->output_info;
670a0d3b6eaSmrg    int		    m;
671a0d3b6eaSmrg
672a0d3b6eaSmrg    for (m = 0; m < output_info->nmode; m++)
673a0d3b6eaSmrg	if (output_info->modes[m] == mode->id)
674a0d3b6eaSmrg	    return True;
675a0d3b6eaSmrg    return False;
676a0d3b6eaSmrg}
677a0d3b6eaSmrg
678a0d3b6eaSmrgstatic Bool
679a0d3b6eaSmrgcrtc_can_use_rotation (crtc_t *crtc, Rotation rotation)
680a0d3b6eaSmrg{
681a0d3b6eaSmrg    Rotation	rotations = crtc->crtc_info->rotations;
682a0d3b6eaSmrg    Rotation	dir = rotation & (RR_Rotate_0|RR_Rotate_90|RR_Rotate_180|RR_Rotate_270);
683a0d3b6eaSmrg    Rotation	reflect = rotation & (RR_Reflect_X|RR_Reflect_Y);
684a0d3b6eaSmrg    if (((rotations & dir) != 0) && ((rotations & reflect) == reflect))
685a0d3b6eaSmrg	return True;
686a0d3b6eaSmrg    return False;
687a0d3b6eaSmrg}
688a0d3b6eaSmrg
689a0d3b6eaSmrg/*
690a0d3b6eaSmrg * Report only rotations that are supported by all crtcs
691a0d3b6eaSmrg */
692a0d3b6eaSmrgstatic Rotation
693a0d3b6eaSmrgoutput_rotations (output_t *output)
694a0d3b6eaSmrg{
695a0d3b6eaSmrg    Bool	    found = False;
696a0d3b6eaSmrg    Rotation	    rotation = RR_Rotate_0;
697a0d3b6eaSmrg    XRROutputInfo   *output_info = output->output_info;
698a0d3b6eaSmrg    int		    c;
699a0d3b6eaSmrg
700a0d3b6eaSmrg    for (c = 0; c < output_info->ncrtc; c++)
701a0d3b6eaSmrg    {
702a0d3b6eaSmrg	crtc_t	*crtc = find_crtc_by_xid (output_info->crtcs[c]);
703a0d3b6eaSmrg	if (crtc)
704a0d3b6eaSmrg	{
705a0d3b6eaSmrg	    if (!found) {
706a0d3b6eaSmrg		rotation = crtc->crtc_info->rotations;
707a0d3b6eaSmrg		found = True;
708a0d3b6eaSmrg	    } else
709a0d3b6eaSmrg		rotation &= crtc->crtc_info->rotations;
710a0d3b6eaSmrg	}
711a0d3b6eaSmrg    }
712a0d3b6eaSmrg    return rotation;
713a0d3b6eaSmrg}
714a0d3b6eaSmrg
715a0d3b6eaSmrgstatic Bool
716a0d3b6eaSmrgoutput_can_use_rotation (output_t *output, Rotation rotation)
717a0d3b6eaSmrg{
718a0d3b6eaSmrg    XRROutputInfo   *output_info = output->output_info;
719a0d3b6eaSmrg    int		    c;
720a0d3b6eaSmrg
721a0d3b6eaSmrg    /* make sure all of the crtcs can use this rotation.
722a0d3b6eaSmrg     * yes, this is not strictly necessary, but it is
723a0d3b6eaSmrg     * simpler,and we expect most drivers to either
724a0d3b6eaSmrg     * support rotation everywhere or nowhere
725a0d3b6eaSmrg     */
726a0d3b6eaSmrg    for (c = 0; c < output_info->ncrtc; c++)
727a0d3b6eaSmrg    {
728a0d3b6eaSmrg	crtc_t	*crtc = find_crtc_by_xid (output_info->crtcs[c]);
729a0d3b6eaSmrg	if (crtc && !crtc_can_use_rotation (crtc, rotation))
730a0d3b6eaSmrg	    return False;
731a0d3b6eaSmrg    }
732a0d3b6eaSmrg    return True;
733a0d3b6eaSmrg}
734a0d3b6eaSmrg
735a0d3b6eaSmrgstatic void
736a0d3b6eaSmrgset_output_info (output_t *output, RROutput xid, XRROutputInfo *output_info)
737a0d3b6eaSmrg{
738a0d3b6eaSmrg    /* sanity check output info */
739a0d3b6eaSmrg    if (output_info->connection != RR_Disconnected && !output_info->nmode)
740a0d3b6eaSmrg	fatal ("Output %s is not disconnected but has no modes\n",
741a0d3b6eaSmrg	       output_info->name);
742a0d3b6eaSmrg
743a0d3b6eaSmrg    /* set output name and info */
744a0d3b6eaSmrg    if (!(output->output.kind & name_xid))
745a0d3b6eaSmrg	set_name_xid (&output->output, xid);
746a0d3b6eaSmrg    if (!(output->output.kind & name_string))
747a0d3b6eaSmrg	set_name_string (&output->output, output_info->name);
748a0d3b6eaSmrg    output->output_info = output_info;
749a0d3b6eaSmrg
750a0d3b6eaSmrg    /* set crtc name and info */
751a0d3b6eaSmrg    if (!(output->changes & changes_crtc))
752a0d3b6eaSmrg	set_name_xid (&output->crtc, output_info->crtc);
753a0d3b6eaSmrg
754a0d3b6eaSmrg    if (output->crtc.kind == name_xid && output->crtc.xid == None)
755a0d3b6eaSmrg	output->crtc_info = NULL;
756a0d3b6eaSmrg    else
757a0d3b6eaSmrg    {
758a0d3b6eaSmrg	output->crtc_info = find_crtc (&output->crtc);
759a0d3b6eaSmrg	if (!output->crtc_info)
760a0d3b6eaSmrg	{
761a0d3b6eaSmrg	    if (output->crtc.kind & name_xid)
762a0d3b6eaSmrg		fatal ("cannot find crtc 0x%x\n", output->crtc.xid);
763a0d3b6eaSmrg	    if (output->crtc.kind & name_index)
764a0d3b6eaSmrg		fatal ("cannot find crtc %d\n", output->crtc.index);
765a0d3b6eaSmrg	}
766a0d3b6eaSmrg	if (!output_can_use_crtc (output, output->crtc_info))
767a0d3b6eaSmrg	    fatal ("output %s cannot use crtc 0x%x\n", output->output.string,
768a0d3b6eaSmrg		   output->crtc_info->crtc.xid);
769a0d3b6eaSmrg    }
770a0d3b6eaSmrg
771a0d3b6eaSmrg    /* set mode name and info */
772a0d3b6eaSmrg    if (!(output->changes & changes_mode))
773a0d3b6eaSmrg    {
774a0d3b6eaSmrg	if (output->crtc_info)
775a0d3b6eaSmrg	    set_name_xid (&output->mode, output->crtc_info->crtc_info->mode);
776a0d3b6eaSmrg	else
777a0d3b6eaSmrg	    set_name_xid (&output->mode, None);
778a0d3b6eaSmrg	if (output->mode.xid)
779a0d3b6eaSmrg	{
780a0d3b6eaSmrg	    output->mode_info = find_mode_by_xid (output->mode.xid);
781a0d3b6eaSmrg	    if (!output->mode_info)
782a0d3b6eaSmrg		fatal ("server did not report mode 0x%x for output %s\n",
783a0d3b6eaSmrg		       output->mode.xid, output->output.string);
784a0d3b6eaSmrg	}
785a0d3b6eaSmrg	else
786a0d3b6eaSmrg	    output->mode_info = NULL;
787a0d3b6eaSmrg    }
788a0d3b6eaSmrg    else if (output->mode.kind == name_xid && output->mode.xid == None)
789a0d3b6eaSmrg	output->mode_info = NULL;
790a0d3b6eaSmrg    else
791a0d3b6eaSmrg    {
792a0d3b6eaSmrg	if (output->mode.kind == name_preferred)
793a0d3b6eaSmrg	    output->mode_info = preferred_mode (output);
794a0d3b6eaSmrg	else
795a0d3b6eaSmrg	    output->mode_info = find_mode_for_output (output, &output->mode);
796a0d3b6eaSmrg	if (!output->mode_info)
797a0d3b6eaSmrg	{
798a0d3b6eaSmrg	    if (output->mode.kind & name_preferred)
799a0d3b6eaSmrg		fatal ("cannot find preferred mode\n");
800a0d3b6eaSmrg	    if (output->mode.kind & name_string)
801a0d3b6eaSmrg		fatal ("cannot find mode %s\n", output->mode.string);
802a0d3b6eaSmrg	    if (output->mode.kind & name_xid)
803a0d3b6eaSmrg		fatal ("cannot find mode 0x%x\n", output->mode.xid);
804a0d3b6eaSmrg	}
805a0d3b6eaSmrg	if (!output_can_use_mode (output, output->mode_info))
806a0d3b6eaSmrg	    fatal ("output %s cannot use mode %s\n", output->output.string,
807a0d3b6eaSmrg		   output->mode_info->name);
808a0d3b6eaSmrg    }
809a0d3b6eaSmrg
810a0d3b6eaSmrg    /* set position */
811a0d3b6eaSmrg    if (!(output->changes & changes_position))
812a0d3b6eaSmrg    {
813a0d3b6eaSmrg	if (output->crtc_info)
814a0d3b6eaSmrg	{
815a0d3b6eaSmrg	    output->x = output->crtc_info->crtc_info->x;
816a0d3b6eaSmrg	    output->y = output->crtc_info->crtc_info->y;
817a0d3b6eaSmrg	}
818a0d3b6eaSmrg	else
819a0d3b6eaSmrg	{
820a0d3b6eaSmrg	    output->x = 0;
821a0d3b6eaSmrg	    output->y = 0;
822a0d3b6eaSmrg	}
823a0d3b6eaSmrg    }
824a0d3b6eaSmrg
825a0d3b6eaSmrg    /* set rotation */
826a0d3b6eaSmrg    if (!(output->changes & changes_rotation))
827a0d3b6eaSmrg    {
828a0d3b6eaSmrg	output->rotation &= ~0xf;
829a0d3b6eaSmrg	if (output->crtc_info)
830a0d3b6eaSmrg	    output->rotation |= (output->crtc_info->crtc_info->rotation & 0xf);
831a0d3b6eaSmrg	else
832a0d3b6eaSmrg	    output->rotation = RR_Rotate_0;
833a0d3b6eaSmrg    }
834a0d3b6eaSmrg    if (!(output->changes & changes_reflection))
835a0d3b6eaSmrg    {
836a0d3b6eaSmrg	output->rotation &= ~(RR_Reflect_X|RR_Reflect_Y);
837a0d3b6eaSmrg	if (output->crtc_info)
838a0d3b6eaSmrg	    output->rotation |= (output->crtc_info->crtc_info->rotation &
839a0d3b6eaSmrg				 (RR_Reflect_X|RR_Reflect_Y));
840a0d3b6eaSmrg    }
841a0d3b6eaSmrg    if (!output_can_use_rotation (output, output->rotation))
842a0d3b6eaSmrg	fatal ("output %s cannot use rotation \"%s\" reflection \"%s\"\n",
843a0d3b6eaSmrg	       output->output.string,
844a0d3b6eaSmrg	       rotation_name (output->rotation),
845a0d3b6eaSmrg	       reflection_name (output->rotation));
846a0d3b6eaSmrg}
847a0d3b6eaSmrg
848a0d3b6eaSmrgstatic void
849a0d3b6eaSmrgget_screen (void)
850a0d3b6eaSmrg{
851a0d3b6eaSmrg    if (!has_1_2)
852a0d3b6eaSmrg        fatal ("Server RandR version before 1.2\n");
853a0d3b6eaSmrg
854a0d3b6eaSmrg    XRRGetScreenSizeRange (dpy, root, &minWidth, &minHeight,
855a0d3b6eaSmrg			   &maxWidth, &maxHeight);
856a0d3b6eaSmrg
857a0d3b6eaSmrg    res = XRRGetScreenResources (dpy, root);
858a0d3b6eaSmrg    if (!res) fatal ("could not get screen resources");
859a0d3b6eaSmrg}
860a0d3b6eaSmrg
861a0d3b6eaSmrgstatic void
862a0d3b6eaSmrgget_crtcs (void)
863a0d3b6eaSmrg{
864a0d3b6eaSmrg    int		c;
865a0d3b6eaSmrg
866a0d3b6eaSmrg    num_crtcs = res->ncrtc;
867a0d3b6eaSmrg    crtcs = calloc (num_crtcs, sizeof (crtc_t));
868a0d3b6eaSmrg    if (!crtcs) fatal ("out of memory");
869a0d3b6eaSmrg
870a0d3b6eaSmrg    for (c = 0; c < res->ncrtc; c++)
871a0d3b6eaSmrg    {
872a0d3b6eaSmrg	XRRCrtcInfo *crtc_info = XRRGetCrtcInfo (dpy, res, res->crtcs[c]);
873a0d3b6eaSmrg	set_name_xid (&crtcs[c].crtc, res->crtcs[c]);
874a0d3b6eaSmrg	set_name_index (&crtcs[c].crtc, c);
875a0d3b6eaSmrg	if (!crtc_info) fatal ("could not get crtc 0x%x information", res->crtcs[c]);
876a0d3b6eaSmrg	crtcs[c].crtc_info = crtc_info;
877a0d3b6eaSmrg	if (crtc_info->mode == None)
878a0d3b6eaSmrg	{
879a0d3b6eaSmrg	    crtcs[c].mode_info = NULL;
880a0d3b6eaSmrg	    crtcs[c].x = 0;
881a0d3b6eaSmrg	    crtcs[c].y = 0;
882a0d3b6eaSmrg	    crtcs[c].rotation = RR_Rotate_0;
883a0d3b6eaSmrg	}
884a0d3b6eaSmrg    }
885a0d3b6eaSmrg}
886a0d3b6eaSmrg
887a0d3b6eaSmrgstatic void
888a0d3b6eaSmrgcrtc_add_output (crtc_t *crtc, output_t *output)
889a0d3b6eaSmrg{
890a0d3b6eaSmrg    if (crtc->outputs)
891a0d3b6eaSmrg	crtc->outputs = realloc (crtc->outputs, (crtc->noutput + 1) * sizeof (output_t *));
892a0d3b6eaSmrg    else
893a0d3b6eaSmrg    {
894a0d3b6eaSmrg	crtc->outputs = malloc (sizeof (output_t *));
895a0d3b6eaSmrg	crtc->x = output->x;
896a0d3b6eaSmrg	crtc->y = output->y;
897a0d3b6eaSmrg	crtc->rotation = output->rotation;
898a0d3b6eaSmrg	crtc->mode_info = output->mode_info;
899a0d3b6eaSmrg    }
900a0d3b6eaSmrg    if (!crtc->outputs) fatal ("out of memory");
901a0d3b6eaSmrg    crtc->outputs[crtc->noutput++] = output;
902a0d3b6eaSmrg}
903a0d3b6eaSmrg
904a0d3b6eaSmrgstatic void
905a0d3b6eaSmrgset_crtcs (void)
906a0d3b6eaSmrg{
907a0d3b6eaSmrg    output_t	*output;
908a0d3b6eaSmrg
909a0d3b6eaSmrg    for (output = outputs; output; output = output->next)
910a0d3b6eaSmrg    {
911a0d3b6eaSmrg	if (!output->mode_info) continue;
912a0d3b6eaSmrg	crtc_add_output (output->crtc_info, output);
913a0d3b6eaSmrg    }
914a0d3b6eaSmrg}
915a0d3b6eaSmrg
916a0d3b6eaSmrgstatic Status
917a0d3b6eaSmrgcrtc_disable (crtc_t *crtc)
918a0d3b6eaSmrg{
919a0d3b6eaSmrg    if (verbose)
920a0d3b6eaSmrg    	printf ("crtc %d: disable\n", crtc->crtc.index);
921a0d3b6eaSmrg
922a0d3b6eaSmrg    if (dryrun)
923a0d3b6eaSmrg	return RRSetConfigSuccess;
924a0d3b6eaSmrg    return XRRSetCrtcConfig (dpy, res, crtc->crtc.xid, CurrentTime,
925a0d3b6eaSmrg			     0, 0, None, RR_Rotate_0, NULL, 0);
926a0d3b6eaSmrg}
927a0d3b6eaSmrg
928a0d3b6eaSmrgstatic Status
929a0d3b6eaSmrgcrtc_revert (crtc_t *crtc)
930a0d3b6eaSmrg{
931a0d3b6eaSmrg    XRRCrtcInfo	*crtc_info = crtc->crtc_info;
932a0d3b6eaSmrg
933a0d3b6eaSmrg    if (verbose)
934a0d3b6eaSmrg    	printf ("crtc %d: revert\n", crtc->crtc.index);
935a0d3b6eaSmrg
936a0d3b6eaSmrg    if (dryrun)
937a0d3b6eaSmrg	return RRSetConfigSuccess;
938a0d3b6eaSmrg    return XRRSetCrtcConfig (dpy, res, crtc->crtc.xid, CurrentTime,
939a0d3b6eaSmrg			    crtc_info->x, crtc_info->y,
940a0d3b6eaSmrg			    crtc_info->mode, crtc_info->rotation,
941a0d3b6eaSmrg			    crtc_info->outputs, crtc_info->noutput);
942a0d3b6eaSmrg}
943a0d3b6eaSmrg
944a0d3b6eaSmrgstatic Status
945a0d3b6eaSmrgcrtc_apply (crtc_t *crtc)
946a0d3b6eaSmrg{
947a0d3b6eaSmrg    RROutput	*rr_outputs;
948a0d3b6eaSmrg    int		o;
949a0d3b6eaSmrg    Status	s;
950a0d3b6eaSmrg    RRMode	mode = None;
951a0d3b6eaSmrg
952a0d3b6eaSmrg    if (!crtc->changing || !crtc->mode_info)
953a0d3b6eaSmrg	return RRSetConfigSuccess;
954a0d3b6eaSmrg
955a0d3b6eaSmrg    rr_outputs = calloc (crtc->noutput, sizeof (RROutput));
956a0d3b6eaSmrg    if (!rr_outputs)
957a0d3b6eaSmrg	return BadAlloc;
958a0d3b6eaSmrg    for (o = 0; o < crtc->noutput; o++)
959a0d3b6eaSmrg	rr_outputs[o] = crtc->outputs[o]->output.xid;
960a0d3b6eaSmrg    mode = crtc->mode_info->id;
961a0d3b6eaSmrg    if (verbose) {
962a0d3b6eaSmrg	printf ("crtc %d: %12s %6.1f +%d+%d", crtc->crtc.index,
963a0d3b6eaSmrg		crtc->mode_info->name, mode_refresh (crtc->mode_info),
964a0d3b6eaSmrg		crtc->x, crtc->y);
965a0d3b6eaSmrg	for (o = 0; o < crtc->noutput; o++)
966a0d3b6eaSmrg	    printf (" \"%s\"", crtc->outputs[o]->output.string);
967a0d3b6eaSmrg	printf ("\n");
968a0d3b6eaSmrg    }
969a0d3b6eaSmrg
970a0d3b6eaSmrg    if (dryrun)
971a0d3b6eaSmrg	s = RRSetConfigSuccess;
972a0d3b6eaSmrg    else
973a0d3b6eaSmrg	s = XRRSetCrtcConfig (dpy, res, crtc->crtc.xid, CurrentTime,
974a0d3b6eaSmrg			      crtc->x, crtc->y, mode, crtc->rotation,
975a0d3b6eaSmrg			      rr_outputs, crtc->noutput);
976a0d3b6eaSmrg    free (rr_outputs);
977a0d3b6eaSmrg    return s;
978a0d3b6eaSmrg}
979a0d3b6eaSmrg
980a0d3b6eaSmrgstatic void
981a0d3b6eaSmrgscreen_revert (void)
982a0d3b6eaSmrg{
983a0d3b6eaSmrg    if (verbose)
984a0d3b6eaSmrg	printf ("screen %d: revert\n", screen);
985a0d3b6eaSmrg
986a0d3b6eaSmrg    if (dryrun)
987a0d3b6eaSmrg	return;
988a0d3b6eaSmrg    XRRSetScreenSize (dpy, root,
989a0d3b6eaSmrg		      DisplayWidth (dpy, screen),
990a0d3b6eaSmrg		      DisplayHeight (dpy, screen),
991a0d3b6eaSmrg		      DisplayWidthMM (dpy, screen),
992a0d3b6eaSmrg		      DisplayHeightMM (dpy, screen));
993a0d3b6eaSmrg}
994a0d3b6eaSmrg
995a0d3b6eaSmrgstatic void
996a0d3b6eaSmrgscreen_apply (void)
997a0d3b6eaSmrg{
998a0d3b6eaSmrg    if (fb_width == DisplayWidth (dpy, screen) &&
999a0d3b6eaSmrg	fb_height == DisplayHeight (dpy, screen) &&
1000a0d3b6eaSmrg	fb_width_mm == DisplayWidthMM (dpy, screen) &&
1001a0d3b6eaSmrg	fb_height_mm == DisplayHeightMM (dpy, screen))
1002a0d3b6eaSmrg    {
1003a0d3b6eaSmrg	return;
1004a0d3b6eaSmrg    }
1005a0d3b6eaSmrg    if (verbose)
1006a0d3b6eaSmrg	printf ("screen %d: %dx%d %dx%d mm %6.2fdpi\n", screen,
1007a0d3b6eaSmrg		fb_width, fb_height, fb_width_mm, fb_height_mm, dpi);
1008a0d3b6eaSmrg    if (dryrun)
1009a0d3b6eaSmrg	return;
1010a0d3b6eaSmrg    XRRSetScreenSize (dpy, root, fb_width, fb_height,
1011a0d3b6eaSmrg		      fb_width_mm, fb_height_mm);
1012a0d3b6eaSmrg}
1013a0d3b6eaSmrg
1014a0d3b6eaSmrgstatic void
1015a0d3b6eaSmrgrevert (void)
1016a0d3b6eaSmrg{
1017a0d3b6eaSmrg    int	c;
1018a0d3b6eaSmrg
1019a0d3b6eaSmrg    /* first disable all crtcs */
1020a0d3b6eaSmrg    for (c = 0; c < res->ncrtc; c++)
1021a0d3b6eaSmrg	crtc_disable (&crtcs[c]);
1022a0d3b6eaSmrg    /* next reset screen size */
1023a0d3b6eaSmrg    screen_revert ();
1024a0d3b6eaSmrg    /* now restore all crtcs */
1025a0d3b6eaSmrg    for (c = 0; c < res->ncrtc; c++)
1026a0d3b6eaSmrg	crtc_revert (&crtcs[c]);
1027a0d3b6eaSmrg}
1028a0d3b6eaSmrg
1029a0d3b6eaSmrg/*
1030a0d3b6eaSmrg * uh-oh, something bad happened in the middle of changing
1031a0d3b6eaSmrg * the configuration. Revert to the previous configuration
1032a0d3b6eaSmrg * and bail
1033a0d3b6eaSmrg */
1034a0d3b6eaSmrgstatic void
1035a0d3b6eaSmrgpanic (Status s, crtc_t *crtc)
1036a0d3b6eaSmrg{
1037a0d3b6eaSmrg    int	    c = crtc->crtc.index;
1038a0d3b6eaSmrg    char    *message;
1039a0d3b6eaSmrg
1040a0d3b6eaSmrg    switch (s) {
1041a0d3b6eaSmrg    case RRSetConfigSuccess:		message = "succeeded";		    break;
1042a0d3b6eaSmrg    case BadAlloc:			message = "out of memory";	    break;
1043a0d3b6eaSmrg    case RRSetConfigFailed:		message = "failed";		    break;
1044a0d3b6eaSmrg    case RRSetConfigInvalidConfigTime:	message = "invalid config time";    break;
1045a0d3b6eaSmrg    case RRSetConfigInvalidTime:	message = "invalid time";	    break;
1046a0d3b6eaSmrg    default:				message = "unknown failure";	    break;
1047a0d3b6eaSmrg    }
1048a0d3b6eaSmrg
1049a0d3b6eaSmrg    fprintf (stderr, "%s: Configure crtc %d %s\n", program_name, c, message);
1050a0d3b6eaSmrg    revert ();
1051a0d3b6eaSmrg    exit (1);
1052a0d3b6eaSmrg}
1053a0d3b6eaSmrg
1054a0d3b6eaSmrgvoid
1055a0d3b6eaSmrgapply (void)
1056a0d3b6eaSmrg{
1057a0d3b6eaSmrg    Status  s;
1058a0d3b6eaSmrg    int	    c;
1059a0d3b6eaSmrg
1060a0d3b6eaSmrg    /*
1061a0d3b6eaSmrg     * Turn off any crtcs which are to be disabled or which are
1062a0d3b6eaSmrg     * larger than the target size
1063a0d3b6eaSmrg     */
1064a0d3b6eaSmrg    for (c = 0; c < res->ncrtc; c++)
1065a0d3b6eaSmrg    {
1066a0d3b6eaSmrg	crtc_t	    *crtc = &crtcs[c];
1067a0d3b6eaSmrg	XRRCrtcInfo *crtc_info = crtc->crtc_info;
1068a0d3b6eaSmrg
1069a0d3b6eaSmrg	/* if this crtc is already disabled, skip it */
1070a0d3b6eaSmrg	if (crtc_info->mode == None)
1071a0d3b6eaSmrg	    continue;
1072a0d3b6eaSmrg
1073a0d3b6eaSmrg	/*
1074a0d3b6eaSmrg	 * If this crtc is to be left enabled, make
1075a0d3b6eaSmrg	 * sure the old size fits then new screen
1076a0d3b6eaSmrg	 */
1077a0d3b6eaSmrg	if (crtc->mode_info)
1078a0d3b6eaSmrg	{
1079a0d3b6eaSmrg	    XRRModeInfo	*old_mode = find_mode_by_xid (crtc_info->mode);
1080a0d3b6eaSmrg	    int x, y, w, h;
1081a0d3b6eaSmrg
1082a0d3b6eaSmrg	    if (!old_mode)
1083a0d3b6eaSmrg		panic (RRSetConfigFailed, crtc);
1084a0d3b6eaSmrg
1085a0d3b6eaSmrg	    /* old position and size information */
1086a0d3b6eaSmrg	    x = crtc_info->x;
1087a0d3b6eaSmrg	    y = crtc_info->y;
1088a0d3b6eaSmrg	    w = mode_width (old_mode, crtc_info->rotation);
1089a0d3b6eaSmrg	    h = mode_height (old_mode, crtc_info->rotation);
1090a0d3b6eaSmrg
1091a0d3b6eaSmrg	    /* if it fits, skip it */
1092a0d3b6eaSmrg	    if (x + w <= fb_width && y + h <= fb_height)
1093a0d3b6eaSmrg		continue;
1094a0d3b6eaSmrg	    crtc->changing = True;
1095a0d3b6eaSmrg	}
1096a0d3b6eaSmrg	s = crtc_disable (crtc);
1097a0d3b6eaSmrg	if (s != RRSetConfigSuccess)
1098a0d3b6eaSmrg	    panic (s, crtc);
1099a0d3b6eaSmrg    }
1100a0d3b6eaSmrg
1101a0d3b6eaSmrg    /*
1102a0d3b6eaSmrg     * Hold the server grabbed while messing with
1103a0d3b6eaSmrg     * the screen so that apps which notice the resize
1104a0d3b6eaSmrg     * event and ask for xinerama information from the server
1105a0d3b6eaSmrg     * receive up-to-date information
1106a0d3b6eaSmrg     */
1107a0d3b6eaSmrg    XGrabServer (dpy);
1108a0d3b6eaSmrg
1109a0d3b6eaSmrg    /*
1110a0d3b6eaSmrg     * Set the screen size
1111a0d3b6eaSmrg     */
1112a0d3b6eaSmrg    screen_apply ();
1113a0d3b6eaSmrg
1114a0d3b6eaSmrg    /*
1115a0d3b6eaSmrg     * Set crtcs
1116a0d3b6eaSmrg     */
1117a0d3b6eaSmrg
1118a0d3b6eaSmrg    for (c = 0; c < res->ncrtc; c++)
1119a0d3b6eaSmrg    {
1120a0d3b6eaSmrg	crtc_t	*crtc = &crtcs[c];
1121a0d3b6eaSmrg
1122a0d3b6eaSmrg	s = crtc_apply (crtc);
1123a0d3b6eaSmrg	if (s != RRSetConfigSuccess)
1124a0d3b6eaSmrg	    panic (s, crtc);
1125a0d3b6eaSmrg    }
1126a0d3b6eaSmrg    /*
1127a0d3b6eaSmrg     * Release the server grab and let all clients
1128a0d3b6eaSmrg     * respond to the updated state
1129a0d3b6eaSmrg     */
1130a0d3b6eaSmrg    XUngrabServer (dpy);
1131a0d3b6eaSmrg}
1132a0d3b6eaSmrg
1133a0d3b6eaSmrg/*
1134a0d3b6eaSmrg * Use current output state to complete the output list
1135a0d3b6eaSmrg */
1136a0d3b6eaSmrgvoid
1137a0d3b6eaSmrgget_outputs (void)
1138a0d3b6eaSmrg{
1139a0d3b6eaSmrg    int		o;
1140a0d3b6eaSmrg
1141a0d3b6eaSmrg    for (o = 0; o < res->noutput; o++)
1142a0d3b6eaSmrg    {
1143a0d3b6eaSmrg	XRROutputInfo	*output_info = XRRGetOutputInfo (dpy, res, res->outputs[o]);
1144a0d3b6eaSmrg	output_t	*output;
1145a0d3b6eaSmrg	name_t		output_name;
1146a0d3b6eaSmrg	if (!output_info) fatal ("could not get output 0x%x information", res->outputs[o]);
1147a0d3b6eaSmrg	set_name_xid (&output_name, res->outputs[o]);
1148a0d3b6eaSmrg	set_name_index (&output_name, o);
1149a0d3b6eaSmrg	set_name_string (&output_name, output_info->name);
1150a0d3b6eaSmrg	output = find_output (&output_name);
1151a0d3b6eaSmrg	if (!output)
1152a0d3b6eaSmrg	{
1153a0d3b6eaSmrg	    output = add_output ();
1154a0d3b6eaSmrg	    set_name_all (&output->output, &output_name);
1155a0d3b6eaSmrg	    /*
1156a0d3b6eaSmrg	     * When global --automatic mode is set, turn on connected but off
1157a0d3b6eaSmrg	     * outputs, turn off disconnected but on outputs
1158a0d3b6eaSmrg	     */
1159a0d3b6eaSmrg	    if (automatic)
1160a0d3b6eaSmrg	    {
1161a0d3b6eaSmrg		switch (output_info->connection) {
1162a0d3b6eaSmrg		case RR_Connected:
1163a0d3b6eaSmrg		    if (!output_info->crtc) {
1164a0d3b6eaSmrg			output->changes |= changes_automatic;
1165a0d3b6eaSmrg			output->automatic = True;
1166a0d3b6eaSmrg		    }
1167a0d3b6eaSmrg		    break;
1168a0d3b6eaSmrg		case RR_Disconnected:
1169a0d3b6eaSmrg		    if (output_info->crtc)
1170a0d3b6eaSmrg		    {
1171a0d3b6eaSmrg			output->changes |= changes_automatic;
1172a0d3b6eaSmrg			output->automatic = True;
1173a0d3b6eaSmrg		    }
1174a0d3b6eaSmrg		    break;
1175a0d3b6eaSmrg		}
1176a0d3b6eaSmrg	    }
1177a0d3b6eaSmrg	}
1178a0d3b6eaSmrg
1179a0d3b6eaSmrg	/*
1180a0d3b6eaSmrg	 * Automatic mode -- track connection state and enable/disable outputs
1181a0d3b6eaSmrg	 * as necessary
1182a0d3b6eaSmrg	 */
1183a0d3b6eaSmrg	if (output->automatic)
1184a0d3b6eaSmrg	{
1185a0d3b6eaSmrg	    switch (output_info->connection) {
1186a0d3b6eaSmrg	    case RR_Connected:
1187a0d3b6eaSmrg	    case RR_UnknownConnection:
1188a0d3b6eaSmrg		if ((!(output->changes & changes_mode)))
1189a0d3b6eaSmrg		{
1190a0d3b6eaSmrg		    set_name_preferred (&output->mode);
1191a0d3b6eaSmrg		    output->changes |= changes_mode;
1192a0d3b6eaSmrg		}
1193a0d3b6eaSmrg		break;
1194a0d3b6eaSmrg	    case RR_Disconnected:
1195a0d3b6eaSmrg		if ((!(output->changes & changes_mode)))
1196a0d3b6eaSmrg		{
1197a0d3b6eaSmrg		    set_name_xid (&output->mode, None);
1198a0d3b6eaSmrg		    set_name_xid (&output->crtc, None);
1199a0d3b6eaSmrg		    output->changes |= changes_mode;
1200a0d3b6eaSmrg		    output->changes |= changes_crtc;
1201a0d3b6eaSmrg		}
1202a0d3b6eaSmrg		break;
1203a0d3b6eaSmrg	    }
1204a0d3b6eaSmrg	}
1205a0d3b6eaSmrg
1206a0d3b6eaSmrg	set_output_info (output, res->outputs[o], output_info);
1207a0d3b6eaSmrg    }
1208a0d3b6eaSmrg}
1209a0d3b6eaSmrg
1210a0d3b6eaSmrgvoid
1211a0d3b6eaSmrgmark_changing_crtcs (void)
1212a0d3b6eaSmrg{
1213a0d3b6eaSmrg    int	c;
1214a0d3b6eaSmrg
1215a0d3b6eaSmrg    for (c = 0; c < num_crtcs; c++)
1216a0d3b6eaSmrg    {
1217a0d3b6eaSmrg	crtc_t	    *crtc = &crtcs[c];
1218a0d3b6eaSmrg	int	    o;
1219a0d3b6eaSmrg	output_t    *output;
1220a0d3b6eaSmrg
1221a0d3b6eaSmrg	/* walk old output list (to catch disables) */
1222a0d3b6eaSmrg	for (o = 0; o < crtc->crtc_info->noutput; o++)
1223a0d3b6eaSmrg	{
1224a0d3b6eaSmrg	    output = find_output_by_xid (crtc->crtc_info->outputs[o]);
1225a0d3b6eaSmrg	    if (!output) fatal ("cannot find output 0x%x\n",
1226a0d3b6eaSmrg				crtc->crtc_info->outputs[o]);
1227a0d3b6eaSmrg	    if (output->changes)
1228a0d3b6eaSmrg		crtc->changing = True;
1229a0d3b6eaSmrg	}
1230a0d3b6eaSmrg	/* walk new output list */
1231a0d3b6eaSmrg	for (o = 0; o < crtc->noutput; o++)
1232a0d3b6eaSmrg	{
1233a0d3b6eaSmrg	    output = crtc->outputs[o];
1234a0d3b6eaSmrg	    if (output->changes)
1235a0d3b6eaSmrg		crtc->changing = True;
1236a0d3b6eaSmrg	}
1237a0d3b6eaSmrg    }
1238a0d3b6eaSmrg}
1239a0d3b6eaSmrg
1240a0d3b6eaSmrg/*
1241a0d3b6eaSmrg * Test whether 'crtc' can be used for 'output'
1242a0d3b6eaSmrg */
1243a0d3b6eaSmrgBool
1244a0d3b6eaSmrgcheck_crtc_for_output (crtc_t *crtc, output_t *output)
1245a0d3b6eaSmrg{
1246a0d3b6eaSmrg    int		c;
1247a0d3b6eaSmrg    int		l;
1248a0d3b6eaSmrg    output_t    *other;
1249a0d3b6eaSmrg
1250a0d3b6eaSmrg    for (c = 0; c < output->output_info->ncrtc; c++)
1251a0d3b6eaSmrg	if (output->output_info->crtcs[c] == crtc->crtc.xid)
1252a0d3b6eaSmrg	    break;
1253a0d3b6eaSmrg    if (c == output->output_info->ncrtc)
1254a0d3b6eaSmrg	return False;
1255a0d3b6eaSmrg    for (other = outputs; other; other = other->next)
1256a0d3b6eaSmrg    {
1257a0d3b6eaSmrg	if (other == output)
1258a0d3b6eaSmrg	    continue;
1259a0d3b6eaSmrg
1260a0d3b6eaSmrg	if (other->mode_info == NULL)
1261a0d3b6eaSmrg	    continue;
1262a0d3b6eaSmrg
1263a0d3b6eaSmrg	if (other->crtc_info != crtc)
1264a0d3b6eaSmrg	    continue;
1265a0d3b6eaSmrg
1266a0d3b6eaSmrg	/* see if the output connected to the crtc can clone to this output */
1267a0d3b6eaSmrg	for (l = 0; l < output->output_info->nclone; l++)
1268a0d3b6eaSmrg	    if (output->output_info->clones[l] == other->output.xid)
1269a0d3b6eaSmrg		break;
1270a0d3b6eaSmrg	/* not on the list, can't clone */
1271a0d3b6eaSmrg	if (l == output->output_info->nclone)
1272a0d3b6eaSmrg	    return False;
1273a0d3b6eaSmrg    }
1274a0d3b6eaSmrg
1275a0d3b6eaSmrg    if (crtc->noutput)
1276a0d3b6eaSmrg    {
1277a0d3b6eaSmrg	/* make sure the state matches */
1278a0d3b6eaSmrg	if (crtc->mode_info != output->mode_info)
1279a0d3b6eaSmrg	    return False;
1280a0d3b6eaSmrg	if (crtc->x != output->x)
1281a0d3b6eaSmrg	    return False;
1282a0d3b6eaSmrg	if (crtc->y != output->y)
1283a0d3b6eaSmrg	    return False;
1284a0d3b6eaSmrg	if (crtc->rotation != output->rotation)
1285a0d3b6eaSmrg	    return False;
1286a0d3b6eaSmrg    }
1287a0d3b6eaSmrg    else if (crtc->crtc_info->noutput)
1288a0d3b6eaSmrg    {
1289a0d3b6eaSmrg	/* make sure the state matches the already used state */
1290a0d3b6eaSmrg	XRRModeInfo *mode = find_mode_by_xid (crtc->crtc_info->mode);
1291a0d3b6eaSmrg
1292a0d3b6eaSmrg	if (mode != output->mode_info)
1293a0d3b6eaSmrg	    return False;
1294a0d3b6eaSmrg	if (crtc->crtc_info->x != output->x)
1295a0d3b6eaSmrg	    return False;
1296a0d3b6eaSmrg	if (crtc->crtc_info->y != output->y)
1297a0d3b6eaSmrg	    return False;
1298a0d3b6eaSmrg	if (crtc->crtc_info->rotation != output->rotation)
1299a0d3b6eaSmrg	    return False;
1300a0d3b6eaSmrg    }
1301a0d3b6eaSmrg    return True;
1302a0d3b6eaSmrg}
1303a0d3b6eaSmrg
1304a0d3b6eaSmrgcrtc_t *
1305a0d3b6eaSmrgfind_crtc_for_output (output_t *output)
1306a0d3b6eaSmrg{
1307a0d3b6eaSmrg    int	    c;
1308a0d3b6eaSmrg
1309a0d3b6eaSmrg    for (c = 0; c < output->output_info->ncrtc; c++)
1310a0d3b6eaSmrg    {
1311a0d3b6eaSmrg	crtc_t	    *crtc;
1312a0d3b6eaSmrg
1313a0d3b6eaSmrg	crtc = find_crtc_by_xid (output->output_info->crtcs[c]);
1314a0d3b6eaSmrg	if (!crtc) fatal ("cannot find crtc 0x%x\n", output->output_info->crtcs[c]);
1315a0d3b6eaSmrg
1316a0d3b6eaSmrg	if (check_crtc_for_output (crtc, output))
1317a0d3b6eaSmrg	    return crtc;
1318a0d3b6eaSmrg    }
1319a0d3b6eaSmrg    return NULL;
1320a0d3b6eaSmrg}
1321a0d3b6eaSmrg
1322a0d3b6eaSmrgstatic void
1323a0d3b6eaSmrgset_positions (void)
1324a0d3b6eaSmrg{
1325a0d3b6eaSmrg    output_t	*output;
1326a0d3b6eaSmrg    Bool	keep_going;
1327a0d3b6eaSmrg    Bool	any_set;
1328a0d3b6eaSmrg    int		min_x, min_y;
1329a0d3b6eaSmrg
1330a0d3b6eaSmrg    for (;;)
1331a0d3b6eaSmrg    {
1332a0d3b6eaSmrg	any_set = False;
1333a0d3b6eaSmrg	keep_going = False;
1334a0d3b6eaSmrg	for (output = outputs; output; output = output->next)
1335a0d3b6eaSmrg	{
1336a0d3b6eaSmrg	    output_t    *relation;
1337a0d3b6eaSmrg	    name_t	relation_name;
1338a0d3b6eaSmrg
1339a0d3b6eaSmrg	    if (!(output->changes & changes_relation)) continue;
1340a0d3b6eaSmrg
1341a0d3b6eaSmrg	    if (output->mode_info == NULL) continue;
1342a0d3b6eaSmrg
1343a0d3b6eaSmrg	    init_name (&relation_name);
1344a0d3b6eaSmrg	    set_name_string (&relation_name, output->relative_to);
1345a0d3b6eaSmrg	    relation = find_output (&relation_name);
1346a0d3b6eaSmrg	    if (!relation) fatal ("cannot find output \"%s\"\n", output->relative_to);
1347a0d3b6eaSmrg
1348a0d3b6eaSmrg	    if (relation->mode_info == NULL)
1349a0d3b6eaSmrg	    {
1350a0d3b6eaSmrg		output->x = 0;
1351a0d3b6eaSmrg		output->y = 0;
1352a0d3b6eaSmrg		output->changes |= changes_position;
1353a0d3b6eaSmrg		any_set = True;
1354a0d3b6eaSmrg		continue;
1355a0d3b6eaSmrg	    }
1356a0d3b6eaSmrg	    /*
1357a0d3b6eaSmrg	     * Make sure the dependent object has been set in place
1358a0d3b6eaSmrg	     */
1359a0d3b6eaSmrg	    if ((relation->changes & changes_relation) &&
1360a0d3b6eaSmrg		!(relation->changes & changes_position))
1361a0d3b6eaSmrg	    {
1362a0d3b6eaSmrg		keep_going = True;
1363a0d3b6eaSmrg		continue;
1364a0d3b6eaSmrg	    }
1365a0d3b6eaSmrg
1366a0d3b6eaSmrg	    switch (output->relation) {
1367a0d3b6eaSmrg	    case left_of:
1368a0d3b6eaSmrg		output->y = relation->y;
1369a0d3b6eaSmrg		output->x = relation->x - mode_width (output->mode_info, output->rotation);
1370a0d3b6eaSmrg		break;
1371a0d3b6eaSmrg	    case right_of:
1372a0d3b6eaSmrg		output->y = relation->y;
1373a0d3b6eaSmrg		output->x = relation->x + mode_width (relation->mode_info, relation->rotation);
1374a0d3b6eaSmrg		break;
1375a0d3b6eaSmrg	    case above:
1376a0d3b6eaSmrg		output->x = relation->x;
1377a0d3b6eaSmrg		output->y = relation->y - mode_height (output->mode_info, output->rotation);
1378a0d3b6eaSmrg		break;
1379a0d3b6eaSmrg	    case below:
1380a0d3b6eaSmrg		output->x = relation->x;
1381a0d3b6eaSmrg		output->y = relation->y + mode_height (relation->mode_info, relation->rotation);
1382a0d3b6eaSmrg		break;
1383a0d3b6eaSmrg	    case same_as:
1384a0d3b6eaSmrg		output->x = relation->x;
1385a0d3b6eaSmrg		output->y = relation->y;
1386a0d3b6eaSmrg	    }
1387a0d3b6eaSmrg	    output->changes |= changes_position;
1388a0d3b6eaSmrg	    any_set = True;
1389a0d3b6eaSmrg	}
1390a0d3b6eaSmrg	if (!keep_going)
1391a0d3b6eaSmrg	    break;
1392a0d3b6eaSmrg	if (!any_set)
1393a0d3b6eaSmrg	    fatal ("loop in relative position specifications\n");
1394a0d3b6eaSmrg    }
1395a0d3b6eaSmrg
1396a0d3b6eaSmrg    /*
1397a0d3b6eaSmrg     * Now normalize positions so the upper left corner of all outputs is at 0,0
1398a0d3b6eaSmrg     */
1399a0d3b6eaSmrg    min_x = 32768;
1400a0d3b6eaSmrg    min_y = 32768;
1401a0d3b6eaSmrg    for (output = outputs; output; output = output->next)
1402a0d3b6eaSmrg    {
1403a0d3b6eaSmrg	if (output->mode_info == NULL) continue;
1404a0d3b6eaSmrg
1405a0d3b6eaSmrg	if (output->x < min_x) min_x = output->x;
1406a0d3b6eaSmrg	if (output->y < min_y) min_y = output->y;
1407a0d3b6eaSmrg    }
1408a0d3b6eaSmrg    if (min_x || min_y)
1409a0d3b6eaSmrg    {
1410a0d3b6eaSmrg	/* move all outputs */
1411a0d3b6eaSmrg	for (output = outputs; output; output = output->next)
1412a0d3b6eaSmrg	{
1413a0d3b6eaSmrg	    if (output->mode_info == NULL) continue;
1414a0d3b6eaSmrg
1415a0d3b6eaSmrg	    output->x -= min_x;
1416a0d3b6eaSmrg	    output->y -= min_y;
1417a0d3b6eaSmrg	    output->changes |= changes_position;
1418a0d3b6eaSmrg	}
1419a0d3b6eaSmrg    }
1420a0d3b6eaSmrg}
1421a0d3b6eaSmrg
1422a0d3b6eaSmrgstatic void
1423a0d3b6eaSmrgset_screen_size (void)
1424a0d3b6eaSmrg{
1425a0d3b6eaSmrg    output_t	*output;
1426a0d3b6eaSmrg    Bool	fb_specified = fb_width != 0 && fb_height != 0;
1427a0d3b6eaSmrg
1428a0d3b6eaSmrg    for (output = outputs; output; output = output->next)
1429a0d3b6eaSmrg    {
1430a0d3b6eaSmrg	XRRModeInfo *mode_info = output->mode_info;
1431a0d3b6eaSmrg	int	    x, y, w, h;
1432a0d3b6eaSmrg
1433a0d3b6eaSmrg	if (!mode_info) continue;
1434a0d3b6eaSmrg
1435a0d3b6eaSmrg	x = output->x;
1436a0d3b6eaSmrg	y = output->y;
1437a0d3b6eaSmrg	w = mode_width (mode_info, output->rotation);
1438a0d3b6eaSmrg	h = mode_height (mode_info, output->rotation);
1439a0d3b6eaSmrg	/* make sure output fits in specified size */
1440a0d3b6eaSmrg	if (fb_specified)
1441a0d3b6eaSmrg	{
1442a0d3b6eaSmrg	    if (x + w > fb_width || y + h > fb_height)
1443a0d3b6eaSmrg		fatal ("specified screen %dx%d not large enough for output %s (%dx%d+%d+%d)\n",
1444a0d3b6eaSmrg		       fb_width, fb_height, output->output.string, w, h, x, y);
1445a0d3b6eaSmrg	}
1446a0d3b6eaSmrg	/* fit fb to output */
1447a0d3b6eaSmrg	else
1448a0d3b6eaSmrg	{
1449a0d3b6eaSmrg	    if (x + w > fb_width) fb_width = x + w;
1450a0d3b6eaSmrg	    if (y + h > fb_height) fb_height = y + h;
1451a0d3b6eaSmrg	}
1452a0d3b6eaSmrg    }
1453a0d3b6eaSmrg
1454a0d3b6eaSmrg    if (fb_width > maxWidth || fb_height > maxHeight)
1455a0d3b6eaSmrg        fatal ("screen cannot be larger than %dx%d (desired size %dx%d)\n",
1456a0d3b6eaSmrg	       maxWidth, maxHeight, fb_width, fb_height);
1457a0d3b6eaSmrg    if (fb_specified)
1458a0d3b6eaSmrg    {
1459a0d3b6eaSmrg	if (fb_width < minWidth || fb_height < minHeight)
1460a0d3b6eaSmrg	    fatal ("screen must be at least %dx%d\n", minWidth, minHeight);
1461a0d3b6eaSmrg    }
1462a0d3b6eaSmrg    else
1463a0d3b6eaSmrg    {
1464a0d3b6eaSmrg	if (fb_width < minWidth) fb_width = minWidth;
1465a0d3b6eaSmrg	if (fb_height < minHeight) fb_height = minHeight;
1466a0d3b6eaSmrg    }
1467a0d3b6eaSmrg}
1468a0d3b6eaSmrg
1469a0d3b6eaSmrg#endif
1470a0d3b6eaSmrg
1471a0d3b6eaSmrgvoid
1472a0d3b6eaSmrgdisable_outputs (output_t *outputs)
1473a0d3b6eaSmrg{
1474a0d3b6eaSmrg    while (outputs)
1475a0d3b6eaSmrg    {
1476a0d3b6eaSmrg	outputs->crtc_info = NULL;
1477a0d3b6eaSmrg	outputs = outputs->next;
1478a0d3b6eaSmrg    }
1479a0d3b6eaSmrg}
1480a0d3b6eaSmrg
1481a0d3b6eaSmrg/*
1482a0d3b6eaSmrg * find the best mapping from output to crtc available
1483a0d3b6eaSmrg */
1484a0d3b6eaSmrgint
1485a0d3b6eaSmrgpick_crtcs_score (output_t *outputs)
1486a0d3b6eaSmrg{
1487a0d3b6eaSmrg    output_t	*output;
1488a0d3b6eaSmrg    int		best_score;
1489a0d3b6eaSmrg    int		my_score;
1490a0d3b6eaSmrg    int		score;
1491a0d3b6eaSmrg    crtc_t	*best_crtc;
1492a0d3b6eaSmrg    int		c;
1493a0d3b6eaSmrg
1494a0d3b6eaSmrg    if (!outputs)
1495a0d3b6eaSmrg	return 0;
1496a0d3b6eaSmrg
1497a0d3b6eaSmrg    output = outputs;
1498a0d3b6eaSmrg    outputs = outputs->next;
1499a0d3b6eaSmrg    /*
1500a0d3b6eaSmrg     * Score with this output disabled
1501a0d3b6eaSmrg     */
1502a0d3b6eaSmrg    output->crtc_info = NULL;
1503a0d3b6eaSmrg    best_score = pick_crtcs_score (outputs);
1504a0d3b6eaSmrg    if (output->mode_info == NULL)
1505a0d3b6eaSmrg	return best_score;
1506a0d3b6eaSmrg
1507a0d3b6eaSmrg    best_crtc = NULL;
1508a0d3b6eaSmrg    /*
1509a0d3b6eaSmrg     * Now score with this output any valid crtc
1510a0d3b6eaSmrg     */
1511a0d3b6eaSmrg    for (c = 0; c < output->output_info->ncrtc; c++)
1512a0d3b6eaSmrg    {
1513a0d3b6eaSmrg	crtc_t	    *crtc;
1514a0d3b6eaSmrg
1515a0d3b6eaSmrg	crtc = find_crtc_by_xid (output->output_info->crtcs[c]);
1516a0d3b6eaSmrg	if (!crtc)
1517a0d3b6eaSmrg	    fatal ("cannot find crtc 0x%x\n", output->output_info->crtcs[c]);
1518a0d3b6eaSmrg
1519a0d3b6eaSmrg	/* reset crtc allocation for following outputs */
1520a0d3b6eaSmrg	disable_outputs (outputs);
1521a0d3b6eaSmrg	if (!check_crtc_for_output (crtc, output))
1522a0d3b6eaSmrg	    continue;
1523a0d3b6eaSmrg
1524a0d3b6eaSmrg	my_score = 1000;
1525a0d3b6eaSmrg	/* slight preference for existing connections */
1526a0d3b6eaSmrg	if (crtc == output->current_crtc_info)
1527a0d3b6eaSmrg	    my_score++;
1528a0d3b6eaSmrg
1529a0d3b6eaSmrg	output->crtc_info = crtc;
1530a0d3b6eaSmrg	score = my_score + pick_crtcs_score (outputs);
1531a0d3b6eaSmrg	if (score > best_score)
1532a0d3b6eaSmrg	{
1533a0d3b6eaSmrg	    best_crtc = crtc;
1534a0d3b6eaSmrg	    best_score = score;
1535a0d3b6eaSmrg	}
1536a0d3b6eaSmrg    }
1537a0d3b6eaSmrg    if (output->crtc_info != best_crtc)
1538a0d3b6eaSmrg	output->crtc_info = best_crtc;
1539a0d3b6eaSmrg    /*
1540a0d3b6eaSmrg     * Reset other outputs based on this one using the best crtc
1541a0d3b6eaSmrg     */
1542a0d3b6eaSmrg    (void) pick_crtcs_score (outputs);
1543a0d3b6eaSmrg
1544a0d3b6eaSmrg    return best_score;
1545a0d3b6eaSmrg}
1546a0d3b6eaSmrg
1547a0d3b6eaSmrg/*
1548a0d3b6eaSmrg * Pick crtcs for any changing outputs that don't have one
1549a0d3b6eaSmrg */
1550a0d3b6eaSmrgvoid
1551a0d3b6eaSmrgpick_crtcs (void)
1552a0d3b6eaSmrg{
1553a0d3b6eaSmrg    output_t	*output;
1554a0d3b6eaSmrg
1555a0d3b6eaSmrg    /*
1556a0d3b6eaSmrg     * First try to match up newly enabled outputs with spare crtcs
1557a0d3b6eaSmrg     */
1558a0d3b6eaSmrg    for (output = outputs; output; output = output->next)
1559a0d3b6eaSmrg    {
1560a0d3b6eaSmrg	if (output->changes && output->mode_info)
1561a0d3b6eaSmrg	{
1562a0d3b6eaSmrg	    if (output->crtc_info) {
1563a0d3b6eaSmrg		if (output->crtc_info->crtc_info->noutput > 0 &&
1564a0d3b6eaSmrg		    (output->crtc_info->crtc_info->noutput > 1 ||
1565a0d3b6eaSmrg		     output != find_output_by_xid (output->crtc_info->crtc_info->outputs[0])))
1566a0d3b6eaSmrg		    break;
1567a0d3b6eaSmrg	    } else {
1568a0d3b6eaSmrg		output->crtc_info = find_crtc_for_output (output);
1569a0d3b6eaSmrg		if (!output->crtc_info)
1570a0d3b6eaSmrg		    break;
1571a0d3b6eaSmrg	    }
1572a0d3b6eaSmrg	}
1573a0d3b6eaSmrg    }
1574a0d3b6eaSmrg    /*
1575a0d3b6eaSmrg     * Everyone is happy
1576a0d3b6eaSmrg     */
1577a0d3b6eaSmrg    if (!output)
1578a0d3b6eaSmrg	return;
1579a0d3b6eaSmrg    /*
1580a0d3b6eaSmrg     * When the simple way fails, see if there is a way
1581a0d3b6eaSmrg     * to swap crtcs around and make things work
1582a0d3b6eaSmrg     */
1583a0d3b6eaSmrg    for (output = outputs; output; output = output->next)
1584a0d3b6eaSmrg	output->current_crtc_info = output->crtc_info;
1585a0d3b6eaSmrg    pick_crtcs_score (outputs);
1586a0d3b6eaSmrg    for (output = outputs; output; output = output->next)
1587a0d3b6eaSmrg    {
1588a0d3b6eaSmrg	if (output->mode_info && !output->crtc_info)
1589a0d3b6eaSmrg	    fatal ("cannot find crtc for output %s\n", output->output.string);
1590a0d3b6eaSmrg	if (!output->changes && output->crtc_info != output->current_crtc_info)
1591a0d3b6eaSmrg	    output->changes |= changes_crtc;
1592a0d3b6eaSmrg    }
1593a0d3b6eaSmrg}
1594a0d3b6eaSmrg
1595a0d3b6eaSmrgint
1596a0d3b6eaSmrgmain (int argc, char **argv)
1597a0d3b6eaSmrg{
1598a0d3b6eaSmrg    XRRScreenSize *sizes;
1599a0d3b6eaSmrg    XRRScreenConfiguration *sc;
1600a0d3b6eaSmrg    int		nsize;
1601a0d3b6eaSmrg    int		nrate;
1602a0d3b6eaSmrg    short		*rates;
1603a0d3b6eaSmrg    Status	status = RRSetConfigFailed;
1604a0d3b6eaSmrg    int		rot = -1;
1605a0d3b6eaSmrg    int		query = 0;
1606a0d3b6eaSmrg    Rotation	rotation, current_rotation, rotations;
1607a0d3b6eaSmrg    XEvent	event;
1608a0d3b6eaSmrg    XRRScreenChangeNotifyEvent *sce;
1609a0d3b6eaSmrg    char          *display_name = NULL;
1610a0d3b6eaSmrg    int 		i, j;
1611a0d3b6eaSmrg    SizeID	current_size;
1612a0d3b6eaSmrg    short	current_rate;
1613a0d3b6eaSmrg    float    	rate = -1;
1614a0d3b6eaSmrg    int		size = -1;
1615a0d3b6eaSmrg    int		dirind = 0;
1616a0d3b6eaSmrg    Bool	setit = False;
1617a0d3b6eaSmrg    Bool    	version = False;
1618a0d3b6eaSmrg    int		event_base, error_base;
1619a0d3b6eaSmrg    int		reflection = 0;
1620a0d3b6eaSmrg    int		width = 0, height = 0;
1621a0d3b6eaSmrg    Bool    	have_pixel_size = False;
1622a0d3b6eaSmrg    int		ret = 0;
1623a0d3b6eaSmrg#if HAS_RANDR_1_2
1624a0d3b6eaSmrg    output_t	*output = NULL;
1625a0d3b6eaSmrg    policy_t	policy = clone;
1626a0d3b6eaSmrg    Bool    	setit_1_2 = False;
1627a0d3b6eaSmrg    Bool    	query_1_2 = False;
1628a0d3b6eaSmrg    Bool	modeit = False;
1629a0d3b6eaSmrg    Bool	propit = False;
1630a0d3b6eaSmrg    Bool	query_1 = False;
1631a0d3b6eaSmrg    int		major, minor;
1632a0d3b6eaSmrg#endif
1633a0d3b6eaSmrg
1634a0d3b6eaSmrg    program_name = argv[0];
1635a0d3b6eaSmrg    if (argc == 1) query = True;
1636a0d3b6eaSmrg    for (i = 1; i < argc; i++) {
1637a0d3b6eaSmrg	if (!strcmp ("-display", argv[i]) || !strcmp ("-d", argv[i])) {
1638a0d3b6eaSmrg	    if (++i>=argc) usage ();
1639a0d3b6eaSmrg	    display_name = argv[i];
1640a0d3b6eaSmrg	    continue;
1641a0d3b6eaSmrg	}
1642a0d3b6eaSmrg	if (!strcmp("-help", argv[i])) {
1643a0d3b6eaSmrg	    usage();
1644a0d3b6eaSmrg	    continue;
1645a0d3b6eaSmrg	}
1646a0d3b6eaSmrg	if (!strcmp ("--verbose", argv[i])) {
1647a0d3b6eaSmrg	    verbose = True;
1648a0d3b6eaSmrg	    continue;
1649a0d3b6eaSmrg	}
1650a0d3b6eaSmrg	if (!strcmp ("--dryrun", argv[i])) {
1651a0d3b6eaSmrg	    dryrun = True;
1652a0d3b6eaSmrg	    verbose = True;
1653a0d3b6eaSmrg	    continue;
1654a0d3b6eaSmrg	}
1655a0d3b6eaSmrg
1656a0d3b6eaSmrg	if (!strcmp ("-s", argv[i]) || !strcmp ("--size", argv[i])) {
1657a0d3b6eaSmrg	    if (++i>=argc) usage ();
1658a0d3b6eaSmrg	    if (sscanf (argv[i], "%dx%d", &width, &height) == 2)
1659a0d3b6eaSmrg		have_pixel_size = True;
1660a0d3b6eaSmrg	    else {
1661a0d3b6eaSmrg		size = atoi (argv[i]);
1662a0d3b6eaSmrg		if (size < 0) usage();
1663a0d3b6eaSmrg	    }
1664a0d3b6eaSmrg	    setit = True;
1665a0d3b6eaSmrg	    continue;
1666a0d3b6eaSmrg	}
1667a0d3b6eaSmrg
1668a0d3b6eaSmrg	if (!strcmp ("-r", argv[i]) ||
1669a0d3b6eaSmrg	    !strcmp ("--rate", argv[i]) ||
1670a0d3b6eaSmrg	    !strcmp ("--refresh", argv[i]))
1671a0d3b6eaSmrg	{
1672a0d3b6eaSmrg	    if (++i>=argc) usage ();
1673a0d3b6eaSmrg	    if (sscanf (argv[i], "%f", &rate) != 1)
1674a0d3b6eaSmrg		usage ();
1675a0d3b6eaSmrg	    setit = True;
1676a0d3b6eaSmrg#if HAS_RANDR_1_2
1677a0d3b6eaSmrg	    if (output)
1678a0d3b6eaSmrg	    {
1679a0d3b6eaSmrg		output->refresh = rate;
1680a0d3b6eaSmrg		output->changes |= changes_refresh;
1681a0d3b6eaSmrg		setit_1_2 = True;
1682a0d3b6eaSmrg	    }
1683a0d3b6eaSmrg#endif
1684a0d3b6eaSmrg	    continue;
1685a0d3b6eaSmrg	}
1686a0d3b6eaSmrg
1687a0d3b6eaSmrg	if (!strcmp ("-v", argv[i]) || !strcmp ("--version", argv[i])) {
1688a0d3b6eaSmrg	    version = True;
1689a0d3b6eaSmrg	    continue;
1690a0d3b6eaSmrg	}
1691a0d3b6eaSmrg
1692a0d3b6eaSmrg	if (!strcmp ("-x", argv[i])) {
1693a0d3b6eaSmrg	    reflection |= RR_Reflect_X;
1694a0d3b6eaSmrg	    setit = True;
1695a0d3b6eaSmrg	    continue;
1696a0d3b6eaSmrg	}
1697a0d3b6eaSmrg	if (!strcmp ("-y", argv[i])) {
1698a0d3b6eaSmrg	    reflection |= RR_Reflect_Y;
1699a0d3b6eaSmrg	    setit = True;
1700a0d3b6eaSmrg	    continue;
1701a0d3b6eaSmrg	}
1702a0d3b6eaSmrg	if (!strcmp ("--screen", argv[i])) {
1703a0d3b6eaSmrg	    if (++i>=argc) usage ();
1704a0d3b6eaSmrg	    screen = atoi (argv[i]);
1705a0d3b6eaSmrg	    if (screen < 0) usage();
1706a0d3b6eaSmrg	    continue;
1707a0d3b6eaSmrg	}
1708a0d3b6eaSmrg	if (!strcmp ("-q", argv[i]) || !strcmp ("--query", argv[i])) {
1709a0d3b6eaSmrg	    query = True;
1710a0d3b6eaSmrg	    continue;
1711a0d3b6eaSmrg	}
1712a0d3b6eaSmrg	if (!strcmp ("-o", argv[i]) || !strcmp ("--orientation", argv[i])) {
1713a0d3b6eaSmrg	    char *endptr;
1714a0d3b6eaSmrg	    if (++i>=argc) usage ();
1715a0d3b6eaSmrg	    dirind = strtol(argv[i], &endptr, 0);
1716a0d3b6eaSmrg	    if (*endptr != '\0') {
1717a0d3b6eaSmrg		for (dirind = 0; dirind < 4; dirind++) {
1718a0d3b6eaSmrg		    if (strcmp (direction[dirind], argv[i]) == 0) break;
1719a0d3b6eaSmrg		}
1720a0d3b6eaSmrg		if ((dirind < 0) || (dirind > 3))  usage();
1721a0d3b6eaSmrg	    }
1722a0d3b6eaSmrg	    rot = dirind;
1723a0d3b6eaSmrg	    setit = True;
1724a0d3b6eaSmrg	    continue;
1725a0d3b6eaSmrg	}
1726a0d3b6eaSmrg#if HAS_RANDR_1_2
1727a0d3b6eaSmrg	if (!strcmp ("--prop", argv[i]) || !strcmp ("--properties", argv[i]))
1728a0d3b6eaSmrg	{
1729a0d3b6eaSmrg	    query_1_2 = True;
1730a0d3b6eaSmrg	    properties = True;
1731a0d3b6eaSmrg	    continue;
1732a0d3b6eaSmrg	}
1733a0d3b6eaSmrg	if (!strcmp ("--output", argv[i])) {
1734a0d3b6eaSmrg	    if (++i >= argc) usage();
1735a0d3b6eaSmrg
1736a0d3b6eaSmrg	    output = find_output_by_name (argv[i]);
1737a0d3b6eaSmrg	    if (!output) {
1738a0d3b6eaSmrg		output = add_output ();
1739a0d3b6eaSmrg		set_name (&output->output, argv[i], name_string|name_xid);
1740a0d3b6eaSmrg	    }
1741a0d3b6eaSmrg
1742a0d3b6eaSmrg	    setit_1_2 = True;
1743a0d3b6eaSmrg	    continue;
1744a0d3b6eaSmrg	}
1745a0d3b6eaSmrg	if (!strcmp ("--crtc", argv[i])) {
1746a0d3b6eaSmrg	    if (++i >= argc) usage();
1747a0d3b6eaSmrg	    if (!output) usage();
1748a0d3b6eaSmrg	    set_name (&output->crtc, argv[i], name_xid|name_index);
1749a0d3b6eaSmrg	    output->changes |= changes_crtc;
1750a0d3b6eaSmrg	    continue;
1751a0d3b6eaSmrg	}
1752a0d3b6eaSmrg	if (!strcmp ("--mode", argv[i])) {
1753a0d3b6eaSmrg	    if (++i >= argc) usage();
1754a0d3b6eaSmrg	    if (!output) usage();
1755a0d3b6eaSmrg	    set_name (&output->mode, argv[i], name_string|name_xid);
1756a0d3b6eaSmrg	    output->changes |= changes_mode;
1757a0d3b6eaSmrg	    continue;
1758a0d3b6eaSmrg	}
1759a0d3b6eaSmrg	if (!strcmp ("--preferred", argv[i])) {
1760a0d3b6eaSmrg	    if (!output) usage();
1761a0d3b6eaSmrg	    set_name_preferred (&output->mode);
1762a0d3b6eaSmrg	    output->changes |= changes_mode;
1763a0d3b6eaSmrg	    continue;
1764a0d3b6eaSmrg	}
1765a0d3b6eaSmrg	if (!strcmp ("--pos", argv[i])) {
1766a0d3b6eaSmrg	    if (++i>=argc) usage ();
1767a0d3b6eaSmrg	    if (!output) usage();
1768a0d3b6eaSmrg	    if (sscanf (argv[i], "%dx%d",
1769a0d3b6eaSmrg			&output->x, &output->y) != 2)
1770a0d3b6eaSmrg		usage ();
1771a0d3b6eaSmrg	    output->changes |= changes_position;
1772a0d3b6eaSmrg	    continue;
1773a0d3b6eaSmrg	}
1774a0d3b6eaSmrg	if (!strcmp ("--rotation", argv[i]) || !strcmp ("--rotate", argv[i])) {
1775a0d3b6eaSmrg	    if (++i>=argc) usage ();
1776a0d3b6eaSmrg	    if (!output) usage();
1777a0d3b6eaSmrg	    for (dirind = 0; dirind < 4; dirind++) {
1778a0d3b6eaSmrg		if (strcmp (direction[dirind], argv[i]) == 0) break;
1779a0d3b6eaSmrg	    }
1780a0d3b6eaSmrg	    if (dirind == 4)
1781a0d3b6eaSmrg		usage ();
1782a0d3b6eaSmrg	    output->rotation &= ~0xf;
1783a0d3b6eaSmrg	    output->rotation |= 1 << dirind;
1784a0d3b6eaSmrg	    output->changes |= changes_rotation;
1785a0d3b6eaSmrg	    continue;
1786a0d3b6eaSmrg	}
1787a0d3b6eaSmrg	if (!strcmp ("--reflect", argv[i]) || !strcmp ("--reflection", argv[i])) {
1788a0d3b6eaSmrg	    if (++i>=argc) usage ();
1789a0d3b6eaSmrg	    if (!output) usage();
1790a0d3b6eaSmrg	    for (dirind = 0; dirind < 4; dirind++) {
1791a0d3b6eaSmrg		if (strcmp (reflections[dirind], argv[i]) == 0) break;
1792a0d3b6eaSmrg	    }
1793a0d3b6eaSmrg	    if (dirind == 4)
1794a0d3b6eaSmrg		usage ();
1795a0d3b6eaSmrg	    output->rotation &= ~(RR_Reflect_X|RR_Reflect_Y);
1796a0d3b6eaSmrg	    output->rotation |= dirind * RR_Reflect_X;
1797a0d3b6eaSmrg	    output->changes |= changes_reflection;
1798a0d3b6eaSmrg	    continue;
1799a0d3b6eaSmrg	}
1800a0d3b6eaSmrg	if (!strcmp ("--left-of", argv[i])) {
1801a0d3b6eaSmrg	    if (++i>=argc) usage ();
1802a0d3b6eaSmrg	    if (!output) usage();
1803a0d3b6eaSmrg	    output->relation = left_of;
1804a0d3b6eaSmrg	    output->relative_to = argv[i];
1805a0d3b6eaSmrg	    output->changes |= changes_relation;
1806a0d3b6eaSmrg	    continue;
1807a0d3b6eaSmrg	}
1808a0d3b6eaSmrg	if (!strcmp ("--right-of", argv[i])) {
1809a0d3b6eaSmrg	    if (++i>=argc) usage ();
1810a0d3b6eaSmrg	    if (!output) usage();
1811a0d3b6eaSmrg	    output->relation = right_of;
1812a0d3b6eaSmrg	    output->relative_to = argv[i];
1813a0d3b6eaSmrg	    output->changes |= changes_relation;
1814a0d3b6eaSmrg	    continue;
1815a0d3b6eaSmrg	}
1816a0d3b6eaSmrg	if (!strcmp ("--above", argv[i])) {
1817a0d3b6eaSmrg	    if (++i>=argc) usage ();
1818a0d3b6eaSmrg	    if (!output) usage();
1819a0d3b6eaSmrg	    output->relation = above;
1820a0d3b6eaSmrg	    output->relative_to = argv[i];
1821a0d3b6eaSmrg	    output->changes |= changes_relation;
1822a0d3b6eaSmrg	    continue;
1823a0d3b6eaSmrg	}
1824a0d3b6eaSmrg	if (!strcmp ("--below", argv[i])) {
1825a0d3b6eaSmrg	    if (++i>=argc) usage ();
1826a0d3b6eaSmrg	    if (!output) usage();
1827a0d3b6eaSmrg	    output->relation = below;
1828a0d3b6eaSmrg	    output->relative_to = argv[i];
1829a0d3b6eaSmrg	    output->changes |= changes_relation;
1830a0d3b6eaSmrg	    continue;
1831a0d3b6eaSmrg	}
1832a0d3b6eaSmrg	if (!strcmp ("--same-as", argv[i])) {
1833a0d3b6eaSmrg	    if (++i>=argc) usage ();
1834a0d3b6eaSmrg	    if (!output) usage();
1835a0d3b6eaSmrg	    output->relation = same_as;
1836a0d3b6eaSmrg	    output->relative_to = argv[i];
1837a0d3b6eaSmrg	    output->changes |= changes_relation;
1838a0d3b6eaSmrg	    continue;
1839a0d3b6eaSmrg	}
1840a0d3b6eaSmrg	if (!strcmp ("--set", argv[i])) {
1841a0d3b6eaSmrg	    output_prop_t   *prop;
1842a0d3b6eaSmrg	    if (!output) usage();
1843a0d3b6eaSmrg	    prop = malloc (sizeof (output_prop_t));
1844a0d3b6eaSmrg	    prop->next = output->props;
1845a0d3b6eaSmrg	    output->props = prop;
1846a0d3b6eaSmrg	    if (++i>=argc) usage ();
1847a0d3b6eaSmrg	    prop->name = argv[i];
1848a0d3b6eaSmrg	    if (++i>=argc) usage ();
1849a0d3b6eaSmrg	    prop->value = argv[i];
1850a0d3b6eaSmrg	    propit = True;
1851a0d3b6eaSmrg	    output->changes |= changes_property;
1852a0d3b6eaSmrg	    setit_1_2 = True;
1853a0d3b6eaSmrg	    continue;
1854a0d3b6eaSmrg	}
1855a0d3b6eaSmrg	if (!strcmp ("--off", argv[i])) {
1856a0d3b6eaSmrg	    if (!output) usage();
1857a0d3b6eaSmrg	    set_name_xid (&output->mode, None);
1858a0d3b6eaSmrg	    set_name_xid (&output->crtc, None);
1859a0d3b6eaSmrg	    output->changes |= changes_mode;
1860a0d3b6eaSmrg	    continue;
1861a0d3b6eaSmrg	}
1862a0d3b6eaSmrg	if (!strcmp ("--fb", argv[i])) {
1863a0d3b6eaSmrg	    if (++i>=argc) usage ();
1864a0d3b6eaSmrg	    if (sscanf (argv[i], "%dx%d",
1865a0d3b6eaSmrg			&fb_width, &fb_height) != 2)
1866a0d3b6eaSmrg		usage ();
1867a0d3b6eaSmrg	    setit_1_2 = True;
1868a0d3b6eaSmrg	    continue;
1869a0d3b6eaSmrg	}
1870a0d3b6eaSmrg	if (!strcmp ("--fbmm", argv[i])) {
1871a0d3b6eaSmrg	    if (++i>=argc) usage ();
1872a0d3b6eaSmrg	    if (sscanf (argv[i], "%dx%d",
1873a0d3b6eaSmrg			&fb_width_mm, &fb_height_mm) != 2)
1874a0d3b6eaSmrg		usage ();
1875a0d3b6eaSmrg	    setit_1_2 = True;
1876a0d3b6eaSmrg	    continue;
1877a0d3b6eaSmrg	}
1878a0d3b6eaSmrg	if (!strcmp ("--dpi", argv[i])) {
1879a0d3b6eaSmrg	    if (++i>=argc) usage ();
1880a0d3b6eaSmrg	    if (sscanf (argv[i], "%f", &dpi) != 1)
1881a0d3b6eaSmrg	    {
1882a0d3b6eaSmrg		dpi = 0.0;
1883a0d3b6eaSmrg		dpi_output = argv[i];
1884a0d3b6eaSmrg	    }
1885a0d3b6eaSmrg	    setit_1_2 = True;
1886a0d3b6eaSmrg	    continue;
1887a0d3b6eaSmrg	}
1888a0d3b6eaSmrg	if (!strcmp ("--clone", argv[i])) {
1889a0d3b6eaSmrg	    policy = clone;
1890a0d3b6eaSmrg	    setit_1_2 = True;
1891a0d3b6eaSmrg	    continue;
1892a0d3b6eaSmrg	}
1893a0d3b6eaSmrg	if (!strcmp ("--extend", argv[i])) {
1894a0d3b6eaSmrg	    policy = extend;
1895a0d3b6eaSmrg	    setit_1_2 = True;
1896a0d3b6eaSmrg	    continue;
1897a0d3b6eaSmrg	}
1898a0d3b6eaSmrg	if (!strcmp ("--auto", argv[i])) {
1899a0d3b6eaSmrg	    if (output)
1900a0d3b6eaSmrg	    {
1901a0d3b6eaSmrg		output->automatic = True;
1902a0d3b6eaSmrg		output->changes |= changes_automatic;
1903a0d3b6eaSmrg	    }
1904a0d3b6eaSmrg	    else
1905a0d3b6eaSmrg		automatic = True;
1906a0d3b6eaSmrg	    setit_1_2 = True;
1907a0d3b6eaSmrg	    continue;
1908a0d3b6eaSmrg	}
1909a0d3b6eaSmrg	if (!strcmp ("--q12", argv[i]))
1910a0d3b6eaSmrg	{
1911a0d3b6eaSmrg	    query_1_2 = True;
1912a0d3b6eaSmrg	    continue;
1913a0d3b6eaSmrg	}
1914a0d3b6eaSmrg	if (!strcmp ("--q1", argv[i]))
1915a0d3b6eaSmrg	{
1916a0d3b6eaSmrg	    query_1 = True;
1917a0d3b6eaSmrg	    continue;
1918a0d3b6eaSmrg	}
1919a0d3b6eaSmrg	if (!strcmp ("--newmode", argv[i]))
1920a0d3b6eaSmrg	{
1921a0d3b6eaSmrg	    umode_t  *m = malloc (sizeof (umode_t));
1922a0d3b6eaSmrg	    float   clock;
1923a0d3b6eaSmrg
1924a0d3b6eaSmrg	    ++i;
1925a0d3b6eaSmrg	    if (i + 9 >= argc) usage ();
1926a0d3b6eaSmrg	    m->mode.name = argv[i];
1927a0d3b6eaSmrg	    m->mode.nameLength = strlen (argv[i]);
1928a0d3b6eaSmrg	    i++;
1929a0d3b6eaSmrg	    if (sscanf (argv[i++], "%f", &clock) != 1)
1930a0d3b6eaSmrg		usage ();
1931a0d3b6eaSmrg	    m->mode.dotClock = clock * 1e6;
1932a0d3b6eaSmrg
1933a0d3b6eaSmrg	    if (sscanf (argv[i++], "%d", &m->mode.width) != 1) usage();
1934a0d3b6eaSmrg	    if (sscanf (argv[i++], "%d", &m->mode.hSyncStart) != 1) usage();
1935a0d3b6eaSmrg	    if (sscanf (argv[i++], "%d", &m->mode.hSyncEnd) != 1) usage();
1936a0d3b6eaSmrg	    if (sscanf (argv[i++], "%d", &m->mode.hTotal) != 1) usage();
1937a0d3b6eaSmrg	    if (sscanf (argv[i++], "%d", &m->mode.height) != 1) usage();
1938a0d3b6eaSmrg	    if (sscanf (argv[i++], "%d", &m->mode.vSyncStart) != 1) usage();
1939a0d3b6eaSmrg	    if (sscanf (argv[i++], "%d", &m->mode.vSyncEnd) != 1) usage();
1940a0d3b6eaSmrg	    if (sscanf (argv[i++], "%d", &m->mode.vTotal) != 1) usage();
1941a0d3b6eaSmrg	    m->mode.modeFlags = 0;
1942a0d3b6eaSmrg	    while (i < argc) {
1943a0d3b6eaSmrg		int f;
1944a0d3b6eaSmrg
1945a0d3b6eaSmrg		for (f = 0; mode_flags[f].string; f++)
1946a0d3b6eaSmrg		    if (!strcasecmp (mode_flags[f].string, argv[i]))
1947a0d3b6eaSmrg			break;
1948a0d3b6eaSmrg
1949a0d3b6eaSmrg		if (!mode_flags[f].string)
1950a0d3b6eaSmrg		    break;
1951a0d3b6eaSmrg    		m->mode.modeFlags |= mode_flags[f].flag;
1952a0d3b6eaSmrg    		i++;
1953a0d3b6eaSmrg	    }
1954a0d3b6eaSmrg	    m->next = umodes;
1955a0d3b6eaSmrg	    m->action = umode_create;
1956a0d3b6eaSmrg	    umodes = m;
1957a0d3b6eaSmrg	    modeit = True;
1958a0d3b6eaSmrg	    continue;
1959a0d3b6eaSmrg	}
1960a0d3b6eaSmrg	if (!strcmp ("--rmmode", argv[i]))
1961a0d3b6eaSmrg	{
1962a0d3b6eaSmrg	    umode_t  *m = malloc (sizeof (umode_t));
1963a0d3b6eaSmrg
1964a0d3b6eaSmrg	    if (++i>=argc) usage ();
1965a0d3b6eaSmrg	    set_name (&m->name, argv[i], name_string|name_xid);
1966a0d3b6eaSmrg	    m->action = umode_destroy;
1967a0d3b6eaSmrg	    m->next = umodes;
1968a0d3b6eaSmrg	    umodes = m;
1969a0d3b6eaSmrg	    modeit = True;
1970a0d3b6eaSmrg	    continue;
1971a0d3b6eaSmrg	}
1972a0d3b6eaSmrg	if (!strcmp ("--addmode", argv[i]))
1973a0d3b6eaSmrg	{
1974a0d3b6eaSmrg	    umode_t  *m = malloc (sizeof (umode_t));
1975a0d3b6eaSmrg
1976a0d3b6eaSmrg	    if (++i>=argc) usage ();
1977a0d3b6eaSmrg	    set_name (&m->output, argv[i], name_string|name_xid);
1978a0d3b6eaSmrg	    if (++i>=argc) usage();
1979a0d3b6eaSmrg	    set_name (&m->name, argv[i], name_string|name_xid);
1980a0d3b6eaSmrg	    m->action = umode_add;
1981a0d3b6eaSmrg	    m->next = umodes;
1982a0d3b6eaSmrg	    umodes = m;
1983a0d3b6eaSmrg	    modeit = True;
1984a0d3b6eaSmrg	    continue;
1985a0d3b6eaSmrg	}
1986a0d3b6eaSmrg	if (!strcmp ("--delmode", argv[i]))
1987a0d3b6eaSmrg	{
1988a0d3b6eaSmrg	    umode_t  *m = malloc (sizeof (umode_t));
1989a0d3b6eaSmrg
1990a0d3b6eaSmrg	    if (++i>=argc) usage ();
1991a0d3b6eaSmrg	    set_name (&m->output, argv[i], name_string|name_xid);
1992a0d3b6eaSmrg	    if (++i>=argc) usage();
1993a0d3b6eaSmrg	    set_name (&m->name, argv[i], name_string|name_xid);
1994a0d3b6eaSmrg	    m->action = umode_delete;
1995a0d3b6eaSmrg	    m->next = umodes;
1996a0d3b6eaSmrg	    umodes = m;
1997a0d3b6eaSmrg	    modeit = True;
1998a0d3b6eaSmrg	    continue;
1999a0d3b6eaSmrg	}
2000a0d3b6eaSmrg#endif
2001a0d3b6eaSmrg	usage();
2002a0d3b6eaSmrg    }
2003a0d3b6eaSmrg    if (verbose)
2004a0d3b6eaSmrg    {
2005a0d3b6eaSmrg	query = True;
2006a0d3b6eaSmrg	if (setit && !setit_1_2)
2007a0d3b6eaSmrg	    query_1 = True;
2008a0d3b6eaSmrg    }
2009a0d3b6eaSmrg
2010a0d3b6eaSmrg    dpy = XOpenDisplay (display_name);
2011a0d3b6eaSmrg
2012a0d3b6eaSmrg    if (dpy == NULL) {
2013a0d3b6eaSmrg	fprintf (stderr, "Can't open display %s\n", XDisplayName(display_name));
2014a0d3b6eaSmrg	exit (1);
2015a0d3b6eaSmrg    }
2016a0d3b6eaSmrg    if (screen < 0)
2017a0d3b6eaSmrg	screen = DefaultScreen (dpy);
2018a0d3b6eaSmrg    if (screen >= ScreenCount (dpy)) {
2019a0d3b6eaSmrg	fprintf (stderr, "Invalid screen number %d (display has %d)\n",
2020a0d3b6eaSmrg		 screen, ScreenCount (dpy));
2021a0d3b6eaSmrg	exit (1);
2022a0d3b6eaSmrg    }
2023a0d3b6eaSmrg
2024a0d3b6eaSmrg    root = RootWindow (dpy, screen);
2025a0d3b6eaSmrg
2026a0d3b6eaSmrg#if HAS_RANDR_1_2
2027a0d3b6eaSmrg    if (!XRRQueryVersion (dpy, &major, &minor))
2028a0d3b6eaSmrg    {
2029a0d3b6eaSmrg	fprintf (stderr, "RandR extension missing\n");
2030a0d3b6eaSmrg	exit (1);
2031a0d3b6eaSmrg    }
2032a0d3b6eaSmrg    if (major > 1 || (major == 1 && minor >= 2))
2033a0d3b6eaSmrg	has_1_2 = True;
2034a0d3b6eaSmrg
2035a0d3b6eaSmrg    if (has_1_2 && modeit)
2036a0d3b6eaSmrg    {
2037a0d3b6eaSmrg	umode_t	*m;
2038a0d3b6eaSmrg
2039a0d3b6eaSmrg        get_screen ();
2040a0d3b6eaSmrg	get_crtcs();
2041a0d3b6eaSmrg	get_outputs();
2042a0d3b6eaSmrg
2043a0d3b6eaSmrg	for (m = umodes; m; m = m->next)
2044a0d3b6eaSmrg	{
2045a0d3b6eaSmrg	    XRRModeInfo *e;
2046a0d3b6eaSmrg	    output_t	*o;
2047a0d3b6eaSmrg
2048a0d3b6eaSmrg	    switch (m->action) {
2049a0d3b6eaSmrg	    case umode_create:
2050a0d3b6eaSmrg		XRRCreateMode (dpy, root, &m->mode);
2051a0d3b6eaSmrg		break;
2052a0d3b6eaSmrg	    case umode_destroy:
2053a0d3b6eaSmrg		e = find_mode (&m->name, 0);
2054a0d3b6eaSmrg		if (!e)
2055a0d3b6eaSmrg		    fatal ("cannot find mode \"%s\"\n", m->name.string);
2056a0d3b6eaSmrg		XRRDestroyMode (dpy, e->id);
2057a0d3b6eaSmrg		break;
2058a0d3b6eaSmrg	    case umode_add:
2059a0d3b6eaSmrg		o = find_output (&m->output);
2060a0d3b6eaSmrg		if (!o)
2061a0d3b6eaSmrg		    fatal ("cannot find output \"%s\"\n", m->output.string);
2062a0d3b6eaSmrg		e = find_mode (&m->name, 0);
2063a0d3b6eaSmrg		if (!e)
2064a0d3b6eaSmrg		    fatal ("cannot find mode \"%s\"\n", m->name.string);
2065a0d3b6eaSmrg		XRRAddOutputMode (dpy, o->output.xid, e->id);
2066a0d3b6eaSmrg		break;
2067a0d3b6eaSmrg	    case umode_delete:
2068a0d3b6eaSmrg		o = find_output (&m->output);
2069a0d3b6eaSmrg		if (!o)
2070a0d3b6eaSmrg		    fatal ("cannot find output \"%s\"\n", m->output.string);
2071a0d3b6eaSmrg		e = find_mode (&m->name, 0);
2072a0d3b6eaSmrg		if (!e)
2073a0d3b6eaSmrg		    fatal ("cannot find mode \"%s\"\n", m->name.string);
2074a0d3b6eaSmrg		XRRDeleteOutputMode (dpy, o->output.xid, e->id);
2075a0d3b6eaSmrg		break;
2076a0d3b6eaSmrg	    }
2077a0d3b6eaSmrg	}
2078a0d3b6eaSmrg	if (!setit_1_2)
2079a0d3b6eaSmrg	{
2080a0d3b6eaSmrg	    XSync (dpy, False);
2081a0d3b6eaSmrg	    exit (0);
2082a0d3b6eaSmrg	}
2083a0d3b6eaSmrg    }
2084a0d3b6eaSmrg    if (has_1_2 && propit)
2085a0d3b6eaSmrg    {
2086a0d3b6eaSmrg
2087a0d3b6eaSmrg        get_screen ();
2088a0d3b6eaSmrg	get_crtcs();
2089a0d3b6eaSmrg	get_outputs();
2090a0d3b6eaSmrg
2091a0d3b6eaSmrg	for (output = outputs; output; output = output->next)
2092a0d3b6eaSmrg	{
2093a0d3b6eaSmrg	    output_prop_t   *prop;
2094a0d3b6eaSmrg
2095a0d3b6eaSmrg	    for (prop = output->props; prop; prop = prop->next)
2096a0d3b6eaSmrg	    {
2097a0d3b6eaSmrg		Atom		name = XInternAtom (dpy, prop->name, False);
2098a0d3b6eaSmrg		Atom		type;
2099a0d3b6eaSmrg		int		format;
2100a0d3b6eaSmrg		unsigned char	*data;
2101a0d3b6eaSmrg		int		nelements;
2102a0d3b6eaSmrg		int		int_value;
2103a0d3b6eaSmrg		unsigned long	ulong_value;
2104a0d3b6eaSmrg		unsigned char	*prop_data;
2105a0d3b6eaSmrg		int		actual_format;
2106a0d3b6eaSmrg		unsigned long	nitems, bytes_after;
2107a0d3b6eaSmrg		Atom		actual_type;
2108a0d3b6eaSmrg		XRRPropertyInfo *propinfo;
2109a0d3b6eaSmrg
2110a0d3b6eaSmrg		type = AnyPropertyType;
2111a0d3b6eaSmrg		format=0;
2112a0d3b6eaSmrg
2113a0d3b6eaSmrg		if (XRRGetOutputProperty (dpy, output->output.xid, name,
2114a0d3b6eaSmrg					  0, 100, False, False,
2115a0d3b6eaSmrg					  AnyPropertyType,
2116a0d3b6eaSmrg					  &actual_type, &actual_format,
2117a0d3b6eaSmrg					  &nitems, &bytes_after, &prop_data) == Success &&
2118a0d3b6eaSmrg
2119a0d3b6eaSmrg		    (propinfo = XRRQueryOutputProperty(dpy, output->output.xid,
2120a0d3b6eaSmrg						      name)))
2121a0d3b6eaSmrg		{
2122a0d3b6eaSmrg		    type = actual_type;
2123a0d3b6eaSmrg		    format = actual_format;
2124a0d3b6eaSmrg		}
2125a0d3b6eaSmrg
2126a0d3b6eaSmrg		if ((type == XA_INTEGER || type == AnyPropertyType) &&
2127a0d3b6eaSmrg		    (sscanf (prop->value, "%d", &int_value) == 1 ||
2128a0d3b6eaSmrg		     sscanf (prop->value, "0x%x", &int_value) == 1))
2129a0d3b6eaSmrg		{
2130a0d3b6eaSmrg		    type = XA_INTEGER;
2131a0d3b6eaSmrg		    ulong_value = int_value;
2132a0d3b6eaSmrg		    data = (unsigned char *) &ulong_value;
2133a0d3b6eaSmrg		    nelements = 1;
2134a0d3b6eaSmrg		    format = 32;
2135a0d3b6eaSmrg		}
2136a0d3b6eaSmrg		else if ((type == XA_ATOM))
2137a0d3b6eaSmrg		{
2138a0d3b6eaSmrg		    ulong_value = XInternAtom (dpy, prop->value, False);
2139a0d3b6eaSmrg		    data = (unsigned char *) &ulong_value;
2140a0d3b6eaSmrg		    nelements = 1;
2141a0d3b6eaSmrg		    format = 32;
2142a0d3b6eaSmrg		}
2143a0d3b6eaSmrg		else if ((type == XA_STRING || type == AnyPropertyType))
2144a0d3b6eaSmrg		{
2145a0d3b6eaSmrg		    type = XA_STRING;
2146a0d3b6eaSmrg		    data = (unsigned char *) prop->value;
2147a0d3b6eaSmrg		    nelements = strlen (prop->value);
2148a0d3b6eaSmrg		    format = 8;
2149a0d3b6eaSmrg		}
2150a0d3b6eaSmrg		XRRChangeOutputProperty (dpy, output->output.xid,
2151a0d3b6eaSmrg					 name, type, format, PropModeReplace,
2152a0d3b6eaSmrg					 data, nelements);
2153a0d3b6eaSmrg	    }
2154a0d3b6eaSmrg	}
2155a0d3b6eaSmrg	if (!setit_1_2)
2156a0d3b6eaSmrg	{
2157a0d3b6eaSmrg	    XSync (dpy, False);
2158a0d3b6eaSmrg	    exit (0);
2159a0d3b6eaSmrg	}
2160a0d3b6eaSmrg    }
2161a0d3b6eaSmrg    if (setit_1_2)
2162a0d3b6eaSmrg    {
2163a0d3b6eaSmrg	get_screen ();
2164a0d3b6eaSmrg	get_crtcs ();
2165a0d3b6eaSmrg	get_outputs ();
2166a0d3b6eaSmrg	set_positions ();
2167a0d3b6eaSmrg	set_screen_size ();
2168a0d3b6eaSmrg
2169a0d3b6eaSmrg	pick_crtcs ();
2170a0d3b6eaSmrg
2171a0d3b6eaSmrg	/*
2172a0d3b6eaSmrg	 * Assign outputs to crtcs
2173a0d3b6eaSmrg	 */
2174a0d3b6eaSmrg	set_crtcs ();
2175a0d3b6eaSmrg
2176a0d3b6eaSmrg	/*
2177a0d3b6eaSmrg	 * Mark changing crtcs
2178a0d3b6eaSmrg	 */
2179a0d3b6eaSmrg	mark_changing_crtcs ();
2180a0d3b6eaSmrg
2181a0d3b6eaSmrg	/*
2182a0d3b6eaSmrg	 * If an output was specified to track dpi, use it
2183a0d3b6eaSmrg	 */
2184a0d3b6eaSmrg	if (dpi_output)
2185a0d3b6eaSmrg	{
2186a0d3b6eaSmrg	    output_t	*output = find_output_by_name (dpi_output);
2187a0d3b6eaSmrg	    XRROutputInfo	*output_info;
2188a0d3b6eaSmrg	    XRRModeInfo	*mode_info;
2189a0d3b6eaSmrg	    if (!output)
2190a0d3b6eaSmrg		fatal ("Cannot find output %s\n", dpi_output);
2191a0d3b6eaSmrg	    output_info = output->output_info;
2192a0d3b6eaSmrg	    mode_info = output->mode_info;
2193a0d3b6eaSmrg	    if (output_info && mode_info && output_info->mm_height)
2194a0d3b6eaSmrg	    {
2195a0d3b6eaSmrg		/*
2196a0d3b6eaSmrg		 * When this output covers the whole screen, just use
2197a0d3b6eaSmrg		 * the known physical size
2198a0d3b6eaSmrg		 */
2199a0d3b6eaSmrg		if (fb_width == mode_info->width &&
2200a0d3b6eaSmrg		    fb_height == mode_info->height)
2201a0d3b6eaSmrg		{
2202a0d3b6eaSmrg		    fb_width_mm = output_info->mm_width;
2203a0d3b6eaSmrg		    fb_height_mm = output_info->mm_height;
2204a0d3b6eaSmrg		}
2205a0d3b6eaSmrg		else
2206a0d3b6eaSmrg		{
2207a0d3b6eaSmrg		    dpi = (25.4 * mode_info->height) / output_info->mm_height;
2208a0d3b6eaSmrg		}
2209a0d3b6eaSmrg	    }
2210a0d3b6eaSmrg	}
2211a0d3b6eaSmrg
2212a0d3b6eaSmrg	/*
2213a0d3b6eaSmrg	 * Compute physical screen size
2214a0d3b6eaSmrg	 */
2215a0d3b6eaSmrg	if (fb_width_mm == 0 || fb_height_mm == 0)
2216a0d3b6eaSmrg	{
2217a0d3b6eaSmrg	    if (fb_width != DisplayWidth (dpy, screen) ||
2218a0d3b6eaSmrg		fb_height != DisplayHeight (dpy, screen) || dpi != 0.0)
2219a0d3b6eaSmrg	    {
2220a0d3b6eaSmrg		if (dpi <= 0)
2221a0d3b6eaSmrg		    dpi = (25.4 * DisplayHeight (dpy, screen)) / DisplayHeightMM(dpy, screen);
2222a0d3b6eaSmrg
2223a0d3b6eaSmrg		fb_width_mm = (25.4 * fb_width) / dpi;
2224a0d3b6eaSmrg		fb_height_mm = (25.4 * fb_height) / dpi;
2225a0d3b6eaSmrg	    }
2226a0d3b6eaSmrg	    else
2227a0d3b6eaSmrg	    {
2228a0d3b6eaSmrg		fb_width_mm = DisplayWidthMM (dpy, screen);
2229a0d3b6eaSmrg		fb_height_mm = DisplayHeightMM (dpy, screen);
2230a0d3b6eaSmrg	    }
2231a0d3b6eaSmrg	}
2232a0d3b6eaSmrg
2233a0d3b6eaSmrg	/*
2234a0d3b6eaSmrg	 * Now apply all of the changes
2235a0d3b6eaSmrg	 */
2236a0d3b6eaSmrg	apply ();
2237a0d3b6eaSmrg
2238a0d3b6eaSmrg	XSync (dpy, False);
2239a0d3b6eaSmrg	exit (0);
2240a0d3b6eaSmrg    }
2241a0d3b6eaSmrg    if (query_1_2 || (query && has_1_2 && !query_1))
2242a0d3b6eaSmrg    {
2243a0d3b6eaSmrg	output_t    *output;
2244a0d3b6eaSmrg	int	    m;
2245a0d3b6eaSmrg
2246a0d3b6eaSmrg#define ModeShown   0x80000000
2247a0d3b6eaSmrg
2248a0d3b6eaSmrg	get_screen ();
2249a0d3b6eaSmrg	get_crtcs ();
2250a0d3b6eaSmrg	get_outputs ();
2251a0d3b6eaSmrg
2252a0d3b6eaSmrg        printf ("Screen %d: minimum %d x %d, current %d x %d, maximum %d x %d\n",
2253a0d3b6eaSmrg		screen, minWidth, minHeight,
2254a0d3b6eaSmrg		DisplayWidth (dpy, screen), DisplayHeight(dpy, screen),
2255a0d3b6eaSmrg		maxWidth, maxHeight);
2256a0d3b6eaSmrg
2257a0d3b6eaSmrg	for (output = outputs; output; output = output->next)
2258a0d3b6eaSmrg	{
2259a0d3b6eaSmrg	    XRROutputInfo   *output_info = output->output_info;
2260a0d3b6eaSmrg	    XRRModeInfo	    *mode = output->mode_info;
2261a0d3b6eaSmrg	    Atom	    *props;
2262a0d3b6eaSmrg	    int		    j, k, nprop;
2263a0d3b6eaSmrg	    Bool	    *mode_shown;
2264a0d3b6eaSmrg	    Rotation	    rotations = output_rotations (output);
2265a0d3b6eaSmrg
2266a0d3b6eaSmrg	    printf ("%s %s", output_info->name, connection[output_info->connection]);
2267a0d3b6eaSmrg	    if (mode)
2268a0d3b6eaSmrg	    {
2269a0d3b6eaSmrg		printf (" %dx%d+%d+%d",
2270a0d3b6eaSmrg			mode_width (mode, output->rotation),
2271a0d3b6eaSmrg			mode_height (mode, output->rotation),
2272a0d3b6eaSmrg			output->x, output->y);
2273a0d3b6eaSmrg		if (verbose)
2274a0d3b6eaSmrg		    printf (" (0x%x)", mode->id);
2275a0d3b6eaSmrg		if (output->rotation != RR_Rotate_0 || verbose)
2276a0d3b6eaSmrg		{
2277a0d3b6eaSmrg		    printf (" %s",
2278a0d3b6eaSmrg			    rotation_name (output->rotation));
2279a0d3b6eaSmrg		    if (output->rotation & (RR_Reflect_X|RR_Reflect_Y))
2280a0d3b6eaSmrg			printf (" %s", reflection_name (output->rotation));
2281a0d3b6eaSmrg		}
2282a0d3b6eaSmrg	    }
2283a0d3b6eaSmrg	    if (rotations != RR_Rotate_0 || verbose)
2284a0d3b6eaSmrg	    {
2285a0d3b6eaSmrg		Bool    first = True;
2286a0d3b6eaSmrg		printf (" (");
2287a0d3b6eaSmrg		for (i = 0; i < 4; i ++) {
2288a0d3b6eaSmrg		    if ((rotations >> i) & 1) {
2289a0d3b6eaSmrg			if (!first) printf (" "); first = False;
2290a0d3b6eaSmrg			printf("%s", direction[i]);
2291a0d3b6eaSmrg			first = False;
2292a0d3b6eaSmrg		    }
2293a0d3b6eaSmrg		}
2294a0d3b6eaSmrg		if (rotations & RR_Reflect_X)
2295a0d3b6eaSmrg		{
2296a0d3b6eaSmrg		    if (!first) printf (" "); first = False;
2297a0d3b6eaSmrg		    printf ("x axis");
2298a0d3b6eaSmrg		}
2299a0d3b6eaSmrg		if (rotations & RR_Reflect_Y)
2300a0d3b6eaSmrg		{
2301a0d3b6eaSmrg		    if (!first) printf (" "); first = False;
2302a0d3b6eaSmrg		    printf ("y axis");
2303a0d3b6eaSmrg		}
2304a0d3b6eaSmrg		printf (")");
2305a0d3b6eaSmrg	    }
2306a0d3b6eaSmrg
2307a0d3b6eaSmrg	    if (mode)
2308a0d3b6eaSmrg	    {
2309a0d3b6eaSmrg		printf (" %dmm x %dmm",
2310a0d3b6eaSmrg			output_info->mm_width, output_info->mm_height);
2311a0d3b6eaSmrg	    }
2312a0d3b6eaSmrg	    printf ("\n");
2313a0d3b6eaSmrg
2314a0d3b6eaSmrg	    if (verbose)
2315a0d3b6eaSmrg	    {
2316a0d3b6eaSmrg		printf ("\tIdentifier: 0x%x\n", output->output.xid);
2317a0d3b6eaSmrg		printf ("\tTimestamp:  %d\n", output_info->timestamp);
2318a0d3b6eaSmrg		printf ("\tSubpixel:   %s\n", order[output_info->subpixel_order]);
2319a0d3b6eaSmrg		printf ("\tClones:    ");
2320a0d3b6eaSmrg		for (j = 0; j < output_info->nclone; j++)
2321a0d3b6eaSmrg		{
2322a0d3b6eaSmrg		    output_t	*clone = find_output_by_xid (output_info->clones[j]);
2323a0d3b6eaSmrg
2324a0d3b6eaSmrg		    if (clone) printf (" %s", clone->output.string);
2325a0d3b6eaSmrg		}
2326a0d3b6eaSmrg		printf ("\n");
2327a0d3b6eaSmrg		if (output->crtc_info)
2328a0d3b6eaSmrg		    printf ("\tCRTC:       %d\n", output->crtc_info->crtc.index);
2329a0d3b6eaSmrg		printf ("\tCRTCs:     ");
2330a0d3b6eaSmrg		for (j = 0; j < output_info->ncrtc; j++)
2331a0d3b6eaSmrg		{
2332a0d3b6eaSmrg		    crtc_t	*crtc = find_crtc_by_xid (output_info->crtcs[j]);
2333a0d3b6eaSmrg		    if (crtc)
2334a0d3b6eaSmrg			printf (" %d", crtc->crtc.index);
2335a0d3b6eaSmrg		}
2336a0d3b6eaSmrg		printf ("\n");
2337a0d3b6eaSmrg	    }
2338a0d3b6eaSmrg	    if (verbose || properties)
2339a0d3b6eaSmrg	    {
2340a0d3b6eaSmrg		props = XRRListOutputProperties (dpy, output->output.xid,
2341a0d3b6eaSmrg						 &nprop);
2342a0d3b6eaSmrg		for (j = 0; j < nprop; j++) {
2343a0d3b6eaSmrg		    unsigned char *prop;
2344a0d3b6eaSmrg		    int actual_format;
2345a0d3b6eaSmrg		    unsigned long nitems, bytes_after;
2346a0d3b6eaSmrg		    Atom actual_type;
2347a0d3b6eaSmrg		    XRRPropertyInfo *propinfo;
2348a0d3b6eaSmrg
2349a0d3b6eaSmrg		    XRRGetOutputProperty (dpy, output->output.xid, props[j],
2350a0d3b6eaSmrg					  0, 100, False, False,
2351a0d3b6eaSmrg					  AnyPropertyType,
2352a0d3b6eaSmrg					  &actual_type, &actual_format,
2353a0d3b6eaSmrg					  &nitems, &bytes_after, &prop);
2354a0d3b6eaSmrg
2355a0d3b6eaSmrg		    propinfo = XRRQueryOutputProperty(dpy, output->output.xid,
2356a0d3b6eaSmrg						      props[j]);
2357a0d3b6eaSmrg
2358a0d3b6eaSmrg		    if (actual_type == XA_INTEGER && actual_format == 8) {
2359a0d3b6eaSmrg			int k;
2360a0d3b6eaSmrg
2361a0d3b6eaSmrg			printf("\t%s:\n", XGetAtomName (dpy, props[j]));
2362a0d3b6eaSmrg			for (k = 0; k < nitems; k++) {
2363a0d3b6eaSmrg			    if (k % 16 == 0)
2364a0d3b6eaSmrg				printf ("\t\t");
2365a0d3b6eaSmrg			    printf("%02x", (unsigned char)prop[k]);
2366a0d3b6eaSmrg			    if (k % 16 == 15)
2367a0d3b6eaSmrg				printf("\n");
2368a0d3b6eaSmrg			}
2369a0d3b6eaSmrg		    } else if (actual_type == XA_INTEGER &&
2370a0d3b6eaSmrg			       actual_format == 32)
2371a0d3b6eaSmrg		    {
2372a0d3b6eaSmrg			printf("\t%s: %d (0x%08x)",
2373a0d3b6eaSmrg			       XGetAtomName (dpy, props[j]),
2374a0d3b6eaSmrg			       *(INT32 *)prop, *(INT32 *)prop);
2375a0d3b6eaSmrg
2376a0d3b6eaSmrg 			if (propinfo->range && propinfo->num_values > 0) {
2377a0d3b6eaSmrg			    printf(" range%s: ",
2378a0d3b6eaSmrg				   (propinfo->num_values == 2) ? "" : "s");
2379a0d3b6eaSmrg
2380a0d3b6eaSmrg			    for (k = 0; k < propinfo->num_values / 2; k++)
2381a0d3b6eaSmrg				printf(" (%d,%d)", propinfo->values[k * 2],
2382a0d3b6eaSmrg				       propinfo->values[k * 2 + 1]);
2383a0d3b6eaSmrg			}
2384a0d3b6eaSmrg
2385a0d3b6eaSmrg			printf("\n");
2386a0d3b6eaSmrg		    } else if (actual_type == XA_ATOM &&
2387a0d3b6eaSmrg			       actual_format == 32)
2388a0d3b6eaSmrg		    {
2389a0d3b6eaSmrg			printf("\t%s: %s",
2390a0d3b6eaSmrg			       XGetAtomName (dpy, props[j]),
2391a0d3b6eaSmrg			       XGetAtomName (dpy, *(Atom *)prop));
2392a0d3b6eaSmrg
2393a0d3b6eaSmrg 			if (!propinfo->range && propinfo->num_values > 0) {
2394a0d3b6eaSmrg			    printf("\n\t\tsupported:");
2395a0d3b6eaSmrg
2396a0d3b6eaSmrg			    for (k = 0; k < propinfo->num_values; k++)
2397a0d3b6eaSmrg			    {
2398a0d3b6eaSmrg				printf(" %-12.12s", XGetAtomName (dpy,
2399a0d3b6eaSmrg							    propinfo->values[k]));
2400a0d3b6eaSmrg				if (k % 4 == 3 && k < propinfo->num_values - 1)
2401a0d3b6eaSmrg				    printf ("\n\t\t          ");
2402a0d3b6eaSmrg			    }
2403a0d3b6eaSmrg			}
2404a0d3b6eaSmrg			printf("\n");
2405a0d3b6eaSmrg
2406a0d3b6eaSmrg		    } else if (actual_format == 8) {
2407a0d3b6eaSmrg			printf ("\t\t%s: %s%s\n", XGetAtomName (dpy, props[j]),
2408a0d3b6eaSmrg				prop, bytes_after ? "..." : "");
2409a0d3b6eaSmrg		    } else {
2410a0d3b6eaSmrg			printf ("\t\t%s: ????\n", XGetAtomName (dpy, props[j]));
2411a0d3b6eaSmrg		    }
2412a0d3b6eaSmrg
2413a0d3b6eaSmrg		    free(propinfo);
2414a0d3b6eaSmrg		}
2415a0d3b6eaSmrg	    }
2416a0d3b6eaSmrg
2417a0d3b6eaSmrg	    if (verbose)
2418a0d3b6eaSmrg	    {
2419a0d3b6eaSmrg		for (j = 0; j < output_info->nmode; j++)
2420a0d3b6eaSmrg		{
2421a0d3b6eaSmrg		    XRRModeInfo	*mode = find_mode_by_xid (output_info->modes[j]);
2422a0d3b6eaSmrg		    int		f;
2423a0d3b6eaSmrg
2424a0d3b6eaSmrg		    printf ("  %s (0x%x) %6.1fMHz",
2425a0d3b6eaSmrg			    mode->name, mode->id,
2426a0d3b6eaSmrg			    (float)mode->dotClock / 1000000.0);
2427a0d3b6eaSmrg		    for (f = 0; mode_flags[f].flag; f++)
2428a0d3b6eaSmrg			if (mode->modeFlags & mode_flags[f].flag)
2429a0d3b6eaSmrg			    printf (" %s", mode_flags[f].string);
2430a0d3b6eaSmrg		    if (mode == output->mode_info)
2431a0d3b6eaSmrg			printf (" *current");
2432a0d3b6eaSmrg		    if (j < output_info->npreferred)
2433a0d3b6eaSmrg			printf (" +preferred");
2434a0d3b6eaSmrg		    printf ("\n");
2435a0d3b6eaSmrg		    printf ("        h: width  %4d start %4d end %4d total %4d skew %4d clock %6.1fKHz\n",
2436a0d3b6eaSmrg			    mode->width, mode->hSyncStart, mode->hSyncEnd,
2437a0d3b6eaSmrg			    mode->hTotal, mode->hSkew, mode_hsync (mode) / 1000);
2438a0d3b6eaSmrg		    printf ("        v: height %4d start %4d end %4d total %4d           clock %6.1fHz\n",
2439a0d3b6eaSmrg			    mode->height, mode->vSyncStart, mode->vSyncEnd, mode->vTotal,
2440a0d3b6eaSmrg			    mode_refresh (mode));
2441a0d3b6eaSmrg		    mode->modeFlags |= ModeShown;
2442a0d3b6eaSmrg		}
2443a0d3b6eaSmrg	    }
2444a0d3b6eaSmrg	    else
2445a0d3b6eaSmrg	    {
2446a0d3b6eaSmrg		mode_shown = calloc (output_info->nmode, sizeof (Bool));
2447a0d3b6eaSmrg		if (!mode_shown) fatal ("out of memory\n");
2448a0d3b6eaSmrg		for (j = 0; j < output_info->nmode; j++)
2449a0d3b6eaSmrg		{
2450a0d3b6eaSmrg		    XRRModeInfo *jmode, *kmode;
2451a0d3b6eaSmrg
2452a0d3b6eaSmrg		    if (mode_shown[j]) continue;
2453a0d3b6eaSmrg
2454a0d3b6eaSmrg		    jmode = find_mode_by_xid (output_info->modes[j]);
2455a0d3b6eaSmrg		    printf (" ");
2456a0d3b6eaSmrg		    printf ("  %-12s", jmode->name);
2457a0d3b6eaSmrg		    for (k = j; k < output_info->nmode; k++)
2458a0d3b6eaSmrg		    {
2459a0d3b6eaSmrg			if (mode_shown[k]) continue;
2460a0d3b6eaSmrg			kmode = find_mode_by_xid (output_info->modes[k]);
2461a0d3b6eaSmrg			if (strcmp (jmode->name, kmode->name) != 0) continue;
2462a0d3b6eaSmrg			mode_shown[k] = True;
2463a0d3b6eaSmrg			kmode->modeFlags |= ModeShown;
2464a0d3b6eaSmrg			printf (" %6.1f", mode_refresh (kmode));
2465a0d3b6eaSmrg			if (kmode == output->mode_info)
2466a0d3b6eaSmrg			    printf ("*");
2467a0d3b6eaSmrg			else
2468a0d3b6eaSmrg			    printf (" ");
2469a0d3b6eaSmrg			if (k < output_info->npreferred)
2470a0d3b6eaSmrg			    printf ("+");
2471a0d3b6eaSmrg			else
2472a0d3b6eaSmrg			    printf (" ");
2473a0d3b6eaSmrg		    }
2474a0d3b6eaSmrg		    printf ("\n");
2475a0d3b6eaSmrg		}
2476a0d3b6eaSmrg		free (mode_shown);
2477a0d3b6eaSmrg	    }
2478a0d3b6eaSmrg	}
2479a0d3b6eaSmrg	for (m = 0; m < res->nmode; m++)
2480a0d3b6eaSmrg	{
2481a0d3b6eaSmrg	    XRRModeInfo	*mode = &res->modes[m];
2482a0d3b6eaSmrg
2483a0d3b6eaSmrg	    if (!(mode->modeFlags & ModeShown))
2484a0d3b6eaSmrg	    {
2485a0d3b6eaSmrg		printf ("  %s (0x%x) %6.1fMHz\n",
2486a0d3b6eaSmrg			mode->name, mode->id,
2487a0d3b6eaSmrg			(float)mode->dotClock / 1000000.0);
2488a0d3b6eaSmrg		printf ("        h: width  %4d start %4d end %4d total %4d skew %4d clock %6.1fKHz\n",
2489a0d3b6eaSmrg			mode->width, mode->hSyncStart, mode->hSyncEnd,
2490a0d3b6eaSmrg			mode->hTotal, mode->hSkew, mode_hsync (mode) / 1000);
2491a0d3b6eaSmrg		printf ("        v: height %4d start %4d end %4d total %4d           clock %6.1fHz\n",
2492a0d3b6eaSmrg			mode->height, mode->vSyncStart, mode->vSyncEnd, mode->vTotal,
2493a0d3b6eaSmrg			mode_refresh (mode));
2494a0d3b6eaSmrg	    }
2495a0d3b6eaSmrg	}
2496a0d3b6eaSmrg	exit (0);
2497a0d3b6eaSmrg    }
2498a0d3b6eaSmrg#endif
2499a0d3b6eaSmrg
2500a0d3b6eaSmrg    sc = XRRGetScreenInfo (dpy, root);
2501a0d3b6eaSmrg
2502a0d3b6eaSmrg    if (sc == NULL)
2503a0d3b6eaSmrg	exit (1);
2504a0d3b6eaSmrg
2505a0d3b6eaSmrg    current_size = XRRConfigCurrentConfiguration (sc, &current_rotation);
2506a0d3b6eaSmrg
2507a0d3b6eaSmrg    sizes = XRRConfigSizes(sc, &nsize);
2508a0d3b6eaSmrg
2509a0d3b6eaSmrg    if (have_pixel_size) {
2510a0d3b6eaSmrg	for (size = 0; size < nsize; size++)
2511a0d3b6eaSmrg	{
2512a0d3b6eaSmrg	    if (sizes[size].width == width && sizes[size].height == height)
2513a0d3b6eaSmrg		break;
2514a0d3b6eaSmrg	}
2515a0d3b6eaSmrg	if (size >= nsize) {
2516a0d3b6eaSmrg	    fprintf (stderr,
2517a0d3b6eaSmrg		     "Size %dx%d not found in available modes\n", width, height);
2518a0d3b6eaSmrg	    exit (1);
2519a0d3b6eaSmrg	}
2520a0d3b6eaSmrg    }
2521a0d3b6eaSmrg    else if (size < 0)
2522a0d3b6eaSmrg	size = current_size;
2523a0d3b6eaSmrg    else if (size >= nsize) {
2524a0d3b6eaSmrg	fprintf (stderr,
2525a0d3b6eaSmrg		 "Size index %d is too large, there are only %d sizes\n",
2526a0d3b6eaSmrg		 size, nsize);
2527a0d3b6eaSmrg	exit (1);
2528a0d3b6eaSmrg    }
2529a0d3b6eaSmrg
2530a0d3b6eaSmrg    if (rot < 0)
2531a0d3b6eaSmrg    {
2532a0d3b6eaSmrg	for (rot = 0; rot < 4; rot++)
2533a0d3b6eaSmrg	    if (1 << rot == (current_rotation & 0xf))
2534a0d3b6eaSmrg		break;
2535a0d3b6eaSmrg    }
2536a0d3b6eaSmrg
2537a0d3b6eaSmrg    current_rate = XRRConfigCurrentRate (sc);
2538a0d3b6eaSmrg
2539a0d3b6eaSmrg    if (rate < 0)
2540a0d3b6eaSmrg    {
2541a0d3b6eaSmrg	if (size == current_size)
2542a0d3b6eaSmrg	    rate = current_rate;
2543a0d3b6eaSmrg	else
2544a0d3b6eaSmrg	    rate = 0;
2545a0d3b6eaSmrg    }
2546a0d3b6eaSmrg    else
2547a0d3b6eaSmrg    {
2548a0d3b6eaSmrg	rates = XRRConfigRates (sc, size, &nrate);
2549a0d3b6eaSmrg	for (i = 0; i < nrate; i++)
2550a0d3b6eaSmrg	    if (rate == rates[i])
2551a0d3b6eaSmrg		break;
2552a0d3b6eaSmrg	if (i == nrate) {
2553a0d3b6eaSmrg	    fprintf (stderr, "Rate %.1f Hz not available for this size\n", rate);
2554a0d3b6eaSmrg	    exit (1);
2555a0d3b6eaSmrg	}
2556a0d3b6eaSmrg    }
2557a0d3b6eaSmrg
2558a0d3b6eaSmrg    if (version) {
2559a0d3b6eaSmrg	int major_version, minor_version;
2560a0d3b6eaSmrg	XRRQueryVersion (dpy, &major_version, &minor_version);
2561a0d3b6eaSmrg	printf("Server reports RandR version %d.%d\n",
2562a0d3b6eaSmrg	       major_version, minor_version);
2563a0d3b6eaSmrg    }
2564a0d3b6eaSmrg
2565a0d3b6eaSmrg    if (query || query_1) {
2566a0d3b6eaSmrg	printf(" SZ:    Pixels          Physical       Refresh\n");
2567a0d3b6eaSmrg	for (i = 0; i < nsize; i++) {
2568a0d3b6eaSmrg	    printf ("%c%-2d %5d x %-5d  (%4dmm x%4dmm )",
2569a0d3b6eaSmrg		    i == current_size ? '*' : ' ',
2570a0d3b6eaSmrg		    i, sizes[i].width, sizes[i].height,
2571a0d3b6eaSmrg		    sizes[i].mwidth, sizes[i].mheight);
2572a0d3b6eaSmrg	    rates = XRRConfigRates (sc, i, &nrate);
2573a0d3b6eaSmrg	    if (nrate) printf ("  ");
2574a0d3b6eaSmrg	    for (j = 0; j < nrate; j++)
2575a0d3b6eaSmrg		printf ("%c%-4d",
2576a0d3b6eaSmrg			i == current_size && rates[j] == current_rate ? '*' : ' ',
2577a0d3b6eaSmrg			rates[j]);
2578a0d3b6eaSmrg	    printf ("\n");
2579a0d3b6eaSmrg	}
2580a0d3b6eaSmrg    }
2581a0d3b6eaSmrg
2582a0d3b6eaSmrg    rotations = XRRConfigRotations(sc, &current_rotation);
2583a0d3b6eaSmrg
2584a0d3b6eaSmrg    rotation = 1 << rot ;
2585a0d3b6eaSmrg    if (query) {
2586a0d3b6eaSmrg    	printf("Current rotation - %s\n",
2587a0d3b6eaSmrg	       rotation_name (current_rotation));
2588a0d3b6eaSmrg
2589a0d3b6eaSmrg	printf("Current reflection - %s\n",
2590a0d3b6eaSmrg	       reflection_name (current_rotation));
2591a0d3b6eaSmrg
2592a0d3b6eaSmrg	printf ("Rotations possible - ");
2593a0d3b6eaSmrg	for (i = 0; i < 4; i ++) {
2594a0d3b6eaSmrg	    if ((rotations >> i) & 1)  printf("%s ", direction[i]);
2595a0d3b6eaSmrg	}
2596a0d3b6eaSmrg	printf ("\n");
2597a0d3b6eaSmrg
2598a0d3b6eaSmrg	printf ("Reflections possible - ");
2599a0d3b6eaSmrg	if (rotations & (RR_Reflect_X|RR_Reflect_Y))
2600a0d3b6eaSmrg	{
2601a0d3b6eaSmrg	    if (rotations & RR_Reflect_X) printf ("X Axis ");
2602a0d3b6eaSmrg	    if (rotations & RR_Reflect_Y) printf ("Y Axis");
2603a0d3b6eaSmrg	}
2604a0d3b6eaSmrg	else
2605a0d3b6eaSmrg	    printf ("none");
2606a0d3b6eaSmrg	printf ("\n");
2607a0d3b6eaSmrg    }
2608a0d3b6eaSmrg
2609a0d3b6eaSmrg    if (verbose) {
2610a0d3b6eaSmrg	printf("Setting size to %d, rotation to %s\n",  size, direction[rot]);
2611a0d3b6eaSmrg
2612a0d3b6eaSmrg	printf ("Setting reflection on ");
2613a0d3b6eaSmrg	if (reflection)
2614a0d3b6eaSmrg	{
2615a0d3b6eaSmrg	    if (reflection & RR_Reflect_X) printf ("X Axis ");
2616a0d3b6eaSmrg	    if (reflection & RR_Reflect_Y) printf ("Y Axis");
2617a0d3b6eaSmrg	}
2618a0d3b6eaSmrg	else
2619a0d3b6eaSmrg	    printf ("neither axis");
2620a0d3b6eaSmrg	printf ("\n");
2621a0d3b6eaSmrg
2622a0d3b6eaSmrg	if (reflection & RR_Reflect_X) printf("Setting reflection on X axis\n");
2623a0d3b6eaSmrg
2624a0d3b6eaSmrg	if (reflection & RR_Reflect_Y) printf("Setting reflection on Y axis\n");
2625a0d3b6eaSmrg    }
2626a0d3b6eaSmrg
2627a0d3b6eaSmrg    /* we should test configureNotify on the root window */
2628a0d3b6eaSmrg    XSelectInput (dpy, root, StructureNotifyMask);
2629a0d3b6eaSmrg
2630a0d3b6eaSmrg    if (setit && !dryrun) XRRSelectInput (dpy, root,
2631a0d3b6eaSmrg			       RRScreenChangeNotifyMask);
2632a0d3b6eaSmrg    if (setit && !dryrun) status = XRRSetScreenConfigAndRate (dpy, sc,
2633a0d3b6eaSmrg						   DefaultRootWindow (dpy),
2634a0d3b6eaSmrg						   (SizeID) size, (Rotation) (rotation | reflection), rate, CurrentTime);
2635a0d3b6eaSmrg
2636a0d3b6eaSmrg    XRRQueryExtension(dpy, &event_base, &error_base);
2637a0d3b6eaSmrg
2638a0d3b6eaSmrg    if (setit && !dryrun && status == RRSetConfigFailed) {
2639a0d3b6eaSmrg	printf ("Failed to change the screen configuration!\n");
2640a0d3b6eaSmrg	ret = 1;
2641a0d3b6eaSmrg    }
2642a0d3b6eaSmrg
2643a0d3b6eaSmrg    if (verbose && setit && !dryrun && size != current_size) {
2644a0d3b6eaSmrg	if (status == RRSetConfigSuccess)
2645a0d3b6eaSmrg	{
2646a0d3b6eaSmrg	    Bool    seen_screen = False;
2647a0d3b6eaSmrg	    while (!seen_screen) {
2648a0d3b6eaSmrg		int spo;
2649a0d3b6eaSmrg		XNextEvent(dpy, (XEvent *) &event);
2650a0d3b6eaSmrg
2651a0d3b6eaSmrg		printf ("Event received, type = %d\n", event.type);
2652a0d3b6eaSmrg		/* update Xlib's knowledge of the event */
2653a0d3b6eaSmrg		XRRUpdateConfiguration (&event);
2654a0d3b6eaSmrg		if (event.type == ConfigureNotify)
2655a0d3b6eaSmrg		    printf("Received ConfigureNotify Event!\n");
2656a0d3b6eaSmrg
2657a0d3b6eaSmrg		switch (event.type - event_base) {
2658a0d3b6eaSmrg		case RRScreenChangeNotify:
2659a0d3b6eaSmrg		    sce = (XRRScreenChangeNotifyEvent *) &event;
2660a0d3b6eaSmrg
2661a0d3b6eaSmrg		    printf("Got a screen change notify event!\n");
2662a0d3b6eaSmrg		    printf(" window = %d\n root = %d\n size_index = %d\n rotation %d\n",
2663a0d3b6eaSmrg			   (int) sce->window, (int) sce->root,
2664a0d3b6eaSmrg			   sce->size_index,  sce->rotation);
2665a0d3b6eaSmrg		    printf(" timestamp = %ld, config_timestamp = %ld\n",
2666a0d3b6eaSmrg			   sce->timestamp, sce->config_timestamp);
2667a0d3b6eaSmrg		    printf(" Rotation = %x\n", sce->rotation);
2668a0d3b6eaSmrg		    printf(" %d X %d pixels, %d X %d mm\n",
2669a0d3b6eaSmrg			   sce->width, sce->height, sce->mwidth, sce->mheight);
2670a0d3b6eaSmrg		    printf("Display width   %d, height   %d\n",
2671a0d3b6eaSmrg			   DisplayWidth(dpy, screen), DisplayHeight(dpy, screen));
2672a0d3b6eaSmrg		    printf("Display widthmm %d, heightmm %d\n",
2673a0d3b6eaSmrg			   DisplayWidthMM(dpy, screen), DisplayHeightMM(dpy, screen));
2674a0d3b6eaSmrg		    spo = sce->subpixel_order;
2675a0d3b6eaSmrg		    if ((spo < 0) || (spo > 5))
2676a0d3b6eaSmrg			printf ("Unknown subpixel order, value = %d\n", spo);
2677a0d3b6eaSmrg		    else printf ("new Subpixel rendering model is %s\n", order[spo]);
2678a0d3b6eaSmrg		    seen_screen = True;
2679a0d3b6eaSmrg		    break;
2680a0d3b6eaSmrg		default:
2681a0d3b6eaSmrg		    if (event.type != ConfigureNotify)
2682a0d3b6eaSmrg			printf("unknown event received, type = %d!\n", event.type);
2683a0d3b6eaSmrg		}
2684a0d3b6eaSmrg	    }
2685a0d3b6eaSmrg	}
2686a0d3b6eaSmrg    }
2687a0d3b6eaSmrg    XRRFreeScreenConfigInfo(sc);
2688a0d3b6eaSmrg    return(ret);
2689a0d3b6eaSmrg}
2690