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, ¤t_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, ¤t_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