xrandr.c revision ea024c75
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 4078038a65Smrg#ifdef HAVE_CONFIG_H 4162770414Smrg#include "config.h" 4278038a65Smrg#endif 4362770414Smrg 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; 5162df5ad0Smrgstatic Bool grab_server = True; 5262df5ad0Smrgstatic Bool no_primary = False; 53a0d3b6eaSmrg 54a0d3b6eaSmrgstatic char *direction[5] = { 55a0d3b6eaSmrg "normal", 56a0d3b6eaSmrg "left", 57a0d3b6eaSmrg "inverted", 58a0d3b6eaSmrg "right", 59a0d3b6eaSmrg "\n"}; 60a0d3b6eaSmrg 61a0d3b6eaSmrgstatic char *reflections[5] = { 62a0d3b6eaSmrg "normal", 63a0d3b6eaSmrg "x", 64a0d3b6eaSmrg "y", 65a0d3b6eaSmrg "xy", 66a0d3b6eaSmrg "\n"}; 67a0d3b6eaSmrg 68a0d3b6eaSmrg/* subpixel order */ 69a0d3b6eaSmrgstatic char *order[6] = { 70a0d3b6eaSmrg "unknown", 71a0d3b6eaSmrg "horizontal rgb", 72a0d3b6eaSmrg "horizontal bgr", 73a0d3b6eaSmrg "vertical rgb", 74a0d3b6eaSmrg "vertical bgr", 75a0d3b6eaSmrg "no subpixels"}; 76a0d3b6eaSmrg 77a0d3b6eaSmrgstatic const struct { 78a0d3b6eaSmrg char *string; 79a0d3b6eaSmrg unsigned long flag; 80a0d3b6eaSmrg} mode_flags[] = { 81a0d3b6eaSmrg { "+HSync", RR_HSyncPositive }, 82a0d3b6eaSmrg { "-HSync", RR_HSyncNegative }, 83a0d3b6eaSmrg { "+VSync", RR_VSyncPositive }, 84a0d3b6eaSmrg { "-VSync", RR_VSyncNegative }, 85a0d3b6eaSmrg { "Interlace", RR_Interlace }, 86a0d3b6eaSmrg { "DoubleScan", RR_DoubleScan }, 87a0d3b6eaSmrg { "CSync", RR_CSync }, 88a0d3b6eaSmrg { "+CSync", RR_CSyncPositive }, 89a0d3b6eaSmrg { "-CSync", RR_CSyncNegative }, 90a0d3b6eaSmrg { NULL, 0 } 91a0d3b6eaSmrg}; 92a0d3b6eaSmrg 93a0d3b6eaSmrgstatic void 94a0d3b6eaSmrgusage(void) 95a0d3b6eaSmrg{ 96a0d3b6eaSmrg fprintf(stderr, "usage: %s [options]\n", program_name); 97a0d3b6eaSmrg fprintf(stderr, " where options are:\n"); 98a0d3b6eaSmrg fprintf(stderr, " -display <display> or -d <display>\n"); 99a0d3b6eaSmrg fprintf(stderr, " -help\n"); 100a0d3b6eaSmrg fprintf(stderr, " -o <normal,inverted,left,right,0,1,2,3>\n"); 101a0d3b6eaSmrg fprintf(stderr, " or --orientation <normal,inverted,left,right,0,1,2,3>\n"); 102a0d3b6eaSmrg fprintf(stderr, " -q or --query\n"); 103a0d3b6eaSmrg fprintf(stderr, " -s <size>/<width>x<height> or --size <size>/<width>x<height>\n"); 104a0d3b6eaSmrg fprintf(stderr, " -r <rate> or --rate <rate> or --refresh <rate>\n"); 105a0d3b6eaSmrg fprintf(stderr, " -v or --version\n"); 106a0d3b6eaSmrg fprintf(stderr, " -x (reflect in x)\n"); 107a0d3b6eaSmrg fprintf(stderr, " -y (reflect in y)\n"); 108a0d3b6eaSmrg fprintf(stderr, " --screen <screen>\n"); 109a0d3b6eaSmrg fprintf(stderr, " --verbose\n"); 110a0d3b6eaSmrg fprintf(stderr, " --dryrun\n"); 11162df5ad0Smrg fprintf(stderr, " --nograb\n"); 112a0d3b6eaSmrg fprintf(stderr, " --prop or --properties\n"); 113a0d3b6eaSmrg fprintf(stderr, " --fb <width>x<height>\n"); 114a0d3b6eaSmrg fprintf(stderr, " --fbmm <width>x<height>\n"); 115a0d3b6eaSmrg fprintf(stderr, " --dpi <dpi>/<output>\n"); 116a0d3b6eaSmrg fprintf(stderr, " --output <output>\n"); 117a0d3b6eaSmrg fprintf(stderr, " --auto\n"); 118a0d3b6eaSmrg fprintf(stderr, " --mode <mode>\n"); 119a0d3b6eaSmrg fprintf(stderr, " --preferred\n"); 120a0d3b6eaSmrg fprintf(stderr, " --pos <x>x<y>\n"); 121a0d3b6eaSmrg fprintf(stderr, " --rate <rate> or --refresh <rate>\n"); 122a0d3b6eaSmrg fprintf(stderr, " --reflect normal,x,y,xy\n"); 123a0d3b6eaSmrg fprintf(stderr, " --rotate normal,inverted,left,right\n"); 124a0d3b6eaSmrg fprintf(stderr, " --left-of <output>\n"); 125a0d3b6eaSmrg fprintf(stderr, " --right-of <output>\n"); 126a0d3b6eaSmrg fprintf(stderr, " --above <output>\n"); 127a0d3b6eaSmrg fprintf(stderr, " --below <output>\n"); 128a0d3b6eaSmrg fprintf(stderr, " --same-as <output>\n"); 129a0d3b6eaSmrg fprintf(stderr, " --set <property> <value>\n"); 13062df5ad0Smrg fprintf(stderr, " --scale <x>x<y>\n"); 13162df5ad0Smrg fprintf(stderr, " --transform <a>,<b>,<c>,<d>,<e>,<f>,<g>,<h>,<i>\n"); 132a0d3b6eaSmrg fprintf(stderr, " --off\n"); 133a0d3b6eaSmrg fprintf(stderr, " --crtc <crtc>\n"); 13462df5ad0Smrg fprintf(stderr, " --panning <w>x<h>[+<x>+<y>[/<track:w>x<h>+<x>+<y>[/<border:l>/<t>/<r>/<b>]]]\n"); 13562df5ad0Smrg fprintf(stderr, " --gamma <r>:<g>:<b>\n"); 13662df5ad0Smrg fprintf(stderr, " --primary\n"); 13762df5ad0Smrg fprintf(stderr, " --noprimary\n"); 138a0d3b6eaSmrg fprintf(stderr, " --newmode <name> <clock MHz>\n"); 139a0d3b6eaSmrg fprintf(stderr, " <hdisp> <hsync-start> <hsync-end> <htotal>\n"); 140a0d3b6eaSmrg fprintf(stderr, " <vdisp> <vsync-start> <vsync-end> <vtotal>\n"); 141a0d3b6eaSmrg fprintf(stderr, " [+HSync] [-HSync] [+VSync] [-VSync]\n"); 142a0d3b6eaSmrg fprintf(stderr, " --rmmode <name>\n"); 143a0d3b6eaSmrg fprintf(stderr, " --addmode <output> <name>\n"); 144a0d3b6eaSmrg fprintf(stderr, " --delmode <output> <name>\n"); 145a0d3b6eaSmrg 146a0d3b6eaSmrg exit(1); 147a0d3b6eaSmrg /*NOTREACHED*/ 148a0d3b6eaSmrg} 149a0d3b6eaSmrg 150a0d3b6eaSmrgstatic void 151a0d3b6eaSmrgfatal (const char *format, ...) 152a0d3b6eaSmrg{ 153a0d3b6eaSmrg va_list ap; 154a0d3b6eaSmrg 155a0d3b6eaSmrg va_start (ap, format); 156a0d3b6eaSmrg fprintf (stderr, "%s: ", program_name); 157a0d3b6eaSmrg vfprintf (stderr, format, ap); 158a0d3b6eaSmrg va_end (ap); 159a0d3b6eaSmrg exit (1); 160a0d3b6eaSmrg /*NOTREACHED*/ 161a0d3b6eaSmrg} 162a0d3b6eaSmrg 16362df5ad0Smrgstatic void 16462df5ad0Smrgwarning (const char *format, ...) 16562df5ad0Smrg{ 16662df5ad0Smrg va_list ap; 16762df5ad0Smrg 16862df5ad0Smrg va_start (ap, format); 16962df5ad0Smrg fprintf (stderr, "%s: ", program_name); 17062df5ad0Smrg vfprintf (stderr, format, ap); 17162df5ad0Smrg va_end (ap); 17262df5ad0Smrg} 17362df5ad0Smrg 1748a16544fSmrg/* Because fmin requires C99 suppport */ 1758a16544fSmrgstatic inline double dmin (double x, double y) 1768a16544fSmrg{ 1778a16544fSmrg return x < y ? x : y; 1788a16544fSmrg} 1798a16544fSmrg 180a0d3b6eaSmrgstatic char * 181a0d3b6eaSmrgrotation_name (Rotation rotation) 182a0d3b6eaSmrg{ 183a0d3b6eaSmrg int i; 184a0d3b6eaSmrg 185a0d3b6eaSmrg if ((rotation & 0xf) == 0) 186a0d3b6eaSmrg return "normal"; 187a0d3b6eaSmrg for (i = 0; i < 4; i++) 188a0d3b6eaSmrg if (rotation & (1 << i)) 189a0d3b6eaSmrg return direction[i]; 190a0d3b6eaSmrg return "invalid rotation"; 191a0d3b6eaSmrg} 192a0d3b6eaSmrg 193a0d3b6eaSmrgstatic char * 194a0d3b6eaSmrgreflection_name (Rotation rotation) 195a0d3b6eaSmrg{ 196a0d3b6eaSmrg rotation &= (RR_Reflect_X|RR_Reflect_Y); 197a0d3b6eaSmrg switch (rotation) { 198a0d3b6eaSmrg case 0: 199a0d3b6eaSmrg return "none"; 200a0d3b6eaSmrg case RR_Reflect_X: 201a0d3b6eaSmrg return "X axis"; 202a0d3b6eaSmrg case RR_Reflect_Y: 203a0d3b6eaSmrg return "Y axis"; 204a0d3b6eaSmrg case RR_Reflect_X|RR_Reflect_Y: 205a0d3b6eaSmrg return "X and Y axis"; 206a0d3b6eaSmrg } 207a0d3b6eaSmrg return "invalid reflection"; 208a0d3b6eaSmrg} 209a0d3b6eaSmrg 210a0d3b6eaSmrgtypedef enum _relation { 2118a16544fSmrg relation_left_of, 2128a16544fSmrg relation_right_of, 2138a16544fSmrg relation_above, 2148a16544fSmrg relation_below, 2158a16544fSmrg relation_same_as, 216a0d3b6eaSmrg} relation_t; 217a0d3b6eaSmrg 21862df5ad0Smrgtypedef struct { 21962df5ad0Smrg int x, y, width, height; 22062df5ad0Smrg} rectangle_t; 22162df5ad0Smrg 22262df5ad0Smrgtypedef struct { 22362df5ad0Smrg int x1, y1, x2, y2; 22462df5ad0Smrg} box_t; 22562df5ad0Smrg 22662df5ad0Smrgtypedef struct { 22762df5ad0Smrg int x, y; 22862df5ad0Smrg} point_t; 22962df5ad0Smrg 230a0d3b6eaSmrgtypedef enum _changes { 231a0d3b6eaSmrg changes_none = 0, 232a0d3b6eaSmrg changes_crtc = (1 << 0), 233a0d3b6eaSmrg changes_mode = (1 << 1), 234a0d3b6eaSmrg changes_relation = (1 << 2), 235a0d3b6eaSmrg changes_position = (1 << 3), 236a0d3b6eaSmrg changes_rotation = (1 << 4), 237a0d3b6eaSmrg changes_reflection = (1 << 5), 238a0d3b6eaSmrg changes_automatic = (1 << 6), 239a0d3b6eaSmrg changes_refresh = (1 << 7), 240a0d3b6eaSmrg changes_property = (1 << 8), 24162df5ad0Smrg changes_transform = (1 << 9), 24262df5ad0Smrg changes_panning = (1 << 10), 24362df5ad0Smrg changes_gamma = (1 << 11), 24462df5ad0Smrg changes_primary = (1 << 12), 245a0d3b6eaSmrg} changes_t; 246a0d3b6eaSmrg 247a0d3b6eaSmrgtypedef enum _name_kind { 248a0d3b6eaSmrg name_none = 0, 249a0d3b6eaSmrg name_string = (1 << 0), 250a0d3b6eaSmrg name_xid = (1 << 1), 251a0d3b6eaSmrg name_index = (1 << 2), 252a0d3b6eaSmrg name_preferred = (1 << 3), 253a0d3b6eaSmrg} name_kind_t; 254a0d3b6eaSmrg 255a0d3b6eaSmrgtypedef struct { 256a0d3b6eaSmrg name_kind_t kind; 257a0d3b6eaSmrg char *string; 258a0d3b6eaSmrg XID xid; 259a0d3b6eaSmrg int index; 260a0d3b6eaSmrg} name_t; 261a0d3b6eaSmrg 262a0d3b6eaSmrgtypedef struct _crtc crtc_t; 263a0d3b6eaSmrgtypedef struct _output output_t; 26462df5ad0Smrgtypedef struct _transform transform_t; 265a0d3b6eaSmrgtypedef struct _umode umode_t; 266a0d3b6eaSmrgtypedef struct _output_prop output_prop_t; 267a0d3b6eaSmrg 26862df5ad0Smrgstruct _transform { 26962df5ad0Smrg XTransform transform; 27062df5ad0Smrg char *filter; 27162df5ad0Smrg int nparams; 27262df5ad0Smrg XFixed *params; 27362df5ad0Smrg}; 27462df5ad0Smrg 275a0d3b6eaSmrgstruct _crtc { 276a0d3b6eaSmrg name_t crtc; 277a0d3b6eaSmrg Bool changing; 278a0d3b6eaSmrg XRRCrtcInfo *crtc_info; 279a0d3b6eaSmrg 280a0d3b6eaSmrg XRRModeInfo *mode_info; 28162df5ad0Smrg XRRPanning *panning_info; 282a0d3b6eaSmrg int x; 283a0d3b6eaSmrg int y; 284a0d3b6eaSmrg Rotation rotation; 285a0d3b6eaSmrg output_t **outputs; 286a0d3b6eaSmrg int noutput; 28762df5ad0Smrg transform_t current_transform, pending_transform; 288a0d3b6eaSmrg}; 289a0d3b6eaSmrg 290a0d3b6eaSmrgstruct _output_prop { 291a0d3b6eaSmrg struct _output_prop *next; 292a0d3b6eaSmrg char *name; 293a0d3b6eaSmrg char *value; 294a0d3b6eaSmrg}; 295a0d3b6eaSmrg 296a0d3b6eaSmrgstruct _output { 297a0d3b6eaSmrg struct _output *next; 298a0d3b6eaSmrg 299a0d3b6eaSmrg changes_t changes; 300a0d3b6eaSmrg 301a0d3b6eaSmrg output_prop_t *props; 302a0d3b6eaSmrg 303a0d3b6eaSmrg name_t output; 304a0d3b6eaSmrg XRROutputInfo *output_info; 305a0d3b6eaSmrg 306a0d3b6eaSmrg name_t crtc; 307a0d3b6eaSmrg crtc_t *crtc_info; 308a0d3b6eaSmrg crtc_t *current_crtc_info; 309a0d3b6eaSmrg 310a0d3b6eaSmrg name_t mode; 311c52f0396Smrg double refresh; 312a0d3b6eaSmrg XRRModeInfo *mode_info; 313a0d3b6eaSmrg 314a0d3b6eaSmrg name_t addmode; 315a0d3b6eaSmrg 316a0d3b6eaSmrg relation_t relation; 317a0d3b6eaSmrg char *relative_to; 318a0d3b6eaSmrg 319a0d3b6eaSmrg int x, y; 320a0d3b6eaSmrg Rotation rotation; 32162df5ad0Smrg 32262df5ad0Smrg XRRPanning panning; 32362df5ad0Smrg 324a0d3b6eaSmrg Bool automatic; 32562df5ad0Smrg transform_t transform; 32662df5ad0Smrg 32762df5ad0Smrg struct { 32862df5ad0Smrg float red; 32962df5ad0Smrg float green; 33062df5ad0Smrg float blue; 33162df5ad0Smrg } gamma; 33262df5ad0Smrg 3338a16544fSmrg float brightness; 3348a16544fSmrg 33562df5ad0Smrg Bool primary; 336c52f0396Smrg 337c52f0396Smrg Bool found; 338a0d3b6eaSmrg}; 339a0d3b6eaSmrg 340a0d3b6eaSmrgtypedef enum _umode_action { 341a0d3b6eaSmrg umode_create, umode_destroy, umode_add, umode_delete 342a0d3b6eaSmrg} umode_action_t; 343a0d3b6eaSmrg 344a0d3b6eaSmrg 345a0d3b6eaSmrgstruct _umode { 346a0d3b6eaSmrg struct _umode *next; 347a0d3b6eaSmrg 348a0d3b6eaSmrg umode_action_t action; 349a0d3b6eaSmrg XRRModeInfo mode; 350a0d3b6eaSmrg name_t output; 351a0d3b6eaSmrg name_t name; 352a0d3b6eaSmrg}; 353a0d3b6eaSmrg 354a0d3b6eaSmrgstatic char *connection[3] = { 355a0d3b6eaSmrg "connected", 356a0d3b6eaSmrg "disconnected", 357a0d3b6eaSmrg "unknown connection"}; 358a0d3b6eaSmrg 359a0d3b6eaSmrg#define OUTPUT_NAME 1 360a0d3b6eaSmrg 361a0d3b6eaSmrg#define CRTC_OFF 2 362a0d3b6eaSmrg#define CRTC_UNSET 3 363a0d3b6eaSmrg#define CRTC_INDEX 0x40000000 364a0d3b6eaSmrg 365a0d3b6eaSmrg#define MODE_NAME 1 366a0d3b6eaSmrg#define MODE_OFF 2 367a0d3b6eaSmrg#define MODE_UNSET 3 368a0d3b6eaSmrg#define MODE_PREF 4 369a0d3b6eaSmrg 370a0d3b6eaSmrg#define POS_UNSET -1 371a0d3b6eaSmrg 372a0d3b6eaSmrgstatic output_t *outputs = NULL; 373a0d3b6eaSmrgstatic output_t **outputs_tail = &outputs; 374a0d3b6eaSmrgstatic crtc_t *crtcs; 375a0d3b6eaSmrgstatic umode_t *umodes; 376a0d3b6eaSmrgstatic int num_crtcs; 377a0d3b6eaSmrgstatic XRRScreenResources *res; 378a0d3b6eaSmrgstatic int fb_width = 0, fb_height = 0; 379a0d3b6eaSmrgstatic int fb_width_mm = 0, fb_height_mm = 0; 380c52f0396Smrgstatic double dpi = 0; 381a0d3b6eaSmrgstatic char *dpi_output = NULL; 382a0d3b6eaSmrgstatic Bool dryrun = False; 383a0d3b6eaSmrgstatic int minWidth, maxWidth, minHeight, maxHeight; 384a0d3b6eaSmrgstatic Bool has_1_2 = False; 38562df5ad0Smrgstatic Bool has_1_3 = False; 386a0d3b6eaSmrg 387a0d3b6eaSmrgstatic int 388a0d3b6eaSmrgmode_height (XRRModeInfo *mode_info, Rotation rotation) 389a0d3b6eaSmrg{ 390a0d3b6eaSmrg switch (rotation & 0xf) { 391a0d3b6eaSmrg case RR_Rotate_0: 392a0d3b6eaSmrg case RR_Rotate_180: 393a0d3b6eaSmrg return mode_info->height; 394a0d3b6eaSmrg case RR_Rotate_90: 395a0d3b6eaSmrg case RR_Rotate_270: 396a0d3b6eaSmrg return mode_info->width; 397a0d3b6eaSmrg default: 398a0d3b6eaSmrg return 0; 399a0d3b6eaSmrg } 400a0d3b6eaSmrg} 401a0d3b6eaSmrg 402a0d3b6eaSmrgstatic int 403a0d3b6eaSmrgmode_width (XRRModeInfo *mode_info, Rotation rotation) 404a0d3b6eaSmrg{ 405a0d3b6eaSmrg switch (rotation & 0xf) { 406a0d3b6eaSmrg case RR_Rotate_0: 407a0d3b6eaSmrg case RR_Rotate_180: 408a0d3b6eaSmrg return mode_info->width; 409a0d3b6eaSmrg case RR_Rotate_90: 410a0d3b6eaSmrg case RR_Rotate_270: 411a0d3b6eaSmrg return mode_info->height; 412a0d3b6eaSmrg default: 413a0d3b6eaSmrg return 0; 414a0d3b6eaSmrg } 415a0d3b6eaSmrg} 416a0d3b6eaSmrg 41762df5ad0Smrgstatic Bool 41862df5ad0Smrgtransform_point (XTransform *transform, double *xp, double *yp) 41962df5ad0Smrg{ 42062df5ad0Smrg double vector[3]; 42162df5ad0Smrg double result[3]; 42262df5ad0Smrg int i, j; 42362df5ad0Smrg double v; 42462df5ad0Smrg 42562df5ad0Smrg vector[0] = *xp; 42662df5ad0Smrg vector[1] = *yp; 42762df5ad0Smrg vector[2] = 1; 42862df5ad0Smrg for (j = 0; j < 3; j++) 42962df5ad0Smrg { 43062df5ad0Smrg v = 0; 43162df5ad0Smrg for (i = 0; i < 3; i++) 43262df5ad0Smrg v += (XFixedToDouble (transform->matrix[j][i]) * vector[i]); 43362df5ad0Smrg if (v > 32767 || v < -32767) 43462df5ad0Smrg return False; 43562df5ad0Smrg result[j] = v; 43662df5ad0Smrg } 43762df5ad0Smrg if (!result[2]) 43862df5ad0Smrg return False; 43962df5ad0Smrg for (j = 0; j < 2; j++) 44062df5ad0Smrg vector[j] = result[j] / result[2]; 44162df5ad0Smrg *xp = vector[0]; 44262df5ad0Smrg *yp = vector[1]; 44362df5ad0Smrg return True; 44462df5ad0Smrg} 44562df5ad0Smrg 44662df5ad0Smrgstatic void 44762df5ad0Smrgpath_bounds (XTransform *transform, point_t *points, int npoints, box_t *box) 44862df5ad0Smrg{ 44962df5ad0Smrg int i; 45062df5ad0Smrg box_t point; 45162df5ad0Smrg 45262df5ad0Smrg for (i = 0; i < npoints; i++) { 45362df5ad0Smrg double x, y; 45462df5ad0Smrg x = points[i].x; 45562df5ad0Smrg y = points[i].y; 45662df5ad0Smrg transform_point (transform, &x, &y); 45762df5ad0Smrg point.x1 = floor (x); 45862df5ad0Smrg point.y1 = floor (y); 45962df5ad0Smrg point.x2 = ceil (x); 46062df5ad0Smrg point.y2 = ceil (y); 46162df5ad0Smrg if (i == 0) 46262df5ad0Smrg *box = point; 46362df5ad0Smrg else { 46462df5ad0Smrg if (point.x1 < box->x1) box->x1 = point.x1; 46562df5ad0Smrg if (point.y1 < box->y1) box->y1 = point.y1; 46662df5ad0Smrg if (point.x2 > box->x2) box->x2 = point.x2; 46762df5ad0Smrg if (point.y2 > box->y2) box->y2 = point.y2; 46862df5ad0Smrg } 46962df5ad0Smrg } 47062df5ad0Smrg} 47162df5ad0Smrg 47262df5ad0Smrgstatic void 47362df5ad0Smrgmode_geometry (XRRModeInfo *mode_info, Rotation rotation, 47462df5ad0Smrg XTransform *transform, 47562df5ad0Smrg box_t *bounds) 47662df5ad0Smrg{ 47762df5ad0Smrg point_t rect[4]; 47862df5ad0Smrg int width = mode_width (mode_info, rotation); 47962df5ad0Smrg int height = mode_height (mode_info, rotation); 48062df5ad0Smrg 48162df5ad0Smrg rect[0].x = 0; 48262df5ad0Smrg rect[0].y = 0; 48362df5ad0Smrg rect[1].x = width; 48462df5ad0Smrg rect[1].y = 0; 48562df5ad0Smrg rect[2].x = width; 48662df5ad0Smrg rect[2].y = height; 48762df5ad0Smrg rect[3].x = 0; 48862df5ad0Smrg rect[3].y = height; 48962df5ad0Smrg path_bounds (transform, rect, 4, bounds); 49062df5ad0Smrg} 49162df5ad0Smrg 492a0d3b6eaSmrg/* v refresh frequency in Hz */ 493c52f0396Smrgstatic double 494a0d3b6eaSmrgmode_refresh (XRRModeInfo *mode_info) 495a0d3b6eaSmrg{ 496c52f0396Smrg double rate; 497a0d3b6eaSmrg 498a0d3b6eaSmrg if (mode_info->hTotal && mode_info->vTotal) 499c52f0396Smrg rate = ((double) mode_info->dotClock / 500c52f0396Smrg ((double) mode_info->hTotal * (double) mode_info->vTotal)); 501a0d3b6eaSmrg else 502a0d3b6eaSmrg rate = 0; 503a0d3b6eaSmrg return rate; 504a0d3b6eaSmrg} 505a0d3b6eaSmrg 506a0d3b6eaSmrg/* h sync frequency in Hz */ 507c52f0396Smrgstatic double 508a0d3b6eaSmrgmode_hsync (XRRModeInfo *mode_info) 509a0d3b6eaSmrg{ 510c52f0396Smrg double rate; 511a0d3b6eaSmrg 512a0d3b6eaSmrg if (mode_info->hTotal) 513c52f0396Smrg rate = (double) mode_info->dotClock / (double) mode_info->hTotal; 514a0d3b6eaSmrg else 515a0d3b6eaSmrg rate = 0; 516a0d3b6eaSmrg return rate; 517a0d3b6eaSmrg} 518a0d3b6eaSmrg 519a0d3b6eaSmrgstatic void 520a0d3b6eaSmrginit_name (name_t *name) 521a0d3b6eaSmrg{ 522a0d3b6eaSmrg name->kind = name_none; 523a0d3b6eaSmrg} 524a0d3b6eaSmrg 525a0d3b6eaSmrgstatic void 526a0d3b6eaSmrgset_name_string (name_t *name, char *string) 527a0d3b6eaSmrg{ 528a0d3b6eaSmrg name->kind |= name_string; 529a0d3b6eaSmrg name->string = string; 530a0d3b6eaSmrg} 531a0d3b6eaSmrg 532a0d3b6eaSmrgstatic void 533a0d3b6eaSmrgset_name_xid (name_t *name, XID xid) 534a0d3b6eaSmrg{ 535a0d3b6eaSmrg name->kind |= name_xid; 536a0d3b6eaSmrg name->xid = xid; 537a0d3b6eaSmrg} 538a0d3b6eaSmrg 539a0d3b6eaSmrgstatic void 540a0d3b6eaSmrgset_name_index (name_t *name, int index) 541a0d3b6eaSmrg{ 542a0d3b6eaSmrg name->kind |= name_index; 543a0d3b6eaSmrg name->index = index; 544a0d3b6eaSmrg} 545a0d3b6eaSmrg 546a0d3b6eaSmrgstatic void 547a0d3b6eaSmrgset_name_preferred (name_t *name) 548a0d3b6eaSmrg{ 549a0d3b6eaSmrg name->kind |= name_preferred; 550a0d3b6eaSmrg} 551a0d3b6eaSmrg 552a0d3b6eaSmrgstatic void 553a0d3b6eaSmrgset_name_all (name_t *name, name_t *old) 554a0d3b6eaSmrg{ 555a0d3b6eaSmrg if (old->kind & name_xid) 556a0d3b6eaSmrg name->xid = old->xid; 557a0d3b6eaSmrg if (old->kind & name_string) 558a0d3b6eaSmrg name->string = old->string; 559a0d3b6eaSmrg if (old->kind & name_index) 560a0d3b6eaSmrg name->index = old->index; 561a0d3b6eaSmrg name->kind |= old->kind; 562a0d3b6eaSmrg} 563a0d3b6eaSmrg 564a0d3b6eaSmrgstatic void 565a0d3b6eaSmrgset_name (name_t *name, char *string, name_kind_t valid) 566a0d3b6eaSmrg{ 56762df5ad0Smrg unsigned int xid; /* don't make it XID (which is unsigned long): 56862df5ad0Smrg scanf() takes unsigned int */ 569a0d3b6eaSmrg int index; 570a0d3b6eaSmrg 571a0d3b6eaSmrg if ((valid & name_xid) && sscanf (string, "0x%x", &xid) == 1) 572a0d3b6eaSmrg set_name_xid (name, xid); 573a0d3b6eaSmrg else if ((valid & name_index) && sscanf (string, "%d", &index) == 1) 574a0d3b6eaSmrg set_name_index (name, index); 575a0d3b6eaSmrg else if (valid & name_string) 576a0d3b6eaSmrg set_name_string (name, string); 577a0d3b6eaSmrg else 578a0d3b6eaSmrg usage (); 579a0d3b6eaSmrg} 580a0d3b6eaSmrg 58162df5ad0Smrgstatic void 58262df5ad0Smrginit_transform (transform_t *transform) 58362df5ad0Smrg{ 58462df5ad0Smrg int x; 58562df5ad0Smrg memset (&transform->transform, '\0', sizeof (transform->transform)); 58662df5ad0Smrg for (x = 0; x < 3; x++) 58762df5ad0Smrg transform->transform.matrix[x][x] = XDoubleToFixed (1.0); 58862df5ad0Smrg transform->filter = ""; 58962df5ad0Smrg transform->nparams = 0; 59062df5ad0Smrg transform->params = NULL; 59162df5ad0Smrg} 59262df5ad0Smrg 59362df5ad0Smrgstatic void 59462df5ad0Smrgset_transform (transform_t *dest, 59562df5ad0Smrg XTransform *transform, 59662df5ad0Smrg char *filter, 59762df5ad0Smrg XFixed *params, 59862df5ad0Smrg int nparams) 59962df5ad0Smrg{ 60062df5ad0Smrg dest->transform = *transform; 60162df5ad0Smrg dest->filter = strdup (filter); 60262df5ad0Smrg dest->nparams = nparams; 60362df5ad0Smrg dest->params = malloc (nparams * sizeof (XFixed)); 60462df5ad0Smrg memcpy (dest->params, params, nparams * sizeof (XFixed)); 60562df5ad0Smrg} 60662df5ad0Smrg 60762df5ad0Smrgstatic void 60862df5ad0Smrgcopy_transform (transform_t *dest, transform_t *src) 60962df5ad0Smrg{ 61062df5ad0Smrg set_transform (dest, &src->transform, 61162df5ad0Smrg src->filter, src->params, src->nparams); 61262df5ad0Smrg} 61362df5ad0Smrg 61462df5ad0Smrgstatic Bool 61562df5ad0Smrgequal_transform (transform_t *a, transform_t *b) 61662df5ad0Smrg{ 61762df5ad0Smrg if (memcmp (&a->transform, &b->transform, sizeof (XTransform)) != 0) 61862df5ad0Smrg return False; 61962df5ad0Smrg if (strcmp (a->filter, b->filter) != 0) 62062df5ad0Smrg return False; 62162df5ad0Smrg if (a->nparams != b->nparams) 62262df5ad0Smrg return False; 62362df5ad0Smrg if (memcmp (a->params, b->params, a->nparams * sizeof (XFixed)) != 0) 62462df5ad0Smrg return False; 62562df5ad0Smrg return True; 62662df5ad0Smrg} 62762df5ad0Smrg 628a0d3b6eaSmrgstatic output_t * 629a0d3b6eaSmrgadd_output (void) 630a0d3b6eaSmrg{ 631a0d3b6eaSmrg output_t *output = calloc (1, sizeof (output_t)); 632a0d3b6eaSmrg 633a0d3b6eaSmrg if (!output) 63462df5ad0Smrg fatal ("out of memory\n"); 635a0d3b6eaSmrg output->next = NULL; 636c52f0396Smrg output->found = False; 6378a16544fSmrg output->brightness = 1.0; 638a0d3b6eaSmrg *outputs_tail = output; 639a0d3b6eaSmrg outputs_tail = &output->next; 640a0d3b6eaSmrg return output; 641a0d3b6eaSmrg} 642a0d3b6eaSmrg 643a0d3b6eaSmrgstatic output_t * 644a0d3b6eaSmrgfind_output (name_t *name) 645a0d3b6eaSmrg{ 646a0d3b6eaSmrg output_t *output; 647a0d3b6eaSmrg 648a0d3b6eaSmrg for (output = outputs; output; output = output->next) 649a0d3b6eaSmrg { 650a0d3b6eaSmrg name_kind_t common = name->kind & output->output.kind; 651a0d3b6eaSmrg 652a0d3b6eaSmrg if ((common & name_xid) && name->xid == output->output.xid) 653a0d3b6eaSmrg break; 654a0d3b6eaSmrg if ((common & name_string) && !strcmp (name->string, output->output.string)) 655a0d3b6eaSmrg break; 656a0d3b6eaSmrg if ((common & name_index) && name->index == output->output.index) 657a0d3b6eaSmrg break; 658a0d3b6eaSmrg } 659a0d3b6eaSmrg return output; 660a0d3b6eaSmrg} 661a0d3b6eaSmrg 662a0d3b6eaSmrgstatic output_t * 663a0d3b6eaSmrgfind_output_by_xid (RROutput output) 664a0d3b6eaSmrg{ 665a0d3b6eaSmrg name_t output_name; 666a0d3b6eaSmrg 667a0d3b6eaSmrg init_name (&output_name); 668a0d3b6eaSmrg set_name_xid (&output_name, output); 669a0d3b6eaSmrg return find_output (&output_name); 670a0d3b6eaSmrg} 671a0d3b6eaSmrg 672a0d3b6eaSmrgstatic output_t * 673a0d3b6eaSmrgfind_output_by_name (char *name) 674a0d3b6eaSmrg{ 675a0d3b6eaSmrg name_t output_name; 676a0d3b6eaSmrg 677a0d3b6eaSmrg init_name (&output_name); 678a0d3b6eaSmrg set_name_string (&output_name, name); 679a0d3b6eaSmrg return find_output (&output_name); 680a0d3b6eaSmrg} 681a0d3b6eaSmrg 682a0d3b6eaSmrgstatic crtc_t * 683a0d3b6eaSmrgfind_crtc (name_t *name) 684a0d3b6eaSmrg{ 685a0d3b6eaSmrg int c; 686a0d3b6eaSmrg crtc_t *crtc = NULL; 687a0d3b6eaSmrg 688a0d3b6eaSmrg for (c = 0; c < num_crtcs; c++) 689a0d3b6eaSmrg { 690a0d3b6eaSmrg name_kind_t common; 691a0d3b6eaSmrg 692a0d3b6eaSmrg crtc = &crtcs[c]; 693a0d3b6eaSmrg common = name->kind & crtc->crtc.kind; 694a0d3b6eaSmrg 695a0d3b6eaSmrg if ((common & name_xid) && name->xid == crtc->crtc.xid) 696a0d3b6eaSmrg break; 697a0d3b6eaSmrg if ((common & name_string) && !strcmp (name->string, crtc->crtc.string)) 698a0d3b6eaSmrg break; 699a0d3b6eaSmrg if ((common & name_index) && name->index == crtc->crtc.index) 700a0d3b6eaSmrg break; 701a0d3b6eaSmrg crtc = NULL; 702a0d3b6eaSmrg } 703a0d3b6eaSmrg return crtc; 704a0d3b6eaSmrg} 705a0d3b6eaSmrg 706a0d3b6eaSmrgstatic crtc_t * 707a0d3b6eaSmrgfind_crtc_by_xid (RRCrtc crtc) 708a0d3b6eaSmrg{ 709a0d3b6eaSmrg name_t crtc_name; 710a0d3b6eaSmrg 711a0d3b6eaSmrg init_name (&crtc_name); 712a0d3b6eaSmrg set_name_xid (&crtc_name, crtc); 713a0d3b6eaSmrg return find_crtc (&crtc_name); 714a0d3b6eaSmrg} 715a0d3b6eaSmrg 716a0d3b6eaSmrgstatic XRRModeInfo * 717c52f0396Smrgfind_mode (name_t *name, double refresh) 718a0d3b6eaSmrg{ 719a0d3b6eaSmrg int m; 720a0d3b6eaSmrg XRRModeInfo *best = NULL; 721c52f0396Smrg double bestDist = 0; 722a0d3b6eaSmrg 723a0d3b6eaSmrg for (m = 0; m < res->nmode; m++) 724a0d3b6eaSmrg { 725a0d3b6eaSmrg XRRModeInfo *mode = &res->modes[m]; 726a0d3b6eaSmrg if ((name->kind & name_xid) && name->xid == mode->id) 727a0d3b6eaSmrg { 728a0d3b6eaSmrg best = mode; 729a0d3b6eaSmrg break; 730a0d3b6eaSmrg } 731a0d3b6eaSmrg if ((name->kind & name_string) && !strcmp (name->string, mode->name)) 732a0d3b6eaSmrg { 733c52f0396Smrg double dist; 734a0d3b6eaSmrg 735a0d3b6eaSmrg if (refresh) 736a0d3b6eaSmrg dist = fabs (mode_refresh (mode) - refresh); 737a0d3b6eaSmrg else 738a0d3b6eaSmrg dist = 0; 739a0d3b6eaSmrg if (!best || dist < bestDist) 740a0d3b6eaSmrg { 741a0d3b6eaSmrg bestDist = dist; 742a0d3b6eaSmrg best = mode; 743a0d3b6eaSmrg } 744a0d3b6eaSmrg break; 745a0d3b6eaSmrg } 746a0d3b6eaSmrg } 747a0d3b6eaSmrg return best; 748a0d3b6eaSmrg} 749a0d3b6eaSmrg 750a0d3b6eaSmrgstatic XRRModeInfo * 751a0d3b6eaSmrgfind_mode_by_xid (RRMode mode) 752a0d3b6eaSmrg{ 753a0d3b6eaSmrg name_t mode_name; 754a0d3b6eaSmrg 755a0d3b6eaSmrg init_name (&mode_name); 756a0d3b6eaSmrg set_name_xid (&mode_name, mode); 757a0d3b6eaSmrg return find_mode (&mode_name, 0); 758a0d3b6eaSmrg} 759a0d3b6eaSmrg 76062df5ad0Smrg#if 0 761a0d3b6eaSmrgstatic XRRModeInfo * 762a0d3b6eaSmrgfind_mode_by_name (char *name) 763a0d3b6eaSmrg{ 764a0d3b6eaSmrg name_t mode_name; 765a0d3b6eaSmrg init_name (&mode_name); 766a0d3b6eaSmrg set_name_string (&mode_name, name); 767a0d3b6eaSmrg return find_mode (&mode_name, 0); 768a0d3b6eaSmrg} 76962df5ad0Smrg#endif 770a0d3b6eaSmrg 771a0d3b6eaSmrgstatic 772a0d3b6eaSmrgXRRModeInfo * 773a0d3b6eaSmrgfind_mode_for_output (output_t *output, name_t *name) 774a0d3b6eaSmrg{ 775a0d3b6eaSmrg XRROutputInfo *output_info = output->output_info; 776a0d3b6eaSmrg int m; 777a0d3b6eaSmrg XRRModeInfo *best = NULL; 778c52f0396Smrg double bestDist = 0; 779a0d3b6eaSmrg 780a0d3b6eaSmrg for (m = 0; m < output_info->nmode; m++) 781a0d3b6eaSmrg { 782a0d3b6eaSmrg XRRModeInfo *mode; 78362df5ad0Smrg 784a0d3b6eaSmrg mode = find_mode_by_xid (output_info->modes[m]); 785a0d3b6eaSmrg if (!mode) continue; 786a0d3b6eaSmrg if ((name->kind & name_xid) && name->xid == mode->id) 787a0d3b6eaSmrg { 788a0d3b6eaSmrg best = mode; 789a0d3b6eaSmrg break; 790a0d3b6eaSmrg } 791a0d3b6eaSmrg if ((name->kind & name_string) && !strcmp (name->string, mode->name)) 792a0d3b6eaSmrg { 793c52f0396Smrg double dist; 79462df5ad0Smrg 79562df5ad0Smrg /* Stay away from doublescan modes unless refresh rate is specified. */ 79662df5ad0Smrg if (!output->refresh && (mode->modeFlags & RR_DoubleScan)) 79762df5ad0Smrg continue; 79862df5ad0Smrg 799a0d3b6eaSmrg if (output->refresh) 800a0d3b6eaSmrg dist = fabs (mode_refresh (mode) - output->refresh); 801a0d3b6eaSmrg else 802a0d3b6eaSmrg dist = 0; 803a0d3b6eaSmrg if (!best || dist < bestDist) 804a0d3b6eaSmrg { 805a0d3b6eaSmrg bestDist = dist; 806a0d3b6eaSmrg best = mode; 807a0d3b6eaSmrg } 808a0d3b6eaSmrg } 809a0d3b6eaSmrg } 810a0d3b6eaSmrg return best; 811a0d3b6eaSmrg} 812a0d3b6eaSmrg 81362df5ad0Smrgstatic XRRModeInfo * 814a0d3b6eaSmrgpreferred_mode (output_t *output) 815a0d3b6eaSmrg{ 816a0d3b6eaSmrg XRROutputInfo *output_info = output->output_info; 817a0d3b6eaSmrg int m; 818a0d3b6eaSmrg XRRModeInfo *best; 819a0d3b6eaSmrg int bestDist; 820a0d3b6eaSmrg 821a0d3b6eaSmrg best = NULL; 822a0d3b6eaSmrg bestDist = 0; 823a0d3b6eaSmrg for (m = 0; m < output_info->nmode; m++) 824a0d3b6eaSmrg { 825a0d3b6eaSmrg XRRModeInfo *mode_info = find_mode_by_xid (output_info->modes[m]); 826a0d3b6eaSmrg int dist; 827a0d3b6eaSmrg 828a0d3b6eaSmrg if (m < output_info->npreferred) 829a0d3b6eaSmrg dist = 0; 830a0d3b6eaSmrg else if (output_info->mm_height) 831a0d3b6eaSmrg dist = (1000 * DisplayHeight(dpy, screen) / DisplayHeightMM(dpy, screen) - 832a0d3b6eaSmrg 1000 * mode_info->height / output_info->mm_height); 833a0d3b6eaSmrg else 834a0d3b6eaSmrg dist = DisplayHeight(dpy, screen) - mode_info->height; 835a0d3b6eaSmrg 836a0d3b6eaSmrg if (dist < 0) dist = -dist; 837a0d3b6eaSmrg if (!best || dist < bestDist) 838a0d3b6eaSmrg { 839a0d3b6eaSmrg best = mode_info; 840a0d3b6eaSmrg bestDist = dist; 841a0d3b6eaSmrg } 842a0d3b6eaSmrg } 843a0d3b6eaSmrg return best; 844a0d3b6eaSmrg} 845a0d3b6eaSmrg 846a0d3b6eaSmrgstatic Bool 847a0d3b6eaSmrgoutput_can_use_crtc (output_t *output, crtc_t *crtc) 848a0d3b6eaSmrg{ 849a0d3b6eaSmrg XRROutputInfo *output_info = output->output_info; 850a0d3b6eaSmrg int c; 851a0d3b6eaSmrg 852a0d3b6eaSmrg for (c = 0; c < output_info->ncrtc; c++) 853a0d3b6eaSmrg if (output_info->crtcs[c] == crtc->crtc.xid) 854a0d3b6eaSmrg return True; 855a0d3b6eaSmrg return False; 856a0d3b6eaSmrg} 857a0d3b6eaSmrg 858a0d3b6eaSmrgstatic Bool 859a0d3b6eaSmrgoutput_can_use_mode (output_t *output, XRRModeInfo *mode) 860a0d3b6eaSmrg{ 861a0d3b6eaSmrg XRROutputInfo *output_info = output->output_info; 862a0d3b6eaSmrg int m; 863a0d3b6eaSmrg 864a0d3b6eaSmrg for (m = 0; m < output_info->nmode; m++) 865a0d3b6eaSmrg if (output_info->modes[m] == mode->id) 866a0d3b6eaSmrg return True; 867a0d3b6eaSmrg return False; 868a0d3b6eaSmrg} 869a0d3b6eaSmrg 870a0d3b6eaSmrgstatic Bool 871a0d3b6eaSmrgcrtc_can_use_rotation (crtc_t *crtc, Rotation rotation) 872a0d3b6eaSmrg{ 873a0d3b6eaSmrg Rotation rotations = crtc->crtc_info->rotations; 874a0d3b6eaSmrg Rotation dir = rotation & (RR_Rotate_0|RR_Rotate_90|RR_Rotate_180|RR_Rotate_270); 875a0d3b6eaSmrg Rotation reflect = rotation & (RR_Reflect_X|RR_Reflect_Y); 876a0d3b6eaSmrg if (((rotations & dir) != 0) && ((rotations & reflect) == reflect)) 877a0d3b6eaSmrg return True; 878a0d3b6eaSmrg return False; 879a0d3b6eaSmrg} 880a0d3b6eaSmrg 88162df5ad0Smrg#if 0 88262df5ad0Smrgstatic Bool 88362df5ad0Smrgcrtc_can_use_transform (crtc_t *crtc, XTransform *transform) 88462df5ad0Smrg{ 88562df5ad0Smrg int major, minor; 88662df5ad0Smrg 88762df5ad0Smrg XRRQueryVersion (dpy, &major, &minor); 88862df5ad0Smrg if (major > 1 || (major == 1 && minor >= 3)) 88962df5ad0Smrg return True; 89062df5ad0Smrg return False; 89162df5ad0Smrg} 89262df5ad0Smrg#endif 89362df5ad0Smrg 894a0d3b6eaSmrg/* 895a0d3b6eaSmrg * Report only rotations that are supported by all crtcs 896a0d3b6eaSmrg */ 897a0d3b6eaSmrgstatic Rotation 898a0d3b6eaSmrgoutput_rotations (output_t *output) 899a0d3b6eaSmrg{ 900a0d3b6eaSmrg Bool found = False; 901a0d3b6eaSmrg Rotation rotation = RR_Rotate_0; 902a0d3b6eaSmrg XRROutputInfo *output_info = output->output_info; 903a0d3b6eaSmrg int c; 904a0d3b6eaSmrg 905a0d3b6eaSmrg for (c = 0; c < output_info->ncrtc; c++) 906a0d3b6eaSmrg { 907a0d3b6eaSmrg crtc_t *crtc = find_crtc_by_xid (output_info->crtcs[c]); 908a0d3b6eaSmrg if (crtc) 909a0d3b6eaSmrg { 910a0d3b6eaSmrg if (!found) { 911a0d3b6eaSmrg rotation = crtc->crtc_info->rotations; 912a0d3b6eaSmrg found = True; 913a0d3b6eaSmrg } else 914a0d3b6eaSmrg rotation &= crtc->crtc_info->rotations; 915a0d3b6eaSmrg } 916a0d3b6eaSmrg } 917a0d3b6eaSmrg return rotation; 918a0d3b6eaSmrg} 919a0d3b6eaSmrg 920a0d3b6eaSmrgstatic Bool 921a0d3b6eaSmrgoutput_can_use_rotation (output_t *output, Rotation rotation) 922a0d3b6eaSmrg{ 923a0d3b6eaSmrg XRROutputInfo *output_info = output->output_info; 924a0d3b6eaSmrg int c; 925a0d3b6eaSmrg 926a0d3b6eaSmrg /* make sure all of the crtcs can use this rotation. 927a0d3b6eaSmrg * yes, this is not strictly necessary, but it is 928a0d3b6eaSmrg * simpler,and we expect most drivers to either 929a0d3b6eaSmrg * support rotation everywhere or nowhere 930a0d3b6eaSmrg */ 931a0d3b6eaSmrg for (c = 0; c < output_info->ncrtc; c++) 932a0d3b6eaSmrg { 933a0d3b6eaSmrg crtc_t *crtc = find_crtc_by_xid (output_info->crtcs[c]); 934a0d3b6eaSmrg if (crtc && !crtc_can_use_rotation (crtc, rotation)) 935a0d3b6eaSmrg return False; 936a0d3b6eaSmrg } 937a0d3b6eaSmrg return True; 938a0d3b6eaSmrg} 939a0d3b6eaSmrg 94062df5ad0Smrgstatic Bool 94162df5ad0Smrgoutput_is_primary(output_t *output) 94262df5ad0Smrg{ 94362df5ad0Smrg if (has_1_3) 94462df5ad0Smrg return XRRGetOutputPrimary(dpy, root) == output->output.xid; 94562df5ad0Smrg return False; 94662df5ad0Smrg} 94762df5ad0Smrg 9488a16544fSmrg/* Returns the index of the last value in an array < 0xffff */ 9498a16544fSmrgstatic int 9508a16544fSmrgfind_last_non_clamped(CARD16 array[], int size) { 9518a16544fSmrg int i; 9528a16544fSmrg for (i = size - 1; i > 0; i--) { 9538a16544fSmrg if (array[i] < 0xffff) 9548a16544fSmrg return i; 9558a16544fSmrg } 9568a16544fSmrg return 0; 9578a16544fSmrg} 9588a16544fSmrg 9598a16544fSmrgstatic void 9608a16544fSmrgset_gamma_info(output_t *output) 9618a16544fSmrg{ 9628a16544fSmrg XRRCrtcGamma *gamma; 9638a16544fSmrg double i1, v1, i2, v2; 9648a16544fSmrg int size, middle, last_best, last_red, last_green, last_blue; 9658a16544fSmrg CARD16 *best_array; 9668a16544fSmrg 9678a16544fSmrg if (!output->crtc_info) 9688a16544fSmrg return; 9698a16544fSmrg 9708a16544fSmrg size = XRRGetCrtcGammaSize(dpy, output->crtc_info->crtc.xid); 9718a16544fSmrg if (!size) { 9728a16544fSmrg warning("Failed to get size of gamma for output %s\n", output->output.string); 9738a16544fSmrg return; 9748a16544fSmrg } 9758a16544fSmrg 9768a16544fSmrg gamma = XRRGetCrtcGamma(dpy, output->crtc_info->crtc.xid); 9778a16544fSmrg if (!gamma) { 9788a16544fSmrg warning("Failed to get gamma for output %s\n", output->output.string); 9798a16544fSmrg return; 9808a16544fSmrg } 9818a16544fSmrg 9828a16544fSmrg /* 9838a16544fSmrg * Here is a bit tricky because gamma is a whole curve for each 9848a16544fSmrg * color. So, typically, we need to represent 3 * 256 values as 3 + 1 9858a16544fSmrg * values. Therefore, we approximate the gamma curve (v) by supposing 9868a16544fSmrg * it always follows the way we set it: a power function (i^g) 9878a16544fSmrg * multiplied by a brightness (b). 9888a16544fSmrg * v = i^g * b 9898a16544fSmrg * so g = (ln(v) - ln(b))/ln(i) 9908a16544fSmrg * and b can be found using two points (v1,i1) and (v2, i2): 9918a16544fSmrg * b = e^((ln(v2)*ln(i1) - ln(v1)*ln(i2))/ln(i1/i2)) 9928a16544fSmrg * For the best resolution, we select i2 at the highest place not 9938a16544fSmrg * clamped and i1 at i2/2. Note that if i2 = 1 (as in most normal 9948a16544fSmrg * cases), then b = v2. 9958a16544fSmrg */ 9968a16544fSmrg last_red = find_last_non_clamped(gamma->red, size); 9978a16544fSmrg last_green = find_last_non_clamped(gamma->green, size); 9988a16544fSmrg last_blue = find_last_non_clamped(gamma->blue, size); 9998a16544fSmrg best_array = gamma->red; 10008a16544fSmrg last_best = last_red; 10018a16544fSmrg if (last_green > last_best) { 10028a16544fSmrg last_best = last_green; 10038a16544fSmrg best_array = gamma->green; 10048a16544fSmrg } 10058a16544fSmrg if (last_blue > last_best) { 10068a16544fSmrg last_best = last_blue; 10078a16544fSmrg best_array = gamma->blue; 10088a16544fSmrg } 10098a16544fSmrg if (last_best == 0) 10108a16544fSmrg last_best = 1; 10118a16544fSmrg 10128a16544fSmrg middle = last_best / 2; 10138a16544fSmrg i1 = (double)(middle + 1) / size; 10148a16544fSmrg v1 = (double)(best_array[middle]) / 65535; 10158a16544fSmrg i2 = (double)(last_best + 1) / size; 10168a16544fSmrg v2 = (double)(best_array[last_best]) / 65535; 10178a16544fSmrg if (v2 < 0.0001) { /* The screen is black */ 10188a16544fSmrg output->brightness = 0; 10198a16544fSmrg output->gamma.red = 1; 10208a16544fSmrg output->gamma.green = 1; 10218a16544fSmrg output->gamma.blue = 1; 10228a16544fSmrg } else { 10238a16544fSmrg if ((last_best + 1) == size) 10248a16544fSmrg output->brightness = v2; 10258a16544fSmrg else 10268a16544fSmrg output->brightness = exp((log(v2)*log(i1) - log(v1)*log(i2))/log(i1/i2)); 10278a16544fSmrg output->gamma.red = log((double)(gamma->red[last_red / 2]) / output->brightness 10288a16544fSmrg / 65535) / log((double)((last_red / 2) + 1) / size); 10298a16544fSmrg output->gamma.green = log((double)(gamma->green[last_green / 2]) / output->brightness 10308a16544fSmrg / 65535) / log((double)((last_green / 2) + 1) / size); 10318a16544fSmrg output->gamma.blue = log((double)(gamma->blue[last_blue / 2]) / output->brightness 10328a16544fSmrg / 65535) / log((double)((last_blue / 2) + 1) / size); 10338a16544fSmrg } 10348a16544fSmrg 10358a16544fSmrg XRRFreeGamma(gamma); 10368a16544fSmrg} 10378a16544fSmrg 1038a0d3b6eaSmrgstatic void 1039a0d3b6eaSmrgset_output_info (output_t *output, RROutput xid, XRROutputInfo *output_info) 1040a0d3b6eaSmrg{ 1041a0d3b6eaSmrg /* sanity check output info */ 1042a0d3b6eaSmrg if (output_info->connection != RR_Disconnected && !output_info->nmode) 104362df5ad0Smrg warning ("Output %s is not disconnected but has no modes\n", 104462df5ad0Smrg output_info->name); 1045a0d3b6eaSmrg 1046a0d3b6eaSmrg /* set output name and info */ 1047a0d3b6eaSmrg if (!(output->output.kind & name_xid)) 1048a0d3b6eaSmrg set_name_xid (&output->output, xid); 1049a0d3b6eaSmrg if (!(output->output.kind & name_string)) 1050a0d3b6eaSmrg set_name_string (&output->output, output_info->name); 1051a0d3b6eaSmrg output->output_info = output_info; 1052a0d3b6eaSmrg 1053a0d3b6eaSmrg /* set crtc name and info */ 1054a0d3b6eaSmrg if (!(output->changes & changes_crtc)) 1055a0d3b6eaSmrg set_name_xid (&output->crtc, output_info->crtc); 1056a0d3b6eaSmrg 1057a0d3b6eaSmrg if (output->crtc.kind == name_xid && output->crtc.xid == None) 1058a0d3b6eaSmrg output->crtc_info = NULL; 1059a0d3b6eaSmrg else 1060a0d3b6eaSmrg { 1061a0d3b6eaSmrg output->crtc_info = find_crtc (&output->crtc); 1062a0d3b6eaSmrg if (!output->crtc_info) 1063a0d3b6eaSmrg { 1064a0d3b6eaSmrg if (output->crtc.kind & name_xid) 1065a0d3b6eaSmrg fatal ("cannot find crtc 0x%x\n", output->crtc.xid); 1066a0d3b6eaSmrg if (output->crtc.kind & name_index) 1067a0d3b6eaSmrg fatal ("cannot find crtc %d\n", output->crtc.index); 1068a0d3b6eaSmrg } 1069a0d3b6eaSmrg if (!output_can_use_crtc (output, output->crtc_info)) 1070a0d3b6eaSmrg fatal ("output %s cannot use crtc 0x%x\n", output->output.string, 1071a0d3b6eaSmrg output->crtc_info->crtc.xid); 1072a0d3b6eaSmrg } 1073a0d3b6eaSmrg 1074a0d3b6eaSmrg /* set mode name and info */ 1075a0d3b6eaSmrg if (!(output->changes & changes_mode)) 1076a0d3b6eaSmrg { 1077a0d3b6eaSmrg if (output->crtc_info) 1078a0d3b6eaSmrg set_name_xid (&output->mode, output->crtc_info->crtc_info->mode); 1079a0d3b6eaSmrg else 1080a0d3b6eaSmrg set_name_xid (&output->mode, None); 1081a0d3b6eaSmrg if (output->mode.xid) 1082a0d3b6eaSmrg { 1083a0d3b6eaSmrg output->mode_info = find_mode_by_xid (output->mode.xid); 1084a0d3b6eaSmrg if (!output->mode_info) 1085a0d3b6eaSmrg fatal ("server did not report mode 0x%x for output %s\n", 1086a0d3b6eaSmrg output->mode.xid, output->output.string); 1087a0d3b6eaSmrg } 1088a0d3b6eaSmrg else 1089a0d3b6eaSmrg output->mode_info = NULL; 1090a0d3b6eaSmrg } 1091a0d3b6eaSmrg else if (output->mode.kind == name_xid && output->mode.xid == None) 1092a0d3b6eaSmrg output->mode_info = NULL; 1093a0d3b6eaSmrg else 1094a0d3b6eaSmrg { 1095a0d3b6eaSmrg if (output->mode.kind == name_preferred) 1096a0d3b6eaSmrg output->mode_info = preferred_mode (output); 1097a0d3b6eaSmrg else 1098a0d3b6eaSmrg output->mode_info = find_mode_for_output (output, &output->mode); 1099a0d3b6eaSmrg if (!output->mode_info) 1100a0d3b6eaSmrg { 1101a0d3b6eaSmrg if (output->mode.kind & name_preferred) 1102a0d3b6eaSmrg fatal ("cannot find preferred mode\n"); 1103a0d3b6eaSmrg if (output->mode.kind & name_string) 1104a0d3b6eaSmrg fatal ("cannot find mode %s\n", output->mode.string); 1105a0d3b6eaSmrg if (output->mode.kind & name_xid) 1106a0d3b6eaSmrg fatal ("cannot find mode 0x%x\n", output->mode.xid); 1107a0d3b6eaSmrg } 1108a0d3b6eaSmrg if (!output_can_use_mode (output, output->mode_info)) 1109a0d3b6eaSmrg fatal ("output %s cannot use mode %s\n", output->output.string, 1110a0d3b6eaSmrg output->mode_info->name); 1111a0d3b6eaSmrg } 1112a0d3b6eaSmrg 1113a0d3b6eaSmrg /* set position */ 1114a0d3b6eaSmrg if (!(output->changes & changes_position)) 1115a0d3b6eaSmrg { 1116a0d3b6eaSmrg if (output->crtc_info) 1117a0d3b6eaSmrg { 1118a0d3b6eaSmrg output->x = output->crtc_info->crtc_info->x; 1119a0d3b6eaSmrg output->y = output->crtc_info->crtc_info->y; 1120a0d3b6eaSmrg } 1121a0d3b6eaSmrg else 1122a0d3b6eaSmrg { 1123a0d3b6eaSmrg output->x = 0; 1124a0d3b6eaSmrg output->y = 0; 1125a0d3b6eaSmrg } 1126a0d3b6eaSmrg } 1127a0d3b6eaSmrg 1128a0d3b6eaSmrg /* set rotation */ 1129a0d3b6eaSmrg if (!(output->changes & changes_rotation)) 1130a0d3b6eaSmrg { 1131a0d3b6eaSmrg output->rotation &= ~0xf; 1132a0d3b6eaSmrg if (output->crtc_info) 1133a0d3b6eaSmrg output->rotation |= (output->crtc_info->crtc_info->rotation & 0xf); 1134a0d3b6eaSmrg else 1135a0d3b6eaSmrg output->rotation = RR_Rotate_0; 1136a0d3b6eaSmrg } 1137a0d3b6eaSmrg if (!(output->changes & changes_reflection)) 1138a0d3b6eaSmrg { 1139a0d3b6eaSmrg output->rotation &= ~(RR_Reflect_X|RR_Reflect_Y); 1140a0d3b6eaSmrg if (output->crtc_info) 1141a0d3b6eaSmrg output->rotation |= (output->crtc_info->crtc_info->rotation & 1142a0d3b6eaSmrg (RR_Reflect_X|RR_Reflect_Y)); 1143a0d3b6eaSmrg } 1144a0d3b6eaSmrg if (!output_can_use_rotation (output, output->rotation)) 1145a0d3b6eaSmrg fatal ("output %s cannot use rotation \"%s\" reflection \"%s\"\n", 1146a0d3b6eaSmrg output->output.string, 1147a0d3b6eaSmrg rotation_name (output->rotation), 1148a0d3b6eaSmrg reflection_name (output->rotation)); 114962df5ad0Smrg 11508a16544fSmrg /* set gamma */ 11518a16544fSmrg if (!(output->changes & changes_gamma)) 11528a16544fSmrg set_gamma_info(output); 11538a16544fSmrg 115462df5ad0Smrg /* set transformation */ 115562df5ad0Smrg if (!(output->changes & changes_transform)) 115662df5ad0Smrg { 115762df5ad0Smrg if (output->crtc_info) 115862df5ad0Smrg copy_transform (&output->transform, &output->crtc_info->current_transform); 115962df5ad0Smrg else 116062df5ad0Smrg init_transform (&output->transform); 116162df5ad0Smrg } 116262df5ad0Smrg 116362df5ad0Smrg /* set primary */ 116462df5ad0Smrg if (!(output->changes & changes_primary)) 116562df5ad0Smrg output->primary = output_is_primary(output); 1166a0d3b6eaSmrg} 1167a0d3b6eaSmrg 1168a0d3b6eaSmrgstatic void 116962df5ad0Smrgget_screen (Bool current) 1170a0d3b6eaSmrg{ 1171a0d3b6eaSmrg if (!has_1_2) 1172a0d3b6eaSmrg fatal ("Server RandR version before 1.2\n"); 1173a0d3b6eaSmrg 1174a0d3b6eaSmrg XRRGetScreenSizeRange (dpy, root, &minWidth, &minHeight, 1175a0d3b6eaSmrg &maxWidth, &maxHeight); 1176a0d3b6eaSmrg 117762df5ad0Smrg if (current) 117862df5ad0Smrg res = XRRGetScreenResourcesCurrent (dpy, root); 117962df5ad0Smrg else 118062df5ad0Smrg res = XRRGetScreenResources (dpy, root); 1181a0d3b6eaSmrg if (!res) fatal ("could not get screen resources"); 1182a0d3b6eaSmrg} 1183a0d3b6eaSmrg 1184a0d3b6eaSmrgstatic void 1185a0d3b6eaSmrgget_crtcs (void) 1186a0d3b6eaSmrg{ 1187a0d3b6eaSmrg int c; 1188a0d3b6eaSmrg 1189a0d3b6eaSmrg num_crtcs = res->ncrtc; 1190a0d3b6eaSmrg crtcs = calloc (num_crtcs, sizeof (crtc_t)); 119162df5ad0Smrg if (!crtcs) fatal ("out of memory\n"); 1192a0d3b6eaSmrg 1193a0d3b6eaSmrg for (c = 0; c < res->ncrtc; c++) 1194a0d3b6eaSmrg { 1195a0d3b6eaSmrg XRRCrtcInfo *crtc_info = XRRGetCrtcInfo (dpy, res, res->crtcs[c]); 119662df5ad0Smrg XRRCrtcTransformAttributes *attr; 119762df5ad0Smrg XRRPanning *panning_info = NULL; 119862df5ad0Smrg 119962df5ad0Smrg if (has_1_3) { 120062df5ad0Smrg XRRPanning zero; 120162df5ad0Smrg memset(&zero, 0, sizeof(zero)); 120262df5ad0Smrg panning_info = XRRGetPanning (dpy, res, res->crtcs[c]); 120362df5ad0Smrg zero.timestamp = panning_info->timestamp; 120462df5ad0Smrg if (!memcmp(panning_info, &zero, sizeof(zero))) { 120562df5ad0Smrg Xfree(panning_info); 120662df5ad0Smrg panning_info = NULL; 120762df5ad0Smrg } 120862df5ad0Smrg } 120962df5ad0Smrg 1210a0d3b6eaSmrg set_name_xid (&crtcs[c].crtc, res->crtcs[c]); 1211a0d3b6eaSmrg set_name_index (&crtcs[c].crtc, c); 121262df5ad0Smrg if (!crtc_info) fatal ("could not get crtc 0x%x information\n", res->crtcs[c]); 1213a0d3b6eaSmrg crtcs[c].crtc_info = crtc_info; 121462df5ad0Smrg crtcs[c].panning_info = panning_info; 1215a0d3b6eaSmrg if (crtc_info->mode == None) 1216a0d3b6eaSmrg { 1217a0d3b6eaSmrg crtcs[c].mode_info = NULL; 1218a0d3b6eaSmrg crtcs[c].x = 0; 1219a0d3b6eaSmrg crtcs[c].y = 0; 1220a0d3b6eaSmrg crtcs[c].rotation = RR_Rotate_0; 1221a0d3b6eaSmrg } 122262df5ad0Smrg if (XRRGetCrtcTransform (dpy, res->crtcs[c], &attr) && attr) { 122362df5ad0Smrg set_transform (&crtcs[c].current_transform, 122462df5ad0Smrg &attr->currentTransform, 122562df5ad0Smrg attr->currentFilter, 122662df5ad0Smrg attr->currentParams, 122762df5ad0Smrg attr->currentNparams); 122862df5ad0Smrg XFree (attr); 122962df5ad0Smrg } 123062df5ad0Smrg else 123162df5ad0Smrg { 123262df5ad0Smrg init_transform (&crtcs[c].current_transform); 123362df5ad0Smrg } 123462df5ad0Smrg copy_transform (&crtcs[c].pending_transform, &crtcs[c].current_transform); 123562df5ad0Smrg } 1236a0d3b6eaSmrg} 1237a0d3b6eaSmrg 1238a0d3b6eaSmrgstatic void 1239a0d3b6eaSmrgcrtc_add_output (crtc_t *crtc, output_t *output) 1240a0d3b6eaSmrg{ 1241a0d3b6eaSmrg if (crtc->outputs) 1242a0d3b6eaSmrg crtc->outputs = realloc (crtc->outputs, (crtc->noutput + 1) * sizeof (output_t *)); 1243a0d3b6eaSmrg else 1244a0d3b6eaSmrg { 1245a0d3b6eaSmrg crtc->outputs = malloc (sizeof (output_t *)); 1246a0d3b6eaSmrg crtc->x = output->x; 1247a0d3b6eaSmrg crtc->y = output->y; 1248a0d3b6eaSmrg crtc->rotation = output->rotation; 1249a0d3b6eaSmrg crtc->mode_info = output->mode_info; 125062df5ad0Smrg copy_transform (&crtc->pending_transform, &output->transform); 125162df5ad0Smrg } 125262df5ad0Smrg if (!crtc->outputs) fatal ("out of memory\n"); 1253a0d3b6eaSmrg crtc->outputs[crtc->noutput++] = output; 1254a0d3b6eaSmrg} 1255a0d3b6eaSmrg 1256a0d3b6eaSmrgstatic void 1257a0d3b6eaSmrgset_crtcs (void) 1258a0d3b6eaSmrg{ 1259a0d3b6eaSmrg output_t *output; 1260a0d3b6eaSmrg 1261a0d3b6eaSmrg for (output = outputs; output; output = output->next) 1262a0d3b6eaSmrg { 1263a0d3b6eaSmrg if (!output->mode_info) continue; 1264a0d3b6eaSmrg crtc_add_output (output->crtc_info, output); 1265a0d3b6eaSmrg } 1266a0d3b6eaSmrg} 1267a0d3b6eaSmrg 126862df5ad0Smrgstatic void 126962df5ad0Smrgset_panning (void) 127062df5ad0Smrg{ 127162df5ad0Smrg output_t *output; 127262df5ad0Smrg 127362df5ad0Smrg for (output = outputs; output; output = output->next) 127462df5ad0Smrg { 127562df5ad0Smrg if (! output->crtc_info) 127662df5ad0Smrg continue; 127762df5ad0Smrg if (! (output->changes & changes_panning)) 127862df5ad0Smrg continue; 127962df5ad0Smrg if (! output->crtc_info->panning_info) 128062df5ad0Smrg output->crtc_info->panning_info = malloc (sizeof(XRRPanning)); 128162df5ad0Smrg memcpy (output->crtc_info->panning_info, &output->panning, sizeof(XRRPanning)); 128262df5ad0Smrg output->crtc_info->changing = 1; 128362df5ad0Smrg } 128462df5ad0Smrg} 128562df5ad0Smrg 128662df5ad0Smrgstatic void 128762df5ad0Smrgset_gamma(void) 128862df5ad0Smrg{ 128962df5ad0Smrg output_t *output; 129062df5ad0Smrg 129162df5ad0Smrg for (output = outputs; output; output = output->next) { 129262df5ad0Smrg int i, size; 129362df5ad0Smrg crtc_t *crtc; 129462df5ad0Smrg XRRCrtcGamma *gamma; 129562df5ad0Smrg 129662df5ad0Smrg if (!(output->changes & changes_gamma)) 129762df5ad0Smrg continue; 129862df5ad0Smrg 129962df5ad0Smrg if (!output->crtc_info) { 130062df5ad0Smrg fatal("Need crtc to set gamma on.\n"); 130162df5ad0Smrg continue; 130262df5ad0Smrg } 130362df5ad0Smrg 130462df5ad0Smrg crtc = output->crtc_info; 130562df5ad0Smrg 130662df5ad0Smrg size = XRRGetCrtcGammaSize(dpy, crtc->crtc.xid); 130762df5ad0Smrg 130862df5ad0Smrg if (!size) { 130962df5ad0Smrg fatal("Gamma size is 0.\n"); 131062df5ad0Smrg continue; 131162df5ad0Smrg } 131262df5ad0Smrg 131362df5ad0Smrg gamma = XRRAllocGamma(size); 131462df5ad0Smrg if (!gamma) { 131562df5ad0Smrg fatal("Gamma allocation failed.\n"); 131662df5ad0Smrg continue; 131762df5ad0Smrg } 131862df5ad0Smrg 13198a16544fSmrg if(output->gamma.red == 0.0 && output->gamma.green == 0.0 && output->gamma.blue == 0.0) 13208a16544fSmrg output->gamma.red = output->gamma.green = output->gamma.blue = 1.0; 13218a16544fSmrg 132262df5ad0Smrg for (i = 0; i < size; i++) { 13238a16544fSmrg if (output->gamma.red == 1.0 && output->brightness == 1.0) 13248a16544fSmrg gamma->red[i] = (i << 8) + i; 132562df5ad0Smrg else 13268a16544fSmrg gamma->red[i] = dmin(pow((double)i/(double)(size - 1), 13278a16544fSmrg output->gamma.red) * output->brightness, 13288a16544fSmrg 1.0) * 65535.0; 132962df5ad0Smrg 13308a16544fSmrg if (output->gamma.green == 1.0 && output->brightness == 1.0) 13318a16544fSmrg gamma->green[i] = (i << 8) + i; 133262df5ad0Smrg else 13338a16544fSmrg gamma->green[i] = dmin(pow((double)i/(double)(size - 1), 13348a16544fSmrg output->gamma.green) * output->brightness, 13358a16544fSmrg 1.0) * 65535.0; 133662df5ad0Smrg 13378a16544fSmrg if (output->gamma.blue == 1.0 && output->brightness == 1.0) 13388a16544fSmrg gamma->blue[i] = (i << 8) + i; 133962df5ad0Smrg else 13408a16544fSmrg gamma->blue[i] = dmin(pow((double)i/(double)(size - 1), 13418a16544fSmrg output->gamma.blue) * output->brightness, 13428a16544fSmrg 1.0) * 65535.0; 134362df5ad0Smrg } 134462df5ad0Smrg 134562df5ad0Smrg XRRSetCrtcGamma(dpy, crtc->crtc.xid, gamma); 134662df5ad0Smrg 134762df5ad0Smrg free(gamma); 134862df5ad0Smrg } 134962df5ad0Smrg} 135062df5ad0Smrg 135162df5ad0Smrgstatic void 135262df5ad0Smrgset_primary(void) 135362df5ad0Smrg{ 135462df5ad0Smrg output_t *output; 135562df5ad0Smrg 135662df5ad0Smrg if (no_primary) { 135762df5ad0Smrg XRRSetOutputPrimary(dpy, root, None); 135862df5ad0Smrg } else { 135962df5ad0Smrg for (output = outputs; output; output = output->next) { 136062df5ad0Smrg if (!(output->changes & changes_primary)) 136162df5ad0Smrg continue; 136262df5ad0Smrg if (output->primary) 136362df5ad0Smrg XRRSetOutputPrimary(dpy, root, output->output.xid); 136462df5ad0Smrg } 136562df5ad0Smrg } 136662df5ad0Smrg} 136762df5ad0Smrg 1368a0d3b6eaSmrgstatic Status 1369a0d3b6eaSmrgcrtc_disable (crtc_t *crtc) 1370a0d3b6eaSmrg{ 1371a0d3b6eaSmrg if (verbose) 1372a0d3b6eaSmrg printf ("crtc %d: disable\n", crtc->crtc.index); 1373a0d3b6eaSmrg 1374a0d3b6eaSmrg if (dryrun) 1375a0d3b6eaSmrg return RRSetConfigSuccess; 1376a0d3b6eaSmrg return XRRSetCrtcConfig (dpy, res, crtc->crtc.xid, CurrentTime, 1377a0d3b6eaSmrg 0, 0, None, RR_Rotate_0, NULL, 0); 1378a0d3b6eaSmrg} 1379a0d3b6eaSmrg 138062df5ad0Smrgstatic void 138162df5ad0Smrgcrtc_set_transform (crtc_t *crtc, transform_t *transform) 138262df5ad0Smrg{ 138362df5ad0Smrg int major, minor; 138462df5ad0Smrg 138562df5ad0Smrg XRRQueryVersion (dpy, &major, &minor); 138662df5ad0Smrg if (major > 1 || (major == 1 && minor >= 3)) 138762df5ad0Smrg XRRSetCrtcTransform (dpy, crtc->crtc.xid, 138862df5ad0Smrg &transform->transform, 138962df5ad0Smrg transform->filter, 139062df5ad0Smrg transform->params, 139162df5ad0Smrg transform->nparams); 139262df5ad0Smrg} 139362df5ad0Smrg 1394a0d3b6eaSmrgstatic Status 1395a0d3b6eaSmrgcrtc_revert (crtc_t *crtc) 1396a0d3b6eaSmrg{ 1397a0d3b6eaSmrg XRRCrtcInfo *crtc_info = crtc->crtc_info; 1398a0d3b6eaSmrg 1399a0d3b6eaSmrg if (verbose) 1400a0d3b6eaSmrg printf ("crtc %d: revert\n", crtc->crtc.index); 1401a0d3b6eaSmrg 1402a0d3b6eaSmrg if (dryrun) 1403a0d3b6eaSmrg return RRSetConfigSuccess; 140462df5ad0Smrg 140562df5ad0Smrg if (!equal_transform (&crtc->current_transform, &crtc->pending_transform)) 140662df5ad0Smrg crtc_set_transform (crtc, &crtc->current_transform); 1407a0d3b6eaSmrg return XRRSetCrtcConfig (dpy, res, crtc->crtc.xid, CurrentTime, 1408a0d3b6eaSmrg crtc_info->x, crtc_info->y, 1409a0d3b6eaSmrg crtc_info->mode, crtc_info->rotation, 1410a0d3b6eaSmrg crtc_info->outputs, crtc_info->noutput); 1411a0d3b6eaSmrg} 1412a0d3b6eaSmrg 1413a0d3b6eaSmrgstatic Status 1414a0d3b6eaSmrgcrtc_apply (crtc_t *crtc) 1415a0d3b6eaSmrg{ 1416a0d3b6eaSmrg RROutput *rr_outputs; 1417a0d3b6eaSmrg int o; 1418a0d3b6eaSmrg Status s; 1419a0d3b6eaSmrg RRMode mode = None; 1420a0d3b6eaSmrg 1421a0d3b6eaSmrg if (!crtc->changing || !crtc->mode_info) 1422a0d3b6eaSmrg return RRSetConfigSuccess; 1423a0d3b6eaSmrg 1424a0d3b6eaSmrg rr_outputs = calloc (crtc->noutput, sizeof (RROutput)); 1425a0d3b6eaSmrg if (!rr_outputs) 1426a0d3b6eaSmrg return BadAlloc; 1427a0d3b6eaSmrg for (o = 0; o < crtc->noutput; o++) 1428a0d3b6eaSmrg rr_outputs[o] = crtc->outputs[o]->output.xid; 1429a0d3b6eaSmrg mode = crtc->mode_info->id; 1430a0d3b6eaSmrg if (verbose) { 1431a0d3b6eaSmrg printf ("crtc %d: %12s %6.1f +%d+%d", crtc->crtc.index, 1432a0d3b6eaSmrg crtc->mode_info->name, mode_refresh (crtc->mode_info), 1433a0d3b6eaSmrg crtc->x, crtc->y); 1434a0d3b6eaSmrg for (o = 0; o < crtc->noutput; o++) 1435a0d3b6eaSmrg printf (" \"%s\"", crtc->outputs[o]->output.string); 1436a0d3b6eaSmrg printf ("\n"); 1437a0d3b6eaSmrg } 1438a0d3b6eaSmrg 1439a0d3b6eaSmrg if (dryrun) 1440a0d3b6eaSmrg s = RRSetConfigSuccess; 1441a0d3b6eaSmrg else 144262df5ad0Smrg { 144362df5ad0Smrg if (!equal_transform (&crtc->current_transform, &crtc->pending_transform)) 144462df5ad0Smrg crtc_set_transform (crtc, &crtc->pending_transform); 1445a0d3b6eaSmrg s = XRRSetCrtcConfig (dpy, res, crtc->crtc.xid, CurrentTime, 1446a0d3b6eaSmrg crtc->x, crtc->y, mode, crtc->rotation, 1447a0d3b6eaSmrg rr_outputs, crtc->noutput); 144862df5ad0Smrg if (s == RRSetConfigSuccess && crtc->panning_info) { 144962df5ad0Smrg if (has_1_3) 145062df5ad0Smrg s = XRRSetPanning (dpy, res, crtc->crtc.xid, crtc->panning_info); 145162df5ad0Smrg else 145262df5ad0Smrg fatal ("panning needs RandR 1.3\n"); 145362df5ad0Smrg } 145462df5ad0Smrg } 1455a0d3b6eaSmrg free (rr_outputs); 1456a0d3b6eaSmrg return s; 1457a0d3b6eaSmrg} 1458a0d3b6eaSmrg 1459a0d3b6eaSmrgstatic void 1460a0d3b6eaSmrgscreen_revert (void) 1461a0d3b6eaSmrg{ 1462a0d3b6eaSmrg if (verbose) 1463a0d3b6eaSmrg printf ("screen %d: revert\n", screen); 1464a0d3b6eaSmrg 1465a0d3b6eaSmrg if (dryrun) 1466a0d3b6eaSmrg return; 1467a0d3b6eaSmrg XRRSetScreenSize (dpy, root, 1468a0d3b6eaSmrg DisplayWidth (dpy, screen), 1469a0d3b6eaSmrg DisplayHeight (dpy, screen), 1470a0d3b6eaSmrg DisplayWidthMM (dpy, screen), 1471a0d3b6eaSmrg DisplayHeightMM (dpy, screen)); 1472a0d3b6eaSmrg} 1473a0d3b6eaSmrg 1474a0d3b6eaSmrgstatic void 1475a0d3b6eaSmrgscreen_apply (void) 1476a0d3b6eaSmrg{ 1477a0d3b6eaSmrg if (fb_width == DisplayWidth (dpy, screen) && 1478a0d3b6eaSmrg fb_height == DisplayHeight (dpy, screen) && 1479a0d3b6eaSmrg fb_width_mm == DisplayWidthMM (dpy, screen) && 1480a0d3b6eaSmrg fb_height_mm == DisplayHeightMM (dpy, screen)) 1481a0d3b6eaSmrg { 1482a0d3b6eaSmrg return; 1483a0d3b6eaSmrg } 1484a0d3b6eaSmrg if (verbose) 1485a0d3b6eaSmrg printf ("screen %d: %dx%d %dx%d mm %6.2fdpi\n", screen, 1486a0d3b6eaSmrg fb_width, fb_height, fb_width_mm, fb_height_mm, dpi); 1487a0d3b6eaSmrg if (dryrun) 1488a0d3b6eaSmrg return; 1489a0d3b6eaSmrg XRRSetScreenSize (dpy, root, fb_width, fb_height, 1490a0d3b6eaSmrg fb_width_mm, fb_height_mm); 1491a0d3b6eaSmrg} 1492a0d3b6eaSmrg 1493a0d3b6eaSmrgstatic void 1494a0d3b6eaSmrgrevert (void) 1495a0d3b6eaSmrg{ 1496a0d3b6eaSmrg int c; 1497a0d3b6eaSmrg 1498a0d3b6eaSmrg /* first disable all crtcs */ 1499a0d3b6eaSmrg for (c = 0; c < res->ncrtc; c++) 1500a0d3b6eaSmrg crtc_disable (&crtcs[c]); 1501a0d3b6eaSmrg /* next reset screen size */ 1502a0d3b6eaSmrg screen_revert (); 1503a0d3b6eaSmrg /* now restore all crtcs */ 1504a0d3b6eaSmrg for (c = 0; c < res->ncrtc; c++) 1505a0d3b6eaSmrg crtc_revert (&crtcs[c]); 1506a0d3b6eaSmrg} 1507a0d3b6eaSmrg 1508a0d3b6eaSmrg/* 1509a0d3b6eaSmrg * uh-oh, something bad happened in the middle of changing 1510a0d3b6eaSmrg * the configuration. Revert to the previous configuration 1511a0d3b6eaSmrg * and bail 1512a0d3b6eaSmrg */ 1513a0d3b6eaSmrgstatic void 1514a0d3b6eaSmrgpanic (Status s, crtc_t *crtc) 1515a0d3b6eaSmrg{ 1516a0d3b6eaSmrg int c = crtc->crtc.index; 1517a0d3b6eaSmrg char *message; 1518a0d3b6eaSmrg 1519a0d3b6eaSmrg switch (s) { 1520a0d3b6eaSmrg case RRSetConfigSuccess: message = "succeeded"; break; 1521a0d3b6eaSmrg case BadAlloc: message = "out of memory"; break; 1522a0d3b6eaSmrg case RRSetConfigFailed: message = "failed"; break; 1523a0d3b6eaSmrg case RRSetConfigInvalidConfigTime: message = "invalid config time"; break; 1524a0d3b6eaSmrg case RRSetConfigInvalidTime: message = "invalid time"; break; 1525a0d3b6eaSmrg default: message = "unknown failure"; break; 1526a0d3b6eaSmrg } 1527a0d3b6eaSmrg 1528a0d3b6eaSmrg fprintf (stderr, "%s: Configure crtc %d %s\n", program_name, c, message); 1529a0d3b6eaSmrg revert (); 1530a0d3b6eaSmrg exit (1); 1531a0d3b6eaSmrg} 1532a0d3b6eaSmrg 153362df5ad0Smrgstatic void 1534a0d3b6eaSmrgapply (void) 1535a0d3b6eaSmrg{ 1536a0d3b6eaSmrg Status s; 1537a0d3b6eaSmrg int c; 1538a0d3b6eaSmrg 153962770414Smrg /* 154062770414Smrg * Hold the server grabbed while messing with 154162770414Smrg * the screen so that apps which notice the resize 154262770414Smrg * event and ask for xinerama information from the server 154362770414Smrg * receive up-to-date information 154462770414Smrg */ 154562770414Smrg if (grab_server) 154662770414Smrg XGrabServer (dpy); 154762770414Smrg 1548a0d3b6eaSmrg /* 1549a0d3b6eaSmrg * Turn off any crtcs which are to be disabled or which are 1550a0d3b6eaSmrg * larger than the target size 1551a0d3b6eaSmrg */ 1552a0d3b6eaSmrg for (c = 0; c < res->ncrtc; c++) 1553a0d3b6eaSmrg { 1554a0d3b6eaSmrg crtc_t *crtc = &crtcs[c]; 1555a0d3b6eaSmrg XRRCrtcInfo *crtc_info = crtc->crtc_info; 1556a0d3b6eaSmrg 1557a0d3b6eaSmrg /* if this crtc is already disabled, skip it */ 1558a0d3b6eaSmrg if (crtc_info->mode == None) 1559a0d3b6eaSmrg continue; 1560a0d3b6eaSmrg 1561a0d3b6eaSmrg /* 1562a0d3b6eaSmrg * If this crtc is to be left enabled, make 1563a0d3b6eaSmrg * sure the old size fits then new screen 1564a0d3b6eaSmrg */ 1565a0d3b6eaSmrg if (crtc->mode_info) 1566a0d3b6eaSmrg { 1567a0d3b6eaSmrg XRRModeInfo *old_mode = find_mode_by_xid (crtc_info->mode); 1568a0d3b6eaSmrg int x, y, w, h; 156962df5ad0Smrg box_t bounds; 1570a0d3b6eaSmrg 1571a0d3b6eaSmrg if (!old_mode) 1572a0d3b6eaSmrg panic (RRSetConfigFailed, crtc); 1573a0d3b6eaSmrg 1574a0d3b6eaSmrg /* old position and size information */ 157562df5ad0Smrg mode_geometry (old_mode, crtc_info->rotation, 157662df5ad0Smrg &crtc->current_transform.transform, 157762df5ad0Smrg &bounds); 157862df5ad0Smrg 157962df5ad0Smrg x = crtc_info->x + bounds.x1; 158062df5ad0Smrg y = crtc_info->y + bounds.y1; 158162df5ad0Smrg w = bounds.x2 - bounds.x1; 158262df5ad0Smrg h = bounds.y2 - bounds.y1; 158362df5ad0Smrg 1584a0d3b6eaSmrg /* if it fits, skip it */ 1585a0d3b6eaSmrg if (x + w <= fb_width && y + h <= fb_height) 1586a0d3b6eaSmrg continue; 1587a0d3b6eaSmrg crtc->changing = True; 1588a0d3b6eaSmrg } 1589a0d3b6eaSmrg s = crtc_disable (crtc); 1590a0d3b6eaSmrg if (s != RRSetConfigSuccess) 1591a0d3b6eaSmrg panic (s, crtc); 1592a0d3b6eaSmrg } 1593a0d3b6eaSmrg 1594a0d3b6eaSmrg /* 1595a0d3b6eaSmrg * Set the screen size 1596a0d3b6eaSmrg */ 1597a0d3b6eaSmrg screen_apply (); 1598a0d3b6eaSmrg 1599a0d3b6eaSmrg /* 1600a0d3b6eaSmrg * Set crtcs 1601a0d3b6eaSmrg */ 1602a0d3b6eaSmrg 1603a0d3b6eaSmrg for (c = 0; c < res->ncrtc; c++) 1604a0d3b6eaSmrg { 1605a0d3b6eaSmrg crtc_t *crtc = &crtcs[c]; 1606a0d3b6eaSmrg 1607a0d3b6eaSmrg s = crtc_apply (crtc); 1608a0d3b6eaSmrg if (s != RRSetConfigSuccess) 1609a0d3b6eaSmrg panic (s, crtc); 1610a0d3b6eaSmrg } 161162df5ad0Smrg 161262df5ad0Smrg set_primary (); 161362df5ad0Smrg 1614a0d3b6eaSmrg /* 1615a0d3b6eaSmrg * Release the server grab and let all clients 1616a0d3b6eaSmrg * respond to the updated state 1617a0d3b6eaSmrg */ 161862df5ad0Smrg if (grab_server) 161962df5ad0Smrg XUngrabServer (dpy); 1620a0d3b6eaSmrg} 1621a0d3b6eaSmrg 1622a0d3b6eaSmrg/* 1623a0d3b6eaSmrg * Use current output state to complete the output list 1624a0d3b6eaSmrg */ 162562df5ad0Smrgstatic void 1626a0d3b6eaSmrgget_outputs (void) 1627a0d3b6eaSmrg{ 1628a0d3b6eaSmrg int o; 1629c52f0396Smrg output_t *q; 1630a0d3b6eaSmrg 1631a0d3b6eaSmrg for (o = 0; o < res->noutput; o++) 1632a0d3b6eaSmrg { 1633a0d3b6eaSmrg XRROutputInfo *output_info = XRRGetOutputInfo (dpy, res, res->outputs[o]); 1634a0d3b6eaSmrg output_t *output; 1635a0d3b6eaSmrg name_t output_name; 163662df5ad0Smrg if (!output_info) fatal ("could not get output 0x%x information\n", res->outputs[o]); 1637a0d3b6eaSmrg set_name_xid (&output_name, res->outputs[o]); 1638a0d3b6eaSmrg set_name_index (&output_name, o); 1639a0d3b6eaSmrg set_name_string (&output_name, output_info->name); 1640a0d3b6eaSmrg output = find_output (&output_name); 1641a0d3b6eaSmrg if (!output) 1642a0d3b6eaSmrg { 1643a0d3b6eaSmrg output = add_output (); 1644a0d3b6eaSmrg set_name_all (&output->output, &output_name); 1645a0d3b6eaSmrg /* 1646a0d3b6eaSmrg * When global --automatic mode is set, turn on connected but off 1647a0d3b6eaSmrg * outputs, turn off disconnected but on outputs 1648a0d3b6eaSmrg */ 1649a0d3b6eaSmrg if (automatic) 1650a0d3b6eaSmrg { 1651a0d3b6eaSmrg switch (output_info->connection) { 1652a0d3b6eaSmrg case RR_Connected: 1653a0d3b6eaSmrg if (!output_info->crtc) { 1654a0d3b6eaSmrg output->changes |= changes_automatic; 1655a0d3b6eaSmrg output->automatic = True; 1656a0d3b6eaSmrg } 1657a0d3b6eaSmrg break; 1658a0d3b6eaSmrg case RR_Disconnected: 1659a0d3b6eaSmrg if (output_info->crtc) 1660a0d3b6eaSmrg { 1661a0d3b6eaSmrg output->changes |= changes_automatic; 1662a0d3b6eaSmrg output->automatic = True; 1663a0d3b6eaSmrg } 1664a0d3b6eaSmrg break; 1665a0d3b6eaSmrg } 1666a0d3b6eaSmrg } 1667a0d3b6eaSmrg } 1668c52f0396Smrg output->found = True; 1669a0d3b6eaSmrg 1670a0d3b6eaSmrg /* 1671a0d3b6eaSmrg * Automatic mode -- track connection state and enable/disable outputs 1672a0d3b6eaSmrg * as necessary 1673a0d3b6eaSmrg */ 1674a0d3b6eaSmrg if (output->automatic) 1675a0d3b6eaSmrg { 1676a0d3b6eaSmrg switch (output_info->connection) { 1677a0d3b6eaSmrg case RR_Connected: 1678a0d3b6eaSmrg case RR_UnknownConnection: 1679a0d3b6eaSmrg if ((!(output->changes & changes_mode))) 1680a0d3b6eaSmrg { 1681a0d3b6eaSmrg set_name_preferred (&output->mode); 1682a0d3b6eaSmrg output->changes |= changes_mode; 1683a0d3b6eaSmrg } 1684a0d3b6eaSmrg break; 1685a0d3b6eaSmrg case RR_Disconnected: 1686a0d3b6eaSmrg if ((!(output->changes & changes_mode))) 1687a0d3b6eaSmrg { 1688a0d3b6eaSmrg set_name_xid (&output->mode, None); 1689a0d3b6eaSmrg set_name_xid (&output->crtc, None); 1690a0d3b6eaSmrg output->changes |= changes_mode; 1691a0d3b6eaSmrg output->changes |= changes_crtc; 1692a0d3b6eaSmrg } 1693a0d3b6eaSmrg break; 1694a0d3b6eaSmrg } 1695a0d3b6eaSmrg } 1696a0d3b6eaSmrg 1697a0d3b6eaSmrg set_output_info (output, res->outputs[o], output_info); 1698a0d3b6eaSmrg } 1699c52f0396Smrg for (q = outputs; q; q = q->next) 1700c52f0396Smrg { 1701c52f0396Smrg if (!q->found) 1702c52f0396Smrg { 1703c52f0396Smrg fprintf(stderr, "warning: output %s not found; ignoring\n", 1704c52f0396Smrg q->output.string); 1705c52f0396Smrg } 1706c52f0396Smrg } 1707a0d3b6eaSmrg} 1708a0d3b6eaSmrg 170962df5ad0Smrgstatic void 1710a0d3b6eaSmrgmark_changing_crtcs (void) 1711a0d3b6eaSmrg{ 1712a0d3b6eaSmrg int c; 1713a0d3b6eaSmrg 1714a0d3b6eaSmrg for (c = 0; c < num_crtcs; c++) 1715a0d3b6eaSmrg { 1716a0d3b6eaSmrg crtc_t *crtc = &crtcs[c]; 1717a0d3b6eaSmrg int o; 1718a0d3b6eaSmrg output_t *output; 1719a0d3b6eaSmrg 1720a0d3b6eaSmrg /* walk old output list (to catch disables) */ 1721a0d3b6eaSmrg for (o = 0; o < crtc->crtc_info->noutput; o++) 1722a0d3b6eaSmrg { 1723a0d3b6eaSmrg output = find_output_by_xid (crtc->crtc_info->outputs[o]); 1724a0d3b6eaSmrg if (!output) fatal ("cannot find output 0x%x\n", 1725a0d3b6eaSmrg crtc->crtc_info->outputs[o]); 1726a0d3b6eaSmrg if (output->changes) 1727a0d3b6eaSmrg crtc->changing = True; 1728a0d3b6eaSmrg } 1729a0d3b6eaSmrg /* walk new output list */ 1730a0d3b6eaSmrg for (o = 0; o < crtc->noutput; o++) 1731a0d3b6eaSmrg { 1732a0d3b6eaSmrg output = crtc->outputs[o]; 1733a0d3b6eaSmrg if (output->changes) 1734a0d3b6eaSmrg crtc->changing = True; 1735a0d3b6eaSmrg } 1736a0d3b6eaSmrg } 1737a0d3b6eaSmrg} 1738a0d3b6eaSmrg 1739a0d3b6eaSmrg/* 1740a0d3b6eaSmrg * Test whether 'crtc' can be used for 'output' 1741a0d3b6eaSmrg */ 174262770414Smrgstatic Bool 1743a0d3b6eaSmrgcheck_crtc_for_output (crtc_t *crtc, output_t *output) 1744a0d3b6eaSmrg{ 1745a0d3b6eaSmrg int c; 1746a0d3b6eaSmrg int l; 1747a0d3b6eaSmrg output_t *other; 1748a0d3b6eaSmrg 1749a0d3b6eaSmrg for (c = 0; c < output->output_info->ncrtc; c++) 1750a0d3b6eaSmrg if (output->output_info->crtcs[c] == crtc->crtc.xid) 1751a0d3b6eaSmrg break; 1752a0d3b6eaSmrg if (c == output->output_info->ncrtc) 1753a0d3b6eaSmrg return False; 1754a0d3b6eaSmrg for (other = outputs; other; other = other->next) 1755a0d3b6eaSmrg { 1756a0d3b6eaSmrg if (other == output) 1757a0d3b6eaSmrg continue; 1758a0d3b6eaSmrg 1759a0d3b6eaSmrg if (other->mode_info == NULL) 1760a0d3b6eaSmrg continue; 1761a0d3b6eaSmrg 1762a0d3b6eaSmrg if (other->crtc_info != crtc) 1763a0d3b6eaSmrg continue; 1764a0d3b6eaSmrg 1765a0d3b6eaSmrg /* see if the output connected to the crtc can clone to this output */ 1766a0d3b6eaSmrg for (l = 0; l < output->output_info->nclone; l++) 1767a0d3b6eaSmrg if (output->output_info->clones[l] == other->output.xid) 1768a0d3b6eaSmrg break; 1769a0d3b6eaSmrg /* not on the list, can't clone */ 1770a0d3b6eaSmrg if (l == output->output_info->nclone) 1771a0d3b6eaSmrg return False; 1772a0d3b6eaSmrg } 1773a0d3b6eaSmrg 1774a0d3b6eaSmrg if (crtc->noutput) 1775a0d3b6eaSmrg { 1776a0d3b6eaSmrg /* make sure the state matches */ 1777a0d3b6eaSmrg if (crtc->mode_info != output->mode_info) 1778a0d3b6eaSmrg return False; 1779a0d3b6eaSmrg if (crtc->x != output->x) 1780a0d3b6eaSmrg return False; 1781a0d3b6eaSmrg if (crtc->y != output->y) 1782a0d3b6eaSmrg return False; 1783a0d3b6eaSmrg if (crtc->rotation != output->rotation) 1784a0d3b6eaSmrg return False; 178562df5ad0Smrg if (!equal_transform (&crtc->current_transform, &output->transform)) 178662df5ad0Smrg return False; 1787a0d3b6eaSmrg } 1788a0d3b6eaSmrg else if (crtc->crtc_info->noutput) 1789a0d3b6eaSmrg { 1790a0d3b6eaSmrg /* make sure the state matches the already used state */ 1791a0d3b6eaSmrg XRRModeInfo *mode = find_mode_by_xid (crtc->crtc_info->mode); 1792a0d3b6eaSmrg 1793a0d3b6eaSmrg if (mode != output->mode_info) 1794a0d3b6eaSmrg return False; 1795a0d3b6eaSmrg if (crtc->crtc_info->x != output->x) 1796a0d3b6eaSmrg return False; 1797a0d3b6eaSmrg if (crtc->crtc_info->y != output->y) 1798a0d3b6eaSmrg return False; 1799a0d3b6eaSmrg if (crtc->crtc_info->rotation != output->rotation) 1800a0d3b6eaSmrg return False; 1801a0d3b6eaSmrg } 1802a0d3b6eaSmrg return True; 1803a0d3b6eaSmrg} 1804a0d3b6eaSmrg 180562df5ad0Smrgstatic crtc_t * 1806a0d3b6eaSmrgfind_crtc_for_output (output_t *output) 1807a0d3b6eaSmrg{ 1808a0d3b6eaSmrg int c; 1809a0d3b6eaSmrg 1810a0d3b6eaSmrg for (c = 0; c < output->output_info->ncrtc; c++) 1811a0d3b6eaSmrg { 1812a0d3b6eaSmrg crtc_t *crtc; 1813a0d3b6eaSmrg 1814a0d3b6eaSmrg crtc = find_crtc_by_xid (output->output_info->crtcs[c]); 1815a0d3b6eaSmrg if (!crtc) fatal ("cannot find crtc 0x%x\n", output->output_info->crtcs[c]); 1816a0d3b6eaSmrg 1817a0d3b6eaSmrg if (check_crtc_for_output (crtc, output)) 1818a0d3b6eaSmrg return crtc; 1819a0d3b6eaSmrg } 1820a0d3b6eaSmrg return NULL; 1821a0d3b6eaSmrg} 1822a0d3b6eaSmrg 1823a0d3b6eaSmrgstatic void 1824a0d3b6eaSmrgset_positions (void) 1825a0d3b6eaSmrg{ 1826a0d3b6eaSmrg output_t *output; 1827a0d3b6eaSmrg Bool keep_going; 1828a0d3b6eaSmrg Bool any_set; 1829a0d3b6eaSmrg int min_x, min_y; 1830a0d3b6eaSmrg 1831a0d3b6eaSmrg for (;;) 1832a0d3b6eaSmrg { 1833a0d3b6eaSmrg any_set = False; 1834a0d3b6eaSmrg keep_going = False; 1835a0d3b6eaSmrg for (output = outputs; output; output = output->next) 1836a0d3b6eaSmrg { 1837a0d3b6eaSmrg output_t *relation; 1838a0d3b6eaSmrg name_t relation_name; 1839a0d3b6eaSmrg 1840a0d3b6eaSmrg if (!(output->changes & changes_relation)) continue; 1841a0d3b6eaSmrg 1842a0d3b6eaSmrg if (output->mode_info == NULL) continue; 1843a0d3b6eaSmrg 1844a0d3b6eaSmrg init_name (&relation_name); 1845a0d3b6eaSmrg set_name_string (&relation_name, output->relative_to); 1846a0d3b6eaSmrg relation = find_output (&relation_name); 1847a0d3b6eaSmrg if (!relation) fatal ("cannot find output \"%s\"\n", output->relative_to); 1848a0d3b6eaSmrg 1849a0d3b6eaSmrg if (relation->mode_info == NULL) 1850a0d3b6eaSmrg { 1851a0d3b6eaSmrg output->x = 0; 1852a0d3b6eaSmrg output->y = 0; 1853a0d3b6eaSmrg output->changes |= changes_position; 1854a0d3b6eaSmrg any_set = True; 1855a0d3b6eaSmrg continue; 1856a0d3b6eaSmrg } 1857a0d3b6eaSmrg /* 1858a0d3b6eaSmrg * Make sure the dependent object has been set in place 1859a0d3b6eaSmrg */ 1860a0d3b6eaSmrg if ((relation->changes & changes_relation) && 1861a0d3b6eaSmrg !(relation->changes & changes_position)) 1862a0d3b6eaSmrg { 1863a0d3b6eaSmrg keep_going = True; 1864a0d3b6eaSmrg continue; 1865a0d3b6eaSmrg } 1866a0d3b6eaSmrg 1867a0d3b6eaSmrg switch (output->relation) { 18688a16544fSmrg case relation_left_of: 1869a0d3b6eaSmrg output->y = relation->y; 1870a0d3b6eaSmrg output->x = relation->x - mode_width (output->mode_info, output->rotation); 1871a0d3b6eaSmrg break; 18728a16544fSmrg case relation_right_of: 1873a0d3b6eaSmrg output->y = relation->y; 1874a0d3b6eaSmrg output->x = relation->x + mode_width (relation->mode_info, relation->rotation); 1875a0d3b6eaSmrg break; 18768a16544fSmrg case relation_above: 1877a0d3b6eaSmrg output->x = relation->x; 1878a0d3b6eaSmrg output->y = relation->y - mode_height (output->mode_info, output->rotation); 1879a0d3b6eaSmrg break; 18808a16544fSmrg case relation_below: 1881a0d3b6eaSmrg output->x = relation->x; 1882a0d3b6eaSmrg output->y = relation->y + mode_height (relation->mode_info, relation->rotation); 1883a0d3b6eaSmrg break; 18848a16544fSmrg case relation_same_as: 1885a0d3b6eaSmrg output->x = relation->x; 1886a0d3b6eaSmrg output->y = relation->y; 1887a0d3b6eaSmrg } 1888a0d3b6eaSmrg output->changes |= changes_position; 1889a0d3b6eaSmrg any_set = True; 1890a0d3b6eaSmrg } 1891a0d3b6eaSmrg if (!keep_going) 1892a0d3b6eaSmrg break; 1893a0d3b6eaSmrg if (!any_set) 1894a0d3b6eaSmrg fatal ("loop in relative position specifications\n"); 1895a0d3b6eaSmrg } 1896a0d3b6eaSmrg 1897a0d3b6eaSmrg /* 1898a0d3b6eaSmrg * Now normalize positions so the upper left corner of all outputs is at 0,0 1899a0d3b6eaSmrg */ 1900a0d3b6eaSmrg min_x = 32768; 1901a0d3b6eaSmrg min_y = 32768; 1902a0d3b6eaSmrg for (output = outputs; output; output = output->next) 1903a0d3b6eaSmrg { 1904a0d3b6eaSmrg if (output->mode_info == NULL) continue; 1905a0d3b6eaSmrg 1906a0d3b6eaSmrg if (output->x < min_x) min_x = output->x; 1907a0d3b6eaSmrg if (output->y < min_y) min_y = output->y; 1908a0d3b6eaSmrg } 1909a0d3b6eaSmrg if (min_x || min_y) 1910a0d3b6eaSmrg { 1911a0d3b6eaSmrg /* move all outputs */ 1912a0d3b6eaSmrg for (output = outputs; output; output = output->next) 1913a0d3b6eaSmrg { 1914a0d3b6eaSmrg if (output->mode_info == NULL) continue; 1915a0d3b6eaSmrg 1916a0d3b6eaSmrg output->x -= min_x; 1917a0d3b6eaSmrg output->y -= min_y; 1918a0d3b6eaSmrg output->changes |= changes_position; 1919a0d3b6eaSmrg } 1920a0d3b6eaSmrg } 1921a0d3b6eaSmrg} 1922a0d3b6eaSmrg 1923a0d3b6eaSmrgstatic void 1924a0d3b6eaSmrgset_screen_size (void) 1925a0d3b6eaSmrg{ 1926a0d3b6eaSmrg output_t *output; 1927a0d3b6eaSmrg Bool fb_specified = fb_width != 0 && fb_height != 0; 1928a0d3b6eaSmrg 1929a0d3b6eaSmrg for (output = outputs; output; output = output->next) 1930a0d3b6eaSmrg { 1931a0d3b6eaSmrg XRRModeInfo *mode_info = output->mode_info; 1932a0d3b6eaSmrg int x, y, w, h; 193362df5ad0Smrg box_t bounds; 1934a0d3b6eaSmrg 1935a0d3b6eaSmrg if (!mode_info) continue; 1936a0d3b6eaSmrg 193762df5ad0Smrg mode_geometry (mode_info, output->rotation, 193862df5ad0Smrg &output->transform.transform, 193962df5ad0Smrg &bounds); 194062df5ad0Smrg x = output->x + bounds.x1; 194162df5ad0Smrg y = output->y + bounds.y1; 194262df5ad0Smrg w = bounds.x2 - bounds.x1; 194362df5ad0Smrg h = bounds.y2 - bounds.y1; 1944a0d3b6eaSmrg /* make sure output fits in specified size */ 1945a0d3b6eaSmrg if (fb_specified) 1946a0d3b6eaSmrg { 1947a0d3b6eaSmrg if (x + w > fb_width || y + h > fb_height) 194862df5ad0Smrg warning ("specified screen %dx%d not large enough for output %s (%dx%d+%d+%d)\n", 194962df5ad0Smrg fb_width, fb_height, output->output.string, w, h, x, y); 1950a0d3b6eaSmrg } 1951a0d3b6eaSmrg /* fit fb to output */ 1952a0d3b6eaSmrg else 1953a0d3b6eaSmrg { 195462df5ad0Smrg XRRPanning *pan; 195562df5ad0Smrg if (x + w > fb_width) 195662df5ad0Smrg fb_width = x + w; 195762df5ad0Smrg if (y + h > fb_height) 195862df5ad0Smrg fb_height = y + h; 195962df5ad0Smrg if (output->changes & changes_panning) 196062df5ad0Smrg pan = &output->panning; 196162df5ad0Smrg else 196262df5ad0Smrg pan = output->crtc_info ? output->crtc_info->panning_info : NULL; 196362df5ad0Smrg if (pan && pan->left + pan->width > fb_width) 196462df5ad0Smrg fb_width = pan->left + pan->width; 196562df5ad0Smrg if (pan && pan->top + pan->height > fb_height) 196662df5ad0Smrg fb_height = pan->top + pan->height; 1967a0d3b6eaSmrg } 1968a0d3b6eaSmrg } 1969a0d3b6eaSmrg 1970a0d3b6eaSmrg if (fb_width > maxWidth || fb_height > maxHeight) 1971a0d3b6eaSmrg fatal ("screen cannot be larger than %dx%d (desired size %dx%d)\n", 1972a0d3b6eaSmrg maxWidth, maxHeight, fb_width, fb_height); 1973a0d3b6eaSmrg if (fb_specified) 1974a0d3b6eaSmrg { 1975a0d3b6eaSmrg if (fb_width < minWidth || fb_height < minHeight) 1976a0d3b6eaSmrg fatal ("screen must be at least %dx%d\n", minWidth, minHeight); 1977a0d3b6eaSmrg } 1978a0d3b6eaSmrg else 1979a0d3b6eaSmrg { 1980a0d3b6eaSmrg if (fb_width < minWidth) fb_width = minWidth; 1981a0d3b6eaSmrg if (fb_height < minHeight) fb_height = minHeight; 1982a0d3b6eaSmrg } 1983a0d3b6eaSmrg} 1984a0d3b6eaSmrg 198562df5ad0Smrg 198662df5ad0Smrgstatic void 1987a0d3b6eaSmrgdisable_outputs (output_t *outputs) 1988a0d3b6eaSmrg{ 1989a0d3b6eaSmrg while (outputs) 1990a0d3b6eaSmrg { 1991a0d3b6eaSmrg outputs->crtc_info = NULL; 1992a0d3b6eaSmrg outputs = outputs->next; 1993a0d3b6eaSmrg } 1994a0d3b6eaSmrg} 1995a0d3b6eaSmrg 1996a0d3b6eaSmrg/* 1997a0d3b6eaSmrg * find the best mapping from output to crtc available 1998a0d3b6eaSmrg */ 199962df5ad0Smrgstatic int 2000a0d3b6eaSmrgpick_crtcs_score (output_t *outputs) 2001a0d3b6eaSmrg{ 2002a0d3b6eaSmrg output_t *output; 2003a0d3b6eaSmrg int best_score; 2004a0d3b6eaSmrg int my_score; 2005a0d3b6eaSmrg int score; 2006a0d3b6eaSmrg crtc_t *best_crtc; 2007a0d3b6eaSmrg int c; 2008a0d3b6eaSmrg 2009a0d3b6eaSmrg if (!outputs) 2010a0d3b6eaSmrg return 0; 2011a0d3b6eaSmrg 2012a0d3b6eaSmrg output = outputs; 2013a0d3b6eaSmrg outputs = outputs->next; 2014a0d3b6eaSmrg /* 2015a0d3b6eaSmrg * Score with this output disabled 2016a0d3b6eaSmrg */ 2017a0d3b6eaSmrg output->crtc_info = NULL; 2018a0d3b6eaSmrg best_score = pick_crtcs_score (outputs); 2019a0d3b6eaSmrg if (output->mode_info == NULL) 2020a0d3b6eaSmrg return best_score; 2021a0d3b6eaSmrg 2022a0d3b6eaSmrg best_crtc = NULL; 2023a0d3b6eaSmrg /* 2024a0d3b6eaSmrg * Now score with this output any valid crtc 2025a0d3b6eaSmrg */ 2026a0d3b6eaSmrg for (c = 0; c < output->output_info->ncrtc; c++) 2027a0d3b6eaSmrg { 2028a0d3b6eaSmrg crtc_t *crtc; 2029a0d3b6eaSmrg 2030a0d3b6eaSmrg crtc = find_crtc_by_xid (output->output_info->crtcs[c]); 2031a0d3b6eaSmrg if (!crtc) 2032a0d3b6eaSmrg fatal ("cannot find crtc 0x%x\n", output->output_info->crtcs[c]); 2033a0d3b6eaSmrg 2034a0d3b6eaSmrg /* reset crtc allocation for following outputs */ 2035a0d3b6eaSmrg disable_outputs (outputs); 2036a0d3b6eaSmrg if (!check_crtc_for_output (crtc, output)) 2037a0d3b6eaSmrg continue; 2038a0d3b6eaSmrg 2039a0d3b6eaSmrg my_score = 1000; 2040a0d3b6eaSmrg /* slight preference for existing connections */ 2041a0d3b6eaSmrg if (crtc == output->current_crtc_info) 2042a0d3b6eaSmrg my_score++; 2043a0d3b6eaSmrg 2044a0d3b6eaSmrg output->crtc_info = crtc; 2045a0d3b6eaSmrg score = my_score + pick_crtcs_score (outputs); 2046a0d3b6eaSmrg if (score > best_score) 2047a0d3b6eaSmrg { 2048a0d3b6eaSmrg best_crtc = crtc; 2049a0d3b6eaSmrg best_score = score; 2050a0d3b6eaSmrg } 2051a0d3b6eaSmrg } 2052a0d3b6eaSmrg if (output->crtc_info != best_crtc) 2053a0d3b6eaSmrg output->crtc_info = best_crtc; 2054a0d3b6eaSmrg /* 2055a0d3b6eaSmrg * Reset other outputs based on this one using the best crtc 2056a0d3b6eaSmrg */ 2057a0d3b6eaSmrg (void) pick_crtcs_score (outputs); 2058a0d3b6eaSmrg 2059a0d3b6eaSmrg return best_score; 2060a0d3b6eaSmrg} 2061a0d3b6eaSmrg 2062a0d3b6eaSmrg/* 2063a0d3b6eaSmrg * Pick crtcs for any changing outputs that don't have one 2064a0d3b6eaSmrg */ 206562df5ad0Smrgstatic void 2066a0d3b6eaSmrgpick_crtcs (void) 2067a0d3b6eaSmrg{ 2068a0d3b6eaSmrg output_t *output; 2069a0d3b6eaSmrg 2070a0d3b6eaSmrg /* 2071a0d3b6eaSmrg * First try to match up newly enabled outputs with spare crtcs 2072a0d3b6eaSmrg */ 2073a0d3b6eaSmrg for (output = outputs; output; output = output->next) 2074a0d3b6eaSmrg { 2075a0d3b6eaSmrg if (output->changes && output->mode_info) 2076a0d3b6eaSmrg { 2077a0d3b6eaSmrg if (output->crtc_info) { 2078a0d3b6eaSmrg if (output->crtc_info->crtc_info->noutput > 0 && 2079a0d3b6eaSmrg (output->crtc_info->crtc_info->noutput > 1 || 2080a0d3b6eaSmrg output != find_output_by_xid (output->crtc_info->crtc_info->outputs[0]))) 2081a0d3b6eaSmrg break; 2082a0d3b6eaSmrg } else { 2083a0d3b6eaSmrg output->crtc_info = find_crtc_for_output (output); 2084a0d3b6eaSmrg if (!output->crtc_info) 2085a0d3b6eaSmrg break; 2086a0d3b6eaSmrg } 2087a0d3b6eaSmrg } 2088a0d3b6eaSmrg } 2089a0d3b6eaSmrg /* 2090a0d3b6eaSmrg * Everyone is happy 2091a0d3b6eaSmrg */ 2092a0d3b6eaSmrg if (!output) 2093a0d3b6eaSmrg return; 2094a0d3b6eaSmrg /* 2095a0d3b6eaSmrg * When the simple way fails, see if there is a way 2096a0d3b6eaSmrg * to swap crtcs around and make things work 2097a0d3b6eaSmrg */ 2098a0d3b6eaSmrg for (output = outputs; output; output = output->next) 2099a0d3b6eaSmrg output->current_crtc_info = output->crtc_info; 2100a0d3b6eaSmrg pick_crtcs_score (outputs); 2101a0d3b6eaSmrg for (output = outputs; output; output = output->next) 2102a0d3b6eaSmrg { 2103a0d3b6eaSmrg if (output->mode_info && !output->crtc_info) 2104a0d3b6eaSmrg fatal ("cannot find crtc for output %s\n", output->output.string); 2105a0d3b6eaSmrg if (!output->changes && output->crtc_info != output->current_crtc_info) 2106a0d3b6eaSmrg output->changes |= changes_crtc; 2107a0d3b6eaSmrg } 2108a0d3b6eaSmrg} 2109a0d3b6eaSmrg 2110c52f0396Smrgstatic int 2111c52f0396Smrgcheck_strtol(char *s) 2112c52f0396Smrg{ 2113c52f0396Smrg char *endptr; 2114c52f0396Smrg int result = strtol(s, &endptr, 10); 2115c52f0396Smrg if (s == endptr) 2116c52f0396Smrg usage(); 2117c52f0396Smrg return result; 2118c52f0396Smrg} 2119c52f0396Smrg 21208a16544fSmrgstatic double 2121c52f0396Smrgcheck_strtod(char *s) 2122c52f0396Smrg{ 2123c52f0396Smrg char *endptr; 2124c52f0396Smrg double result = strtod(s, &endptr); 2125c52f0396Smrg if (s == endptr) 2126c52f0396Smrg usage(); 2127c52f0396Smrg return result; 2128c52f0396Smrg} 2129c52f0396Smrg 2130a0d3b6eaSmrgint 2131a0d3b6eaSmrgmain (int argc, char **argv) 2132a0d3b6eaSmrg{ 2133a0d3b6eaSmrg XRRScreenSize *sizes; 2134a0d3b6eaSmrg XRRScreenConfiguration *sc; 2135a0d3b6eaSmrg int nsize; 2136a0d3b6eaSmrg int nrate; 2137a0d3b6eaSmrg short *rates; 2138a0d3b6eaSmrg Status status = RRSetConfigFailed; 2139a0d3b6eaSmrg int rot = -1; 21408a16544fSmrg int query = False; 21418a16544fSmrg int action_requested = False; 2142a0d3b6eaSmrg Rotation rotation, current_rotation, rotations; 2143a0d3b6eaSmrg XEvent event; 2144a0d3b6eaSmrg XRRScreenChangeNotifyEvent *sce; 2145a0d3b6eaSmrg char *display_name = NULL; 2146a0d3b6eaSmrg int i, j; 2147a0d3b6eaSmrg SizeID current_size; 2148a0d3b6eaSmrg short current_rate; 2149c52f0396Smrg double rate = -1; 2150a0d3b6eaSmrg int size = -1; 2151a0d3b6eaSmrg int dirind = 0; 2152a0d3b6eaSmrg Bool setit = False; 2153a0d3b6eaSmrg Bool version = False; 2154a0d3b6eaSmrg int event_base, error_base; 2155a0d3b6eaSmrg int reflection = 0; 2156a0d3b6eaSmrg int width = 0, height = 0; 2157a0d3b6eaSmrg Bool have_pixel_size = False; 2158a0d3b6eaSmrg int ret = 0; 2159a0d3b6eaSmrg output_t *output = NULL; 2160a0d3b6eaSmrg Bool setit_1_2 = False; 2161a0d3b6eaSmrg Bool query_1_2 = False; 2162a0d3b6eaSmrg Bool modeit = False; 2163a0d3b6eaSmrg Bool propit = False; 2164a0d3b6eaSmrg Bool query_1 = False; 2165a0d3b6eaSmrg int major, minor; 216662df5ad0Smrg Bool current = False; 2167a0d3b6eaSmrg 2168a0d3b6eaSmrg program_name = argv[0]; 2169a0d3b6eaSmrg for (i = 1; i < argc; i++) { 2170a0d3b6eaSmrg if (!strcmp ("-display", argv[i]) || !strcmp ("-d", argv[i])) { 2171a0d3b6eaSmrg if (++i>=argc) usage (); 2172a0d3b6eaSmrg display_name = argv[i]; 2173a0d3b6eaSmrg continue; 2174a0d3b6eaSmrg } 2175a0d3b6eaSmrg if (!strcmp("-help", argv[i])) { 2176a0d3b6eaSmrg usage(); 21778a16544fSmrg action_requested = True; 2178a0d3b6eaSmrg continue; 2179a0d3b6eaSmrg } 2180a0d3b6eaSmrg if (!strcmp ("--verbose", argv[i])) { 2181a0d3b6eaSmrg verbose = True; 2182a0d3b6eaSmrg continue; 2183a0d3b6eaSmrg } 2184a0d3b6eaSmrg if (!strcmp ("--dryrun", argv[i])) { 2185a0d3b6eaSmrg dryrun = True; 2186a0d3b6eaSmrg verbose = True; 2187a0d3b6eaSmrg continue; 2188a0d3b6eaSmrg } 218962df5ad0Smrg if (!strcmp ("--nograb", argv[i])) { 219062df5ad0Smrg grab_server = False; 219162df5ad0Smrg continue; 219262df5ad0Smrg } 219362df5ad0Smrg if (!strcmp("--current", argv[i])) { 219462df5ad0Smrg current = True; 219562df5ad0Smrg continue; 219662df5ad0Smrg } 2197a0d3b6eaSmrg 2198a0d3b6eaSmrg if (!strcmp ("-s", argv[i]) || !strcmp ("--size", argv[i])) { 2199a0d3b6eaSmrg if (++i>=argc) usage (); 2200c52f0396Smrg if (sscanf (argv[i], "%dx%d", &width, &height) == 2) { 2201a0d3b6eaSmrg have_pixel_size = True; 2202c52f0396Smrg } else { 2203c52f0396Smrg size = check_strtol(argv[i]); 2204c52f0396Smrg if (size < 0) usage(); 2205c52f0396Smrg } 2206a0d3b6eaSmrg setit = True; 22078a16544fSmrg action_requested = True; 2208a0d3b6eaSmrg continue; 2209a0d3b6eaSmrg } 2210a0d3b6eaSmrg 2211a0d3b6eaSmrg if (!strcmp ("-r", argv[i]) || 2212a0d3b6eaSmrg !strcmp ("--rate", argv[i]) || 2213a0d3b6eaSmrg !strcmp ("--refresh", argv[i])) 2214a0d3b6eaSmrg { 2215a0d3b6eaSmrg if (++i>=argc) usage (); 2216c52f0396Smrg rate = check_strtod(argv[i]); 2217a0d3b6eaSmrg setit = True; 2218a0d3b6eaSmrg if (output) 2219a0d3b6eaSmrg { 2220a0d3b6eaSmrg output->refresh = rate; 2221a0d3b6eaSmrg output->changes |= changes_refresh; 2222a0d3b6eaSmrg setit_1_2 = True; 2223a0d3b6eaSmrg } 22248a16544fSmrg action_requested = True; 2225a0d3b6eaSmrg continue; 2226a0d3b6eaSmrg } 2227a0d3b6eaSmrg 2228a0d3b6eaSmrg if (!strcmp ("-v", argv[i]) || !strcmp ("--version", argv[i])) { 2229a0d3b6eaSmrg version = True; 22308a16544fSmrg action_requested = True; 2231a0d3b6eaSmrg continue; 2232a0d3b6eaSmrg } 2233a0d3b6eaSmrg 2234a0d3b6eaSmrg if (!strcmp ("-x", argv[i])) { 2235a0d3b6eaSmrg reflection |= RR_Reflect_X; 2236a0d3b6eaSmrg setit = True; 22378a16544fSmrg action_requested = True; 2238a0d3b6eaSmrg continue; 2239a0d3b6eaSmrg } 2240a0d3b6eaSmrg if (!strcmp ("-y", argv[i])) { 2241a0d3b6eaSmrg reflection |= RR_Reflect_Y; 2242a0d3b6eaSmrg setit = True; 22438a16544fSmrg action_requested = True; 2244a0d3b6eaSmrg continue; 2245a0d3b6eaSmrg } 2246a0d3b6eaSmrg if (!strcmp ("--screen", argv[i])) { 2247a0d3b6eaSmrg if (++i>=argc) usage (); 2248c52f0396Smrg screen = check_strtol(argv[i]); 2249a0d3b6eaSmrg if (screen < 0) usage(); 2250a0d3b6eaSmrg continue; 2251a0d3b6eaSmrg } 2252a0d3b6eaSmrg if (!strcmp ("-q", argv[i]) || !strcmp ("--query", argv[i])) { 2253a0d3b6eaSmrg query = True; 2254a0d3b6eaSmrg continue; 2255a0d3b6eaSmrg } 2256a0d3b6eaSmrg if (!strcmp ("-o", argv[i]) || !strcmp ("--orientation", argv[i])) { 2257a0d3b6eaSmrg char *endptr; 2258a0d3b6eaSmrg if (++i>=argc) usage (); 2259c52f0396Smrg dirind = strtol(argv[i], &endptr, 10); 2260c52f0396Smrg if (argv[i] == endptr) { 2261a0d3b6eaSmrg for (dirind = 0; dirind < 4; dirind++) { 2262a0d3b6eaSmrg if (strcmp (direction[dirind], argv[i]) == 0) break; 2263a0d3b6eaSmrg } 2264a0d3b6eaSmrg if ((dirind < 0) || (dirind > 3)) usage(); 2265a0d3b6eaSmrg } 2266a0d3b6eaSmrg rot = dirind; 2267a0d3b6eaSmrg setit = True; 22688a16544fSmrg action_requested = True; 2269a0d3b6eaSmrg continue; 2270a0d3b6eaSmrg } 227162df5ad0Smrg if (!strcmp ("--prop", argv[i]) || 227262df5ad0Smrg !strcmp ("--props", argv[i]) || 227362df5ad0Smrg !strcmp ("--madprops", argv[i]) || 227462df5ad0Smrg !strcmp ("--properties", argv[i])) 2275a0d3b6eaSmrg { 2276a0d3b6eaSmrg query_1_2 = True; 2277a0d3b6eaSmrg properties = True; 22788a16544fSmrg action_requested = True; 2279a0d3b6eaSmrg continue; 2280a0d3b6eaSmrg } 2281a0d3b6eaSmrg if (!strcmp ("--output", argv[i])) { 2282a0d3b6eaSmrg if (++i >= argc) usage(); 2283a0d3b6eaSmrg 2284a0d3b6eaSmrg output = find_output_by_name (argv[i]); 2285a0d3b6eaSmrg if (!output) { 2286a0d3b6eaSmrg output = add_output (); 2287a0d3b6eaSmrg set_name (&output->output, argv[i], name_string|name_xid); 2288a0d3b6eaSmrg } 2289a0d3b6eaSmrg 2290a0d3b6eaSmrg setit_1_2 = True; 22918a16544fSmrg action_requested = True; 2292a0d3b6eaSmrg continue; 2293a0d3b6eaSmrg } 2294a0d3b6eaSmrg if (!strcmp ("--crtc", argv[i])) { 2295a0d3b6eaSmrg if (++i >= argc) usage(); 2296a0d3b6eaSmrg if (!output) usage(); 2297a0d3b6eaSmrg set_name (&output->crtc, argv[i], name_xid|name_index); 2298a0d3b6eaSmrg output->changes |= changes_crtc; 2299a0d3b6eaSmrg continue; 2300a0d3b6eaSmrg } 2301a0d3b6eaSmrg if (!strcmp ("--mode", argv[i])) { 2302a0d3b6eaSmrg if (++i >= argc) usage(); 2303a0d3b6eaSmrg if (!output) usage(); 2304a0d3b6eaSmrg set_name (&output->mode, argv[i], name_string|name_xid); 2305a0d3b6eaSmrg output->changes |= changes_mode; 2306a0d3b6eaSmrg continue; 2307a0d3b6eaSmrg } 2308a0d3b6eaSmrg if (!strcmp ("--preferred", argv[i])) { 2309a0d3b6eaSmrg if (!output) usage(); 2310a0d3b6eaSmrg set_name_preferred (&output->mode); 2311a0d3b6eaSmrg output->changes |= changes_mode; 2312a0d3b6eaSmrg continue; 2313a0d3b6eaSmrg } 2314a0d3b6eaSmrg if (!strcmp ("--pos", argv[i])) { 2315a0d3b6eaSmrg if (++i>=argc) usage (); 2316a0d3b6eaSmrg if (!output) usage(); 2317a0d3b6eaSmrg if (sscanf (argv[i], "%dx%d", 2318a0d3b6eaSmrg &output->x, &output->y) != 2) 2319a0d3b6eaSmrg usage (); 2320a0d3b6eaSmrg output->changes |= changes_position; 2321a0d3b6eaSmrg continue; 2322a0d3b6eaSmrg } 2323a0d3b6eaSmrg if (!strcmp ("--rotation", argv[i]) || !strcmp ("--rotate", argv[i])) { 2324a0d3b6eaSmrg if (++i>=argc) usage (); 2325a0d3b6eaSmrg if (!output) usage(); 2326a0d3b6eaSmrg for (dirind = 0; dirind < 4; dirind++) { 2327a0d3b6eaSmrg if (strcmp (direction[dirind], argv[i]) == 0) break; 2328a0d3b6eaSmrg } 2329a0d3b6eaSmrg if (dirind == 4) 2330a0d3b6eaSmrg usage (); 2331a0d3b6eaSmrg output->rotation &= ~0xf; 2332a0d3b6eaSmrg output->rotation |= 1 << dirind; 2333a0d3b6eaSmrg output->changes |= changes_rotation; 2334a0d3b6eaSmrg continue; 2335a0d3b6eaSmrg } 2336a0d3b6eaSmrg if (!strcmp ("--reflect", argv[i]) || !strcmp ("--reflection", argv[i])) { 2337a0d3b6eaSmrg if (++i>=argc) usage (); 2338a0d3b6eaSmrg if (!output) usage(); 2339a0d3b6eaSmrg for (dirind = 0; dirind < 4; dirind++) { 2340a0d3b6eaSmrg if (strcmp (reflections[dirind], argv[i]) == 0) break; 2341a0d3b6eaSmrg } 2342a0d3b6eaSmrg if (dirind == 4) 2343a0d3b6eaSmrg usage (); 2344a0d3b6eaSmrg output->rotation &= ~(RR_Reflect_X|RR_Reflect_Y); 2345a0d3b6eaSmrg output->rotation |= dirind * RR_Reflect_X; 2346a0d3b6eaSmrg output->changes |= changes_reflection; 2347a0d3b6eaSmrg continue; 2348a0d3b6eaSmrg } 2349a0d3b6eaSmrg if (!strcmp ("--left-of", argv[i])) { 2350a0d3b6eaSmrg if (++i>=argc) usage (); 2351a0d3b6eaSmrg if (!output) usage(); 23528a16544fSmrg output->relation = relation_left_of; 2353a0d3b6eaSmrg output->relative_to = argv[i]; 2354a0d3b6eaSmrg output->changes |= changes_relation; 2355a0d3b6eaSmrg continue; 2356a0d3b6eaSmrg } 2357a0d3b6eaSmrg if (!strcmp ("--right-of", argv[i])) { 2358a0d3b6eaSmrg if (++i>=argc) usage (); 2359a0d3b6eaSmrg if (!output) usage(); 23608a16544fSmrg output->relation = relation_right_of; 2361a0d3b6eaSmrg output->relative_to = argv[i]; 2362a0d3b6eaSmrg output->changes |= changes_relation; 2363a0d3b6eaSmrg continue; 2364a0d3b6eaSmrg } 2365a0d3b6eaSmrg if (!strcmp ("--above", argv[i])) { 2366a0d3b6eaSmrg if (++i>=argc) usage (); 2367a0d3b6eaSmrg if (!output) usage(); 23688a16544fSmrg output->relation = relation_above; 2369a0d3b6eaSmrg output->relative_to = argv[i]; 2370a0d3b6eaSmrg output->changes |= changes_relation; 2371a0d3b6eaSmrg continue; 2372a0d3b6eaSmrg } 2373a0d3b6eaSmrg if (!strcmp ("--below", argv[i])) { 2374a0d3b6eaSmrg if (++i>=argc) usage (); 2375a0d3b6eaSmrg if (!output) usage(); 23768a16544fSmrg output->relation = relation_below; 2377a0d3b6eaSmrg output->relative_to = argv[i]; 2378a0d3b6eaSmrg output->changes |= changes_relation; 2379a0d3b6eaSmrg continue; 2380a0d3b6eaSmrg } 2381a0d3b6eaSmrg if (!strcmp ("--same-as", argv[i])) { 2382a0d3b6eaSmrg if (++i>=argc) usage (); 2383a0d3b6eaSmrg if (!output) usage(); 23848a16544fSmrg output->relation = relation_same_as; 2385a0d3b6eaSmrg output->relative_to = argv[i]; 2386a0d3b6eaSmrg output->changes |= changes_relation; 2387a0d3b6eaSmrg continue; 2388a0d3b6eaSmrg } 238962df5ad0Smrg if (!strcmp ("--panning", argv[i])) { 239062df5ad0Smrg XRRPanning *pan; 239162df5ad0Smrg if (++i>=argc) usage (); 239262df5ad0Smrg if (!output) usage(); 239362df5ad0Smrg pan = &output->panning; 239462df5ad0Smrg switch (sscanf (argv[i], "%dx%d+%d+%d/%dx%d+%d+%d/%d/%d/%d/%d", 239562df5ad0Smrg &pan->width, &pan->height, &pan->left, &pan->top, 239662df5ad0Smrg &pan->track_width, &pan->track_height, 239762df5ad0Smrg &pan->track_left, &pan->track_top, 239862df5ad0Smrg &pan->border_left, &pan->border_top, 239962df5ad0Smrg &pan->border_right, &pan->border_bottom)) { 240062df5ad0Smrg case 2: 240162df5ad0Smrg pan->left = pan->top = 0; 240262df5ad0Smrg /* fall through */ 240362df5ad0Smrg case 4: 240462df5ad0Smrg pan->track_left = pan->track_top = 240562df5ad0Smrg pan->track_width = pan->track_height = 0; 240662df5ad0Smrg /* fall through */ 240762df5ad0Smrg case 8: 240862df5ad0Smrg pan->border_left = pan->border_top = 240962df5ad0Smrg pan->border_right = pan->border_bottom = 0; 241062df5ad0Smrg /* fall through */ 241162df5ad0Smrg case 12: 241262df5ad0Smrg break; 241362df5ad0Smrg default: 241462df5ad0Smrg usage (); 241562df5ad0Smrg } 241662df5ad0Smrg output->changes |= changes_panning; 241762df5ad0Smrg continue; 241862df5ad0Smrg } 241962df5ad0Smrg if (!strcmp ("--gamma", argv[i])) { 242062df5ad0Smrg if (!output) usage(); 242162df5ad0Smrg if (++i>=argc) usage (); 242262df5ad0Smrg if (sscanf(argv[i], "%f:%f:%f", &output->gamma.red, 242362df5ad0Smrg &output->gamma.green, &output->gamma.blue) != 3) 242462df5ad0Smrg usage (); 242562df5ad0Smrg output->changes |= changes_gamma; 242662df5ad0Smrg setit_1_2 = True; 242762df5ad0Smrg continue; 242862df5ad0Smrg } 24298a16544fSmrg if (!strcmp ("--brightness", argv[i])) { 24308a16544fSmrg if (!output) usage(); 24318a16544fSmrg if (++i>=argc) usage(); 24328a16544fSmrg if (sscanf(argv[i], "%f", &output->brightness) != 1) 24338a16544fSmrg usage (); 24348a16544fSmrg output->changes |= changes_gamma; 24358a16544fSmrg setit_1_2 = True; 24368a16544fSmrg continue; 24378a16544fSmrg } 243862df5ad0Smrg if (!strcmp ("--primary", argv[i])) { 243962df5ad0Smrg if (!output) usage(); 244062df5ad0Smrg output->changes |= changes_primary; 244162df5ad0Smrg output->primary = True; 244262df5ad0Smrg setit_1_2 = True; 244362df5ad0Smrg continue; 244462df5ad0Smrg } 244562df5ad0Smrg if (!strcmp ("--noprimary", argv[i])) { 244662df5ad0Smrg no_primary = True; 244762df5ad0Smrg setit_1_2 = True; 244862df5ad0Smrg continue; 244962df5ad0Smrg } 2450a0d3b6eaSmrg if (!strcmp ("--set", argv[i])) { 2451a0d3b6eaSmrg output_prop_t *prop; 2452a0d3b6eaSmrg if (!output) usage(); 2453a0d3b6eaSmrg prop = malloc (sizeof (output_prop_t)); 2454a0d3b6eaSmrg prop->next = output->props; 2455a0d3b6eaSmrg output->props = prop; 2456a0d3b6eaSmrg if (++i>=argc) usage (); 2457a0d3b6eaSmrg prop->name = argv[i]; 2458a0d3b6eaSmrg if (++i>=argc) usage (); 2459a0d3b6eaSmrg prop->value = argv[i]; 2460a0d3b6eaSmrg propit = True; 2461a0d3b6eaSmrg output->changes |= changes_property; 2462a0d3b6eaSmrg setit_1_2 = True; 2463a0d3b6eaSmrg continue; 2464a0d3b6eaSmrg } 246562df5ad0Smrg if (!strcmp ("--scale", argv[i])) 246662df5ad0Smrg { 246762df5ad0Smrg double sx, sy; 24688a16544fSmrg if (!output) usage(); 246962df5ad0Smrg if (++i>=argc) usage(); 247062df5ad0Smrg if (sscanf (argv[i], "%lfx%lf", &sx, &sy) != 2) 247162df5ad0Smrg usage (); 247262df5ad0Smrg init_transform (&output->transform); 247362df5ad0Smrg output->transform.transform.matrix[0][0] = XDoubleToFixed (sx); 247462df5ad0Smrg output->transform.transform.matrix[1][1] = XDoubleToFixed (sy); 247562df5ad0Smrg output->transform.transform.matrix[2][2] = XDoubleToFixed (1.0); 247662df5ad0Smrg if (sx != 1 || sy != 1) 247762df5ad0Smrg output->transform.filter = "bilinear"; 247862df5ad0Smrg else 247962df5ad0Smrg output->transform.filter = "nearest"; 248062df5ad0Smrg output->transform.nparams = 0; 248162df5ad0Smrg output->transform.params = NULL; 248262df5ad0Smrg output->changes |= changes_transform; 248362df5ad0Smrg continue; 248462df5ad0Smrg } 248562df5ad0Smrg if (!strcmp ("--transform", argv[i])) { 248662df5ad0Smrg double transform[3][3]; 248762df5ad0Smrg int k, l; 24888a16544fSmrg if (!output) usage(); 248962df5ad0Smrg if (++i>=argc) usage (); 249062df5ad0Smrg init_transform (&output->transform); 249162df5ad0Smrg if (strcmp (argv[i], "none") != 0) 249262df5ad0Smrg { 249362df5ad0Smrg if (sscanf(argv[i], "%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf", 249462df5ad0Smrg &transform[0][0],&transform[0][1],&transform[0][2], 249562df5ad0Smrg &transform[1][0],&transform[1][1],&transform[1][2], 249662df5ad0Smrg &transform[2][0],&transform[2][1],&transform[2][2]) 249762df5ad0Smrg != 9) 249862df5ad0Smrg usage (); 249962df5ad0Smrg init_transform (&output->transform); 250062df5ad0Smrg for (k = 0; k < 3; k++) 250162df5ad0Smrg for (l = 0; l < 3; l++) { 250262df5ad0Smrg output->transform.transform.matrix[k][l] = XDoubleToFixed (transform[k][l]); 250362df5ad0Smrg } 250462df5ad0Smrg output->transform.filter = "bilinear"; 250562df5ad0Smrg output->transform.nparams = 0; 250662df5ad0Smrg output->transform.params = NULL; 250762df5ad0Smrg } 250862df5ad0Smrg output->changes |= changes_transform; 250962df5ad0Smrg continue; 251062df5ad0Smrg } 2511a0d3b6eaSmrg if (!strcmp ("--off", argv[i])) { 2512a0d3b6eaSmrg if (!output) usage(); 2513a0d3b6eaSmrg set_name_xid (&output->mode, None); 2514a0d3b6eaSmrg set_name_xid (&output->crtc, None); 2515a0d3b6eaSmrg output->changes |= changes_mode; 2516a0d3b6eaSmrg continue; 2517a0d3b6eaSmrg } 2518a0d3b6eaSmrg if (!strcmp ("--fb", argv[i])) { 2519a0d3b6eaSmrg if (++i>=argc) usage (); 2520a0d3b6eaSmrg if (sscanf (argv[i], "%dx%d", 2521a0d3b6eaSmrg &fb_width, &fb_height) != 2) 2522a0d3b6eaSmrg usage (); 2523a0d3b6eaSmrg setit_1_2 = True; 25248a16544fSmrg action_requested = True; 2525a0d3b6eaSmrg continue; 2526a0d3b6eaSmrg } 2527a0d3b6eaSmrg if (!strcmp ("--fbmm", argv[i])) { 2528a0d3b6eaSmrg if (++i>=argc) usage (); 2529a0d3b6eaSmrg if (sscanf (argv[i], "%dx%d", 2530a0d3b6eaSmrg &fb_width_mm, &fb_height_mm) != 2) 2531a0d3b6eaSmrg usage (); 2532a0d3b6eaSmrg setit_1_2 = True; 25338a16544fSmrg action_requested = True; 2534a0d3b6eaSmrg continue; 2535a0d3b6eaSmrg } 2536a0d3b6eaSmrg if (!strcmp ("--dpi", argv[i])) { 2537c52f0396Smrg char *strtod_error; 2538a0d3b6eaSmrg if (++i>=argc) usage (); 2539c52f0396Smrg dpi = strtod(argv[i], &strtod_error); 2540c52f0396Smrg if (argv[i] == strtod_error) 2541a0d3b6eaSmrg { 2542a0d3b6eaSmrg dpi = 0.0; 2543a0d3b6eaSmrg dpi_output = argv[i]; 2544a0d3b6eaSmrg } 2545a0d3b6eaSmrg setit_1_2 = True; 25468a16544fSmrg action_requested = True; 2547a0d3b6eaSmrg continue; 2548a0d3b6eaSmrg } 2549a0d3b6eaSmrg if (!strcmp ("--auto", argv[i])) { 2550a0d3b6eaSmrg if (output) 2551a0d3b6eaSmrg { 2552a0d3b6eaSmrg output->automatic = True; 2553a0d3b6eaSmrg output->changes |= changes_automatic; 2554a0d3b6eaSmrg } 2555a0d3b6eaSmrg else 2556a0d3b6eaSmrg automatic = True; 2557a0d3b6eaSmrg setit_1_2 = True; 25588a16544fSmrg action_requested = True; 2559a0d3b6eaSmrg continue; 2560a0d3b6eaSmrg } 2561a0d3b6eaSmrg if (!strcmp ("--q12", argv[i])) 2562a0d3b6eaSmrg { 2563a0d3b6eaSmrg query_1_2 = True; 2564a0d3b6eaSmrg continue; 2565a0d3b6eaSmrg } 2566a0d3b6eaSmrg if (!strcmp ("--q1", argv[i])) 2567a0d3b6eaSmrg { 2568a0d3b6eaSmrg query_1 = True; 2569a0d3b6eaSmrg continue; 2570a0d3b6eaSmrg } 2571a0d3b6eaSmrg if (!strcmp ("--newmode", argv[i])) 2572a0d3b6eaSmrg { 2573a0d3b6eaSmrg umode_t *m = malloc (sizeof (umode_t)); 2574c52f0396Smrg double clock; 2575a0d3b6eaSmrg 2576a0d3b6eaSmrg ++i; 2577a0d3b6eaSmrg if (i + 9 >= argc) usage (); 2578a0d3b6eaSmrg m->mode.name = argv[i]; 2579a0d3b6eaSmrg m->mode.nameLength = strlen (argv[i]); 2580a0d3b6eaSmrg i++; 2581c52f0396Smrg clock = check_strtod(argv[i++]); 2582a0d3b6eaSmrg m->mode.dotClock = clock * 1e6; 2583a0d3b6eaSmrg 2584c52f0396Smrg m->mode.width = check_strtol(argv[i++]); 2585c52f0396Smrg m->mode.hSyncStart = check_strtol(argv[i++]); 2586c52f0396Smrg m->mode.hSyncEnd = check_strtol(argv[i++]); 2587c52f0396Smrg m->mode.hTotal = check_strtol(argv[i++]); 2588c52f0396Smrg m->mode.height = check_strtol(argv[i++]); 2589c52f0396Smrg m->mode.vSyncStart = check_strtol(argv[i++]); 2590c52f0396Smrg m->mode.vSyncEnd = check_strtol(argv[i++]); 2591c52f0396Smrg m->mode.vTotal = check_strtol(argv[i++]); 2592a0d3b6eaSmrg m->mode.modeFlags = 0; 2593a0d3b6eaSmrg while (i < argc) { 2594a0d3b6eaSmrg int f; 2595a0d3b6eaSmrg 2596a0d3b6eaSmrg for (f = 0; mode_flags[f].string; f++) 2597a0d3b6eaSmrg if (!strcasecmp (mode_flags[f].string, argv[i])) 2598a0d3b6eaSmrg break; 2599a0d3b6eaSmrg 2600a0d3b6eaSmrg if (!mode_flags[f].string) 2601a0d3b6eaSmrg break; 2602a0d3b6eaSmrg m->mode.modeFlags |= mode_flags[f].flag; 2603a0d3b6eaSmrg i++; 2604a0d3b6eaSmrg } 2605a0d3b6eaSmrg m->next = umodes; 2606a0d3b6eaSmrg m->action = umode_create; 2607a0d3b6eaSmrg umodes = m; 2608a0d3b6eaSmrg modeit = True; 26098a16544fSmrg action_requested = True; 2610a0d3b6eaSmrg continue; 2611a0d3b6eaSmrg } 2612a0d3b6eaSmrg if (!strcmp ("--rmmode", argv[i])) 2613a0d3b6eaSmrg { 2614a0d3b6eaSmrg umode_t *m = malloc (sizeof (umode_t)); 2615a0d3b6eaSmrg 2616a0d3b6eaSmrg if (++i>=argc) usage (); 2617a0d3b6eaSmrg set_name (&m->name, argv[i], name_string|name_xid); 2618a0d3b6eaSmrg m->action = umode_destroy; 2619a0d3b6eaSmrg m->next = umodes; 2620a0d3b6eaSmrg umodes = m; 2621a0d3b6eaSmrg modeit = True; 26228a16544fSmrg action_requested = True; 2623a0d3b6eaSmrg continue; 2624a0d3b6eaSmrg } 2625a0d3b6eaSmrg if (!strcmp ("--addmode", argv[i])) 2626a0d3b6eaSmrg { 2627a0d3b6eaSmrg umode_t *m = malloc (sizeof (umode_t)); 2628a0d3b6eaSmrg 2629a0d3b6eaSmrg if (++i>=argc) usage (); 2630a0d3b6eaSmrg set_name (&m->output, argv[i], name_string|name_xid); 2631a0d3b6eaSmrg if (++i>=argc) usage(); 2632a0d3b6eaSmrg set_name (&m->name, argv[i], name_string|name_xid); 2633a0d3b6eaSmrg m->action = umode_add; 2634a0d3b6eaSmrg m->next = umodes; 2635a0d3b6eaSmrg umodes = m; 2636a0d3b6eaSmrg modeit = True; 26378a16544fSmrg action_requested = True; 2638a0d3b6eaSmrg continue; 2639a0d3b6eaSmrg } 2640a0d3b6eaSmrg if (!strcmp ("--delmode", argv[i])) 2641a0d3b6eaSmrg { 2642a0d3b6eaSmrg umode_t *m = malloc (sizeof (umode_t)); 2643a0d3b6eaSmrg 2644a0d3b6eaSmrg if (++i>=argc) usage (); 2645a0d3b6eaSmrg set_name (&m->output, argv[i], name_string|name_xid); 2646a0d3b6eaSmrg if (++i>=argc) usage(); 2647a0d3b6eaSmrg set_name (&m->name, argv[i], name_string|name_xid); 2648a0d3b6eaSmrg m->action = umode_delete; 2649a0d3b6eaSmrg m->next = umodes; 2650a0d3b6eaSmrg umodes = m; 2651a0d3b6eaSmrg modeit = True; 26528a16544fSmrg action_requested = True; 2653a0d3b6eaSmrg continue; 2654a0d3b6eaSmrg } 2655a0d3b6eaSmrg usage(); 2656a0d3b6eaSmrg } 26578a16544fSmrg if (!action_requested) 26588a16544fSmrg query = True; 2659a0d3b6eaSmrg if (verbose) 2660a0d3b6eaSmrg { 2661a0d3b6eaSmrg query = True; 2662a0d3b6eaSmrg if (setit && !setit_1_2) 2663a0d3b6eaSmrg query_1 = True; 2664a0d3b6eaSmrg } 266562770414Smrg if (version) 266662770414Smrg printf("xrandr program version " VERSION "\n"); 2667a0d3b6eaSmrg 2668a0d3b6eaSmrg dpy = XOpenDisplay (display_name); 2669a0d3b6eaSmrg 2670a0d3b6eaSmrg if (dpy == NULL) { 2671a0d3b6eaSmrg fprintf (stderr, "Can't open display %s\n", XDisplayName(display_name)); 2672a0d3b6eaSmrg exit (1); 2673a0d3b6eaSmrg } 2674a0d3b6eaSmrg if (screen < 0) 2675a0d3b6eaSmrg screen = DefaultScreen (dpy); 2676a0d3b6eaSmrg if (screen >= ScreenCount (dpy)) { 2677a0d3b6eaSmrg fprintf (stderr, "Invalid screen number %d (display has %d)\n", 2678a0d3b6eaSmrg screen, ScreenCount (dpy)); 2679a0d3b6eaSmrg exit (1); 2680a0d3b6eaSmrg } 2681a0d3b6eaSmrg 2682a0d3b6eaSmrg root = RootWindow (dpy, screen); 2683a0d3b6eaSmrg 2684ea024c75Smrg if (!XRRQueryExtension (dpy, &event_base, &error_base) || 2685ea024c75Smrg !XRRQueryVersion (dpy, &major, &minor)) 2686a0d3b6eaSmrg { 2687a0d3b6eaSmrg fprintf (stderr, "RandR extension missing\n"); 2688a0d3b6eaSmrg exit (1); 2689a0d3b6eaSmrg } 2690a0d3b6eaSmrg if (major > 1 || (major == 1 && minor >= 2)) 2691a0d3b6eaSmrg has_1_2 = True; 269262df5ad0Smrg if (major > 1 || (major == 1 && minor >= 3)) 269362df5ad0Smrg has_1_3 = True; 2694a0d3b6eaSmrg 2695a0d3b6eaSmrg if (has_1_2 && modeit) 2696a0d3b6eaSmrg { 2697a0d3b6eaSmrg umode_t *m; 2698a0d3b6eaSmrg 269962df5ad0Smrg get_screen (current); 2700a0d3b6eaSmrg get_crtcs(); 2701a0d3b6eaSmrg get_outputs(); 2702a0d3b6eaSmrg 2703a0d3b6eaSmrg for (m = umodes; m; m = m->next) 2704a0d3b6eaSmrg { 2705a0d3b6eaSmrg XRRModeInfo *e; 2706a0d3b6eaSmrg output_t *o; 2707a0d3b6eaSmrg 2708a0d3b6eaSmrg switch (m->action) { 2709a0d3b6eaSmrg case umode_create: 2710a0d3b6eaSmrg XRRCreateMode (dpy, root, &m->mode); 2711a0d3b6eaSmrg break; 2712a0d3b6eaSmrg case umode_destroy: 2713a0d3b6eaSmrg e = find_mode (&m->name, 0); 2714a0d3b6eaSmrg if (!e) 2715a0d3b6eaSmrg fatal ("cannot find mode \"%s\"\n", m->name.string); 2716a0d3b6eaSmrg XRRDestroyMode (dpy, e->id); 2717a0d3b6eaSmrg break; 2718a0d3b6eaSmrg case umode_add: 2719a0d3b6eaSmrg o = find_output (&m->output); 2720a0d3b6eaSmrg if (!o) 2721a0d3b6eaSmrg fatal ("cannot find output \"%s\"\n", m->output.string); 2722a0d3b6eaSmrg e = find_mode (&m->name, 0); 2723a0d3b6eaSmrg if (!e) 2724a0d3b6eaSmrg fatal ("cannot find mode \"%s\"\n", m->name.string); 2725a0d3b6eaSmrg XRRAddOutputMode (dpy, o->output.xid, e->id); 2726a0d3b6eaSmrg break; 2727a0d3b6eaSmrg case umode_delete: 2728a0d3b6eaSmrg o = find_output (&m->output); 2729a0d3b6eaSmrg if (!o) 2730a0d3b6eaSmrg fatal ("cannot find output \"%s\"\n", m->output.string); 2731a0d3b6eaSmrg e = find_mode (&m->name, 0); 2732a0d3b6eaSmrg if (!e) 2733a0d3b6eaSmrg fatal ("cannot find mode \"%s\"\n", m->name.string); 2734a0d3b6eaSmrg XRRDeleteOutputMode (dpy, o->output.xid, e->id); 2735a0d3b6eaSmrg break; 2736a0d3b6eaSmrg } 2737a0d3b6eaSmrg } 2738a0d3b6eaSmrg if (!setit_1_2) 2739a0d3b6eaSmrg { 2740a0d3b6eaSmrg XSync (dpy, False); 2741a0d3b6eaSmrg exit (0); 2742a0d3b6eaSmrg } 2743a0d3b6eaSmrg } 2744a0d3b6eaSmrg if (has_1_2 && propit) 2745a0d3b6eaSmrg { 2746a0d3b6eaSmrg 274762df5ad0Smrg get_screen (current); 2748a0d3b6eaSmrg get_crtcs(); 2749a0d3b6eaSmrg get_outputs(); 2750a0d3b6eaSmrg 2751a0d3b6eaSmrg for (output = outputs; output; output = output->next) 2752a0d3b6eaSmrg { 2753a0d3b6eaSmrg output_prop_t *prop; 2754a0d3b6eaSmrg 2755a0d3b6eaSmrg for (prop = output->props; prop; prop = prop->next) 2756a0d3b6eaSmrg { 2757a0d3b6eaSmrg Atom name = XInternAtom (dpy, prop->name, False); 2758a0d3b6eaSmrg Atom type; 2759a0d3b6eaSmrg int format; 2760a0d3b6eaSmrg unsigned char *data; 2761a0d3b6eaSmrg int nelements; 2762a0d3b6eaSmrg int int_value; 2763a0d3b6eaSmrg unsigned long ulong_value; 2764a0d3b6eaSmrg unsigned char *prop_data; 2765a0d3b6eaSmrg int actual_format; 2766a0d3b6eaSmrg unsigned long nitems, bytes_after; 2767a0d3b6eaSmrg Atom actual_type; 2768a0d3b6eaSmrg XRRPropertyInfo *propinfo; 2769a0d3b6eaSmrg 2770a0d3b6eaSmrg type = AnyPropertyType; 2771a0d3b6eaSmrg format=0; 2772a0d3b6eaSmrg 2773a0d3b6eaSmrg if (XRRGetOutputProperty (dpy, output->output.xid, name, 2774a0d3b6eaSmrg 0, 100, False, False, 2775a0d3b6eaSmrg AnyPropertyType, 2776a0d3b6eaSmrg &actual_type, &actual_format, 2777a0d3b6eaSmrg &nitems, &bytes_after, &prop_data) == Success && 2778a0d3b6eaSmrg 2779a0d3b6eaSmrg (propinfo = XRRQueryOutputProperty(dpy, output->output.xid, 2780a0d3b6eaSmrg name))) 2781a0d3b6eaSmrg { 2782a0d3b6eaSmrg type = actual_type; 2783a0d3b6eaSmrg format = actual_format; 2784a0d3b6eaSmrg } 2785a0d3b6eaSmrg 2786a0d3b6eaSmrg if ((type == XA_INTEGER || type == AnyPropertyType) && 2787a0d3b6eaSmrg (sscanf (prop->value, "%d", &int_value) == 1 || 2788a0d3b6eaSmrg sscanf (prop->value, "0x%x", &int_value) == 1)) 2789a0d3b6eaSmrg { 2790a0d3b6eaSmrg type = XA_INTEGER; 2791a0d3b6eaSmrg ulong_value = int_value; 2792a0d3b6eaSmrg data = (unsigned char *) &ulong_value; 2793a0d3b6eaSmrg nelements = 1; 2794a0d3b6eaSmrg format = 32; 2795a0d3b6eaSmrg } 2796a0d3b6eaSmrg else if ((type == XA_ATOM)) 2797a0d3b6eaSmrg { 2798a0d3b6eaSmrg ulong_value = XInternAtom (dpy, prop->value, False); 2799a0d3b6eaSmrg data = (unsigned char *) &ulong_value; 2800a0d3b6eaSmrg nelements = 1; 2801a0d3b6eaSmrg format = 32; 2802a0d3b6eaSmrg } 2803a0d3b6eaSmrg else if ((type == XA_STRING || type == AnyPropertyType)) 2804a0d3b6eaSmrg { 2805a0d3b6eaSmrg type = XA_STRING; 2806a0d3b6eaSmrg data = (unsigned char *) prop->value; 2807a0d3b6eaSmrg nelements = strlen (prop->value); 2808a0d3b6eaSmrg format = 8; 2809a0d3b6eaSmrg } 281062df5ad0Smrg else 281162df5ad0Smrg continue; 2812a0d3b6eaSmrg XRRChangeOutputProperty (dpy, output->output.xid, 2813a0d3b6eaSmrg name, type, format, PropModeReplace, 2814a0d3b6eaSmrg data, nelements); 2815a0d3b6eaSmrg } 2816a0d3b6eaSmrg } 2817a0d3b6eaSmrg if (!setit_1_2) 2818a0d3b6eaSmrg { 2819a0d3b6eaSmrg XSync (dpy, False); 2820a0d3b6eaSmrg exit (0); 2821a0d3b6eaSmrg } 2822a0d3b6eaSmrg } 2823a0d3b6eaSmrg if (setit_1_2) 2824a0d3b6eaSmrg { 282562df5ad0Smrg get_screen (current); 2826a0d3b6eaSmrg get_crtcs (); 2827a0d3b6eaSmrg get_outputs (); 2828a0d3b6eaSmrg set_positions (); 2829a0d3b6eaSmrg set_screen_size (); 2830a0d3b6eaSmrg 2831a0d3b6eaSmrg pick_crtcs (); 2832a0d3b6eaSmrg 2833a0d3b6eaSmrg /* 2834a0d3b6eaSmrg * Assign outputs to crtcs 2835a0d3b6eaSmrg */ 2836a0d3b6eaSmrg set_crtcs (); 2837a0d3b6eaSmrg 2838a0d3b6eaSmrg /* 2839a0d3b6eaSmrg * Mark changing crtcs 2840a0d3b6eaSmrg */ 2841a0d3b6eaSmrg mark_changing_crtcs (); 2842a0d3b6eaSmrg 2843a0d3b6eaSmrg /* 2844a0d3b6eaSmrg * If an output was specified to track dpi, use it 2845a0d3b6eaSmrg */ 2846a0d3b6eaSmrg if (dpi_output) 2847a0d3b6eaSmrg { 2848a0d3b6eaSmrg output_t *output = find_output_by_name (dpi_output); 2849a0d3b6eaSmrg XRROutputInfo *output_info; 2850a0d3b6eaSmrg XRRModeInfo *mode_info; 2851a0d3b6eaSmrg if (!output) 2852a0d3b6eaSmrg fatal ("Cannot find output %s\n", dpi_output); 2853a0d3b6eaSmrg output_info = output->output_info; 2854a0d3b6eaSmrg mode_info = output->mode_info; 2855a0d3b6eaSmrg if (output_info && mode_info && output_info->mm_height) 2856a0d3b6eaSmrg { 2857a0d3b6eaSmrg /* 2858a0d3b6eaSmrg * When this output covers the whole screen, just use 2859a0d3b6eaSmrg * the known physical size 2860a0d3b6eaSmrg */ 2861a0d3b6eaSmrg if (fb_width == mode_info->width && 2862a0d3b6eaSmrg fb_height == mode_info->height) 2863a0d3b6eaSmrg { 2864a0d3b6eaSmrg fb_width_mm = output_info->mm_width; 2865a0d3b6eaSmrg fb_height_mm = output_info->mm_height; 2866a0d3b6eaSmrg } 2867a0d3b6eaSmrg else 2868a0d3b6eaSmrg { 2869a0d3b6eaSmrg dpi = (25.4 * mode_info->height) / output_info->mm_height; 2870a0d3b6eaSmrg } 2871a0d3b6eaSmrg } 2872a0d3b6eaSmrg } 2873a0d3b6eaSmrg 2874a0d3b6eaSmrg /* 2875a0d3b6eaSmrg * Compute physical screen size 2876a0d3b6eaSmrg */ 2877a0d3b6eaSmrg if (fb_width_mm == 0 || fb_height_mm == 0) 2878a0d3b6eaSmrg { 2879a0d3b6eaSmrg if (fb_width != DisplayWidth (dpy, screen) || 2880a0d3b6eaSmrg fb_height != DisplayHeight (dpy, screen) || dpi != 0.0) 2881a0d3b6eaSmrg { 2882a0d3b6eaSmrg if (dpi <= 0) 2883a0d3b6eaSmrg dpi = (25.4 * DisplayHeight (dpy, screen)) / DisplayHeightMM(dpy, screen); 2884a0d3b6eaSmrg 2885a0d3b6eaSmrg fb_width_mm = (25.4 * fb_width) / dpi; 2886a0d3b6eaSmrg fb_height_mm = (25.4 * fb_height) / dpi; 2887a0d3b6eaSmrg } 2888a0d3b6eaSmrg else 2889a0d3b6eaSmrg { 2890a0d3b6eaSmrg fb_width_mm = DisplayWidthMM (dpy, screen); 2891a0d3b6eaSmrg fb_height_mm = DisplayHeightMM (dpy, screen); 2892a0d3b6eaSmrg } 2893a0d3b6eaSmrg } 2894a0d3b6eaSmrg 289562df5ad0Smrg /* 289662df5ad0Smrg * Set panning 289762df5ad0Smrg */ 289862df5ad0Smrg set_panning (); 289962df5ad0Smrg 290062df5ad0Smrg /* 290162df5ad0Smrg * Set gamma on crtc's that belong to the outputs. 290262df5ad0Smrg */ 290362df5ad0Smrg set_gamma (); 290462df5ad0Smrg 2905a0d3b6eaSmrg /* 2906a0d3b6eaSmrg * Now apply all of the changes 2907a0d3b6eaSmrg */ 2908a0d3b6eaSmrg apply (); 2909a0d3b6eaSmrg 2910a0d3b6eaSmrg XSync (dpy, False); 2911a0d3b6eaSmrg exit (0); 2912a0d3b6eaSmrg } 2913a0d3b6eaSmrg if (query_1_2 || (query && has_1_2 && !query_1)) 2914a0d3b6eaSmrg { 2915a0d3b6eaSmrg output_t *output; 2916a0d3b6eaSmrg int m; 2917a0d3b6eaSmrg 2918a0d3b6eaSmrg#define ModeShown 0x80000000 2919a0d3b6eaSmrg 292062df5ad0Smrg get_screen (current); 2921a0d3b6eaSmrg get_crtcs (); 2922a0d3b6eaSmrg get_outputs (); 2923a0d3b6eaSmrg 2924a0d3b6eaSmrg printf ("Screen %d: minimum %d x %d, current %d x %d, maximum %d x %d\n", 2925a0d3b6eaSmrg screen, minWidth, minHeight, 2926a0d3b6eaSmrg DisplayWidth (dpy, screen), DisplayHeight(dpy, screen), 2927a0d3b6eaSmrg maxWidth, maxHeight); 2928a0d3b6eaSmrg 2929a0d3b6eaSmrg for (output = outputs; output; output = output->next) 2930a0d3b6eaSmrg { 2931a0d3b6eaSmrg XRROutputInfo *output_info = output->output_info; 293262df5ad0Smrg crtc_t *crtc = output->crtc_info; 293362df5ad0Smrg XRRCrtcInfo *crtc_info = crtc ? crtc->crtc_info : NULL; 2934a0d3b6eaSmrg XRRModeInfo *mode = output->mode_info; 2935a0d3b6eaSmrg Atom *props; 2936a0d3b6eaSmrg int j, k, nprop; 2937a0d3b6eaSmrg Bool *mode_shown; 2938a0d3b6eaSmrg Rotation rotations = output_rotations (output); 2939a0d3b6eaSmrg 2940a0d3b6eaSmrg printf ("%s %s", output_info->name, connection[output_info->connection]); 2941a0d3b6eaSmrg if (mode) 2942a0d3b6eaSmrg { 294362df5ad0Smrg if (crtc_info) { 294462df5ad0Smrg printf (" %dx%d+%d+%d", 294562df5ad0Smrg crtc_info->width, crtc_info->height, 294662df5ad0Smrg crtc_info->x, crtc_info->y); 294762df5ad0Smrg } else { 294862df5ad0Smrg printf (" %dx%d+%d+%d", 294962df5ad0Smrg mode->width, mode->height, output->x, output->y); 295062df5ad0Smrg } 2951a0d3b6eaSmrg if (verbose) 295262df5ad0Smrg printf (" (0x%x)", (int)mode->id); 2953a0d3b6eaSmrg if (output->rotation != RR_Rotate_0 || verbose) 2954a0d3b6eaSmrg { 2955a0d3b6eaSmrg printf (" %s", 2956a0d3b6eaSmrg rotation_name (output->rotation)); 2957a0d3b6eaSmrg if (output->rotation & (RR_Reflect_X|RR_Reflect_Y)) 2958a0d3b6eaSmrg printf (" %s", reflection_name (output->rotation)); 2959a0d3b6eaSmrg } 2960a0d3b6eaSmrg } 2961a0d3b6eaSmrg if (rotations != RR_Rotate_0 || verbose) 2962a0d3b6eaSmrg { 2963a0d3b6eaSmrg Bool first = True; 2964a0d3b6eaSmrg printf (" ("); 2965a0d3b6eaSmrg for (i = 0; i < 4; i ++) { 2966a0d3b6eaSmrg if ((rotations >> i) & 1) { 2967a0d3b6eaSmrg if (!first) printf (" "); first = False; 2968a0d3b6eaSmrg printf("%s", direction[i]); 2969a0d3b6eaSmrg first = False; 2970a0d3b6eaSmrg } 2971a0d3b6eaSmrg } 2972a0d3b6eaSmrg if (rotations & RR_Reflect_X) 2973a0d3b6eaSmrg { 2974a0d3b6eaSmrg if (!first) printf (" "); first = False; 2975a0d3b6eaSmrg printf ("x axis"); 2976a0d3b6eaSmrg } 2977a0d3b6eaSmrg if (rotations & RR_Reflect_Y) 2978a0d3b6eaSmrg { 2979a0d3b6eaSmrg if (!first) printf (" "); first = False; 2980a0d3b6eaSmrg printf ("y axis"); 2981a0d3b6eaSmrg } 2982a0d3b6eaSmrg printf (")"); 2983a0d3b6eaSmrg } 2984a0d3b6eaSmrg 2985a0d3b6eaSmrg if (mode) 2986a0d3b6eaSmrg { 2987a0d3b6eaSmrg printf (" %dmm x %dmm", 298862df5ad0Smrg (int)output_info->mm_width, (int)output_info->mm_height); 298962df5ad0Smrg } 299062df5ad0Smrg 299162df5ad0Smrg if (crtc && crtc->panning_info && crtc->panning_info->width > 0) 299262df5ad0Smrg { 299362df5ad0Smrg XRRPanning *pan = crtc->panning_info; 299462df5ad0Smrg printf (" panning %dx%d+%d+%d", 299562df5ad0Smrg pan->width, pan->height, pan->left, pan->top); 299662df5ad0Smrg if ((pan->track_width != 0 && 299762df5ad0Smrg (pan->track_left != pan->left || 299862df5ad0Smrg pan->track_width != pan->width || 299962df5ad0Smrg pan->border_left != 0 || 300062df5ad0Smrg pan->border_right != 0)) || 300162df5ad0Smrg (pan->track_height != 0 && 300262df5ad0Smrg (pan->track_top != pan->top || 300362df5ad0Smrg pan->track_height != pan->height || 300462df5ad0Smrg pan->border_top != 0 || 300562df5ad0Smrg pan->border_bottom != 0))) 300662df5ad0Smrg printf (" tracking %dx%d+%d+%d border %d/%d/%d/%d", 300762df5ad0Smrg pan->track_width, pan->track_height, 300862df5ad0Smrg pan->track_left, pan->track_top, 300962df5ad0Smrg pan->border_left, pan->border_top, 301062df5ad0Smrg pan->border_right, pan->border_bottom); 3011a0d3b6eaSmrg } 3012a0d3b6eaSmrg printf ("\n"); 3013a0d3b6eaSmrg 3014a0d3b6eaSmrg if (verbose) 3015a0d3b6eaSmrg { 301662df5ad0Smrg printf ("\tIdentifier: 0x%x\n", (int)output->output.xid); 301762df5ad0Smrg printf ("\tTimestamp: %d\n", (int)output_info->timestamp); 3018a0d3b6eaSmrg printf ("\tSubpixel: %s\n", order[output_info->subpixel_order]); 30198a16544fSmrg if (output->gamma.red != 0.0 && output->gamma.green != 0.0 && output->gamma.blue != 0.0) { 30208a16544fSmrg printf ("\tGamma: %#.2g:%#.2g:%#.2g\n", 30218a16544fSmrg output->gamma.red, output->gamma.green, output->gamma.blue); 30228a16544fSmrg printf ("\tBrightness: %#.2g\n", output->brightness); 30238a16544fSmrg } 3024a0d3b6eaSmrg printf ("\tClones: "); 3025a0d3b6eaSmrg for (j = 0; j < output_info->nclone; j++) 3026a0d3b6eaSmrg { 3027a0d3b6eaSmrg output_t *clone = find_output_by_xid (output_info->clones[j]); 3028a0d3b6eaSmrg 3029a0d3b6eaSmrg if (clone) printf (" %s", clone->output.string); 3030a0d3b6eaSmrg } 3031a0d3b6eaSmrg printf ("\n"); 3032a0d3b6eaSmrg if (output->crtc_info) 3033a0d3b6eaSmrg printf ("\tCRTC: %d\n", output->crtc_info->crtc.index); 3034a0d3b6eaSmrg printf ("\tCRTCs: "); 3035a0d3b6eaSmrg for (j = 0; j < output_info->ncrtc; j++) 3036a0d3b6eaSmrg { 3037a0d3b6eaSmrg crtc_t *crtc = find_crtc_by_xid (output_info->crtcs[j]); 3038a0d3b6eaSmrg if (crtc) 3039a0d3b6eaSmrg printf (" %d", crtc->crtc.index); 3040a0d3b6eaSmrg } 3041a0d3b6eaSmrg printf ("\n"); 304262df5ad0Smrg if (output->crtc_info && output->crtc_info->panning_info) { 304362df5ad0Smrg XRRPanning *pan = output->crtc_info->panning_info; 304462df5ad0Smrg printf ("\tPanning: %dx%d+%d+%d\n", 304562df5ad0Smrg pan->width, pan->height, pan->left, pan->top); 304662df5ad0Smrg printf ("\tTracking: %dx%d+%d+%d\n", 304762df5ad0Smrg pan->track_width, pan->track_height, 304862df5ad0Smrg pan->track_left, pan->track_top); 304962df5ad0Smrg printf ("\tBorder: %d/%d/%d/%d\n", 305062df5ad0Smrg pan->border_left, pan->border_top, 305162df5ad0Smrg pan->border_right, pan->border_bottom); 305262df5ad0Smrg } 305362df5ad0Smrg } 305462df5ad0Smrg if (verbose) 305562df5ad0Smrg { 305662df5ad0Smrg int x, y; 305762df5ad0Smrg 305862df5ad0Smrg printf ("\tTransform: "); 305962df5ad0Smrg for (y = 0; y < 3; y++) 306062df5ad0Smrg { 306162df5ad0Smrg for (x = 0; x < 3; x++) 306262df5ad0Smrg printf (" %f", XFixedToDouble (output->transform.transform.matrix[y][x])); 306362df5ad0Smrg if (y < 2) 306462df5ad0Smrg printf ("\n\t "); 306562df5ad0Smrg } 306662df5ad0Smrg if (output->transform.filter) 306762df5ad0Smrg printf ("\n\t filter: %s", output->transform.filter); 306862df5ad0Smrg printf ("\n"); 3069a0d3b6eaSmrg } 3070a0d3b6eaSmrg if (verbose || properties) 3071a0d3b6eaSmrg { 3072a0d3b6eaSmrg props = XRRListOutputProperties (dpy, output->output.xid, 3073a0d3b6eaSmrg &nprop); 3074a0d3b6eaSmrg for (j = 0; j < nprop; j++) { 3075a0d3b6eaSmrg unsigned char *prop; 3076a0d3b6eaSmrg int actual_format; 3077a0d3b6eaSmrg unsigned long nitems, bytes_after; 3078a0d3b6eaSmrg Atom actual_type; 3079a0d3b6eaSmrg XRRPropertyInfo *propinfo; 3080a0d3b6eaSmrg 3081a0d3b6eaSmrg XRRGetOutputProperty (dpy, output->output.xid, props[j], 3082a0d3b6eaSmrg 0, 100, False, False, 3083a0d3b6eaSmrg AnyPropertyType, 3084a0d3b6eaSmrg &actual_type, &actual_format, 3085a0d3b6eaSmrg &nitems, &bytes_after, &prop); 3086a0d3b6eaSmrg 3087a0d3b6eaSmrg propinfo = XRRQueryOutputProperty(dpy, output->output.xid, 3088a0d3b6eaSmrg props[j]); 3089a0d3b6eaSmrg 3090a0d3b6eaSmrg if (actual_type == XA_INTEGER && actual_format == 8) { 3091a0d3b6eaSmrg int k; 3092a0d3b6eaSmrg 3093a0d3b6eaSmrg printf("\t%s:\n", XGetAtomName (dpy, props[j])); 3094a0d3b6eaSmrg for (k = 0; k < nitems; k++) { 3095a0d3b6eaSmrg if (k % 16 == 0) 3096a0d3b6eaSmrg printf ("\t\t"); 3097a0d3b6eaSmrg printf("%02x", (unsigned char)prop[k]); 3098a0d3b6eaSmrg if (k % 16 == 15) 3099a0d3b6eaSmrg printf("\n"); 3100a0d3b6eaSmrg } 3101a0d3b6eaSmrg } else if (actual_type == XA_INTEGER && 3102a0d3b6eaSmrg actual_format == 32) 3103a0d3b6eaSmrg { 310462df5ad0Smrg printf("\t%s: ", XGetAtomName (dpy, props[j])); 310562df5ad0Smrg for (k = 0; k < nitems; k++) { 310662df5ad0Smrg if (k > 0) 310762df5ad0Smrg printf ("\n\t\t\t"); 310862df5ad0Smrg printf("%d (0x%08x)", 310962df5ad0Smrg (int)((INT32 *)prop)[k], (int)((INT32 *)prop)[k]); 311062df5ad0Smrg } 3111a0d3b6eaSmrg 3112a0d3b6eaSmrg if (propinfo->range && propinfo->num_values > 0) { 311362df5ad0Smrg if (nitems > 1) 311462df5ad0Smrg printf ("\n\t\t"); 311562df5ad0Smrg printf("\trange%s: ", 3116a0d3b6eaSmrg (propinfo->num_values == 2) ? "" : "s"); 3117a0d3b6eaSmrg 3118a0d3b6eaSmrg for (k = 0; k < propinfo->num_values / 2; k++) 311962df5ad0Smrg printf(" (%d,%d)", (int)propinfo->values[k * 2], 312062df5ad0Smrg (int)propinfo->values[k * 2 + 1]); 3121a0d3b6eaSmrg } 3122a0d3b6eaSmrg 3123a0d3b6eaSmrg printf("\n"); 3124a0d3b6eaSmrg } else if (actual_type == XA_ATOM && 3125a0d3b6eaSmrg actual_format == 32) 3126a0d3b6eaSmrg { 312762df5ad0Smrg printf("\t%s:", XGetAtomName (dpy, props[j])); 312862df5ad0Smrg for (k = 0; k < nitems; k++) { 312962df5ad0Smrg if (k > 0 && (k & 1) == 0) 313062df5ad0Smrg printf ("\n\t\t"); 313162df5ad0Smrg printf("\t%s", XGetAtomName (dpy, ((Atom *)prop)[k])); 313262df5ad0Smrg } 3133a0d3b6eaSmrg 3134a0d3b6eaSmrg if (!propinfo->range && propinfo->num_values > 0) { 3135a0d3b6eaSmrg printf("\n\t\tsupported:"); 3136a0d3b6eaSmrg 3137a0d3b6eaSmrg for (k = 0; k < propinfo->num_values; k++) 3138a0d3b6eaSmrg { 3139a0d3b6eaSmrg printf(" %-12.12s", XGetAtomName (dpy, 3140a0d3b6eaSmrg propinfo->values[k])); 3141a0d3b6eaSmrg if (k % 4 == 3 && k < propinfo->num_values - 1) 3142a0d3b6eaSmrg printf ("\n\t\t "); 3143a0d3b6eaSmrg } 3144a0d3b6eaSmrg } 3145a0d3b6eaSmrg printf("\n"); 3146a0d3b6eaSmrg } else if (actual_format == 8) { 314762df5ad0Smrg printf ("\t%s: %s%s\n", XGetAtomName (dpy, props[j]), 3148a0d3b6eaSmrg prop, bytes_after ? "..." : ""); 3149a0d3b6eaSmrg } else { 315062df5ad0Smrg char *type = actual_type ? XGetAtomName (dpy, actual_type) : "none"; 315162df5ad0Smrg printf ("\t%s: %s(%d) (format %d items %d) ????\n", 315262df5ad0Smrg XGetAtomName (dpy, props[j]), 315362df5ad0Smrg type, (int)actual_type, actual_format, (int)nitems); 3154a0d3b6eaSmrg } 3155a0d3b6eaSmrg 3156a0d3b6eaSmrg free(propinfo); 3157a0d3b6eaSmrg } 3158a0d3b6eaSmrg } 3159a0d3b6eaSmrg 3160a0d3b6eaSmrg if (verbose) 3161a0d3b6eaSmrg { 3162a0d3b6eaSmrg for (j = 0; j < output_info->nmode; j++) 3163a0d3b6eaSmrg { 3164a0d3b6eaSmrg XRRModeInfo *mode = find_mode_by_xid (output_info->modes[j]); 3165a0d3b6eaSmrg int f; 3166a0d3b6eaSmrg 3167a0d3b6eaSmrg printf (" %s (0x%x) %6.1fMHz", 316862df5ad0Smrg mode->name, (int)mode->id, 3169c52f0396Smrg (double)mode->dotClock / 1000000.0); 3170a0d3b6eaSmrg for (f = 0; mode_flags[f].flag; f++) 3171a0d3b6eaSmrg if (mode->modeFlags & mode_flags[f].flag) 3172a0d3b6eaSmrg printf (" %s", mode_flags[f].string); 3173a0d3b6eaSmrg if (mode == output->mode_info) 3174a0d3b6eaSmrg printf (" *current"); 3175a0d3b6eaSmrg if (j < output_info->npreferred) 3176a0d3b6eaSmrg printf (" +preferred"); 3177a0d3b6eaSmrg printf ("\n"); 3178a0d3b6eaSmrg printf (" h: width %4d start %4d end %4d total %4d skew %4d clock %6.1fKHz\n", 3179a0d3b6eaSmrg mode->width, mode->hSyncStart, mode->hSyncEnd, 3180a0d3b6eaSmrg mode->hTotal, mode->hSkew, mode_hsync (mode) / 1000); 3181a0d3b6eaSmrg printf (" v: height %4d start %4d end %4d total %4d clock %6.1fHz\n", 3182a0d3b6eaSmrg mode->height, mode->vSyncStart, mode->vSyncEnd, mode->vTotal, 3183a0d3b6eaSmrg mode_refresh (mode)); 3184a0d3b6eaSmrg mode->modeFlags |= ModeShown; 3185a0d3b6eaSmrg } 3186a0d3b6eaSmrg } 3187a0d3b6eaSmrg else 3188a0d3b6eaSmrg { 3189a0d3b6eaSmrg mode_shown = calloc (output_info->nmode, sizeof (Bool)); 3190a0d3b6eaSmrg if (!mode_shown) fatal ("out of memory\n"); 3191a0d3b6eaSmrg for (j = 0; j < output_info->nmode; j++) 3192a0d3b6eaSmrg { 3193a0d3b6eaSmrg XRRModeInfo *jmode, *kmode; 3194a0d3b6eaSmrg 3195a0d3b6eaSmrg if (mode_shown[j]) continue; 3196a0d3b6eaSmrg 3197a0d3b6eaSmrg jmode = find_mode_by_xid (output_info->modes[j]); 3198a0d3b6eaSmrg printf (" "); 3199a0d3b6eaSmrg printf (" %-12s", jmode->name); 3200a0d3b6eaSmrg for (k = j; k < output_info->nmode; k++) 3201a0d3b6eaSmrg { 3202a0d3b6eaSmrg if (mode_shown[k]) continue; 3203a0d3b6eaSmrg kmode = find_mode_by_xid (output_info->modes[k]); 3204a0d3b6eaSmrg if (strcmp (jmode->name, kmode->name) != 0) continue; 3205a0d3b6eaSmrg mode_shown[k] = True; 3206a0d3b6eaSmrg kmode->modeFlags |= ModeShown; 3207a0d3b6eaSmrg printf (" %6.1f", mode_refresh (kmode)); 3208a0d3b6eaSmrg if (kmode == output->mode_info) 3209a0d3b6eaSmrg printf ("*"); 3210a0d3b6eaSmrg else 3211a0d3b6eaSmrg printf (" "); 3212a0d3b6eaSmrg if (k < output_info->npreferred) 3213a0d3b6eaSmrg printf ("+"); 3214a0d3b6eaSmrg else 3215a0d3b6eaSmrg printf (" "); 3216a0d3b6eaSmrg } 3217a0d3b6eaSmrg printf ("\n"); 3218a0d3b6eaSmrg } 3219a0d3b6eaSmrg free (mode_shown); 3220a0d3b6eaSmrg } 3221a0d3b6eaSmrg } 3222a0d3b6eaSmrg for (m = 0; m < res->nmode; m++) 3223a0d3b6eaSmrg { 3224a0d3b6eaSmrg XRRModeInfo *mode = &res->modes[m]; 3225a0d3b6eaSmrg 3226a0d3b6eaSmrg if (!(mode->modeFlags & ModeShown)) 3227a0d3b6eaSmrg { 3228a0d3b6eaSmrg printf (" %s (0x%x) %6.1fMHz\n", 322962df5ad0Smrg mode->name, (int)mode->id, 3230c52f0396Smrg (double)mode->dotClock / 1000000.0); 3231a0d3b6eaSmrg printf (" h: width %4d start %4d end %4d total %4d skew %4d clock %6.1fKHz\n", 3232a0d3b6eaSmrg mode->width, mode->hSyncStart, mode->hSyncEnd, 3233a0d3b6eaSmrg mode->hTotal, mode->hSkew, mode_hsync (mode) / 1000); 3234a0d3b6eaSmrg printf (" v: height %4d start %4d end %4d total %4d clock %6.1fHz\n", 3235a0d3b6eaSmrg mode->height, mode->vSyncStart, mode->vSyncEnd, mode->vTotal, 3236a0d3b6eaSmrg mode_refresh (mode)); 3237a0d3b6eaSmrg } 3238a0d3b6eaSmrg } 3239a0d3b6eaSmrg exit (0); 3240a0d3b6eaSmrg } 3241a0d3b6eaSmrg 3242a0d3b6eaSmrg sc = XRRGetScreenInfo (dpy, root); 3243a0d3b6eaSmrg 3244a0d3b6eaSmrg if (sc == NULL) 3245a0d3b6eaSmrg exit (1); 3246a0d3b6eaSmrg 3247a0d3b6eaSmrg current_size = XRRConfigCurrentConfiguration (sc, ¤t_rotation); 3248a0d3b6eaSmrg 3249a0d3b6eaSmrg sizes = XRRConfigSizes(sc, &nsize); 3250a0d3b6eaSmrg 3251a0d3b6eaSmrg if (have_pixel_size) { 3252a0d3b6eaSmrg for (size = 0; size < nsize; size++) 3253a0d3b6eaSmrg { 3254a0d3b6eaSmrg if (sizes[size].width == width && sizes[size].height == height) 3255a0d3b6eaSmrg break; 3256a0d3b6eaSmrg } 3257a0d3b6eaSmrg if (size >= nsize) { 3258a0d3b6eaSmrg fprintf (stderr, 3259a0d3b6eaSmrg "Size %dx%d not found in available modes\n", width, height); 3260a0d3b6eaSmrg exit (1); 3261a0d3b6eaSmrg } 3262a0d3b6eaSmrg } 3263a0d3b6eaSmrg else if (size < 0) 3264a0d3b6eaSmrg size = current_size; 3265a0d3b6eaSmrg else if (size >= nsize) { 3266a0d3b6eaSmrg fprintf (stderr, 3267a0d3b6eaSmrg "Size index %d is too large, there are only %d sizes\n", 3268a0d3b6eaSmrg size, nsize); 3269a0d3b6eaSmrg exit (1); 3270a0d3b6eaSmrg } 3271a0d3b6eaSmrg 3272a0d3b6eaSmrg if (rot < 0) 3273a0d3b6eaSmrg { 3274a0d3b6eaSmrg for (rot = 0; rot < 4; rot++) 3275a0d3b6eaSmrg if (1 << rot == (current_rotation & 0xf)) 3276a0d3b6eaSmrg break; 3277a0d3b6eaSmrg } 3278a0d3b6eaSmrg 3279a0d3b6eaSmrg current_rate = XRRConfigCurrentRate (sc); 3280a0d3b6eaSmrg 3281a0d3b6eaSmrg if (rate < 0) 3282a0d3b6eaSmrg { 3283a0d3b6eaSmrg if (size == current_size) 3284a0d3b6eaSmrg rate = current_rate; 3285a0d3b6eaSmrg else 3286a0d3b6eaSmrg rate = 0; 3287a0d3b6eaSmrg } 3288a0d3b6eaSmrg else 3289a0d3b6eaSmrg { 3290a0d3b6eaSmrg rates = XRRConfigRates (sc, size, &nrate); 3291a0d3b6eaSmrg for (i = 0; i < nrate; i++) 3292a0d3b6eaSmrg if (rate == rates[i]) 3293a0d3b6eaSmrg break; 3294a0d3b6eaSmrg if (i == nrate) { 3295a0d3b6eaSmrg fprintf (stderr, "Rate %.1f Hz not available for this size\n", rate); 3296a0d3b6eaSmrg exit (1); 3297a0d3b6eaSmrg } 3298a0d3b6eaSmrg } 3299a0d3b6eaSmrg 3300a0d3b6eaSmrg if (version) { 3301a0d3b6eaSmrg int major_version, minor_version; 3302a0d3b6eaSmrg XRRQueryVersion (dpy, &major_version, &minor_version); 3303a0d3b6eaSmrg printf("Server reports RandR version %d.%d\n", 3304a0d3b6eaSmrg major_version, minor_version); 3305a0d3b6eaSmrg } 3306a0d3b6eaSmrg 3307a0d3b6eaSmrg if (query || query_1) { 3308a0d3b6eaSmrg printf(" SZ: Pixels Physical Refresh\n"); 3309a0d3b6eaSmrg for (i = 0; i < nsize; i++) { 3310a0d3b6eaSmrg printf ("%c%-2d %5d x %-5d (%4dmm x%4dmm )", 3311a0d3b6eaSmrg i == current_size ? '*' : ' ', 3312a0d3b6eaSmrg i, sizes[i].width, sizes[i].height, 3313a0d3b6eaSmrg sizes[i].mwidth, sizes[i].mheight); 3314a0d3b6eaSmrg rates = XRRConfigRates (sc, i, &nrate); 3315a0d3b6eaSmrg if (nrate) printf (" "); 3316a0d3b6eaSmrg for (j = 0; j < nrate; j++) 3317a0d3b6eaSmrg printf ("%c%-4d", 3318a0d3b6eaSmrg i == current_size && rates[j] == current_rate ? '*' : ' ', 3319a0d3b6eaSmrg rates[j]); 3320a0d3b6eaSmrg printf ("\n"); 3321a0d3b6eaSmrg } 3322a0d3b6eaSmrg } 3323a0d3b6eaSmrg 3324a0d3b6eaSmrg rotations = XRRConfigRotations(sc, ¤t_rotation); 3325a0d3b6eaSmrg 3326a0d3b6eaSmrg rotation = 1 << rot ; 3327a0d3b6eaSmrg if (query) { 3328a0d3b6eaSmrg printf("Current rotation - %s\n", 3329a0d3b6eaSmrg rotation_name (current_rotation)); 3330a0d3b6eaSmrg 3331a0d3b6eaSmrg printf("Current reflection - %s\n", 3332a0d3b6eaSmrg reflection_name (current_rotation)); 3333a0d3b6eaSmrg 3334a0d3b6eaSmrg printf ("Rotations possible - "); 3335a0d3b6eaSmrg for (i = 0; i < 4; i ++) { 3336a0d3b6eaSmrg if ((rotations >> i) & 1) printf("%s ", direction[i]); 3337a0d3b6eaSmrg } 3338a0d3b6eaSmrg printf ("\n"); 3339a0d3b6eaSmrg 3340a0d3b6eaSmrg printf ("Reflections possible - "); 3341a0d3b6eaSmrg if (rotations & (RR_Reflect_X|RR_Reflect_Y)) 3342a0d3b6eaSmrg { 3343a0d3b6eaSmrg if (rotations & RR_Reflect_X) printf ("X Axis "); 3344a0d3b6eaSmrg if (rotations & RR_Reflect_Y) printf ("Y Axis"); 3345a0d3b6eaSmrg } 3346a0d3b6eaSmrg else 3347a0d3b6eaSmrg printf ("none"); 3348a0d3b6eaSmrg printf ("\n"); 3349a0d3b6eaSmrg } 3350a0d3b6eaSmrg 3351a0d3b6eaSmrg if (verbose) { 3352a0d3b6eaSmrg printf("Setting size to %d, rotation to %s\n", size, direction[rot]); 3353a0d3b6eaSmrg 3354a0d3b6eaSmrg printf ("Setting reflection on "); 3355a0d3b6eaSmrg if (reflection) 3356a0d3b6eaSmrg { 3357a0d3b6eaSmrg if (reflection & RR_Reflect_X) printf ("X Axis "); 3358a0d3b6eaSmrg if (reflection & RR_Reflect_Y) printf ("Y Axis"); 3359a0d3b6eaSmrg } 3360a0d3b6eaSmrg else 3361a0d3b6eaSmrg printf ("neither axis"); 3362a0d3b6eaSmrg printf ("\n"); 3363a0d3b6eaSmrg 3364a0d3b6eaSmrg if (reflection & RR_Reflect_X) printf("Setting reflection on X axis\n"); 3365a0d3b6eaSmrg 3366a0d3b6eaSmrg if (reflection & RR_Reflect_Y) printf("Setting reflection on Y axis\n"); 3367a0d3b6eaSmrg } 3368a0d3b6eaSmrg 3369a0d3b6eaSmrg /* we should test configureNotify on the root window */ 3370a0d3b6eaSmrg XSelectInput (dpy, root, StructureNotifyMask); 3371a0d3b6eaSmrg 3372a0d3b6eaSmrg if (setit && !dryrun) XRRSelectInput (dpy, root, 3373a0d3b6eaSmrg RRScreenChangeNotifyMask); 3374a0d3b6eaSmrg if (setit && !dryrun) status = XRRSetScreenConfigAndRate (dpy, sc, 337562df5ad0Smrg root, 3376a0d3b6eaSmrg (SizeID) size, (Rotation) (rotation | reflection), rate, CurrentTime); 3377a0d3b6eaSmrg 3378a0d3b6eaSmrg if (setit && !dryrun && status == RRSetConfigFailed) { 3379a0d3b6eaSmrg printf ("Failed to change the screen configuration!\n"); 3380a0d3b6eaSmrg ret = 1; 3381a0d3b6eaSmrg } 3382a0d3b6eaSmrg 3383a0d3b6eaSmrg if (verbose && setit && !dryrun && size != current_size) { 3384a0d3b6eaSmrg if (status == RRSetConfigSuccess) 3385a0d3b6eaSmrg { 3386a0d3b6eaSmrg Bool seen_screen = False; 3387a0d3b6eaSmrg while (!seen_screen) { 3388a0d3b6eaSmrg int spo; 3389a0d3b6eaSmrg XNextEvent(dpy, (XEvent *) &event); 3390a0d3b6eaSmrg 3391a0d3b6eaSmrg printf ("Event received, type = %d\n", event.type); 3392a0d3b6eaSmrg /* update Xlib's knowledge of the event */ 3393a0d3b6eaSmrg XRRUpdateConfiguration (&event); 3394a0d3b6eaSmrg if (event.type == ConfigureNotify) 3395a0d3b6eaSmrg printf("Received ConfigureNotify Event!\n"); 3396a0d3b6eaSmrg 3397a0d3b6eaSmrg switch (event.type - event_base) { 3398a0d3b6eaSmrg case RRScreenChangeNotify: 3399a0d3b6eaSmrg sce = (XRRScreenChangeNotifyEvent *) &event; 3400a0d3b6eaSmrg 3401a0d3b6eaSmrg printf("Got a screen change notify event!\n"); 3402a0d3b6eaSmrg printf(" window = %d\n root = %d\n size_index = %d\n rotation %d\n", 3403a0d3b6eaSmrg (int) sce->window, (int) sce->root, 3404a0d3b6eaSmrg sce->size_index, sce->rotation); 3405a0d3b6eaSmrg printf(" timestamp = %ld, config_timestamp = %ld\n", 3406a0d3b6eaSmrg sce->timestamp, sce->config_timestamp); 3407a0d3b6eaSmrg printf(" Rotation = %x\n", sce->rotation); 3408a0d3b6eaSmrg printf(" %d X %d pixels, %d X %d mm\n", 3409a0d3b6eaSmrg sce->width, sce->height, sce->mwidth, sce->mheight); 3410a0d3b6eaSmrg printf("Display width %d, height %d\n", 3411a0d3b6eaSmrg DisplayWidth(dpy, screen), DisplayHeight(dpy, screen)); 3412a0d3b6eaSmrg printf("Display widthmm %d, heightmm %d\n", 3413a0d3b6eaSmrg DisplayWidthMM(dpy, screen), DisplayHeightMM(dpy, screen)); 3414a0d3b6eaSmrg spo = sce->subpixel_order; 3415a0d3b6eaSmrg if ((spo < 0) || (spo > 5)) 3416a0d3b6eaSmrg printf ("Unknown subpixel order, value = %d\n", spo); 3417a0d3b6eaSmrg else printf ("new Subpixel rendering model is %s\n", order[spo]); 3418a0d3b6eaSmrg seen_screen = True; 3419a0d3b6eaSmrg break; 3420a0d3b6eaSmrg default: 3421a0d3b6eaSmrg if (event.type != ConfigureNotify) 3422a0d3b6eaSmrg printf("unknown event received, type = %d!\n", event.type); 3423a0d3b6eaSmrg } 3424a0d3b6eaSmrg } 3425a0d3b6eaSmrg } 3426a0d3b6eaSmrg } 3427a0d3b6eaSmrg XRRFreeScreenConfigInfo(sc); 3428a0d3b6eaSmrg return(ret); 3429a0d3b6eaSmrg} 3430