xrandr.c revision 35e1b5b7
1a0d3b6eaSmrg/* 2a0d3b6eaSmrg * Copyright © 2001 Keith Packard, member of The XFree86 Project, Inc. 3a0d3b6eaSmrg * Copyright © 2002 Hewlett Packard Company, Inc. 4a0d3b6eaSmrg * Copyright © 2006 Intel Corporation 5cf2cd791Smrg * Copyright © 2013 NVIDIA Corporation 6a0d3b6eaSmrg * 7a0d3b6eaSmrg * Permission to use, copy, modify, distribute, and sell this software and its 8a0d3b6eaSmrg * documentation for any purpose is hereby granted without fee, provided that 9a0d3b6eaSmrg * the above copyright notice appear in all copies and that both that copyright 10a0d3b6eaSmrg * notice and this permission notice appear in supporting documentation, and 11a0d3b6eaSmrg * that the name of the copyright holders not be used in advertising or 12a0d3b6eaSmrg * publicity pertaining to distribution of the software without specific, 13a0d3b6eaSmrg * written prior permission. The copyright holders make no representations 14a0d3b6eaSmrg * about the suitability of this software for any purpose. It is provided "as 15a0d3b6eaSmrg * is" without express or implied warranty. 16a0d3b6eaSmrg * 17a0d3b6eaSmrg * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 18a0d3b6eaSmrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 19a0d3b6eaSmrg * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 20a0d3b6eaSmrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 21a0d3b6eaSmrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 22a0d3b6eaSmrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 23a0d3b6eaSmrg * OF THIS SOFTWARE. 24a0d3b6eaSmrg * 25a0d3b6eaSmrg * Thanks to Jim Gettys who wrote most of the client side code, 26a0d3b6eaSmrg * and part of the server code for randr. 27a0d3b6eaSmrg */ 28a0d3b6eaSmrg 29a0d3b6eaSmrg#include <stdio.h> 30a0d3b6eaSmrg#include <X11/Xlib.h> 31a0d3b6eaSmrg#include <X11/Xlibint.h> 32a0d3b6eaSmrg#include <X11/Xproto.h> 33a0d3b6eaSmrg#include <X11/Xatom.h> 34a0d3b6eaSmrg#include <X11/extensions/Xrandr.h> 35a0d3b6eaSmrg#include <X11/extensions/Xrender.h> /* we share subpixel information */ 36cf2cd791Smrg#include <strings.h> 37a0d3b6eaSmrg#include <string.h> 38a0d3b6eaSmrg#include <stdlib.h> 39cf2cd791Smrg#include <stdint.h> 40cf2cd791Smrg#include <inttypes.h> 41a0d3b6eaSmrg#include <stdarg.h> 42a0d3b6eaSmrg#include <math.h> 43a0d3b6eaSmrg 4478038a65Smrg#ifdef HAVE_CONFIG_H 4562770414Smrg#include "config.h" 4678038a65Smrg#endif 4762770414Smrg 48a0d3b6eaSmrgstatic char *program_name; 49a0d3b6eaSmrgstatic Display *dpy; 50a0d3b6eaSmrgstatic Window root; 51a0d3b6eaSmrgstatic int screen = -1; 52a0d3b6eaSmrgstatic Bool verbose = False; 53a0d3b6eaSmrgstatic Bool automatic = False; 54a0d3b6eaSmrgstatic Bool properties = False; 5562df5ad0Smrgstatic Bool grab_server = True; 5662df5ad0Smrgstatic Bool no_primary = False; 57a0d3b6eaSmrg 58cf2cd791Smrgstatic const char *direction[5] = { 59a0d3b6eaSmrg "normal", 60a0d3b6eaSmrg "left", 61a0d3b6eaSmrg "inverted", 62a0d3b6eaSmrg "right", 63a0d3b6eaSmrg "\n"}; 64a0d3b6eaSmrg 65cf2cd791Smrgstatic const char *reflections[5] = { 66a0d3b6eaSmrg "normal", 67a0d3b6eaSmrg "x", 68a0d3b6eaSmrg "y", 69a0d3b6eaSmrg "xy", 70a0d3b6eaSmrg "\n"}; 71a0d3b6eaSmrg 72a0d3b6eaSmrg/* subpixel order */ 73cf2cd791Smrgstatic const char *order[6] = { 74a0d3b6eaSmrg "unknown", 75a0d3b6eaSmrg "horizontal rgb", 76a0d3b6eaSmrg "horizontal bgr", 77a0d3b6eaSmrg "vertical rgb", 78a0d3b6eaSmrg "vertical bgr", 79a0d3b6eaSmrg "no subpixels"}; 80a0d3b6eaSmrg 81a0d3b6eaSmrgstatic const struct { 82cf2cd791Smrg const char *string; 83a0d3b6eaSmrg unsigned long flag; 84a0d3b6eaSmrg} mode_flags[] = { 85a0d3b6eaSmrg { "+HSync", RR_HSyncPositive }, 86a0d3b6eaSmrg { "-HSync", RR_HSyncNegative }, 87a0d3b6eaSmrg { "+VSync", RR_VSyncPositive }, 88a0d3b6eaSmrg { "-VSync", RR_VSyncNegative }, 89a0d3b6eaSmrg { "Interlace", RR_Interlace }, 90a0d3b6eaSmrg { "DoubleScan", RR_DoubleScan }, 91a0d3b6eaSmrg { "CSync", RR_CSync }, 92a0d3b6eaSmrg { "+CSync", RR_CSyncPositive }, 93a0d3b6eaSmrg { "-CSync", RR_CSyncNegative }, 94a0d3b6eaSmrg { NULL, 0 } 95a0d3b6eaSmrg}; 96a0d3b6eaSmrg 97cf2cd791Smrgstatic void 98a0d3b6eaSmrgusage(void) 99a0d3b6eaSmrg{ 100f86b2e6cSmrg printf("usage: %s [options]\n%s", program_name, 101f86b2e6cSmrg " where options are:\n" 102f86b2e6cSmrg " --display <display> or -d <display>\n" 103f86b2e6cSmrg " --help\n" 104f86b2e6cSmrg " -o <normal,inverted,left,right,0,1,2,3>\n" 105f86b2e6cSmrg " or --orientation <normal,inverted,left,right,0,1,2,3>\n" 106f86b2e6cSmrg " -q or --query\n" 107f86b2e6cSmrg " -s <size>/<width>x<height> or --size <size>/<width>x<height>\n" 108f86b2e6cSmrg " -r <rate> or --rate <rate> or --refresh <rate>\n" 109f86b2e6cSmrg " -v or --version\n" 110f86b2e6cSmrg " -x (reflect in x)\n" 111f86b2e6cSmrg " -y (reflect in y)\n" 112f86b2e6cSmrg " --screen <screen>\n" 113f86b2e6cSmrg " --verbose\n" 114f86b2e6cSmrg " --current\n" 115f86b2e6cSmrg " --dryrun\n" 116f86b2e6cSmrg " --nograb\n" 117f86b2e6cSmrg " --prop or --properties\n" 118f86b2e6cSmrg " --fb <width>x<height>\n" 119f86b2e6cSmrg " --fbmm <width>x<height>\n" 120f86b2e6cSmrg " --dpi <dpi>/<output>\n" 121f86b2e6cSmrg " --output <output>\n" 122f86b2e6cSmrg " --auto\n" 123f86b2e6cSmrg " --mode <mode>\n" 124f86b2e6cSmrg " --preferred\n" 125f86b2e6cSmrg " --pos <x>x<y>\n" 126f86b2e6cSmrg " --rate <rate> or --refresh <rate>\n" 127f86b2e6cSmrg " --reflect normal,x,y,xy\n" 128f86b2e6cSmrg " --rotate normal,inverted,left,right\n" 129f86b2e6cSmrg " --left-of <output>\n" 130f86b2e6cSmrg " --right-of <output>\n" 131f86b2e6cSmrg " --above <output>\n" 132f86b2e6cSmrg " --below <output>\n" 133f86b2e6cSmrg " --same-as <output>\n" 134f86b2e6cSmrg " --set <property> <value>\n" 135f86b2e6cSmrg " --scale <x>x<y>\n" 136f86b2e6cSmrg " --scale-from <w>x<h>\n" 137f86b2e6cSmrg " --transform <a>,<b>,<c>,<d>,<e>,<f>,<g>,<h>,<i>\n" 138f86b2e6cSmrg " --off\n" 139f86b2e6cSmrg " --crtc <crtc>\n" 140f86b2e6cSmrg " --panning <w>x<h>[+<x>+<y>[/<track:w>x<h>+<x>+<y>[/<border:l>/<t>/<r>/<b>]]]\n" 141f86b2e6cSmrg " --gamma <r>:<g>:<b>\n" 142305217b6Smrg " --brightness <value>\n" 143f86b2e6cSmrg " --primary\n" 144f86b2e6cSmrg " --noprimary\n" 145f86b2e6cSmrg " --newmode <name> <clock MHz>\n" 146f86b2e6cSmrg " <hdisp> <hsync-start> <hsync-end> <htotal>\n" 147f86b2e6cSmrg " <vdisp> <vsync-start> <vsync-end> <vtotal>\n" 148f86b2e6cSmrg " [flags...]\n" 149f86b2e6cSmrg " Valid flags: +HSync -HSync +VSync -VSync\n" 150f86b2e6cSmrg " +CSync -CSync CSync Interlace DoubleScan\n" 151f86b2e6cSmrg " --rmmode <name>\n" 152f86b2e6cSmrg " --addmode <output> <name>\n" 153f86b2e6cSmrg " --delmode <output> <name>\n" 154f86b2e6cSmrg " --listproviders\n" 155f86b2e6cSmrg " --setprovideroutputsource <prov-xid> <source-xid>\n" 156319fa471Smrg " --setprovideroffloadsink <prov-xid> <sink-xid>\n" 157319fa471Smrg " --listmonitors\n" 158319fa471Smrg " --listactivemonitors\n" 159319fa471Smrg " --setmonitor <name> {auto|<w>/<mmw>x<h>/<mmh>+<x>+<y>} {none|<output>,<output>,...}\n" 160319fa471Smrg " --delmonitor <name>\n"); 161cf2cd791Smrg} 162cf2cd791Smrg 163cf2cd791Smrgstatic void _X_NORETURN _X_ATTRIBUTE_PRINTF(1,2) 164a0d3b6eaSmrgfatal (const char *format, ...) 165a0d3b6eaSmrg{ 166a0d3b6eaSmrg va_list ap; 167a0d3b6eaSmrg 168a0d3b6eaSmrg va_start (ap, format); 169a0d3b6eaSmrg fprintf (stderr, "%s: ", program_name); 170a0d3b6eaSmrg vfprintf (stderr, format, ap); 171a0d3b6eaSmrg va_end (ap); 172a0d3b6eaSmrg exit (1); 173a0d3b6eaSmrg /*NOTREACHED*/ 174a0d3b6eaSmrg} 175a0d3b6eaSmrg 176cf2cd791Smrgstatic void _X_ATTRIBUTE_PRINTF(1,2) 17762df5ad0Smrgwarning (const char *format, ...) 17862df5ad0Smrg{ 17962df5ad0Smrg va_list ap; 18062df5ad0Smrg 18162df5ad0Smrg va_start (ap, format); 18262df5ad0Smrg fprintf (stderr, "%s: ", program_name); 18362df5ad0Smrg vfprintf (stderr, format, ap); 18462df5ad0Smrg va_end (ap); 18562df5ad0Smrg} 18662df5ad0Smrg 187cf2cd791Smrgstatic void _X_NORETURN _X_ATTRIBUTE_PRINTF(1,2) 188cf2cd791Smrgargerr (const char *format, ...) 189cf2cd791Smrg{ 190cf2cd791Smrg va_list ap; 191cf2cd791Smrg 192cf2cd791Smrg va_start (ap, format); 193cf2cd791Smrg fprintf (stderr, "%s: ", program_name); 194cf2cd791Smrg vfprintf (stderr, format, ap); 195cf2cd791Smrg fprintf (stderr, "Try '%s --help' for more information.\n", program_name); 196cf2cd791Smrg va_end (ap); 197cf2cd791Smrg exit (1); 198cf2cd791Smrg /*NOTREACHED*/ 199cf2cd791Smrg} 200cf2cd791Smrg 2018a16544fSmrg/* Because fmin requires C99 suppport */ 2028a16544fSmrgstatic inline double dmin (double x, double y) 2038a16544fSmrg{ 2048a16544fSmrg return x < y ? x : y; 2058a16544fSmrg} 2068a16544fSmrg 207cf2cd791Smrgstatic const char * 208a0d3b6eaSmrgrotation_name (Rotation rotation) 209a0d3b6eaSmrg{ 210a0d3b6eaSmrg int i; 211a0d3b6eaSmrg 212a0d3b6eaSmrg if ((rotation & 0xf) == 0) 213a0d3b6eaSmrg return "normal"; 214a0d3b6eaSmrg for (i = 0; i < 4; i++) 215a0d3b6eaSmrg if (rotation & (1 << i)) 216a0d3b6eaSmrg return direction[i]; 217a0d3b6eaSmrg return "invalid rotation"; 218a0d3b6eaSmrg} 219a0d3b6eaSmrg 220cf2cd791Smrgstatic const char * 221a0d3b6eaSmrgreflection_name (Rotation rotation) 222a0d3b6eaSmrg{ 223a0d3b6eaSmrg rotation &= (RR_Reflect_X|RR_Reflect_Y); 224a0d3b6eaSmrg switch (rotation) { 225a0d3b6eaSmrg case 0: 226a0d3b6eaSmrg return "none"; 227a0d3b6eaSmrg case RR_Reflect_X: 228a0d3b6eaSmrg return "X axis"; 229a0d3b6eaSmrg case RR_Reflect_Y: 230a0d3b6eaSmrg return "Y axis"; 231a0d3b6eaSmrg case RR_Reflect_X|RR_Reflect_Y: 232a0d3b6eaSmrg return "X and Y axis"; 233a0d3b6eaSmrg } 234a0d3b6eaSmrg return "invalid reflection"; 235a0d3b6eaSmrg} 236a0d3b6eaSmrg 237f86b2e6cSmrgstatic const char * 238cf2cd791Smrgcapability_name (int cap_bit) 239cf2cd791Smrg{ 240cf2cd791Smrg switch (cap_bit) { 241cf2cd791Smrg case RR_Capability_SourceOutput: 242cf2cd791Smrg return "Source Output"; 243cf2cd791Smrg case RR_Capability_SinkOutput: 244cf2cd791Smrg return "Sink Output"; 245cf2cd791Smrg case RR_Capability_SourceOffload: 246cf2cd791Smrg return "Source Offload"; 247cf2cd791Smrg case RR_Capability_SinkOffload: 248cf2cd791Smrg return "Sink Offload"; 249cf2cd791Smrg } 250cf2cd791Smrg return "invalid capability"; 251cf2cd791Smrg} 252cf2cd791Smrg 253a0d3b6eaSmrgtypedef enum _relation { 2548a16544fSmrg relation_left_of, 2558a16544fSmrg relation_right_of, 2568a16544fSmrg relation_above, 2578a16544fSmrg relation_below, 2588a16544fSmrg relation_same_as, 259a0d3b6eaSmrg} relation_t; 260a0d3b6eaSmrg 26162df5ad0Smrgtypedef struct { 26262df5ad0Smrg int x, y, width, height; 26362df5ad0Smrg} rectangle_t; 26462df5ad0Smrg 26562df5ad0Smrgtypedef struct { 26662df5ad0Smrg int x1, y1, x2, y2; 26762df5ad0Smrg} box_t; 26862df5ad0Smrg 26962df5ad0Smrgtypedef struct { 27062df5ad0Smrg int x, y; 27162df5ad0Smrg} point_t; 27262df5ad0Smrg 273a0d3b6eaSmrgtypedef enum _changes { 274a0d3b6eaSmrg changes_none = 0, 275a0d3b6eaSmrg changes_crtc = (1 << 0), 276a0d3b6eaSmrg changes_mode = (1 << 1), 277a0d3b6eaSmrg changes_relation = (1 << 2), 278a0d3b6eaSmrg changes_position = (1 << 3), 279a0d3b6eaSmrg changes_rotation = (1 << 4), 280a0d3b6eaSmrg changes_reflection = (1 << 5), 281a0d3b6eaSmrg changes_automatic = (1 << 6), 282a0d3b6eaSmrg changes_refresh = (1 << 7), 283a0d3b6eaSmrg changes_property = (1 << 8), 28462df5ad0Smrg changes_transform = (1 << 9), 28562df5ad0Smrg changes_panning = (1 << 10), 28662df5ad0Smrg changes_gamma = (1 << 11), 28762df5ad0Smrg changes_primary = (1 << 12), 288a0d3b6eaSmrg} changes_t; 289a0d3b6eaSmrg 290a0d3b6eaSmrgtypedef enum _name_kind { 291a0d3b6eaSmrg name_none = 0, 292a0d3b6eaSmrg name_string = (1 << 0), 293a0d3b6eaSmrg name_xid = (1 << 1), 294a0d3b6eaSmrg name_index = (1 << 2), 295a0d3b6eaSmrg name_preferred = (1 << 3), 296a0d3b6eaSmrg} name_kind_t; 297a0d3b6eaSmrg 298a0d3b6eaSmrgtypedef struct { 299a0d3b6eaSmrg name_kind_t kind; 300a0d3b6eaSmrg char *string; 301a0d3b6eaSmrg XID xid; 302a0d3b6eaSmrg int index; 303a0d3b6eaSmrg} name_t; 304a0d3b6eaSmrg 305a0d3b6eaSmrgtypedef struct _crtc crtc_t; 306a0d3b6eaSmrgtypedef struct _output output_t; 30762df5ad0Smrgtypedef struct _transform transform_t; 308a0d3b6eaSmrgtypedef struct _umode umode_t; 309a0d3b6eaSmrgtypedef struct _output_prop output_prop_t; 310cf2cd791Smrgtypedef struct _provider provider_t; 311319fa471Smrgtypedef struct _monitors monitors_t; 312319fa471Smrgtypedef struct _umonitor umonitor_t; 313a0d3b6eaSmrg 31462df5ad0Smrgstruct _transform { 31562df5ad0Smrg XTransform transform; 316cf2cd791Smrg const char *filter; 31762df5ad0Smrg int nparams; 31862df5ad0Smrg XFixed *params; 31962df5ad0Smrg}; 32062df5ad0Smrg 321a0d3b6eaSmrgstruct _crtc { 322a0d3b6eaSmrg name_t crtc; 323a0d3b6eaSmrg Bool changing; 324a0d3b6eaSmrg XRRCrtcInfo *crtc_info; 325a0d3b6eaSmrg 326a0d3b6eaSmrg XRRModeInfo *mode_info; 32762df5ad0Smrg XRRPanning *panning_info; 328a0d3b6eaSmrg int x; 329a0d3b6eaSmrg int y; 330a0d3b6eaSmrg Rotation rotation; 331a0d3b6eaSmrg output_t **outputs; 332a0d3b6eaSmrg int noutput; 33362df5ad0Smrg transform_t current_transform, pending_transform; 334a0d3b6eaSmrg}; 335a0d3b6eaSmrg 336a0d3b6eaSmrgstruct _output_prop { 337a0d3b6eaSmrg struct _output_prop *next; 338a0d3b6eaSmrg char *name; 339a0d3b6eaSmrg char *value; 340a0d3b6eaSmrg}; 341a0d3b6eaSmrg 342a0d3b6eaSmrgstruct _output { 343a0d3b6eaSmrg struct _output *next; 344a0d3b6eaSmrg 345a0d3b6eaSmrg changes_t changes; 346a0d3b6eaSmrg 347a0d3b6eaSmrg output_prop_t *props; 348a0d3b6eaSmrg 349a0d3b6eaSmrg name_t output; 350a0d3b6eaSmrg XRROutputInfo *output_info; 351a0d3b6eaSmrg 352a0d3b6eaSmrg name_t crtc; 353a0d3b6eaSmrg crtc_t *crtc_info; 354a0d3b6eaSmrg crtc_t *current_crtc_info; 355a0d3b6eaSmrg 356a0d3b6eaSmrg name_t mode; 357c52f0396Smrg double refresh; 358a0d3b6eaSmrg XRRModeInfo *mode_info; 359a0d3b6eaSmrg 360a0d3b6eaSmrg name_t addmode; 361a0d3b6eaSmrg 362a0d3b6eaSmrg relation_t relation; 363a0d3b6eaSmrg char *relative_to; 364a0d3b6eaSmrg 365a0d3b6eaSmrg int x, y; 366a0d3b6eaSmrg Rotation rotation; 36762df5ad0Smrg 36862df5ad0Smrg XRRPanning panning; 36962df5ad0Smrg 370a0d3b6eaSmrg Bool automatic; 371cf2cd791Smrg int scale_from_w, scale_from_h; 37262df5ad0Smrg transform_t transform; 37362df5ad0Smrg 37462df5ad0Smrg struct { 37562df5ad0Smrg float red; 37662df5ad0Smrg float green; 37762df5ad0Smrg float blue; 37862df5ad0Smrg } gamma; 37962df5ad0Smrg 3808a16544fSmrg float brightness; 3818a16544fSmrg 38262df5ad0Smrg Bool primary; 383c52f0396Smrg 384c52f0396Smrg Bool found; 385a0d3b6eaSmrg}; 386a0d3b6eaSmrg 387a0d3b6eaSmrgtypedef enum _umode_action { 388a0d3b6eaSmrg umode_create, umode_destroy, umode_add, umode_delete 389a0d3b6eaSmrg} umode_action_t; 390a0d3b6eaSmrg 391a0d3b6eaSmrg 392a0d3b6eaSmrgstruct _umode { 393a0d3b6eaSmrg struct _umode *next; 394a0d3b6eaSmrg 395a0d3b6eaSmrg umode_action_t action; 396a0d3b6eaSmrg XRRModeInfo mode; 397a0d3b6eaSmrg name_t output; 398a0d3b6eaSmrg name_t name; 399a0d3b6eaSmrg}; 400a0d3b6eaSmrg 401cf2cd791Smrgstruct _provider { 402cf2cd791Smrg name_t provider; 403cf2cd791Smrg XRRProviderInfo *info; 404cf2cd791Smrg}; 405cf2cd791Smrg 406319fa471Smrgstruct _monitors { 407319fa471Smrg int n; 408319fa471Smrg XRRMonitorInfo *monitors; 409319fa471Smrg}; 410319fa471Smrg 411319fa471Smrgstruct _umonitor { 412319fa471Smrg struct _umonitor *next; 413319fa471Smrg char *name; 414319fa471Smrg Bool set; 415319fa471Smrg Bool primary; 416319fa471Smrg int x, y, width, height; 417319fa471Smrg int mmwidth, mmheight; 418319fa471Smrg int noutput; 419319fa471Smrg name_t *outputs; 420319fa471Smrg}; 421319fa471Smrg 422cf2cd791Smrgstatic const char *connection[3] = { 423a0d3b6eaSmrg "connected", 424a0d3b6eaSmrg "disconnected", 425a0d3b6eaSmrg "unknown connection"}; 426a0d3b6eaSmrg 427a0d3b6eaSmrg#define OUTPUT_NAME 1 428a0d3b6eaSmrg 429a0d3b6eaSmrg#define CRTC_OFF 2 430a0d3b6eaSmrg#define CRTC_UNSET 3 431a0d3b6eaSmrg#define CRTC_INDEX 0x40000000 432a0d3b6eaSmrg 433a0d3b6eaSmrg#define MODE_NAME 1 434a0d3b6eaSmrg#define MODE_OFF 2 435a0d3b6eaSmrg#define MODE_UNSET 3 436a0d3b6eaSmrg#define MODE_PREF 4 437a0d3b6eaSmrg 438a0d3b6eaSmrg#define POS_UNSET -1 439a0d3b6eaSmrg 440cf2cd791Smrgstatic output_t *all_outputs = NULL; 441cf2cd791Smrgstatic output_t **all_outputs_tail = &all_outputs; 442a0d3b6eaSmrgstatic crtc_t *crtcs; 443cf2cd791Smrgstatic provider_t *providers; 444a0d3b6eaSmrgstatic umode_t *umodes; 445cf2cd791Smrgstatic int num_crtcs, num_providers; 446a0d3b6eaSmrgstatic XRRScreenResources *res; 447a0d3b6eaSmrgstatic int fb_width = 0, fb_height = 0; 448a0d3b6eaSmrgstatic int fb_width_mm = 0, fb_height_mm = 0; 449c52f0396Smrgstatic double dpi = 0; 450cf2cd791Smrgstatic char *dpi_output_name = NULL; 451a0d3b6eaSmrgstatic Bool dryrun = False; 452a0d3b6eaSmrgstatic int minWidth, maxWidth, minHeight, maxHeight; 453a0d3b6eaSmrgstatic Bool has_1_2 = False; 45462df5ad0Smrgstatic Bool has_1_3 = False; 455cf2cd791Smrgstatic Bool has_1_4 = False; 456319fa471Smrgstatic Bool has_1_5 = False; 457cf2cd791Smrgstatic name_t provider_name, output_source_provider_name, offload_sink_provider_name; 458319fa471Smrgstatic monitors_t *monitors; 459319fa471Smrgstatic umonitor_t *umonitors; 460a0d3b6eaSmrg 461a0d3b6eaSmrgstatic int 462a0d3b6eaSmrgmode_height (XRRModeInfo *mode_info, Rotation rotation) 463a0d3b6eaSmrg{ 464a0d3b6eaSmrg switch (rotation & 0xf) { 465a0d3b6eaSmrg case RR_Rotate_0: 466a0d3b6eaSmrg case RR_Rotate_180: 467a0d3b6eaSmrg return mode_info->height; 468a0d3b6eaSmrg case RR_Rotate_90: 469a0d3b6eaSmrg case RR_Rotate_270: 470a0d3b6eaSmrg return mode_info->width; 471a0d3b6eaSmrg default: 472a0d3b6eaSmrg return 0; 473a0d3b6eaSmrg } 474a0d3b6eaSmrg} 475a0d3b6eaSmrg 476a0d3b6eaSmrgstatic int 477a0d3b6eaSmrgmode_width (XRRModeInfo *mode_info, Rotation rotation) 478a0d3b6eaSmrg{ 479a0d3b6eaSmrg switch (rotation & 0xf) { 480a0d3b6eaSmrg case RR_Rotate_0: 481a0d3b6eaSmrg case RR_Rotate_180: 482a0d3b6eaSmrg return mode_info->width; 483a0d3b6eaSmrg case RR_Rotate_90: 484a0d3b6eaSmrg case RR_Rotate_270: 485a0d3b6eaSmrg return mode_info->height; 486a0d3b6eaSmrg default: 487a0d3b6eaSmrg return 0; 488a0d3b6eaSmrg } 489a0d3b6eaSmrg} 490a0d3b6eaSmrg 49162df5ad0Smrgstatic Bool 49262df5ad0Smrgtransform_point (XTransform *transform, double *xp, double *yp) 49362df5ad0Smrg{ 49462df5ad0Smrg double vector[3]; 49562df5ad0Smrg double result[3]; 49662df5ad0Smrg int i, j; 49762df5ad0Smrg double v; 49862df5ad0Smrg 49962df5ad0Smrg vector[0] = *xp; 50062df5ad0Smrg vector[1] = *yp; 50162df5ad0Smrg vector[2] = 1; 50262df5ad0Smrg for (j = 0; j < 3; j++) 50362df5ad0Smrg { 50462df5ad0Smrg v = 0; 50562df5ad0Smrg for (i = 0; i < 3; i++) 50662df5ad0Smrg v += (XFixedToDouble (transform->matrix[j][i]) * vector[i]); 50762df5ad0Smrg result[j] = v; 50862df5ad0Smrg } 50962df5ad0Smrg if (!result[2]) 51062df5ad0Smrg return False; 511cf2cd791Smrg for (j = 0; j < 2; j++) { 51262df5ad0Smrg vector[j] = result[j] / result[2]; 513cf2cd791Smrg if (vector[j] > 32767 || vector[j] < -32767) 514cf2cd791Smrg return False; 515cf2cd791Smrg } 51662df5ad0Smrg *xp = vector[0]; 51762df5ad0Smrg *yp = vector[1]; 51862df5ad0Smrg return True; 51962df5ad0Smrg} 52062df5ad0Smrg 52162df5ad0Smrgstatic void 52262df5ad0Smrgpath_bounds (XTransform *transform, point_t *points, int npoints, box_t *box) 52362df5ad0Smrg{ 52462df5ad0Smrg int i; 52562df5ad0Smrg box_t point; 52662df5ad0Smrg 52762df5ad0Smrg for (i = 0; i < npoints; i++) { 52862df5ad0Smrg double x, y; 52962df5ad0Smrg x = points[i].x; 53062df5ad0Smrg y = points[i].y; 53162df5ad0Smrg transform_point (transform, &x, &y); 53262df5ad0Smrg point.x1 = floor (x); 53362df5ad0Smrg point.y1 = floor (y); 53462df5ad0Smrg point.x2 = ceil (x); 53562df5ad0Smrg point.y2 = ceil (y); 53662df5ad0Smrg if (i == 0) 53762df5ad0Smrg *box = point; 53862df5ad0Smrg else { 53962df5ad0Smrg if (point.x1 < box->x1) box->x1 = point.x1; 54062df5ad0Smrg if (point.y1 < box->y1) box->y1 = point.y1; 54162df5ad0Smrg if (point.x2 > box->x2) box->x2 = point.x2; 54262df5ad0Smrg if (point.y2 > box->y2) box->y2 = point.y2; 54362df5ad0Smrg } 54462df5ad0Smrg } 54562df5ad0Smrg} 54662df5ad0Smrg 54762df5ad0Smrgstatic void 54862df5ad0Smrgmode_geometry (XRRModeInfo *mode_info, Rotation rotation, 54962df5ad0Smrg XTransform *transform, 55062df5ad0Smrg box_t *bounds) 55162df5ad0Smrg{ 55262df5ad0Smrg point_t rect[4]; 55362df5ad0Smrg int width = mode_width (mode_info, rotation); 55462df5ad0Smrg int height = mode_height (mode_info, rotation); 55562df5ad0Smrg 55662df5ad0Smrg rect[0].x = 0; 55762df5ad0Smrg rect[0].y = 0; 55862df5ad0Smrg rect[1].x = width; 55962df5ad0Smrg rect[1].y = 0; 56062df5ad0Smrg rect[2].x = width; 56162df5ad0Smrg rect[2].y = height; 56262df5ad0Smrg rect[3].x = 0; 56362df5ad0Smrg rect[3].y = height; 56462df5ad0Smrg path_bounds (transform, rect, 4, bounds); 56562df5ad0Smrg} 56662df5ad0Smrg 567a0d3b6eaSmrg/* v refresh frequency in Hz */ 568c52f0396Smrgstatic double 569319fa471Smrgmode_refresh (const XRRModeInfo *mode_info) 570a0d3b6eaSmrg{ 571c52f0396Smrg double rate; 5727936445dSmrg double vTotal = mode_info->vTotal; 573cf2cd791Smrg 574cf2cd791Smrg if (mode_info->modeFlags & RR_DoubleScan) { 575cf2cd791Smrg /* doublescan doubles the number of lines */ 576cf2cd791Smrg vTotal *= 2; 577cf2cd791Smrg } 578cf2cd791Smrg 579cf2cd791Smrg if (mode_info->modeFlags & RR_Interlace) { 580cf2cd791Smrg /* interlace splits the frame into two fields */ 581cf2cd791Smrg /* the field rate is what is typically reported by monitors */ 582cf2cd791Smrg vTotal /= 2; 583cf2cd791Smrg } 584a0d3b6eaSmrg 585cf2cd791Smrg if (mode_info->hTotal && vTotal) 586c52f0396Smrg rate = ((double) mode_info->dotClock / 587cf2cd791Smrg ((double) mode_info->hTotal * (double) vTotal)); 588a0d3b6eaSmrg else 589a0d3b6eaSmrg rate = 0; 590a0d3b6eaSmrg return rate; 591a0d3b6eaSmrg} 592a0d3b6eaSmrg 593a0d3b6eaSmrg/* h sync frequency in Hz */ 594c52f0396Smrgstatic double 595319fa471Smrgmode_hsync (const XRRModeInfo *mode_info) 596a0d3b6eaSmrg{ 597c52f0396Smrg double rate; 598a0d3b6eaSmrg 599a0d3b6eaSmrg if (mode_info->hTotal) 600c52f0396Smrg rate = (double) mode_info->dotClock / (double) mode_info->hTotal; 601a0d3b6eaSmrg else 602a0d3b6eaSmrg rate = 0; 603a0d3b6eaSmrg return rate; 604a0d3b6eaSmrg} 605a0d3b6eaSmrg 606319fa471Smrgstatic void 607319fa471Smrgprint_verbose_mode (const XRRModeInfo *mode, Bool current, Bool preferred) 608319fa471Smrg{ 609319fa471Smrg int f; 610319fa471Smrg 611319fa471Smrg printf (" %s (0x%x) %6.3fMHz", 612319fa471Smrg mode->name, (int)mode->id, 613319fa471Smrg (double)mode->dotClock / 1000000.0); 614319fa471Smrg for (f = 0; mode_flags[f].flag; f++) 615319fa471Smrg if (mode->modeFlags & mode_flags[f].flag) 616319fa471Smrg printf (" %s", mode_flags[f].string); 617319fa471Smrg if (current) 618319fa471Smrg printf (" *current"); 619319fa471Smrg if (preferred) 620319fa471Smrg printf (" +preferred"); 621319fa471Smrg printf ("\n"); 622319fa471Smrg printf (" h: width %4d start %4d end %4d total %4d skew %4d clock %6.2fKHz\n", 623319fa471Smrg mode->width, mode->hSyncStart, mode->hSyncEnd, 624319fa471Smrg mode->hTotal, mode->hSkew, mode_hsync (mode) / 1000); 625319fa471Smrg printf (" v: height %4d start %4d end %4d total %4d clock %6.2fHz\n", 626319fa471Smrg mode->height, mode->vSyncStart, mode->vSyncEnd, mode->vTotal, 627319fa471Smrg mode_refresh (mode)); 628319fa471Smrg} 629319fa471Smrg 630a0d3b6eaSmrgstatic void 631a0d3b6eaSmrginit_name (name_t *name) 632a0d3b6eaSmrg{ 633a0d3b6eaSmrg name->kind = name_none; 634a0d3b6eaSmrg} 635a0d3b6eaSmrg 636a0d3b6eaSmrgstatic void 637a0d3b6eaSmrgset_name_string (name_t *name, char *string) 638a0d3b6eaSmrg{ 639a0d3b6eaSmrg name->kind |= name_string; 640a0d3b6eaSmrg name->string = string; 641a0d3b6eaSmrg} 642a0d3b6eaSmrg 643a0d3b6eaSmrgstatic void 644a0d3b6eaSmrgset_name_xid (name_t *name, XID xid) 645a0d3b6eaSmrg{ 646a0d3b6eaSmrg name->kind |= name_xid; 647a0d3b6eaSmrg name->xid = xid; 648a0d3b6eaSmrg} 649a0d3b6eaSmrg 650a0d3b6eaSmrgstatic void 651cf2cd791Smrgset_name_index (name_t *name, int idx) 652a0d3b6eaSmrg{ 653a0d3b6eaSmrg name->kind |= name_index; 654cf2cd791Smrg name->index = idx; 655a0d3b6eaSmrg} 656a0d3b6eaSmrg 657a0d3b6eaSmrgstatic void 658a0d3b6eaSmrgset_name_preferred (name_t *name) 659a0d3b6eaSmrg{ 660a0d3b6eaSmrg name->kind |= name_preferred; 661a0d3b6eaSmrg} 662a0d3b6eaSmrg 663a0d3b6eaSmrgstatic void 664a0d3b6eaSmrgset_name_all (name_t *name, name_t *old) 665a0d3b6eaSmrg{ 666a0d3b6eaSmrg if (old->kind & name_xid) 667a0d3b6eaSmrg name->xid = old->xid; 668a0d3b6eaSmrg if (old->kind & name_string) 669a0d3b6eaSmrg name->string = old->string; 670a0d3b6eaSmrg if (old->kind & name_index) 671a0d3b6eaSmrg name->index = old->index; 672a0d3b6eaSmrg name->kind |= old->kind; 673a0d3b6eaSmrg} 674a0d3b6eaSmrg 675a0d3b6eaSmrgstatic void 676a0d3b6eaSmrgset_name (name_t *name, char *string, name_kind_t valid) 677a0d3b6eaSmrg{ 67862df5ad0Smrg unsigned int xid; /* don't make it XID (which is unsigned long): 67962df5ad0Smrg scanf() takes unsigned int */ 680cf2cd791Smrg int idx; 681a0d3b6eaSmrg 682a0d3b6eaSmrg if ((valid & name_xid) && sscanf (string, "0x%x", &xid) == 1) 683a0d3b6eaSmrg set_name_xid (name, xid); 684cf2cd791Smrg else if ((valid & name_index) && sscanf (string, "%d", &idx) == 1) 685cf2cd791Smrg set_name_index (name, idx); 686a0d3b6eaSmrg else if (valid & name_string) 687a0d3b6eaSmrg set_name_string (name, string); 688a0d3b6eaSmrg else 689cf2cd791Smrg argerr ("invalid name '%s'\n", string); 690cf2cd791Smrg} 691cf2cd791Smrg 692cf2cd791Smrgstatic int 693cf2cd791Smrgprint_name (const name_t *name) 694cf2cd791Smrg{ 695cf2cd791Smrg name_kind_t kind = name->kind; 696cf2cd791Smrg 697cf2cd791Smrg if ((kind & name_xid)) return printf("XID 0x%x", (unsigned int)name->xid); 698cf2cd791Smrg else if ((kind & name_string)) return printf("name %s", name->string); 699cf2cd791Smrg else if ((kind & name_index)) return printf("index %d", name->index); 700cf2cd791Smrg else return printf("unknown name"); 701a0d3b6eaSmrg} 702a0d3b6eaSmrg 70362df5ad0Smrgstatic void 70462df5ad0Smrginit_transform (transform_t *transform) 70562df5ad0Smrg{ 70662df5ad0Smrg int x; 70762df5ad0Smrg memset (&transform->transform, '\0', sizeof (transform->transform)); 70862df5ad0Smrg for (x = 0; x < 3; x++) 70962df5ad0Smrg transform->transform.matrix[x][x] = XDoubleToFixed (1.0); 71062df5ad0Smrg transform->filter = ""; 71162df5ad0Smrg transform->nparams = 0; 71262df5ad0Smrg transform->params = NULL; 71362df5ad0Smrg} 71462df5ad0Smrg 71562df5ad0Smrgstatic void 71662df5ad0Smrgset_transform (transform_t *dest, 71762df5ad0Smrg XTransform *transform, 718cf2cd791Smrg const char *filter, 71962df5ad0Smrg XFixed *params, 72062df5ad0Smrg int nparams) 72162df5ad0Smrg{ 72262df5ad0Smrg dest->transform = *transform; 723cf2cd791Smrg /* note: this string is leaked */ 72462df5ad0Smrg dest->filter = strdup (filter); 72562df5ad0Smrg dest->nparams = nparams; 72662df5ad0Smrg dest->params = malloc (nparams * sizeof (XFixed)); 72762df5ad0Smrg memcpy (dest->params, params, nparams * sizeof (XFixed)); 72862df5ad0Smrg} 72962df5ad0Smrg 73062df5ad0Smrgstatic void 73162df5ad0Smrgcopy_transform (transform_t *dest, transform_t *src) 73262df5ad0Smrg{ 73362df5ad0Smrg set_transform (dest, &src->transform, 73462df5ad0Smrg src->filter, src->params, src->nparams); 73562df5ad0Smrg} 73662df5ad0Smrg 73762df5ad0Smrgstatic Bool 73862df5ad0Smrgequal_transform (transform_t *a, transform_t *b) 73962df5ad0Smrg{ 74062df5ad0Smrg if (memcmp (&a->transform, &b->transform, sizeof (XTransform)) != 0) 74162df5ad0Smrg return False; 74262df5ad0Smrg if (strcmp (a->filter, b->filter) != 0) 74362df5ad0Smrg return False; 74462df5ad0Smrg if (a->nparams != b->nparams) 74562df5ad0Smrg return False; 74662df5ad0Smrg if (memcmp (a->params, b->params, a->nparams * sizeof (XFixed)) != 0) 74762df5ad0Smrg return False; 74862df5ad0Smrg return True; 74962df5ad0Smrg} 75062df5ad0Smrg 751a0d3b6eaSmrgstatic output_t * 752a0d3b6eaSmrgadd_output (void) 753a0d3b6eaSmrg{ 754a0d3b6eaSmrg output_t *output = calloc (1, sizeof (output_t)); 755a0d3b6eaSmrg 756a0d3b6eaSmrg if (!output) 75762df5ad0Smrg fatal ("out of memory\n"); 758a0d3b6eaSmrg output->next = NULL; 759c52f0396Smrg output->found = False; 7608a16544fSmrg output->brightness = 1.0; 761cf2cd791Smrg *all_outputs_tail = output; 762cf2cd791Smrg all_outputs_tail = &output->next; 763a0d3b6eaSmrg return output; 764a0d3b6eaSmrg} 765a0d3b6eaSmrg 766a0d3b6eaSmrgstatic output_t * 767a0d3b6eaSmrgfind_output (name_t *name) 768a0d3b6eaSmrg{ 769a0d3b6eaSmrg output_t *output; 770a0d3b6eaSmrg 771cf2cd791Smrg for (output = all_outputs; output; output = output->next) 772a0d3b6eaSmrg { 773a0d3b6eaSmrg name_kind_t common = name->kind & output->output.kind; 774a0d3b6eaSmrg 775a0d3b6eaSmrg if ((common & name_xid) && name->xid == output->output.xid) 776a0d3b6eaSmrg break; 777a0d3b6eaSmrg if ((common & name_string) && !strcmp (name->string, output->output.string)) 778a0d3b6eaSmrg break; 779a0d3b6eaSmrg if ((common & name_index) && name->index == output->output.index) 780a0d3b6eaSmrg break; 781a0d3b6eaSmrg } 782a0d3b6eaSmrg return output; 783a0d3b6eaSmrg} 784a0d3b6eaSmrg 785a0d3b6eaSmrgstatic output_t * 786a0d3b6eaSmrgfind_output_by_xid (RROutput output) 787a0d3b6eaSmrg{ 788a0d3b6eaSmrg name_t output_name; 789a0d3b6eaSmrg 790a0d3b6eaSmrg init_name (&output_name); 791a0d3b6eaSmrg set_name_xid (&output_name, output); 792a0d3b6eaSmrg return find_output (&output_name); 793a0d3b6eaSmrg} 794a0d3b6eaSmrg 795a0d3b6eaSmrgstatic output_t * 796a0d3b6eaSmrgfind_output_by_name (char *name) 797a0d3b6eaSmrg{ 798a0d3b6eaSmrg name_t output_name; 799a0d3b6eaSmrg 800a0d3b6eaSmrg init_name (&output_name); 801a0d3b6eaSmrg set_name_string (&output_name, name); 802a0d3b6eaSmrg return find_output (&output_name); 803a0d3b6eaSmrg} 804a0d3b6eaSmrg 805a0d3b6eaSmrgstatic crtc_t * 806a0d3b6eaSmrgfind_crtc (name_t *name) 807a0d3b6eaSmrg{ 808a0d3b6eaSmrg int c; 809a0d3b6eaSmrg crtc_t *crtc = NULL; 810a0d3b6eaSmrg 811a0d3b6eaSmrg for (c = 0; c < num_crtcs; c++) 812a0d3b6eaSmrg { 813a0d3b6eaSmrg name_kind_t common; 814a0d3b6eaSmrg 815a0d3b6eaSmrg crtc = &crtcs[c]; 816a0d3b6eaSmrg common = name->kind & crtc->crtc.kind; 817a0d3b6eaSmrg 818a0d3b6eaSmrg if ((common & name_xid) && name->xid == crtc->crtc.xid) 819a0d3b6eaSmrg break; 820a0d3b6eaSmrg if ((common & name_string) && !strcmp (name->string, crtc->crtc.string)) 821a0d3b6eaSmrg break; 822a0d3b6eaSmrg if ((common & name_index) && name->index == crtc->crtc.index) 823a0d3b6eaSmrg break; 824a0d3b6eaSmrg crtc = NULL; 825a0d3b6eaSmrg } 826a0d3b6eaSmrg return crtc; 827a0d3b6eaSmrg} 828a0d3b6eaSmrg 829a0d3b6eaSmrgstatic crtc_t * 830a0d3b6eaSmrgfind_crtc_by_xid (RRCrtc crtc) 831a0d3b6eaSmrg{ 832a0d3b6eaSmrg name_t crtc_name; 833a0d3b6eaSmrg 834a0d3b6eaSmrg init_name (&crtc_name); 835a0d3b6eaSmrg set_name_xid (&crtc_name, crtc); 836a0d3b6eaSmrg return find_crtc (&crtc_name); 837a0d3b6eaSmrg} 838a0d3b6eaSmrg 839a0d3b6eaSmrgstatic XRRModeInfo * 840c52f0396Smrgfind_mode (name_t *name, double refresh) 841a0d3b6eaSmrg{ 842a0d3b6eaSmrg int m; 843a0d3b6eaSmrg XRRModeInfo *best = NULL; 844c52f0396Smrg double bestDist = 0; 845a0d3b6eaSmrg 846a0d3b6eaSmrg for (m = 0; m < res->nmode; m++) 847a0d3b6eaSmrg { 848a0d3b6eaSmrg XRRModeInfo *mode = &res->modes[m]; 849a0d3b6eaSmrg if ((name->kind & name_xid) && name->xid == mode->id) 850a0d3b6eaSmrg { 851a0d3b6eaSmrg best = mode; 852a0d3b6eaSmrg break; 853a0d3b6eaSmrg } 854a0d3b6eaSmrg if ((name->kind & name_string) && !strcmp (name->string, mode->name)) 855a0d3b6eaSmrg { 856c52f0396Smrg double dist; 857a0d3b6eaSmrg 858a0d3b6eaSmrg if (refresh) 859a0d3b6eaSmrg dist = fabs (mode_refresh (mode) - refresh); 860a0d3b6eaSmrg else 861a0d3b6eaSmrg dist = 0; 862a0d3b6eaSmrg if (!best || dist < bestDist) 863a0d3b6eaSmrg { 864a0d3b6eaSmrg bestDist = dist; 865a0d3b6eaSmrg best = mode; 866a0d3b6eaSmrg } 867a0d3b6eaSmrg } 868a0d3b6eaSmrg } 869a0d3b6eaSmrg return best; 870a0d3b6eaSmrg} 871a0d3b6eaSmrg 872a0d3b6eaSmrgstatic XRRModeInfo * 873a0d3b6eaSmrgfind_mode_by_xid (RRMode mode) 874a0d3b6eaSmrg{ 875a0d3b6eaSmrg name_t mode_name; 876a0d3b6eaSmrg 877a0d3b6eaSmrg init_name (&mode_name); 878a0d3b6eaSmrg set_name_xid (&mode_name, mode); 879a0d3b6eaSmrg return find_mode (&mode_name, 0); 880a0d3b6eaSmrg} 881a0d3b6eaSmrg 88262df5ad0Smrg#if 0 883a0d3b6eaSmrgstatic XRRModeInfo * 884a0d3b6eaSmrgfind_mode_by_name (char *name) 885a0d3b6eaSmrg{ 886a0d3b6eaSmrg name_t mode_name; 887a0d3b6eaSmrg init_name (&mode_name); 888a0d3b6eaSmrg set_name_string (&mode_name, name); 889a0d3b6eaSmrg return find_mode (&mode_name, 0); 890a0d3b6eaSmrg} 89162df5ad0Smrg#endif 892a0d3b6eaSmrg 893a0d3b6eaSmrgstatic 894a0d3b6eaSmrgXRRModeInfo * 895a0d3b6eaSmrgfind_mode_for_output (output_t *output, name_t *name) 896a0d3b6eaSmrg{ 897a0d3b6eaSmrg XRROutputInfo *output_info = output->output_info; 898a0d3b6eaSmrg int m; 899a0d3b6eaSmrg XRRModeInfo *best = NULL; 900c52f0396Smrg double bestDist = 0; 901a0d3b6eaSmrg 902a0d3b6eaSmrg for (m = 0; m < output_info->nmode; m++) 903a0d3b6eaSmrg { 904a0d3b6eaSmrg XRRModeInfo *mode; 90562df5ad0Smrg 906a0d3b6eaSmrg mode = find_mode_by_xid (output_info->modes[m]); 907a0d3b6eaSmrg if (!mode) continue; 908a0d3b6eaSmrg if ((name->kind & name_xid) && name->xid == mode->id) 909a0d3b6eaSmrg { 910a0d3b6eaSmrg best = mode; 911a0d3b6eaSmrg break; 912a0d3b6eaSmrg } 913a0d3b6eaSmrg if ((name->kind & name_string) && !strcmp (name->string, mode->name)) 914a0d3b6eaSmrg { 915c52f0396Smrg double dist; 91662df5ad0Smrg 91762df5ad0Smrg /* Stay away from doublescan modes unless refresh rate is specified. */ 91862df5ad0Smrg if (!output->refresh && (mode->modeFlags & RR_DoubleScan)) 91962df5ad0Smrg continue; 92062df5ad0Smrg 921a0d3b6eaSmrg if (output->refresh) 922a0d3b6eaSmrg dist = fabs (mode_refresh (mode) - output->refresh); 923a0d3b6eaSmrg else 924a0d3b6eaSmrg dist = 0; 925a0d3b6eaSmrg if (!best || dist < bestDist) 926a0d3b6eaSmrg { 927a0d3b6eaSmrg bestDist = dist; 928a0d3b6eaSmrg best = mode; 929a0d3b6eaSmrg } 930a0d3b6eaSmrg } 931a0d3b6eaSmrg } 932a0d3b6eaSmrg return best; 933a0d3b6eaSmrg} 934a0d3b6eaSmrg 93562df5ad0Smrgstatic XRRModeInfo * 936a0d3b6eaSmrgpreferred_mode (output_t *output) 937a0d3b6eaSmrg{ 938a0d3b6eaSmrg XRROutputInfo *output_info = output->output_info; 939a0d3b6eaSmrg int m; 940a0d3b6eaSmrg XRRModeInfo *best; 941a0d3b6eaSmrg int bestDist; 942a0d3b6eaSmrg 943a0d3b6eaSmrg best = NULL; 944a0d3b6eaSmrg bestDist = 0; 945a0d3b6eaSmrg for (m = 0; m < output_info->nmode; m++) 946a0d3b6eaSmrg { 947a0d3b6eaSmrg XRRModeInfo *mode_info = find_mode_by_xid (output_info->modes[m]); 948a0d3b6eaSmrg int dist; 949a0d3b6eaSmrg 950a0d3b6eaSmrg if (m < output_info->npreferred) 951a0d3b6eaSmrg dist = 0; 952a0d3b6eaSmrg else if (output_info->mm_height) 953a0d3b6eaSmrg dist = (1000 * DisplayHeight(dpy, screen) / DisplayHeightMM(dpy, screen) - 954a0d3b6eaSmrg 1000 * mode_info->height / output_info->mm_height); 955a0d3b6eaSmrg else 956a0d3b6eaSmrg dist = DisplayHeight(dpy, screen) - mode_info->height; 957a0d3b6eaSmrg 958a0d3b6eaSmrg if (dist < 0) dist = -dist; 959a0d3b6eaSmrg if (!best || dist < bestDist) 960a0d3b6eaSmrg { 961a0d3b6eaSmrg best = mode_info; 962a0d3b6eaSmrg bestDist = dist; 963a0d3b6eaSmrg } 964a0d3b6eaSmrg } 965a0d3b6eaSmrg return best; 966a0d3b6eaSmrg} 967a0d3b6eaSmrg 968a0d3b6eaSmrgstatic Bool 969a0d3b6eaSmrgoutput_can_use_crtc (output_t *output, crtc_t *crtc) 970a0d3b6eaSmrg{ 971a0d3b6eaSmrg XRROutputInfo *output_info = output->output_info; 972a0d3b6eaSmrg int c; 973a0d3b6eaSmrg 974a0d3b6eaSmrg for (c = 0; c < output_info->ncrtc; c++) 975a0d3b6eaSmrg if (output_info->crtcs[c] == crtc->crtc.xid) 976a0d3b6eaSmrg return True; 977a0d3b6eaSmrg return False; 978a0d3b6eaSmrg} 979a0d3b6eaSmrg 980a0d3b6eaSmrgstatic Bool 981a0d3b6eaSmrgoutput_can_use_mode (output_t *output, XRRModeInfo *mode) 982a0d3b6eaSmrg{ 983a0d3b6eaSmrg XRROutputInfo *output_info = output->output_info; 984a0d3b6eaSmrg int m; 985a0d3b6eaSmrg 986a0d3b6eaSmrg for (m = 0; m < output_info->nmode; m++) 987a0d3b6eaSmrg if (output_info->modes[m] == mode->id) 988a0d3b6eaSmrg return True; 989a0d3b6eaSmrg return False; 990a0d3b6eaSmrg} 991a0d3b6eaSmrg 992a0d3b6eaSmrgstatic Bool 993a0d3b6eaSmrgcrtc_can_use_rotation (crtc_t *crtc, Rotation rotation) 994a0d3b6eaSmrg{ 995a0d3b6eaSmrg Rotation rotations = crtc->crtc_info->rotations; 996a0d3b6eaSmrg Rotation dir = rotation & (RR_Rotate_0|RR_Rotate_90|RR_Rotate_180|RR_Rotate_270); 997a0d3b6eaSmrg Rotation reflect = rotation & (RR_Reflect_X|RR_Reflect_Y); 998a0d3b6eaSmrg if (((rotations & dir) != 0) && ((rotations & reflect) == reflect)) 999a0d3b6eaSmrg return True; 1000a0d3b6eaSmrg return False; 1001a0d3b6eaSmrg} 1002a0d3b6eaSmrg 100362df5ad0Smrg#if 0 100462df5ad0Smrgstatic Bool 100562df5ad0Smrgcrtc_can_use_transform (crtc_t *crtc, XTransform *transform) 100662df5ad0Smrg{ 100762df5ad0Smrg int major, minor; 100862df5ad0Smrg 100962df5ad0Smrg XRRQueryVersion (dpy, &major, &minor); 101062df5ad0Smrg if (major > 1 || (major == 1 && minor >= 3)) 101162df5ad0Smrg return True; 101262df5ad0Smrg return False; 101362df5ad0Smrg} 101462df5ad0Smrg#endif 101562df5ad0Smrg 1016a0d3b6eaSmrg/* 1017a0d3b6eaSmrg * Report only rotations that are supported by all crtcs 1018a0d3b6eaSmrg */ 1019a0d3b6eaSmrgstatic Rotation 1020a0d3b6eaSmrgoutput_rotations (output_t *output) 1021a0d3b6eaSmrg{ 1022a0d3b6eaSmrg Bool found = False; 1023a0d3b6eaSmrg Rotation rotation = RR_Rotate_0; 1024a0d3b6eaSmrg XRROutputInfo *output_info = output->output_info; 1025a0d3b6eaSmrg int c; 1026a0d3b6eaSmrg 1027a0d3b6eaSmrg for (c = 0; c < output_info->ncrtc; c++) 1028a0d3b6eaSmrg { 1029a0d3b6eaSmrg crtc_t *crtc = find_crtc_by_xid (output_info->crtcs[c]); 1030a0d3b6eaSmrg if (crtc) 1031a0d3b6eaSmrg { 1032a0d3b6eaSmrg if (!found) { 1033a0d3b6eaSmrg rotation = crtc->crtc_info->rotations; 1034a0d3b6eaSmrg found = True; 1035a0d3b6eaSmrg } else 1036a0d3b6eaSmrg rotation &= crtc->crtc_info->rotations; 1037a0d3b6eaSmrg } 1038a0d3b6eaSmrg } 1039a0d3b6eaSmrg return rotation; 1040a0d3b6eaSmrg} 1041a0d3b6eaSmrg 1042a0d3b6eaSmrgstatic Bool 1043a0d3b6eaSmrgoutput_can_use_rotation (output_t *output, Rotation rotation) 1044a0d3b6eaSmrg{ 1045a0d3b6eaSmrg XRROutputInfo *output_info = output->output_info; 1046a0d3b6eaSmrg int c; 1047a0d3b6eaSmrg 1048a0d3b6eaSmrg /* make sure all of the crtcs can use this rotation. 1049a0d3b6eaSmrg * yes, this is not strictly necessary, but it is 1050a0d3b6eaSmrg * simpler,and we expect most drivers to either 1051a0d3b6eaSmrg * support rotation everywhere or nowhere 1052a0d3b6eaSmrg */ 1053a0d3b6eaSmrg for (c = 0; c < output_info->ncrtc; c++) 1054a0d3b6eaSmrg { 1055a0d3b6eaSmrg crtc_t *crtc = find_crtc_by_xid (output_info->crtcs[c]); 1056a0d3b6eaSmrg if (crtc && !crtc_can_use_rotation (crtc, rotation)) 1057a0d3b6eaSmrg return False; 1058a0d3b6eaSmrg } 1059a0d3b6eaSmrg return True; 1060a0d3b6eaSmrg} 1061a0d3b6eaSmrg 106262df5ad0Smrgstatic Bool 106362df5ad0Smrgoutput_is_primary(output_t *output) 106462df5ad0Smrg{ 106562df5ad0Smrg if (has_1_3) 106662df5ad0Smrg return XRRGetOutputPrimary(dpy, root) == output->output.xid; 106762df5ad0Smrg return False; 106862df5ad0Smrg} 106962df5ad0Smrg 10708a16544fSmrg/* Returns the index of the last value in an array < 0xffff */ 10718a16544fSmrgstatic int 10728a16544fSmrgfind_last_non_clamped(CARD16 array[], int size) { 10738a16544fSmrg int i; 10748a16544fSmrg for (i = size - 1; i > 0; i--) { 10758a16544fSmrg if (array[i] < 0xffff) 10768a16544fSmrg return i; 10778a16544fSmrg } 10788a16544fSmrg return 0; 10798a16544fSmrg} 10808a16544fSmrg 10818a16544fSmrgstatic void 10828a16544fSmrgset_gamma_info(output_t *output) 10838a16544fSmrg{ 1084cf2cd791Smrg XRRCrtcGamma *crtc_gamma; 10858a16544fSmrg double i1, v1, i2, v2; 10868a16544fSmrg int size, middle, last_best, last_red, last_green, last_blue; 10878a16544fSmrg CARD16 *best_array; 10888a16544fSmrg 10898a16544fSmrg if (!output->crtc_info) 10908a16544fSmrg return; 10918a16544fSmrg 10928a16544fSmrg size = XRRGetCrtcGammaSize(dpy, output->crtc_info->crtc.xid); 10938a16544fSmrg if (!size) { 10948a16544fSmrg warning("Failed to get size of gamma for output %s\n", output->output.string); 10958a16544fSmrg return; 10968a16544fSmrg } 10978a16544fSmrg 1098cf2cd791Smrg crtc_gamma = XRRGetCrtcGamma(dpy, output->crtc_info->crtc.xid); 1099cf2cd791Smrg if (!crtc_gamma) { 11008a16544fSmrg warning("Failed to get gamma for output %s\n", output->output.string); 11018a16544fSmrg return; 11028a16544fSmrg } 11038a16544fSmrg 11048a16544fSmrg /* 11058a16544fSmrg * Here is a bit tricky because gamma is a whole curve for each 11068a16544fSmrg * color. So, typically, we need to represent 3 * 256 values as 3 + 1 11078a16544fSmrg * values. Therefore, we approximate the gamma curve (v) by supposing 11088a16544fSmrg * it always follows the way we set it: a power function (i^g) 11098a16544fSmrg * multiplied by a brightness (b). 11108a16544fSmrg * v = i^g * b 11118a16544fSmrg * so g = (ln(v) - ln(b))/ln(i) 11128a16544fSmrg * and b can be found using two points (v1,i1) and (v2, i2): 11138a16544fSmrg * b = e^((ln(v2)*ln(i1) - ln(v1)*ln(i2))/ln(i1/i2)) 11148a16544fSmrg * For the best resolution, we select i2 at the highest place not 11158a16544fSmrg * clamped and i1 at i2/2. Note that if i2 = 1 (as in most normal 11168a16544fSmrg * cases), then b = v2. 11178a16544fSmrg */ 1118cf2cd791Smrg last_red = find_last_non_clamped(crtc_gamma->red, size); 1119cf2cd791Smrg last_green = find_last_non_clamped(crtc_gamma->green, size); 1120cf2cd791Smrg last_blue = find_last_non_clamped(crtc_gamma->blue, size); 1121cf2cd791Smrg best_array = crtc_gamma->red; 11228a16544fSmrg last_best = last_red; 11238a16544fSmrg if (last_green > last_best) { 11248a16544fSmrg last_best = last_green; 1125cf2cd791Smrg best_array = crtc_gamma->green; 11268a16544fSmrg } 11278a16544fSmrg if (last_blue > last_best) { 11288a16544fSmrg last_best = last_blue; 1129cf2cd791Smrg best_array = crtc_gamma->blue; 11308a16544fSmrg } 11318a16544fSmrg if (last_best == 0) 11328a16544fSmrg last_best = 1; 11338a16544fSmrg 11348a16544fSmrg middle = last_best / 2; 11358a16544fSmrg i1 = (double)(middle + 1) / size; 11368a16544fSmrg v1 = (double)(best_array[middle]) / 65535; 11378a16544fSmrg i2 = (double)(last_best + 1) / size; 11388a16544fSmrg v2 = (double)(best_array[last_best]) / 65535; 11398a16544fSmrg if (v2 < 0.0001) { /* The screen is black */ 11408a16544fSmrg output->brightness = 0; 11418a16544fSmrg output->gamma.red = 1; 11428a16544fSmrg output->gamma.green = 1; 11438a16544fSmrg output->gamma.blue = 1; 11448a16544fSmrg } else { 11458a16544fSmrg if ((last_best + 1) == size) 11468a16544fSmrg output->brightness = v2; 11478a16544fSmrg else 11488a16544fSmrg output->brightness = exp((log(v2)*log(i1) - log(v1)*log(i2))/log(i1/i2)); 1149cf2cd791Smrg output->gamma.red = log((double)(crtc_gamma->red[last_red / 2]) / output->brightness 11508a16544fSmrg / 65535) / log((double)((last_red / 2) + 1) / size); 1151cf2cd791Smrg output->gamma.green = log((double)(crtc_gamma->green[last_green / 2]) / output->brightness 11528a16544fSmrg / 65535) / log((double)((last_green / 2) + 1) / size); 1153cf2cd791Smrg output->gamma.blue = log((double)(crtc_gamma->blue[last_blue / 2]) / output->brightness 11548a16544fSmrg / 65535) / log((double)((last_blue / 2) + 1) / size); 11558a16544fSmrg } 11568a16544fSmrg 1157cf2cd791Smrg XRRFreeGamma(crtc_gamma); 11588a16544fSmrg} 11598a16544fSmrg 1160a0d3b6eaSmrgstatic void 1161a0d3b6eaSmrgset_output_info (output_t *output, RROutput xid, XRROutputInfo *output_info) 1162a0d3b6eaSmrg{ 1163a0d3b6eaSmrg /* sanity check output info */ 1164a0d3b6eaSmrg if (output_info->connection != RR_Disconnected && !output_info->nmode) 116562df5ad0Smrg warning ("Output %s is not disconnected but has no modes\n", 116662df5ad0Smrg output_info->name); 1167a0d3b6eaSmrg 1168a0d3b6eaSmrg /* set output name and info */ 1169a0d3b6eaSmrg if (!(output->output.kind & name_xid)) 1170a0d3b6eaSmrg set_name_xid (&output->output, xid); 1171a0d3b6eaSmrg if (!(output->output.kind & name_string)) 1172a0d3b6eaSmrg set_name_string (&output->output, output_info->name); 1173a0d3b6eaSmrg output->output_info = output_info; 1174a0d3b6eaSmrg 1175a0d3b6eaSmrg /* set crtc name and info */ 1176a0d3b6eaSmrg if (!(output->changes & changes_crtc)) 1177a0d3b6eaSmrg set_name_xid (&output->crtc, output_info->crtc); 1178a0d3b6eaSmrg 1179a0d3b6eaSmrg if (output->crtc.kind == name_xid && output->crtc.xid == None) 1180a0d3b6eaSmrg output->crtc_info = NULL; 1181a0d3b6eaSmrg else 1182a0d3b6eaSmrg { 1183a0d3b6eaSmrg output->crtc_info = find_crtc (&output->crtc); 1184a0d3b6eaSmrg if (!output->crtc_info) 1185a0d3b6eaSmrg { 1186a0d3b6eaSmrg if (output->crtc.kind & name_xid) 1187cf2cd791Smrg fatal ("cannot find crtc 0x%lx\n", output->crtc.xid); 1188a0d3b6eaSmrg if (output->crtc.kind & name_index) 1189a0d3b6eaSmrg fatal ("cannot find crtc %d\n", output->crtc.index); 1190a0d3b6eaSmrg } 1191a0d3b6eaSmrg if (!output_can_use_crtc (output, output->crtc_info)) 1192cf2cd791Smrg fatal ("output %s cannot use crtc 0x%lx\n", output->output.string, 1193a0d3b6eaSmrg output->crtc_info->crtc.xid); 1194a0d3b6eaSmrg } 1195a0d3b6eaSmrg 1196a0d3b6eaSmrg /* set mode name and info */ 1197a0d3b6eaSmrg if (!(output->changes & changes_mode)) 1198a0d3b6eaSmrg { 1199cf2cd791Smrg crtc_t *crtc = NULL; 1200cf2cd791Smrg 1201cf2cd791Smrg if (output_info->crtc) 1202cf2cd791Smrg crtc = find_crtc_by_xid(output_info->crtc); 1203cf2cd791Smrg if (crtc && crtc->crtc_info) 1204cf2cd791Smrg set_name_xid (&output->mode, crtc->crtc_info->mode); 1205cf2cd791Smrg else if (output->crtc_info) 1206a0d3b6eaSmrg set_name_xid (&output->mode, output->crtc_info->crtc_info->mode); 1207a0d3b6eaSmrg else 1208a0d3b6eaSmrg set_name_xid (&output->mode, None); 1209a0d3b6eaSmrg if (output->mode.xid) 1210a0d3b6eaSmrg { 1211a0d3b6eaSmrg output->mode_info = find_mode_by_xid (output->mode.xid); 1212a0d3b6eaSmrg if (!output->mode_info) 1213cf2cd791Smrg fatal ("server did not report mode 0x%lx for output %s\n", 1214a0d3b6eaSmrg output->mode.xid, output->output.string); 1215a0d3b6eaSmrg } 1216a0d3b6eaSmrg else 1217a0d3b6eaSmrg output->mode_info = NULL; 1218a0d3b6eaSmrg } 1219a0d3b6eaSmrg else if (output->mode.kind == name_xid && output->mode.xid == None) 1220a0d3b6eaSmrg output->mode_info = NULL; 1221a0d3b6eaSmrg else 1222a0d3b6eaSmrg { 1223a0d3b6eaSmrg if (output->mode.kind == name_preferred) 1224a0d3b6eaSmrg output->mode_info = preferred_mode (output); 1225a0d3b6eaSmrg else 1226a0d3b6eaSmrg output->mode_info = find_mode_for_output (output, &output->mode); 1227a0d3b6eaSmrg if (!output->mode_info) 1228a0d3b6eaSmrg { 1229a0d3b6eaSmrg if (output->mode.kind & name_preferred) 1230a0d3b6eaSmrg fatal ("cannot find preferred mode\n"); 1231a0d3b6eaSmrg if (output->mode.kind & name_string) 1232a0d3b6eaSmrg fatal ("cannot find mode %s\n", output->mode.string); 1233a0d3b6eaSmrg if (output->mode.kind & name_xid) 1234cf2cd791Smrg fatal ("cannot find mode 0x%lx\n", output->mode.xid); 1235a0d3b6eaSmrg } 1236a0d3b6eaSmrg if (!output_can_use_mode (output, output->mode_info)) 1237a0d3b6eaSmrg fatal ("output %s cannot use mode %s\n", output->output.string, 1238a0d3b6eaSmrg output->mode_info->name); 1239a0d3b6eaSmrg } 1240a0d3b6eaSmrg 1241a0d3b6eaSmrg /* set position */ 1242a0d3b6eaSmrg if (!(output->changes & changes_position)) 1243a0d3b6eaSmrg { 1244a0d3b6eaSmrg if (output->crtc_info) 1245a0d3b6eaSmrg { 1246a0d3b6eaSmrg output->x = output->crtc_info->crtc_info->x; 1247a0d3b6eaSmrg output->y = output->crtc_info->crtc_info->y; 1248a0d3b6eaSmrg } 1249a0d3b6eaSmrg else 1250a0d3b6eaSmrg { 1251a0d3b6eaSmrg output->x = 0; 1252a0d3b6eaSmrg output->y = 0; 1253a0d3b6eaSmrg } 1254a0d3b6eaSmrg } 1255a0d3b6eaSmrg 1256a0d3b6eaSmrg /* set rotation */ 1257a0d3b6eaSmrg if (!(output->changes & changes_rotation)) 1258a0d3b6eaSmrg { 1259a0d3b6eaSmrg output->rotation &= ~0xf; 1260a0d3b6eaSmrg if (output->crtc_info) 1261a0d3b6eaSmrg output->rotation |= (output->crtc_info->crtc_info->rotation & 0xf); 1262a0d3b6eaSmrg else 1263a0d3b6eaSmrg output->rotation = RR_Rotate_0; 1264a0d3b6eaSmrg } 1265a0d3b6eaSmrg if (!(output->changes & changes_reflection)) 1266a0d3b6eaSmrg { 1267a0d3b6eaSmrg output->rotation &= ~(RR_Reflect_X|RR_Reflect_Y); 1268a0d3b6eaSmrg if (output->crtc_info) 1269a0d3b6eaSmrg output->rotation |= (output->crtc_info->crtc_info->rotation & 1270a0d3b6eaSmrg (RR_Reflect_X|RR_Reflect_Y)); 1271a0d3b6eaSmrg } 1272a0d3b6eaSmrg if (!output_can_use_rotation (output, output->rotation)) 1273a0d3b6eaSmrg fatal ("output %s cannot use rotation \"%s\" reflection \"%s\"\n", 1274a0d3b6eaSmrg output->output.string, 1275a0d3b6eaSmrg rotation_name (output->rotation), 1276a0d3b6eaSmrg reflection_name (output->rotation)); 127762df5ad0Smrg 12788a16544fSmrg /* set gamma */ 12798a16544fSmrg if (!(output->changes & changes_gamma)) 12808a16544fSmrg set_gamma_info(output); 12818a16544fSmrg 128262df5ad0Smrg /* set transformation */ 128362df5ad0Smrg if (!(output->changes & changes_transform)) 128462df5ad0Smrg { 128562df5ad0Smrg if (output->crtc_info) 128662df5ad0Smrg copy_transform (&output->transform, &output->crtc_info->current_transform); 128762df5ad0Smrg else 128862df5ad0Smrg init_transform (&output->transform); 1289cf2cd791Smrg } else { 1290cf2cd791Smrg /* transform was already set for --scale or --transform */ 1291cf2cd791Smrg 1292cf2cd791Smrg /* for --scale-from, figure out the mode size and compute the transform 1293cf2cd791Smrg * for the target framebuffer area */ 1294cf2cd791Smrg if (output->scale_from_w > 0 && output->mode_info) { 1295cf2cd791Smrg double sx = (double)output->scale_from_w / 1296cf2cd791Smrg output->mode_info->width; 1297cf2cd791Smrg double sy = (double)output->scale_from_h / 1298cf2cd791Smrg output->mode_info->height; 1299cf2cd791Smrg if (verbose) 1300cf2cd791Smrg printf("scaling %s by %lfx%lf\n", output->output.string, sx, 1301cf2cd791Smrg sy); 1302cf2cd791Smrg init_transform (&output->transform); 1303cf2cd791Smrg output->transform.transform.matrix[0][0] = XDoubleToFixed (sx); 1304cf2cd791Smrg output->transform.transform.matrix[1][1] = XDoubleToFixed (sy); 1305cf2cd791Smrg output->transform.transform.matrix[2][2] = XDoubleToFixed (1.0); 1306cf2cd791Smrg if (sx != 1 || sy != 1) 1307cf2cd791Smrg output->transform.filter = "bilinear"; 1308cf2cd791Smrg else 1309cf2cd791Smrg output->transform.filter = "nearest"; 1310cf2cd791Smrg output->transform.nparams = 0; 1311cf2cd791Smrg output->transform.params = NULL; 1312cf2cd791Smrg } 131362df5ad0Smrg } 131462df5ad0Smrg 131562df5ad0Smrg /* set primary */ 131662df5ad0Smrg if (!(output->changes & changes_primary)) 131762df5ad0Smrg output->primary = output_is_primary(output); 1318a0d3b6eaSmrg} 1319a0d3b6eaSmrg 1320a0d3b6eaSmrgstatic void 132162df5ad0Smrgget_screen (Bool current) 1322a0d3b6eaSmrg{ 1323a0d3b6eaSmrg if (!has_1_2) 1324a0d3b6eaSmrg fatal ("Server RandR version before 1.2\n"); 1325cf2cd791Smrg 1326cf2cd791Smrg if (res) 1327cf2cd791Smrg return; 1328cf2cd791Smrg 1329a0d3b6eaSmrg XRRGetScreenSizeRange (dpy, root, &minWidth, &minHeight, 1330a0d3b6eaSmrg &maxWidth, &maxHeight); 1331a0d3b6eaSmrg 133262df5ad0Smrg if (current) 133362df5ad0Smrg res = XRRGetScreenResourcesCurrent (dpy, root); 133462df5ad0Smrg else 133562df5ad0Smrg res = XRRGetScreenResources (dpy, root); 1336a0d3b6eaSmrg if (!res) fatal ("could not get screen resources"); 1337a0d3b6eaSmrg} 1338a0d3b6eaSmrg 1339a0d3b6eaSmrgstatic void 1340a0d3b6eaSmrgget_crtcs (void) 1341a0d3b6eaSmrg{ 1342a0d3b6eaSmrg int c; 1343a0d3b6eaSmrg 1344a0d3b6eaSmrg num_crtcs = res->ncrtc; 1345a0d3b6eaSmrg crtcs = calloc (num_crtcs, sizeof (crtc_t)); 134662df5ad0Smrg if (!crtcs) fatal ("out of memory\n"); 1347a0d3b6eaSmrg 1348a0d3b6eaSmrg for (c = 0; c < res->ncrtc; c++) 1349a0d3b6eaSmrg { 1350a0d3b6eaSmrg XRRCrtcInfo *crtc_info = XRRGetCrtcInfo (dpy, res, res->crtcs[c]); 135162df5ad0Smrg XRRCrtcTransformAttributes *attr; 135262df5ad0Smrg XRRPanning *panning_info = NULL; 135362df5ad0Smrg 135462df5ad0Smrg if (has_1_3) { 135562df5ad0Smrg XRRPanning zero; 135662df5ad0Smrg memset(&zero, 0, sizeof(zero)); 135762df5ad0Smrg panning_info = XRRGetPanning (dpy, res, res->crtcs[c]); 135862df5ad0Smrg zero.timestamp = panning_info->timestamp; 135962df5ad0Smrg if (!memcmp(panning_info, &zero, sizeof(zero))) { 136062df5ad0Smrg Xfree(panning_info); 136162df5ad0Smrg panning_info = NULL; 136262df5ad0Smrg } 136362df5ad0Smrg } 136462df5ad0Smrg 1365a0d3b6eaSmrg set_name_xid (&crtcs[c].crtc, res->crtcs[c]); 1366a0d3b6eaSmrg set_name_index (&crtcs[c].crtc, c); 1367cf2cd791Smrg if (!crtc_info) fatal ("could not get crtc 0x%lx information\n", res->crtcs[c]); 1368a0d3b6eaSmrg crtcs[c].crtc_info = crtc_info; 136962df5ad0Smrg crtcs[c].panning_info = panning_info; 1370a0d3b6eaSmrg if (crtc_info->mode == None) 1371a0d3b6eaSmrg { 1372a0d3b6eaSmrg crtcs[c].mode_info = NULL; 1373a0d3b6eaSmrg crtcs[c].x = 0; 1374a0d3b6eaSmrg crtcs[c].y = 0; 1375a0d3b6eaSmrg crtcs[c].rotation = RR_Rotate_0; 1376a0d3b6eaSmrg } 137762df5ad0Smrg if (XRRGetCrtcTransform (dpy, res->crtcs[c], &attr) && attr) { 137862df5ad0Smrg set_transform (&crtcs[c].current_transform, 137962df5ad0Smrg &attr->currentTransform, 138062df5ad0Smrg attr->currentFilter, 138162df5ad0Smrg attr->currentParams, 138262df5ad0Smrg attr->currentNparams); 138362df5ad0Smrg XFree (attr); 138462df5ad0Smrg } 138562df5ad0Smrg else 138662df5ad0Smrg { 138762df5ad0Smrg init_transform (&crtcs[c].current_transform); 138862df5ad0Smrg } 138962df5ad0Smrg copy_transform (&crtcs[c].pending_transform, &crtcs[c].current_transform); 139062df5ad0Smrg } 1391a0d3b6eaSmrg} 1392a0d3b6eaSmrg 1393a0d3b6eaSmrgstatic void 1394a0d3b6eaSmrgcrtc_add_output (crtc_t *crtc, output_t *output) 1395a0d3b6eaSmrg{ 1396a0d3b6eaSmrg if (crtc->outputs) 1397a0d3b6eaSmrg crtc->outputs = realloc (crtc->outputs, (crtc->noutput + 1) * sizeof (output_t *)); 1398a0d3b6eaSmrg else 1399a0d3b6eaSmrg { 1400a0d3b6eaSmrg crtc->outputs = malloc (sizeof (output_t *)); 1401a0d3b6eaSmrg crtc->x = output->x; 1402a0d3b6eaSmrg crtc->y = output->y; 1403a0d3b6eaSmrg crtc->rotation = output->rotation; 1404a0d3b6eaSmrg crtc->mode_info = output->mode_info; 140562df5ad0Smrg copy_transform (&crtc->pending_transform, &output->transform); 140662df5ad0Smrg } 140762df5ad0Smrg if (!crtc->outputs) fatal ("out of memory\n"); 1408a0d3b6eaSmrg crtc->outputs[crtc->noutput++] = output; 1409a0d3b6eaSmrg} 1410a0d3b6eaSmrg 1411a0d3b6eaSmrgstatic void 1412a0d3b6eaSmrgset_crtcs (void) 1413a0d3b6eaSmrg{ 1414a0d3b6eaSmrg output_t *output; 1415a0d3b6eaSmrg 1416cf2cd791Smrg for (output = all_outputs; output; output = output->next) 1417a0d3b6eaSmrg { 1418a0d3b6eaSmrg if (!output->mode_info) continue; 1419a0d3b6eaSmrg crtc_add_output (output->crtc_info, output); 1420a0d3b6eaSmrg } 1421a0d3b6eaSmrg} 1422a0d3b6eaSmrg 142362df5ad0Smrgstatic void 142462df5ad0Smrgset_panning (void) 142562df5ad0Smrg{ 142662df5ad0Smrg output_t *output; 142762df5ad0Smrg 1428cf2cd791Smrg for (output = all_outputs; output; output = output->next) 142962df5ad0Smrg { 143062df5ad0Smrg if (! output->crtc_info) 143162df5ad0Smrg continue; 143262df5ad0Smrg if (! (output->changes & changes_panning)) 143362df5ad0Smrg continue; 143462df5ad0Smrg if (! output->crtc_info->panning_info) 143562df5ad0Smrg output->crtc_info->panning_info = malloc (sizeof(XRRPanning)); 143662df5ad0Smrg memcpy (output->crtc_info->panning_info, &output->panning, sizeof(XRRPanning)); 143762df5ad0Smrg output->crtc_info->changing = 1; 143862df5ad0Smrg } 143962df5ad0Smrg} 144062df5ad0Smrg 144162df5ad0Smrgstatic void 144262df5ad0Smrgset_gamma(void) 144362df5ad0Smrg{ 144462df5ad0Smrg output_t *output; 144562df5ad0Smrg 1446cf2cd791Smrg for (output = all_outputs; output; output = output->next) { 1447305217b6Smrg int i, size; 144862df5ad0Smrg crtc_t *crtc; 1449cf2cd791Smrg XRRCrtcGamma *crtc_gamma; 1450cf2cd791Smrg float gammaRed; 1451cf2cd791Smrg float gammaGreen; 1452cf2cd791Smrg float gammaBlue; 145362df5ad0Smrg 145462df5ad0Smrg if (!(output->changes & changes_gamma)) 145562df5ad0Smrg continue; 145662df5ad0Smrg 145762df5ad0Smrg if (!output->crtc_info) { 145862df5ad0Smrg fatal("Need crtc to set gamma on.\n"); 145962df5ad0Smrg continue; 146062df5ad0Smrg } 146162df5ad0Smrg 146262df5ad0Smrg crtc = output->crtc_info; 146362df5ad0Smrg 146462df5ad0Smrg size = XRRGetCrtcGammaSize(dpy, crtc->crtc.xid); 146562df5ad0Smrg 146662df5ad0Smrg if (!size) { 146762df5ad0Smrg fatal("Gamma size is 0.\n"); 146862df5ad0Smrg continue; 146962df5ad0Smrg } 147062df5ad0Smrg 1471cf2cd791Smrg /* 1472cf2cd791Smrg * The gamma-correction lookup table managed through XRR[GS]etCrtcGamma 1473cf2cd791Smrg * is 2^n in size, where 'n' is the number of significant bits in 1474cf2cd791Smrg * the X Color. Because an X Color is 16 bits, size cannot be larger 1475cf2cd791Smrg * than 2^16. 1476cf2cd791Smrg */ 1477cf2cd791Smrg if (size > 65536) { 1478cf2cd791Smrg fatal("Gamma correction table is impossibly large.\n"); 1479cf2cd791Smrg continue; 1480cf2cd791Smrg } 1481cf2cd791Smrg 1482cf2cd791Smrg crtc_gamma = XRRAllocGamma(size); 1483cf2cd791Smrg if (!crtc_gamma) { 148462df5ad0Smrg fatal("Gamma allocation failed.\n"); 148562df5ad0Smrg continue; 148662df5ad0Smrg } 148762df5ad0Smrg 1488cf2cd791Smrg if (output->gamma.red == 0.0) 1489cf2cd791Smrg output->gamma.red = 1.0; 1490cf2cd791Smrg if (output->gamma.green == 0.0) 1491cf2cd791Smrg output->gamma.green = 1.0; 1492cf2cd791Smrg if (output->gamma.blue == 0.0) 1493cf2cd791Smrg output->gamma.blue = 1.0; 1494cf2cd791Smrg 1495cf2cd791Smrg gammaRed = 1.0 / output->gamma.red; 1496cf2cd791Smrg gammaGreen = 1.0 / output->gamma.green; 1497cf2cd791Smrg gammaBlue = 1.0 / output->gamma.blue; 14988a16544fSmrg 149962df5ad0Smrg for (i = 0; i < size; i++) { 1500cf2cd791Smrg if (gammaRed == 1.0 && output->brightness == 1.0) 1501305217b6Smrg crtc_gamma->red[i] = (double)i / (double)(size - 1) * 65535.0; 150262df5ad0Smrg else 1503cf2cd791Smrg crtc_gamma->red[i] = dmin(pow((double)i/(double)(size - 1), 1504cf2cd791Smrg gammaRed) * output->brightness, 1505305217b6Smrg 1.0) * 65535.0; 150662df5ad0Smrg 1507cf2cd791Smrg if (gammaGreen == 1.0 && output->brightness == 1.0) 1508305217b6Smrg crtc_gamma->green[i] = (double)i / (double)(size - 1) * 65535.0; 150962df5ad0Smrg else 1510cf2cd791Smrg crtc_gamma->green[i] = dmin(pow((double)i/(double)(size - 1), 1511cf2cd791Smrg gammaGreen) * output->brightness, 1512305217b6Smrg 1.0) * 65535.0; 151362df5ad0Smrg 1514cf2cd791Smrg if (gammaBlue == 1.0 && output->brightness == 1.0) 1515305217b6Smrg crtc_gamma->blue[i] = (double)i / (double)(size - 1) * 65535.0; 151662df5ad0Smrg else 1517cf2cd791Smrg crtc_gamma->blue[i] = dmin(pow((double)i/(double)(size - 1), 1518cf2cd791Smrg gammaBlue) * output->brightness, 1519305217b6Smrg 1.0) * 65535.0; 152062df5ad0Smrg } 152162df5ad0Smrg 1522cf2cd791Smrg XRRSetCrtcGamma(dpy, crtc->crtc.xid, crtc_gamma); 152362df5ad0Smrg 1524cf2cd791Smrg free(crtc_gamma); 152562df5ad0Smrg } 152662df5ad0Smrg} 152762df5ad0Smrg 152862df5ad0Smrgstatic void 152962df5ad0Smrgset_primary(void) 153062df5ad0Smrg{ 153162df5ad0Smrg output_t *output; 153262df5ad0Smrg 153362df5ad0Smrg if (no_primary) { 153462df5ad0Smrg XRRSetOutputPrimary(dpy, root, None); 153562df5ad0Smrg } else { 1536cf2cd791Smrg for (output = all_outputs; output; output = output->next) { 153762df5ad0Smrg if (!(output->changes & changes_primary)) 153862df5ad0Smrg continue; 153962df5ad0Smrg if (output->primary) 154062df5ad0Smrg XRRSetOutputPrimary(dpy, root, output->output.xid); 154162df5ad0Smrg } 154262df5ad0Smrg } 154362df5ad0Smrg} 154462df5ad0Smrg 1545a0d3b6eaSmrgstatic Status 1546a0d3b6eaSmrgcrtc_disable (crtc_t *crtc) 1547a0d3b6eaSmrg{ 1548a0d3b6eaSmrg if (verbose) 1549a0d3b6eaSmrg printf ("crtc %d: disable\n", crtc->crtc.index); 1550a0d3b6eaSmrg 1551a0d3b6eaSmrg if (dryrun) 1552a0d3b6eaSmrg return RRSetConfigSuccess; 1553a0d3b6eaSmrg return XRRSetCrtcConfig (dpy, res, crtc->crtc.xid, CurrentTime, 1554a0d3b6eaSmrg 0, 0, None, RR_Rotate_0, NULL, 0); 1555a0d3b6eaSmrg} 1556a0d3b6eaSmrg 155762df5ad0Smrgstatic void 155862df5ad0Smrgcrtc_set_transform (crtc_t *crtc, transform_t *transform) 155962df5ad0Smrg{ 156062df5ad0Smrg int major, minor; 156162df5ad0Smrg 156262df5ad0Smrg XRRQueryVersion (dpy, &major, &minor); 156362df5ad0Smrg if (major > 1 || (major == 1 && minor >= 3)) 156462df5ad0Smrg XRRSetCrtcTransform (dpy, crtc->crtc.xid, 156562df5ad0Smrg &transform->transform, 156606879bd5Smrg transform->filter, 156762df5ad0Smrg transform->params, 156862df5ad0Smrg transform->nparams); 156962df5ad0Smrg} 157062df5ad0Smrg 1571a0d3b6eaSmrgstatic Status 1572a0d3b6eaSmrgcrtc_revert (crtc_t *crtc) 1573a0d3b6eaSmrg{ 1574a0d3b6eaSmrg XRRCrtcInfo *crtc_info = crtc->crtc_info; 1575a0d3b6eaSmrg 1576a0d3b6eaSmrg if (verbose) 1577a0d3b6eaSmrg printf ("crtc %d: revert\n", crtc->crtc.index); 1578a0d3b6eaSmrg 1579a0d3b6eaSmrg if (dryrun) 1580a0d3b6eaSmrg return RRSetConfigSuccess; 158162df5ad0Smrg 158262df5ad0Smrg if (!equal_transform (&crtc->current_transform, &crtc->pending_transform)) 158362df5ad0Smrg crtc_set_transform (crtc, &crtc->current_transform); 1584a0d3b6eaSmrg return XRRSetCrtcConfig (dpy, res, crtc->crtc.xid, CurrentTime, 1585a0d3b6eaSmrg crtc_info->x, crtc_info->y, 1586a0d3b6eaSmrg crtc_info->mode, crtc_info->rotation, 1587a0d3b6eaSmrg crtc_info->outputs, crtc_info->noutput); 1588a0d3b6eaSmrg} 1589a0d3b6eaSmrg 1590a0d3b6eaSmrgstatic Status 1591a0d3b6eaSmrgcrtc_apply (crtc_t *crtc) 1592a0d3b6eaSmrg{ 1593a0d3b6eaSmrg RROutput *rr_outputs; 1594a0d3b6eaSmrg int o; 1595a0d3b6eaSmrg Status s; 1596a0d3b6eaSmrg RRMode mode = None; 1597a0d3b6eaSmrg 1598a0d3b6eaSmrg if (!crtc->changing || !crtc->mode_info) 1599a0d3b6eaSmrg return RRSetConfigSuccess; 1600a0d3b6eaSmrg 1601a0d3b6eaSmrg rr_outputs = calloc (crtc->noutput, sizeof (RROutput)); 1602a0d3b6eaSmrg if (!rr_outputs) 1603a0d3b6eaSmrg return BadAlloc; 1604a0d3b6eaSmrg for (o = 0; o < crtc->noutput; o++) 1605a0d3b6eaSmrg rr_outputs[o] = crtc->outputs[o]->output.xid; 1606a0d3b6eaSmrg mode = crtc->mode_info->id; 1607a0d3b6eaSmrg if (verbose) { 16087936445dSmrg printf ("crtc %d: %12s %6.2f +%d+%d", crtc->crtc.index, 1609a0d3b6eaSmrg crtc->mode_info->name, mode_refresh (crtc->mode_info), 1610a0d3b6eaSmrg crtc->x, crtc->y); 1611a0d3b6eaSmrg for (o = 0; o < crtc->noutput; o++) 1612a0d3b6eaSmrg printf (" \"%s\"", crtc->outputs[o]->output.string); 1613a0d3b6eaSmrg printf ("\n"); 1614a0d3b6eaSmrg } 1615a0d3b6eaSmrg 1616a0d3b6eaSmrg if (dryrun) 1617a0d3b6eaSmrg s = RRSetConfigSuccess; 1618a0d3b6eaSmrg else 161962df5ad0Smrg { 162062df5ad0Smrg if (!equal_transform (&crtc->current_transform, &crtc->pending_transform)) 162162df5ad0Smrg crtc_set_transform (crtc, &crtc->pending_transform); 1622a0d3b6eaSmrg s = XRRSetCrtcConfig (dpy, res, crtc->crtc.xid, CurrentTime, 1623a0d3b6eaSmrg crtc->x, crtc->y, mode, crtc->rotation, 1624a0d3b6eaSmrg rr_outputs, crtc->noutput); 162562df5ad0Smrg if (s == RRSetConfigSuccess && crtc->panning_info) { 162662df5ad0Smrg if (has_1_3) 162762df5ad0Smrg s = XRRSetPanning (dpy, res, crtc->crtc.xid, crtc->panning_info); 162862df5ad0Smrg else 162962df5ad0Smrg fatal ("panning needs RandR 1.3\n"); 163062df5ad0Smrg } 163162df5ad0Smrg } 1632a0d3b6eaSmrg free (rr_outputs); 1633a0d3b6eaSmrg return s; 1634a0d3b6eaSmrg} 1635a0d3b6eaSmrg 1636a0d3b6eaSmrgstatic void 1637a0d3b6eaSmrgscreen_revert (void) 1638a0d3b6eaSmrg{ 1639a0d3b6eaSmrg if (verbose) 1640a0d3b6eaSmrg printf ("screen %d: revert\n", screen); 1641a0d3b6eaSmrg 1642a0d3b6eaSmrg if (dryrun) 1643a0d3b6eaSmrg return; 1644a0d3b6eaSmrg XRRSetScreenSize (dpy, root, 1645a0d3b6eaSmrg DisplayWidth (dpy, screen), 1646a0d3b6eaSmrg DisplayHeight (dpy, screen), 1647a0d3b6eaSmrg DisplayWidthMM (dpy, screen), 1648a0d3b6eaSmrg DisplayHeightMM (dpy, screen)); 1649a0d3b6eaSmrg} 1650a0d3b6eaSmrg 1651a0d3b6eaSmrgstatic void 1652a0d3b6eaSmrgscreen_apply (void) 1653a0d3b6eaSmrg{ 1654a0d3b6eaSmrg if (fb_width == DisplayWidth (dpy, screen) && 1655a0d3b6eaSmrg fb_height == DisplayHeight (dpy, screen) && 1656a0d3b6eaSmrg fb_width_mm == DisplayWidthMM (dpy, screen) && 1657a0d3b6eaSmrg fb_height_mm == DisplayHeightMM (dpy, screen)) 1658a0d3b6eaSmrg { 1659a0d3b6eaSmrg return; 1660a0d3b6eaSmrg } 1661a0d3b6eaSmrg if (verbose) 1662a0d3b6eaSmrg printf ("screen %d: %dx%d %dx%d mm %6.2fdpi\n", screen, 1663a0d3b6eaSmrg fb_width, fb_height, fb_width_mm, fb_height_mm, dpi); 1664a0d3b6eaSmrg if (dryrun) 1665a0d3b6eaSmrg return; 1666a0d3b6eaSmrg XRRSetScreenSize (dpy, root, fb_width, fb_height, 1667a0d3b6eaSmrg fb_width_mm, fb_height_mm); 1668a0d3b6eaSmrg} 1669a0d3b6eaSmrg 1670a0d3b6eaSmrgstatic void 1671a0d3b6eaSmrgrevert (void) 1672a0d3b6eaSmrg{ 1673a0d3b6eaSmrg int c; 1674a0d3b6eaSmrg 1675a0d3b6eaSmrg /* first disable all crtcs */ 1676a0d3b6eaSmrg for (c = 0; c < res->ncrtc; c++) 1677a0d3b6eaSmrg crtc_disable (&crtcs[c]); 1678a0d3b6eaSmrg /* next reset screen size */ 1679a0d3b6eaSmrg screen_revert (); 1680a0d3b6eaSmrg /* now restore all crtcs */ 1681a0d3b6eaSmrg for (c = 0; c < res->ncrtc; c++) 1682a0d3b6eaSmrg crtc_revert (&crtcs[c]); 1683a0d3b6eaSmrg} 1684a0d3b6eaSmrg 1685a0d3b6eaSmrg/* 1686a0d3b6eaSmrg * uh-oh, something bad happened in the middle of changing 1687a0d3b6eaSmrg * the configuration. Revert to the previous configuration 1688a0d3b6eaSmrg * and bail 1689a0d3b6eaSmrg */ 1690558b030aSmrgstatic void _X_NORETURN 1691a0d3b6eaSmrgpanic (Status s, crtc_t *crtc) 1692a0d3b6eaSmrg{ 1693a0d3b6eaSmrg int c = crtc->crtc.index; 1694cf2cd791Smrg const char *message; 1695a0d3b6eaSmrg 1696a0d3b6eaSmrg switch (s) { 1697a0d3b6eaSmrg case RRSetConfigSuccess: message = "succeeded"; break; 1698a0d3b6eaSmrg case BadAlloc: message = "out of memory"; break; 1699a0d3b6eaSmrg case RRSetConfigFailed: message = "failed"; break; 1700a0d3b6eaSmrg case RRSetConfigInvalidConfigTime: message = "invalid config time"; break; 1701a0d3b6eaSmrg case RRSetConfigInvalidTime: message = "invalid time"; break; 1702a0d3b6eaSmrg default: message = "unknown failure"; break; 1703a0d3b6eaSmrg } 1704a0d3b6eaSmrg 1705a0d3b6eaSmrg fprintf (stderr, "%s: Configure crtc %d %s\n", program_name, c, message); 1706a0d3b6eaSmrg revert (); 1707a0d3b6eaSmrg exit (1); 1708a0d3b6eaSmrg} 1709a0d3b6eaSmrg 171062df5ad0Smrgstatic void 1711a0d3b6eaSmrgapply (void) 1712a0d3b6eaSmrg{ 1713a0d3b6eaSmrg Status s; 1714a0d3b6eaSmrg int c; 1715a0d3b6eaSmrg 171662770414Smrg /* 171762770414Smrg * Hold the server grabbed while messing with 171862770414Smrg * the screen so that apps which notice the resize 171962770414Smrg * event and ask for xinerama information from the server 172062770414Smrg * receive up-to-date information 172162770414Smrg */ 172262770414Smrg if (grab_server) 172362770414Smrg XGrabServer (dpy); 172462770414Smrg 1725a0d3b6eaSmrg /* 1726a0d3b6eaSmrg * Turn off any crtcs which are to be disabled or which are 1727a0d3b6eaSmrg * larger than the target size 1728a0d3b6eaSmrg */ 1729a0d3b6eaSmrg for (c = 0; c < res->ncrtc; c++) 1730a0d3b6eaSmrg { 1731a0d3b6eaSmrg crtc_t *crtc = &crtcs[c]; 1732a0d3b6eaSmrg XRRCrtcInfo *crtc_info = crtc->crtc_info; 1733a0d3b6eaSmrg 1734a0d3b6eaSmrg /* if this crtc is already disabled, skip it */ 1735a0d3b6eaSmrg if (crtc_info->mode == None) 1736a0d3b6eaSmrg continue; 1737a0d3b6eaSmrg 1738a0d3b6eaSmrg /* 1739a0d3b6eaSmrg * If this crtc is to be left enabled, make 1740a0d3b6eaSmrg * sure the old size fits then new screen 1741a0d3b6eaSmrg */ 1742a0d3b6eaSmrg if (crtc->mode_info) 1743a0d3b6eaSmrg { 1744a0d3b6eaSmrg XRRModeInfo *old_mode = find_mode_by_xid (crtc_info->mode); 1745a0d3b6eaSmrg int x, y, w, h; 174662df5ad0Smrg box_t bounds; 1747a0d3b6eaSmrg 1748a0d3b6eaSmrg if (!old_mode) 1749a0d3b6eaSmrg panic (RRSetConfigFailed, crtc); 1750a0d3b6eaSmrg 1751a0d3b6eaSmrg /* old position and size information */ 175262df5ad0Smrg mode_geometry (old_mode, crtc_info->rotation, 175362df5ad0Smrg &crtc->current_transform.transform, 175462df5ad0Smrg &bounds); 175562df5ad0Smrg 175662df5ad0Smrg x = crtc_info->x + bounds.x1; 175762df5ad0Smrg y = crtc_info->y + bounds.y1; 175862df5ad0Smrg w = bounds.x2 - bounds.x1; 175962df5ad0Smrg h = bounds.y2 - bounds.y1; 176062df5ad0Smrg 1761a0d3b6eaSmrg /* if it fits, skip it */ 1762a0d3b6eaSmrg if (x + w <= fb_width && y + h <= fb_height) 1763a0d3b6eaSmrg continue; 1764a0d3b6eaSmrg crtc->changing = True; 1765a0d3b6eaSmrg } 1766a0d3b6eaSmrg s = crtc_disable (crtc); 1767a0d3b6eaSmrg if (s != RRSetConfigSuccess) 1768a0d3b6eaSmrg panic (s, crtc); 1769a0d3b6eaSmrg } 1770a0d3b6eaSmrg 1771a0d3b6eaSmrg /* 1772a0d3b6eaSmrg * Set the screen size 1773a0d3b6eaSmrg */ 1774a0d3b6eaSmrg screen_apply (); 1775a0d3b6eaSmrg 1776a0d3b6eaSmrg /* 1777a0d3b6eaSmrg * Set crtcs 1778a0d3b6eaSmrg */ 1779a0d3b6eaSmrg 1780a0d3b6eaSmrg for (c = 0; c < res->ncrtc; c++) 1781a0d3b6eaSmrg { 1782a0d3b6eaSmrg crtc_t *crtc = &crtcs[c]; 1783a0d3b6eaSmrg 1784a0d3b6eaSmrg s = crtc_apply (crtc); 1785a0d3b6eaSmrg if (s != RRSetConfigSuccess) 1786a0d3b6eaSmrg panic (s, crtc); 1787a0d3b6eaSmrg } 178862df5ad0Smrg 178962df5ad0Smrg set_primary (); 179062df5ad0Smrg 1791a0d3b6eaSmrg /* 1792a0d3b6eaSmrg * Release the server grab and let all clients 1793a0d3b6eaSmrg * respond to the updated state 1794a0d3b6eaSmrg */ 179562df5ad0Smrg if (grab_server) 179662df5ad0Smrg XUngrabServer (dpy); 1797a0d3b6eaSmrg} 1798a0d3b6eaSmrg 1799a0d3b6eaSmrg/* 1800a0d3b6eaSmrg * Use current output state to complete the output list 1801a0d3b6eaSmrg */ 180262df5ad0Smrgstatic void 1803a0d3b6eaSmrgget_outputs (void) 1804a0d3b6eaSmrg{ 1805a0d3b6eaSmrg int o; 1806c52f0396Smrg output_t *q; 1807a0d3b6eaSmrg 1808a0d3b6eaSmrg for (o = 0; o < res->noutput; o++) 1809a0d3b6eaSmrg { 1810a0d3b6eaSmrg XRROutputInfo *output_info = XRRGetOutputInfo (dpy, res, res->outputs[o]); 1811a0d3b6eaSmrg output_t *output; 1812a0d3b6eaSmrg name_t output_name; 1813cf2cd791Smrg if (!output_info) fatal ("could not get output 0x%lx information\n", res->outputs[o]); 1814a0d3b6eaSmrg set_name_xid (&output_name, res->outputs[o]); 1815a0d3b6eaSmrg set_name_index (&output_name, o); 1816a0d3b6eaSmrg set_name_string (&output_name, output_info->name); 1817a0d3b6eaSmrg output = find_output (&output_name); 1818a0d3b6eaSmrg if (!output) 1819a0d3b6eaSmrg { 1820a0d3b6eaSmrg output = add_output (); 1821a0d3b6eaSmrg set_name_all (&output->output, &output_name); 1822a0d3b6eaSmrg /* 1823a0d3b6eaSmrg * When global --automatic mode is set, turn on connected but off 1824a0d3b6eaSmrg * outputs, turn off disconnected but on outputs 1825a0d3b6eaSmrg */ 1826a0d3b6eaSmrg if (automatic) 1827a0d3b6eaSmrg { 1828a0d3b6eaSmrg switch (output_info->connection) { 1829a0d3b6eaSmrg case RR_Connected: 1830a0d3b6eaSmrg if (!output_info->crtc) { 1831a0d3b6eaSmrg output->changes |= changes_automatic; 1832a0d3b6eaSmrg output->automatic = True; 1833a0d3b6eaSmrg } 1834a0d3b6eaSmrg break; 1835a0d3b6eaSmrg case RR_Disconnected: 1836a0d3b6eaSmrg if (output_info->crtc) 1837a0d3b6eaSmrg { 1838a0d3b6eaSmrg output->changes |= changes_automatic; 1839a0d3b6eaSmrg output->automatic = True; 1840a0d3b6eaSmrg } 1841a0d3b6eaSmrg break; 1842a0d3b6eaSmrg } 1843a0d3b6eaSmrg } 1844a0d3b6eaSmrg } 1845c52f0396Smrg output->found = True; 1846a0d3b6eaSmrg 1847a0d3b6eaSmrg /* 1848a0d3b6eaSmrg * Automatic mode -- track connection state and enable/disable outputs 1849a0d3b6eaSmrg * as necessary 1850a0d3b6eaSmrg */ 1851a0d3b6eaSmrg if (output->automatic) 1852a0d3b6eaSmrg { 1853a0d3b6eaSmrg switch (output_info->connection) { 1854a0d3b6eaSmrg case RR_Connected: 1855a0d3b6eaSmrg case RR_UnknownConnection: 1856a0d3b6eaSmrg if ((!(output->changes & changes_mode))) 1857a0d3b6eaSmrg { 1858a0d3b6eaSmrg set_name_preferred (&output->mode); 1859a0d3b6eaSmrg output->changes |= changes_mode; 1860a0d3b6eaSmrg } 1861a0d3b6eaSmrg break; 1862a0d3b6eaSmrg case RR_Disconnected: 1863a0d3b6eaSmrg if ((!(output->changes & changes_mode))) 1864a0d3b6eaSmrg { 1865a0d3b6eaSmrg set_name_xid (&output->mode, None); 1866a0d3b6eaSmrg set_name_xid (&output->crtc, None); 1867a0d3b6eaSmrg output->changes |= changes_mode; 1868a0d3b6eaSmrg output->changes |= changes_crtc; 1869a0d3b6eaSmrg } 1870a0d3b6eaSmrg break; 1871a0d3b6eaSmrg } 1872a0d3b6eaSmrg } 1873a0d3b6eaSmrg 1874a0d3b6eaSmrg set_output_info (output, res->outputs[o], output_info); 1875a0d3b6eaSmrg } 1876cf2cd791Smrg for (q = all_outputs; q; q = q->next) 1877c52f0396Smrg { 1878c52f0396Smrg if (!q->found) 1879c52f0396Smrg { 1880c52f0396Smrg fprintf(stderr, "warning: output %s not found; ignoring\n", 1881c52f0396Smrg q->output.string); 1882c52f0396Smrg } 1883c52f0396Smrg } 1884a0d3b6eaSmrg} 1885a0d3b6eaSmrg 188662df5ad0Smrgstatic void 1887a0d3b6eaSmrgmark_changing_crtcs (void) 1888a0d3b6eaSmrg{ 1889a0d3b6eaSmrg int c; 1890a0d3b6eaSmrg 1891a0d3b6eaSmrg for (c = 0; c < num_crtcs; c++) 1892a0d3b6eaSmrg { 1893a0d3b6eaSmrg crtc_t *crtc = &crtcs[c]; 1894a0d3b6eaSmrg int o; 1895a0d3b6eaSmrg output_t *output; 1896a0d3b6eaSmrg 1897a0d3b6eaSmrg /* walk old output list (to catch disables) */ 1898a0d3b6eaSmrg for (o = 0; o < crtc->crtc_info->noutput; o++) 1899a0d3b6eaSmrg { 1900a0d3b6eaSmrg output = find_output_by_xid (crtc->crtc_info->outputs[o]); 1901cf2cd791Smrg if (!output) fatal ("cannot find output 0x%lx\n", 1902a0d3b6eaSmrg crtc->crtc_info->outputs[o]); 1903a0d3b6eaSmrg if (output->changes) 1904a0d3b6eaSmrg crtc->changing = True; 1905a0d3b6eaSmrg } 1906a0d3b6eaSmrg /* walk new output list */ 1907a0d3b6eaSmrg for (o = 0; o < crtc->noutput; o++) 1908a0d3b6eaSmrg { 1909a0d3b6eaSmrg output = crtc->outputs[o]; 1910a0d3b6eaSmrg if (output->changes) 1911a0d3b6eaSmrg crtc->changing = True; 1912a0d3b6eaSmrg } 1913a0d3b6eaSmrg } 1914a0d3b6eaSmrg} 1915a0d3b6eaSmrg 1916a0d3b6eaSmrg/* 1917a0d3b6eaSmrg * Test whether 'crtc' can be used for 'output' 1918a0d3b6eaSmrg */ 191962770414Smrgstatic Bool 1920a0d3b6eaSmrgcheck_crtc_for_output (crtc_t *crtc, output_t *output) 1921a0d3b6eaSmrg{ 1922a0d3b6eaSmrg int c; 1923a0d3b6eaSmrg int l; 1924a0d3b6eaSmrg output_t *other; 1925a0d3b6eaSmrg 1926a0d3b6eaSmrg for (c = 0; c < output->output_info->ncrtc; c++) 1927a0d3b6eaSmrg if (output->output_info->crtcs[c] == crtc->crtc.xid) 1928a0d3b6eaSmrg break; 1929a0d3b6eaSmrg if (c == output->output_info->ncrtc) 1930a0d3b6eaSmrg return False; 1931cf2cd791Smrg for (other = all_outputs; other; other = other->next) 1932a0d3b6eaSmrg { 1933a0d3b6eaSmrg if (other == output) 1934a0d3b6eaSmrg continue; 1935a0d3b6eaSmrg 1936a0d3b6eaSmrg if (other->mode_info == NULL) 1937a0d3b6eaSmrg continue; 1938a0d3b6eaSmrg 1939a0d3b6eaSmrg if (other->crtc_info != crtc) 1940a0d3b6eaSmrg continue; 1941a0d3b6eaSmrg 1942a0d3b6eaSmrg /* see if the output connected to the crtc can clone to this output */ 1943a0d3b6eaSmrg for (l = 0; l < output->output_info->nclone; l++) 1944a0d3b6eaSmrg if (output->output_info->clones[l] == other->output.xid) 1945a0d3b6eaSmrg break; 1946a0d3b6eaSmrg /* not on the list, can't clone */ 1947a0d3b6eaSmrg if (l == output->output_info->nclone) 1948a0d3b6eaSmrg return False; 1949a0d3b6eaSmrg } 1950a0d3b6eaSmrg 1951a0d3b6eaSmrg if (crtc->noutput) 1952a0d3b6eaSmrg { 1953a0d3b6eaSmrg /* make sure the state matches */ 1954a0d3b6eaSmrg if (crtc->mode_info != output->mode_info) 1955a0d3b6eaSmrg return False; 1956a0d3b6eaSmrg if (crtc->x != output->x) 1957a0d3b6eaSmrg return False; 1958a0d3b6eaSmrg if (crtc->y != output->y) 1959a0d3b6eaSmrg return False; 1960a0d3b6eaSmrg if (crtc->rotation != output->rotation) 1961a0d3b6eaSmrg return False; 196262df5ad0Smrg if (!equal_transform (&crtc->current_transform, &output->transform)) 196362df5ad0Smrg return False; 1964a0d3b6eaSmrg } 1965a0d3b6eaSmrg else if (crtc->crtc_info->noutput) 1966a0d3b6eaSmrg { 1967a0d3b6eaSmrg /* make sure the state matches the already used state */ 1968a0d3b6eaSmrg XRRModeInfo *mode = find_mode_by_xid (crtc->crtc_info->mode); 1969a0d3b6eaSmrg 1970a0d3b6eaSmrg if (mode != output->mode_info) 1971a0d3b6eaSmrg return False; 1972a0d3b6eaSmrg if (crtc->crtc_info->x != output->x) 1973a0d3b6eaSmrg return False; 1974a0d3b6eaSmrg if (crtc->crtc_info->y != output->y) 1975a0d3b6eaSmrg return False; 1976a0d3b6eaSmrg if (crtc->crtc_info->rotation != output->rotation) 1977a0d3b6eaSmrg return False; 1978a0d3b6eaSmrg } 1979a0d3b6eaSmrg return True; 1980a0d3b6eaSmrg} 1981a0d3b6eaSmrg 198262df5ad0Smrgstatic crtc_t * 1983a0d3b6eaSmrgfind_crtc_for_output (output_t *output) 1984a0d3b6eaSmrg{ 1985a0d3b6eaSmrg int c; 1986a0d3b6eaSmrg 1987a0d3b6eaSmrg for (c = 0; c < output->output_info->ncrtc; c++) 1988a0d3b6eaSmrg { 1989a0d3b6eaSmrg crtc_t *crtc; 1990a0d3b6eaSmrg 1991a0d3b6eaSmrg crtc = find_crtc_by_xid (output->output_info->crtcs[c]); 1992cf2cd791Smrg if (!crtc) fatal ("cannot find crtc 0x%lx\n", output->output_info->crtcs[c]); 1993a0d3b6eaSmrg 1994a0d3b6eaSmrg if (check_crtc_for_output (crtc, output)) 1995a0d3b6eaSmrg return crtc; 1996a0d3b6eaSmrg } 1997a0d3b6eaSmrg return NULL; 1998a0d3b6eaSmrg} 1999a0d3b6eaSmrg 2000a0d3b6eaSmrgstatic void 2001a0d3b6eaSmrgset_positions (void) 2002a0d3b6eaSmrg{ 2003a0d3b6eaSmrg output_t *output; 2004a0d3b6eaSmrg Bool keep_going; 2005a0d3b6eaSmrg Bool any_set; 2006a0d3b6eaSmrg int min_x, min_y; 2007a0d3b6eaSmrg 2008a0d3b6eaSmrg for (;;) 2009a0d3b6eaSmrg { 2010a0d3b6eaSmrg any_set = False; 2011a0d3b6eaSmrg keep_going = False; 2012cf2cd791Smrg for (output = all_outputs; output; output = output->next) 2013a0d3b6eaSmrg { 2014a0d3b6eaSmrg output_t *relation; 2015a0d3b6eaSmrg name_t relation_name; 2016a0d3b6eaSmrg 2017a0d3b6eaSmrg if (!(output->changes & changes_relation)) continue; 2018a0d3b6eaSmrg 2019a0d3b6eaSmrg if (output->mode_info == NULL) continue; 2020a0d3b6eaSmrg 2021a0d3b6eaSmrg init_name (&relation_name); 2022a0d3b6eaSmrg set_name_string (&relation_name, output->relative_to); 2023a0d3b6eaSmrg relation = find_output (&relation_name); 2024a0d3b6eaSmrg if (!relation) fatal ("cannot find output \"%s\"\n", output->relative_to); 2025a0d3b6eaSmrg 2026a0d3b6eaSmrg if (relation->mode_info == NULL) 2027a0d3b6eaSmrg { 2028a0d3b6eaSmrg output->x = 0; 2029a0d3b6eaSmrg output->y = 0; 2030a0d3b6eaSmrg output->changes |= changes_position; 2031a0d3b6eaSmrg any_set = True; 2032a0d3b6eaSmrg continue; 2033a0d3b6eaSmrg } 2034a0d3b6eaSmrg /* 2035a0d3b6eaSmrg * Make sure the dependent object has been set in place 2036a0d3b6eaSmrg */ 2037a0d3b6eaSmrg if ((relation->changes & changes_relation) && 2038a0d3b6eaSmrg !(relation->changes & changes_position)) 2039a0d3b6eaSmrg { 2040a0d3b6eaSmrg keep_going = True; 2041a0d3b6eaSmrg continue; 2042a0d3b6eaSmrg } 2043a0d3b6eaSmrg 2044a0d3b6eaSmrg switch (output->relation) { 20458a16544fSmrg case relation_left_of: 2046a0d3b6eaSmrg output->y = relation->y; 2047a0d3b6eaSmrg output->x = relation->x - mode_width (output->mode_info, output->rotation); 2048a0d3b6eaSmrg break; 20498a16544fSmrg case relation_right_of: 2050a0d3b6eaSmrg output->y = relation->y; 2051a0d3b6eaSmrg output->x = relation->x + mode_width (relation->mode_info, relation->rotation); 2052a0d3b6eaSmrg break; 20538a16544fSmrg case relation_above: 2054a0d3b6eaSmrg output->x = relation->x; 2055a0d3b6eaSmrg output->y = relation->y - mode_height (output->mode_info, output->rotation); 2056a0d3b6eaSmrg break; 20578a16544fSmrg case relation_below: 2058a0d3b6eaSmrg output->x = relation->x; 2059a0d3b6eaSmrg output->y = relation->y + mode_height (relation->mode_info, relation->rotation); 2060a0d3b6eaSmrg break; 20618a16544fSmrg case relation_same_as: 2062a0d3b6eaSmrg output->x = relation->x; 2063a0d3b6eaSmrg output->y = relation->y; 2064a0d3b6eaSmrg } 2065a0d3b6eaSmrg output->changes |= changes_position; 2066a0d3b6eaSmrg any_set = True; 2067a0d3b6eaSmrg } 2068a0d3b6eaSmrg if (!keep_going) 2069a0d3b6eaSmrg break; 2070a0d3b6eaSmrg if (!any_set) 2071a0d3b6eaSmrg fatal ("loop in relative position specifications\n"); 2072a0d3b6eaSmrg } 2073a0d3b6eaSmrg 2074a0d3b6eaSmrg /* 2075a0d3b6eaSmrg * Now normalize positions so the upper left corner of all outputs is at 0,0 2076a0d3b6eaSmrg */ 2077a0d3b6eaSmrg min_x = 32768; 2078a0d3b6eaSmrg min_y = 32768; 2079cf2cd791Smrg for (output = all_outputs; output; output = output->next) 2080a0d3b6eaSmrg { 2081a0d3b6eaSmrg if (output->mode_info == NULL) continue; 2082a0d3b6eaSmrg 2083a0d3b6eaSmrg if (output->x < min_x) min_x = output->x; 2084a0d3b6eaSmrg if (output->y < min_y) min_y = output->y; 2085a0d3b6eaSmrg } 2086a0d3b6eaSmrg if (min_x || min_y) 2087a0d3b6eaSmrg { 2088a0d3b6eaSmrg /* move all outputs */ 2089cf2cd791Smrg for (output = all_outputs; output; output = output->next) 2090a0d3b6eaSmrg { 2091a0d3b6eaSmrg if (output->mode_info == NULL) continue; 2092a0d3b6eaSmrg 2093a0d3b6eaSmrg output->x -= min_x; 2094a0d3b6eaSmrg output->y -= min_y; 2095a0d3b6eaSmrg output->changes |= changes_position; 2096a0d3b6eaSmrg } 2097a0d3b6eaSmrg } 2098a0d3b6eaSmrg} 2099a0d3b6eaSmrg 2100a0d3b6eaSmrgstatic void 2101a0d3b6eaSmrgset_screen_size (void) 2102a0d3b6eaSmrg{ 2103a0d3b6eaSmrg output_t *output; 2104a0d3b6eaSmrg Bool fb_specified = fb_width != 0 && fb_height != 0; 2105a0d3b6eaSmrg 2106cf2cd791Smrg for (output = all_outputs; output; output = output->next) 2107a0d3b6eaSmrg { 2108a0d3b6eaSmrg XRRModeInfo *mode_info = output->mode_info; 2109a0d3b6eaSmrg int x, y, w, h; 211062df5ad0Smrg box_t bounds; 2111a0d3b6eaSmrg 2112a0d3b6eaSmrg if (!mode_info) continue; 2113a0d3b6eaSmrg 211462df5ad0Smrg mode_geometry (mode_info, output->rotation, 211562df5ad0Smrg &output->transform.transform, 211662df5ad0Smrg &bounds); 211762df5ad0Smrg x = output->x + bounds.x1; 211862df5ad0Smrg y = output->y + bounds.y1; 211962df5ad0Smrg w = bounds.x2 - bounds.x1; 212062df5ad0Smrg h = bounds.y2 - bounds.y1; 2121a0d3b6eaSmrg /* make sure output fits in specified size */ 2122a0d3b6eaSmrg if (fb_specified) 2123a0d3b6eaSmrg { 2124a0d3b6eaSmrg if (x + w > fb_width || y + h > fb_height) 212562df5ad0Smrg warning ("specified screen %dx%d not large enough for output %s (%dx%d+%d+%d)\n", 212662df5ad0Smrg fb_width, fb_height, output->output.string, w, h, x, y); 2127a0d3b6eaSmrg } 2128a0d3b6eaSmrg /* fit fb to output */ 2129a0d3b6eaSmrg else 2130a0d3b6eaSmrg { 213162df5ad0Smrg XRRPanning *pan; 213262df5ad0Smrg if (x + w > fb_width) 213362df5ad0Smrg fb_width = x + w; 213462df5ad0Smrg if (y + h > fb_height) 213562df5ad0Smrg fb_height = y + h; 213662df5ad0Smrg if (output->changes & changes_panning) 213762df5ad0Smrg pan = &output->panning; 213862df5ad0Smrg else 213962df5ad0Smrg pan = output->crtc_info ? output->crtc_info->panning_info : NULL; 214062df5ad0Smrg if (pan && pan->left + pan->width > fb_width) 214162df5ad0Smrg fb_width = pan->left + pan->width; 214262df5ad0Smrg if (pan && pan->top + pan->height > fb_height) 214362df5ad0Smrg fb_height = pan->top + pan->height; 2144a0d3b6eaSmrg } 2145a0d3b6eaSmrg } 2146a0d3b6eaSmrg 2147a0d3b6eaSmrg if (fb_width > maxWidth || fb_height > maxHeight) 2148a0d3b6eaSmrg fatal ("screen cannot be larger than %dx%d (desired size %dx%d)\n", 2149a0d3b6eaSmrg maxWidth, maxHeight, fb_width, fb_height); 2150a0d3b6eaSmrg if (fb_specified) 2151a0d3b6eaSmrg { 2152a0d3b6eaSmrg if (fb_width < minWidth || fb_height < minHeight) 2153a0d3b6eaSmrg fatal ("screen must be at least %dx%d\n", minWidth, minHeight); 2154a0d3b6eaSmrg } 2155a0d3b6eaSmrg else 2156a0d3b6eaSmrg { 2157a0d3b6eaSmrg if (fb_width < minWidth) fb_width = minWidth; 2158a0d3b6eaSmrg if (fb_height < minHeight) fb_height = minHeight; 2159a0d3b6eaSmrg } 2160a0d3b6eaSmrg} 2161a0d3b6eaSmrg 216262df5ad0Smrg 216362df5ad0Smrgstatic void 2164a0d3b6eaSmrgdisable_outputs (output_t *outputs) 2165a0d3b6eaSmrg{ 2166a0d3b6eaSmrg while (outputs) 2167a0d3b6eaSmrg { 2168a0d3b6eaSmrg outputs->crtc_info = NULL; 2169a0d3b6eaSmrg outputs = outputs->next; 2170a0d3b6eaSmrg } 2171a0d3b6eaSmrg} 2172a0d3b6eaSmrg 2173a0d3b6eaSmrg/* 2174a0d3b6eaSmrg * find the best mapping from output to crtc available 2175a0d3b6eaSmrg */ 217662df5ad0Smrgstatic int 2177a0d3b6eaSmrgpick_crtcs_score (output_t *outputs) 2178a0d3b6eaSmrg{ 2179a0d3b6eaSmrg output_t *output; 2180a0d3b6eaSmrg int best_score; 2181a0d3b6eaSmrg int my_score; 2182a0d3b6eaSmrg int score; 2183a0d3b6eaSmrg crtc_t *best_crtc; 2184a0d3b6eaSmrg int c; 2185a0d3b6eaSmrg 2186a0d3b6eaSmrg if (!outputs) 2187a0d3b6eaSmrg return 0; 2188a0d3b6eaSmrg 2189a0d3b6eaSmrg output = outputs; 2190a0d3b6eaSmrg outputs = outputs->next; 2191a0d3b6eaSmrg /* 2192a0d3b6eaSmrg * Score with this output disabled 2193a0d3b6eaSmrg */ 2194a0d3b6eaSmrg output->crtc_info = NULL; 2195a0d3b6eaSmrg best_score = pick_crtcs_score (outputs); 2196a0d3b6eaSmrg if (output->mode_info == NULL) 2197a0d3b6eaSmrg return best_score; 2198a0d3b6eaSmrg 2199a0d3b6eaSmrg best_crtc = NULL; 2200a0d3b6eaSmrg /* 2201a0d3b6eaSmrg * Now score with this output any valid crtc 2202a0d3b6eaSmrg */ 2203a0d3b6eaSmrg for (c = 0; c < output->output_info->ncrtc; c++) 2204a0d3b6eaSmrg { 2205a0d3b6eaSmrg crtc_t *crtc; 2206a0d3b6eaSmrg 2207a0d3b6eaSmrg crtc = find_crtc_by_xid (output->output_info->crtcs[c]); 2208a0d3b6eaSmrg if (!crtc) 2209cf2cd791Smrg fatal ("cannot find crtc 0x%lx\n", output->output_info->crtcs[c]); 2210a0d3b6eaSmrg 2211a0d3b6eaSmrg /* reset crtc allocation for following outputs */ 2212a0d3b6eaSmrg disable_outputs (outputs); 2213a0d3b6eaSmrg if (!check_crtc_for_output (crtc, output)) 2214a0d3b6eaSmrg continue; 2215a0d3b6eaSmrg 2216a0d3b6eaSmrg my_score = 1000; 2217a0d3b6eaSmrg /* slight preference for existing connections */ 2218a0d3b6eaSmrg if (crtc == output->current_crtc_info) 2219a0d3b6eaSmrg my_score++; 2220a0d3b6eaSmrg 2221a0d3b6eaSmrg output->crtc_info = crtc; 2222a0d3b6eaSmrg score = my_score + pick_crtcs_score (outputs); 2223a0d3b6eaSmrg if (score > best_score) 2224a0d3b6eaSmrg { 2225a0d3b6eaSmrg best_crtc = crtc; 2226a0d3b6eaSmrg best_score = score; 2227a0d3b6eaSmrg } 2228a0d3b6eaSmrg } 2229a0d3b6eaSmrg if (output->crtc_info != best_crtc) 2230a0d3b6eaSmrg output->crtc_info = best_crtc; 2231a0d3b6eaSmrg /* 2232a0d3b6eaSmrg * Reset other outputs based on this one using the best crtc 2233a0d3b6eaSmrg */ 2234a0d3b6eaSmrg (void) pick_crtcs_score (outputs); 2235a0d3b6eaSmrg 2236a0d3b6eaSmrg return best_score; 2237a0d3b6eaSmrg} 2238a0d3b6eaSmrg 2239a0d3b6eaSmrg/* 2240a0d3b6eaSmrg * Pick crtcs for any changing outputs that don't have one 2241a0d3b6eaSmrg */ 224262df5ad0Smrgstatic void 2243a0d3b6eaSmrgpick_crtcs (void) 2244a0d3b6eaSmrg{ 2245a0d3b6eaSmrg output_t *output; 2246319fa471Smrg int saved_crtc_noutput[num_crtcs]; 2247319fa471Smrg int n; 2248a0d3b6eaSmrg 2249a0d3b6eaSmrg /* 2250a0d3b6eaSmrg * First try to match up newly enabled outputs with spare crtcs 2251a0d3b6eaSmrg */ 2252cf2cd791Smrg for (output = all_outputs; output; output = output->next) 2253a0d3b6eaSmrg { 2254a0d3b6eaSmrg if (output->changes && output->mode_info) 2255a0d3b6eaSmrg { 2256a0d3b6eaSmrg if (output->crtc_info) { 2257a0d3b6eaSmrg if (output->crtc_info->crtc_info->noutput > 0 && 2258a0d3b6eaSmrg (output->crtc_info->crtc_info->noutput > 1 || 2259a0d3b6eaSmrg output != find_output_by_xid (output->crtc_info->crtc_info->outputs[0]))) 2260a0d3b6eaSmrg break; 2261a0d3b6eaSmrg } else { 2262a0d3b6eaSmrg output->crtc_info = find_crtc_for_output (output); 2263a0d3b6eaSmrg if (!output->crtc_info) 2264a0d3b6eaSmrg break; 2265a0d3b6eaSmrg } 2266a0d3b6eaSmrg } 2267a0d3b6eaSmrg } 2268a0d3b6eaSmrg /* 2269a0d3b6eaSmrg * Everyone is happy 2270a0d3b6eaSmrg */ 2271a0d3b6eaSmrg if (!output) 2272a0d3b6eaSmrg return; 2273a0d3b6eaSmrg /* 2274a0d3b6eaSmrg * When the simple way fails, see if there is a way 2275a0d3b6eaSmrg * to swap crtcs around and make things work 2276a0d3b6eaSmrg */ 2277cf2cd791Smrg for (output = all_outputs; output; output = output->next) 2278a0d3b6eaSmrg output->current_crtc_info = output->crtc_info; 2279319fa471Smrg 2280319fa471Smrg /* Mark all CRTC as currently unused */ 2281319fa471Smrg for (n = 0; n < num_crtcs; n++) { 2282319fa471Smrg saved_crtc_noutput[n] = crtcs[n].crtc_info->noutput; 2283319fa471Smrg crtcs[n].crtc_info->noutput = 0; 2284319fa471Smrg } 2285319fa471Smrg 2286cf2cd791Smrg pick_crtcs_score (all_outputs); 2287319fa471Smrg 2288319fa471Smrg for (n = 0; n < num_crtcs; n++) 2289319fa471Smrg crtcs[n].crtc_info->noutput = saved_crtc_noutput[n]; 2290319fa471Smrg 2291cf2cd791Smrg for (output = all_outputs; output; output = output->next) 2292a0d3b6eaSmrg { 2293a0d3b6eaSmrg if (output->mode_info && !output->crtc_info) 2294a0d3b6eaSmrg fatal ("cannot find crtc for output %s\n", output->output.string); 2295a0d3b6eaSmrg if (!output->changes && output->crtc_info != output->current_crtc_info) 2296a0d3b6eaSmrg output->changes |= changes_crtc; 2297a0d3b6eaSmrg } 2298a0d3b6eaSmrg} 2299a0d3b6eaSmrg 2300c52f0396Smrgstatic int 2301c52f0396Smrgcheck_strtol(char *s) 2302c52f0396Smrg{ 2303c52f0396Smrg char *endptr; 2304c52f0396Smrg int result = strtol(s, &endptr, 10); 2305c52f0396Smrg if (s == endptr) 2306cf2cd791Smrg argerr ("failed to parse '%s' as a number\n", s); 2307c52f0396Smrg return result; 2308c52f0396Smrg} 2309c52f0396Smrg 23108a16544fSmrgstatic double 2311c52f0396Smrgcheck_strtod(char *s) 2312c52f0396Smrg{ 2313c52f0396Smrg char *endptr; 2314c52f0396Smrg double result = strtod(s, &endptr); 2315c52f0396Smrg if (s == endptr) 2316cf2cd791Smrg argerr ("failed to parse '%s' as a number\n", s); 2317c52f0396Smrg return result; 2318c52f0396Smrg} 2319c52f0396Smrg 2320cf2cd791Smrg 2321cf2cd791Smrgstatic void * 2322cf2cd791Smrgproperty_values_from_string(const char *str, const Atom type, const int format, 2323cf2cd791Smrg int *returned_nitems) 2324cf2cd791Smrg{ 2325cf2cd791Smrg char *token, *tmp; 2326cf2cd791Smrg void *returned_bytes = NULL; 2327319fa471Smrg int nitems = 0, bytes_per_item; 2328cf2cd791Smrg 2329319fa471Smrg if (type != XA_INTEGER && type != XA_CARDINAL) 2330cf2cd791Smrg return NULL; 2331319fa471Smrg 2332319fa471Smrg /* compute memory needed for Xlib datatype (sigh) */ 2333319fa471Smrg switch (format) { 2334319fa471Smrg case 8: 2335319fa471Smrg bytes_per_item = sizeof(char); 2336319fa471Smrg break; 2337319fa471Smrg case 16: 2338319fa471Smrg bytes_per_item = sizeof(short); 2339319fa471Smrg break; 2340319fa471Smrg case 32: 2341319fa471Smrg bytes_per_item = sizeof(long); 2342319fa471Smrg break; 2343319fa471Smrg default: 2344319fa471Smrg return NULL; 2345cf2cd791Smrg } 2346cf2cd791Smrg 2347cf2cd791Smrg tmp = strdup (str); 2348cf2cd791Smrg 2349cf2cd791Smrg for (token = strtok (tmp, ","); token; token = strtok (NULL, ",")) 2350cf2cd791Smrg { 2351cf2cd791Smrg char *endptr; 2352cf2cd791Smrg long int val = strtol (token, &endptr, 0); 2353cf2cd791Smrg 2354cf2cd791Smrg if (token == endptr || *endptr != '\0') 2355cf2cd791Smrg { 2356cf2cd791Smrg argerr ("failed to parse '%s' as a number\n", token); 2357cf2cd791Smrg } 2358cf2cd791Smrg 2359cf2cd791Smrg returned_bytes = realloc (returned_bytes, (nitems + 1) * bytes_per_item); 2360cf2cd791Smrg 2361cf2cd791Smrg if (type == XA_INTEGER && format == 8) 2362cf2cd791Smrg { 2363319fa471Smrg signed char *ptr = returned_bytes; 2364319fa471Smrg ptr[nitems] = (char) val; 2365cf2cd791Smrg } 2366cf2cd791Smrg else if (type == XA_INTEGER && format == 16) 2367cf2cd791Smrg { 2368319fa471Smrg short *ptr = returned_bytes; 2369319fa471Smrg ptr[nitems] = (short) val; 2370cf2cd791Smrg } 2371cf2cd791Smrg else if (type == XA_INTEGER && format == 32) 2372cf2cd791Smrg { 2373319fa471Smrg long *ptr = returned_bytes; 2374319fa471Smrg ptr[nitems] = (long) val; 2375cf2cd791Smrg } 2376cf2cd791Smrg else if (type == XA_CARDINAL && format == 8) 2377cf2cd791Smrg { 2378319fa471Smrg unsigned char *ptr = returned_bytes; 2379319fa471Smrg ptr[nitems] = (unsigned char) val; 2380cf2cd791Smrg } 2381cf2cd791Smrg else if (type == XA_CARDINAL && format == 16) 2382cf2cd791Smrg { 2383319fa471Smrg unsigned short *ptr = returned_bytes; 2384319fa471Smrg ptr[nitems] = (unsigned short) val; 2385cf2cd791Smrg } 2386cf2cd791Smrg else if (type == XA_CARDINAL && format == 32) 2387cf2cd791Smrg { 2388319fa471Smrg unsigned long *ptr = returned_bytes; 2389319fa471Smrg ptr[nitems] = (unsigned long) val; 2390cf2cd791Smrg } 2391cf2cd791Smrg else 2392cf2cd791Smrg { 2393cf2cd791Smrg free (tmp); 2394cf2cd791Smrg free (returned_bytes); 2395cf2cd791Smrg return NULL; 2396cf2cd791Smrg } 2397cf2cd791Smrg 2398cf2cd791Smrg nitems++; 2399cf2cd791Smrg } 2400cf2cd791Smrg 2401cf2cd791Smrg free (tmp); 2402cf2cd791Smrg 2403cf2cd791Smrg *returned_nitems = nitems; 2404cf2cd791Smrg return returned_bytes; 2405cf2cd791Smrg} 2406cf2cd791Smrg 2407cf2cd791Smrg 2408cf2cd791Smrgstatic void 24097936445dSmrgprint_output_property_value(int value_format, /* 8, 16, 32 */ 2410cf2cd791Smrg Atom value_type, /* XA_{ATOM,INTEGER,CARDINAL} */ 2411cf2cd791Smrg const void *value_bytes) 2412cf2cd791Smrg{ 2413cf2cd791Smrg if (value_type == XA_ATOM && value_format == 32) 2414cf2cd791Smrg { 2415cf2cd791Smrg const Atom *val = value_bytes; 2416cf2cd791Smrg char *str = XGetAtomName (dpy, *val); 2417cf2cd791Smrg if (str != NULL) 2418cf2cd791Smrg { 2419cf2cd791Smrg printf ("%s", str); 2420cf2cd791Smrg XFree (str); 2421cf2cd791Smrg return; 2422cf2cd791Smrg } 2423cf2cd791Smrg } 2424cf2cd791Smrg 2425cf2cd791Smrg if (value_type == XA_INTEGER) 2426cf2cd791Smrg { 2427cf2cd791Smrg if (value_format == 8) 2428cf2cd791Smrg { 2429319fa471Smrg const signed char *val = value_bytes; 2430319fa471Smrg printf ("%d", *val); 2431cf2cd791Smrg return; 2432cf2cd791Smrg } 2433cf2cd791Smrg if (value_format == 16) 2434cf2cd791Smrg { 2435319fa471Smrg const short *val = value_bytes; 2436319fa471Smrg printf ("%d", *val); 2437cf2cd791Smrg return; 2438cf2cd791Smrg } 2439cf2cd791Smrg if (value_format == 32) 2440cf2cd791Smrg { 2441319fa471Smrg const long *val = value_bytes; 2442319fa471Smrg printf ("%ld", *val); 2443cf2cd791Smrg return; 2444cf2cd791Smrg } 2445cf2cd791Smrg } 2446cf2cd791Smrg 2447cf2cd791Smrg if (value_type == XA_CARDINAL) 2448cf2cd791Smrg { 2449cf2cd791Smrg if (value_format == 8) 2450cf2cd791Smrg { 2451319fa471Smrg const unsigned char *val = value_bytes; 2452319fa471Smrg printf ("%u", *val); 2453cf2cd791Smrg return; 2454cf2cd791Smrg } 2455cf2cd791Smrg if (value_format == 16) 2456cf2cd791Smrg { 2457319fa471Smrg const unsigned short *val = value_bytes; 2458319fa471Smrg printf ("%u", *val); 2459cf2cd791Smrg return; 2460cf2cd791Smrg } 2461cf2cd791Smrg if (value_format == 32) 2462cf2cd791Smrg { 2463319fa471Smrg const unsigned long *val = value_bytes; 2464319fa471Smrg printf ("%lu", *val); 2465cf2cd791Smrg return; 2466cf2cd791Smrg } 2467cf2cd791Smrg } 2468cf2cd791Smrg 2469cf2cd791Smrg printf ("?"); 2470cf2cd791Smrg} 2471cf2cd791Smrg 24727936445dSmrgstatic void 24737936445dSmrgprint_edid(int nitems, const unsigned char *prop) 24747936445dSmrg{ 24757936445dSmrg int k; 24767936445dSmrg 24777936445dSmrg printf ("\n\t\t"); 24787936445dSmrg 24797936445dSmrg for (k = 0; k < nitems; k++) 24807936445dSmrg { 24817936445dSmrg if (k != 0 && (k % 16) == 0) 24827936445dSmrg { 24837936445dSmrg printf ("\n\t\t"); 24847936445dSmrg } 24857936445dSmrg 24867936445dSmrg printf("%02" PRIx8, prop[k]); 24877936445dSmrg } 24887936445dSmrg 24897936445dSmrg printf("\n"); 24907936445dSmrg} 24917936445dSmrg 24927936445dSmrgstatic void 24937936445dSmrgprint_guid(const unsigned char *prop) 24947936445dSmrg{ 24957936445dSmrg int k; 24967936445dSmrg 24977936445dSmrg printf("{"); 24987936445dSmrg 24997936445dSmrg for (k = 0; k < 16; k++) 25007936445dSmrg { 25017936445dSmrg printf("%02" PRIX8, prop[k]); 25027936445dSmrg if (k == 3 || k == 5 || k == 7 || k == 9) 25037936445dSmrg { 25047936445dSmrg printf("-"); 25057936445dSmrg } 25067936445dSmrg } 25077936445dSmrg 25087936445dSmrg printf("}\n"); 25097936445dSmrg} 25107936445dSmrg 25117936445dSmrgstatic void 25127936445dSmrgprint_output_property(const char *atom_name, 25137936445dSmrg int value_format, 25147936445dSmrg Atom value_type, 25157936445dSmrg int nitems, 25167936445dSmrg const unsigned char *prop) 25177936445dSmrg{ 2518319fa471Smrg int bytes_per_item; 25197936445dSmrg int k; 25207936445dSmrg 2521319fa471Smrg switch (value_format) { 2522319fa471Smrg case 8: 2523319fa471Smrg bytes_per_item = sizeof(char); 2524319fa471Smrg break; 2525319fa471Smrg case 16: 2526319fa471Smrg bytes_per_item = sizeof(short); 2527319fa471Smrg break; 2528319fa471Smrg case 32: 2529319fa471Smrg bytes_per_item = sizeof(long); 2530319fa471Smrg break; 2531319fa471Smrg default: 2532319fa471Smrg return; 2533319fa471Smrg } 25347936445dSmrg /* 25357936445dSmrg * Check for properties that need special formatting. 25367936445dSmrg */ 25377936445dSmrg if (strcmp (atom_name, "EDID") == 0 && value_format == 8 && 25387936445dSmrg value_type == XA_INTEGER) 25397936445dSmrg { 25407936445dSmrg print_edid (nitems, prop); 25417936445dSmrg return; 25427936445dSmrg } 25437936445dSmrg else if (strcmp (atom_name, "GUID") == 0 && value_format == 8 && 25447936445dSmrg value_type == XA_INTEGER && nitems == 16) 25457936445dSmrg { 25467936445dSmrg print_guid (prop); 25477936445dSmrg return; 25487936445dSmrg } 25497936445dSmrg 25507936445dSmrg for (k = 0; k < nitems; k++) 25517936445dSmrg { 25527936445dSmrg if (k != 0) 25537936445dSmrg { 25547936445dSmrg if ((k % 16) == 0) 25557936445dSmrg { 25567936445dSmrg printf ("\n\t\t"); 25577936445dSmrg } 25587936445dSmrg } 25597936445dSmrg print_output_property_value (value_format, value_type, 25607936445dSmrg prop + (k * bytes_per_item)); 25617936445dSmrg printf (" "); 25627936445dSmrg } 25637936445dSmrg 25647936445dSmrg printf ("\n"); 25657936445dSmrg} 25667936445dSmrg 2567cf2cd791Smrgstatic void 2568cf2cd791Smrgget_providers (void) 2569cf2cd791Smrg{ 2570cf2cd791Smrg XRRProviderResources *pr; 2571cf2cd791Smrg int i; 2572cf2cd791Smrg 2573cf2cd791Smrg if (!has_1_4 || providers) 2574cf2cd791Smrg return; 2575cf2cd791Smrg 2576cf2cd791Smrg pr = XRRGetProviderResources(dpy, root); 2577cf2cd791Smrg num_providers = pr->nproviders; 2578cf2cd791Smrg providers = calloc (num_providers, sizeof (provider_t)); 2579cf2cd791Smrg if (!providers) 2580cf2cd791Smrg fatal ("out of memory\n"); 2581cf2cd791Smrg 2582cf2cd791Smrg for (i = 0; i < num_providers; i++) { 2583cf2cd791Smrg provider_t *provider = &providers[i]; 2584cf2cd791Smrg name_t *name = &provider->provider; 2585cf2cd791Smrg XRRProviderInfo *info = XRRGetProviderInfo(dpy, res, pr->providers[i]); 2586cf2cd791Smrg 2587cf2cd791Smrg provider->info = info; 2588cf2cd791Smrg set_name_xid (name, pr->providers[i]); 2589cf2cd791Smrg set_name_index (name, i); 2590cf2cd791Smrg set_name_string (name, info->name); 2591cf2cd791Smrg } 2592cf2cd791Smrg 2593cf2cd791Smrg XRRFreeProviderResources(pr); 2594cf2cd791Smrg} 2595cf2cd791Smrg 2596cf2cd791Smrgstatic provider_t * 2597cf2cd791Smrgfind_provider (name_t *name) 2598cf2cd791Smrg{ 2599cf2cd791Smrg int i; 2600cf2cd791Smrg 26017936445dSmrg if ((name->kind & name_xid) && name->xid == 0) 26027936445dSmrg return NULL; 2603cf2cd791Smrg for (i = 0; i < num_providers; i++) { 2604cf2cd791Smrg provider_t *p = &providers[i]; 2605cf2cd791Smrg name_kind_t common = name->kind & p->provider.kind; 2606cf2cd791Smrg 2607cf2cd791Smrg if ((common & name_xid) && name->xid == p->provider.xid) 2608cf2cd791Smrg return p; 2609cf2cd791Smrg if ((common & name_string) && !strcmp (name->string, p->provider.string)) 2610cf2cd791Smrg return p; 2611cf2cd791Smrg if ((common & name_index) && name->index == p->provider.index) 2612cf2cd791Smrg return p; 2613cf2cd791Smrg } 2614cf2cd791Smrg 2615cf2cd791Smrg printf ("Could not find provider with "); 2616cf2cd791Smrg print_name (name); 2617cf2cd791Smrg printf ("\n"); 2618cf2cd791Smrg exit (1); 2619cf2cd791Smrg} 2620cf2cd791Smrg 2621319fa471Smrgstatic void 2622319fa471Smrgget_monitors(Bool get_active) 2623319fa471Smrg{ 2624319fa471Smrg XRRMonitorInfo *m; 2625319fa471Smrg int n; 2626319fa471Smrg 2627319fa471Smrg if (!has_1_5 || monitors) 2628319fa471Smrg return; 2629319fa471Smrg 2630319fa471Smrg m = XRRGetMonitors(dpy, root, get_active, &n); 2631319fa471Smrg if (n == -1) 2632319fa471Smrg fatal("get monitors failed\n"); 2633319fa471Smrg monitors = calloc(1, sizeof (monitors_t)); 2634319fa471Smrg monitors->n = n; 2635319fa471Smrg monitors->monitors = m; 2636319fa471Smrg} 2637cf2cd791Smrg 2638a0d3b6eaSmrgint 2639a0d3b6eaSmrgmain (int argc, char **argv) 2640a0d3b6eaSmrg{ 2641a0d3b6eaSmrg XRRScreenSize *sizes; 2642a0d3b6eaSmrg XRRScreenConfiguration *sc; 2643a0d3b6eaSmrg int nsize; 2644a0d3b6eaSmrg int nrate; 2645a0d3b6eaSmrg short *rates; 2646a0d3b6eaSmrg Status status = RRSetConfigFailed; 2647a0d3b6eaSmrg int rot = -1; 26488a16544fSmrg int query = False; 26498a16544fSmrg int action_requested = False; 2650cf2cd791Smrg Rotation current_rotation; 2651a0d3b6eaSmrg XEvent event; 2652a0d3b6eaSmrg XRRScreenChangeNotifyEvent *sce; 2653a0d3b6eaSmrg char *display_name = NULL; 2654cf2cd791Smrg int i; 2655a0d3b6eaSmrg SizeID current_size; 2656a0d3b6eaSmrg short current_rate; 2657c52f0396Smrg double rate = -1; 2658a0d3b6eaSmrg int size = -1; 2659a0d3b6eaSmrg int dirind = 0; 2660a0d3b6eaSmrg Bool setit = False; 2661a0d3b6eaSmrg Bool version = False; 2662a0d3b6eaSmrg int event_base, error_base; 2663a0d3b6eaSmrg int reflection = 0; 2664a0d3b6eaSmrg int width = 0, height = 0; 2665a0d3b6eaSmrg Bool have_pixel_size = False; 2666a0d3b6eaSmrg int ret = 0; 2667cf2cd791Smrg output_t *config_output = NULL; 2668a0d3b6eaSmrg Bool setit_1_2 = False; 2669a0d3b6eaSmrg Bool query_1_2 = False; 2670a0d3b6eaSmrg Bool modeit = False; 2671a0d3b6eaSmrg Bool propit = False; 2672a0d3b6eaSmrg Bool query_1 = False; 2673cf2cd791Smrg Bool list_providers = False; 2674cf2cd791Smrg Bool provsetoutsource = False; 2675cf2cd791Smrg Bool provsetoffsink = False; 2676319fa471Smrg Bool monitorit = False; 2677319fa471Smrg Bool list_monitors = False; 2678319fa471Smrg Bool list_active_monitors = False; 2679a0d3b6eaSmrg int major, minor; 268062df5ad0Smrg Bool current = False; 2681305217b6Smrg Bool toggle_x = False; 2682305217b6Smrg Bool toggle_y = False; 2683a0d3b6eaSmrg 2684a0d3b6eaSmrg program_name = argv[0]; 2685a0d3b6eaSmrg for (i = 1; i < argc; i++) { 2686f86b2e6cSmrg if (!strcmp ("-display", argv[i]) || !strcmp ("--display", argv[i]) || 2687f86b2e6cSmrg !strcmp ("-d", argv[i])) { 2688cf2cd791Smrg if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); 2689a0d3b6eaSmrg display_name = argv[i]; 2690a0d3b6eaSmrg continue; 2691a0d3b6eaSmrg } 2692cf2cd791Smrg if (!strcmp("-help", argv[i]) || !strcmp("--help", argv[i])) { 2693a0d3b6eaSmrg usage(); 2694cf2cd791Smrg exit(0); 2695a0d3b6eaSmrg } 2696a0d3b6eaSmrg if (!strcmp ("--verbose", argv[i])) { 2697a0d3b6eaSmrg verbose = True; 2698a0d3b6eaSmrg continue; 2699a0d3b6eaSmrg } 2700a0d3b6eaSmrg if (!strcmp ("--dryrun", argv[i])) { 2701a0d3b6eaSmrg dryrun = True; 2702a0d3b6eaSmrg verbose = True; 2703a0d3b6eaSmrg continue; 2704a0d3b6eaSmrg } 270562df5ad0Smrg if (!strcmp ("--nograb", argv[i])) { 270662df5ad0Smrg grab_server = False; 270762df5ad0Smrg continue; 270862df5ad0Smrg } 270962df5ad0Smrg if (!strcmp("--current", argv[i])) { 271062df5ad0Smrg current = True; 271162df5ad0Smrg continue; 271262df5ad0Smrg } 2713a0d3b6eaSmrg 2714a0d3b6eaSmrg if (!strcmp ("-s", argv[i]) || !strcmp ("--size", argv[i])) { 2715cf2cd791Smrg if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); 2716c52f0396Smrg if (sscanf (argv[i], "%dx%d", &width, &height) == 2) { 2717a0d3b6eaSmrg have_pixel_size = True; 2718c52f0396Smrg } else { 2719c52f0396Smrg size = check_strtol(argv[i]); 2720cf2cd791Smrg if (size < 0) argerr ("--size argument must be nonnegative\n"); 2721c52f0396Smrg } 2722a0d3b6eaSmrg setit = True; 27238a16544fSmrg action_requested = True; 2724a0d3b6eaSmrg continue; 2725a0d3b6eaSmrg } 2726a0d3b6eaSmrg 2727a0d3b6eaSmrg if (!strcmp ("-r", argv[i]) || 2728a0d3b6eaSmrg !strcmp ("--rate", argv[i]) || 2729a0d3b6eaSmrg !strcmp ("--refresh", argv[i])) 2730a0d3b6eaSmrg { 2731cf2cd791Smrg if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); 2732c52f0396Smrg rate = check_strtod(argv[i]); 2733a0d3b6eaSmrg setit = True; 2734cf2cd791Smrg if (config_output) 2735a0d3b6eaSmrg { 2736cf2cd791Smrg config_output->refresh = rate; 2737cf2cd791Smrg config_output->changes |= changes_refresh; 2738a0d3b6eaSmrg setit_1_2 = True; 2739a0d3b6eaSmrg } 27408a16544fSmrg action_requested = True; 2741a0d3b6eaSmrg continue; 2742a0d3b6eaSmrg } 2743a0d3b6eaSmrg 2744a0d3b6eaSmrg if (!strcmp ("-v", argv[i]) || !strcmp ("--version", argv[i])) { 2745a0d3b6eaSmrg version = True; 27468a16544fSmrg action_requested = True; 2747a0d3b6eaSmrg continue; 2748a0d3b6eaSmrg } 2749a0d3b6eaSmrg 2750a0d3b6eaSmrg if (!strcmp ("-x", argv[i])) { 2751305217b6Smrg toggle_x = True; 2752a0d3b6eaSmrg setit = True; 27538a16544fSmrg action_requested = True; 2754a0d3b6eaSmrg continue; 2755a0d3b6eaSmrg } 2756a0d3b6eaSmrg if (!strcmp ("-y", argv[i])) { 2757305217b6Smrg toggle_y = True; 2758a0d3b6eaSmrg setit = True; 27598a16544fSmrg action_requested = True; 2760a0d3b6eaSmrg continue; 2761a0d3b6eaSmrg } 2762a0d3b6eaSmrg if (!strcmp ("--screen", argv[i])) { 2763cf2cd791Smrg if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); 2764c52f0396Smrg screen = check_strtol(argv[i]); 2765cf2cd791Smrg if (screen < 0) argerr ("--screen argument must be nonnegative\n"); 2766a0d3b6eaSmrg continue; 2767a0d3b6eaSmrg } 2768a0d3b6eaSmrg if (!strcmp ("-q", argv[i]) || !strcmp ("--query", argv[i])) { 2769a0d3b6eaSmrg query = True; 2770a0d3b6eaSmrg continue; 2771a0d3b6eaSmrg } 2772a0d3b6eaSmrg if (!strcmp ("-o", argv[i]) || !strcmp ("--orientation", argv[i])) { 2773a0d3b6eaSmrg char *endptr; 2774cf2cd791Smrg if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); 2775c52f0396Smrg dirind = strtol(argv[i], &endptr, 10); 2776c52f0396Smrg if (argv[i] == endptr) { 2777a0d3b6eaSmrg for (dirind = 0; dirind < 4; dirind++) { 2778a0d3b6eaSmrg if (strcmp (direction[dirind], argv[i]) == 0) break; 2779a0d3b6eaSmrg } 2780a0d3b6eaSmrg } 2781cf2cd791Smrg if ((dirind < 0) || (dirind > 3)) 2782cf2cd791Smrg argerr ("%s: invalid argument '%s'\n", argv[i-1], argv[i]); 2783a0d3b6eaSmrg rot = dirind; 2784a0d3b6eaSmrg setit = True; 27858a16544fSmrg action_requested = True; 2786a0d3b6eaSmrg continue; 2787a0d3b6eaSmrg } 278862df5ad0Smrg if (!strcmp ("--prop", argv[i]) || 278962df5ad0Smrg !strcmp ("--props", argv[i]) || 279062df5ad0Smrg !strcmp ("--madprops", argv[i]) || 279162df5ad0Smrg !strcmp ("--properties", argv[i])) 2792a0d3b6eaSmrg { 2793a0d3b6eaSmrg query_1_2 = True; 2794a0d3b6eaSmrg properties = True; 27958a16544fSmrg action_requested = True; 2796a0d3b6eaSmrg continue; 2797a0d3b6eaSmrg } 2798a0d3b6eaSmrg if (!strcmp ("--output", argv[i])) { 2799cf2cd791Smrg if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); 2800a0d3b6eaSmrg 2801cf2cd791Smrg config_output = find_output_by_name (argv[i]); 2802cf2cd791Smrg if (!config_output) { 2803cf2cd791Smrg config_output = add_output (); 2804cf2cd791Smrg set_name (&config_output->output, argv[i], name_string|name_xid); 2805a0d3b6eaSmrg } 2806a0d3b6eaSmrg 2807a0d3b6eaSmrg setit_1_2 = True; 28088a16544fSmrg action_requested = True; 2809a0d3b6eaSmrg continue; 2810a0d3b6eaSmrg } 2811a0d3b6eaSmrg if (!strcmp ("--crtc", argv[i])) { 2812cf2cd791Smrg if (!config_output) argerr ("%s must be used after --output\n", argv[i]); 2813cf2cd791Smrg if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); 2814cf2cd791Smrg set_name (&config_output->crtc, argv[i], name_xid|name_index); 2815cf2cd791Smrg config_output->changes |= changes_crtc; 2816a0d3b6eaSmrg continue; 2817a0d3b6eaSmrg } 2818a0d3b6eaSmrg if (!strcmp ("--mode", argv[i])) { 2819cf2cd791Smrg if (!config_output) argerr ("%s must be used after --output\n", argv[i]); 2820cf2cd791Smrg if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); 2821cf2cd791Smrg set_name (&config_output->mode, argv[i], name_string|name_xid); 2822cf2cd791Smrg config_output->changes |= changes_mode; 2823a0d3b6eaSmrg continue; 2824a0d3b6eaSmrg } 2825a0d3b6eaSmrg if (!strcmp ("--preferred", argv[i])) { 2826cf2cd791Smrg if (!config_output) argerr ("%s must be used after --output\n", argv[i]); 2827cf2cd791Smrg set_name_preferred (&config_output->mode); 2828cf2cd791Smrg config_output->changes |= changes_mode; 2829a0d3b6eaSmrg continue; 2830a0d3b6eaSmrg } 2831a0d3b6eaSmrg if (!strcmp ("--pos", argv[i])) { 2832cf2cd791Smrg if (!config_output) argerr ("%s must be used after --output\n", argv[i]); 2833cf2cd791Smrg if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); 2834a0d3b6eaSmrg if (sscanf (argv[i], "%dx%d", 2835cf2cd791Smrg &config_output->x, &config_output->y) != 2) 2836cf2cd791Smrg argerr ("failed to parse '%s' as a position\n", argv[i]); 2837cf2cd791Smrg config_output->changes |= changes_position; 2838a0d3b6eaSmrg continue; 2839a0d3b6eaSmrg } 2840a0d3b6eaSmrg if (!strcmp ("--rotation", argv[i]) || !strcmp ("--rotate", argv[i])) { 2841cf2cd791Smrg if (!config_output) argerr ("%s must be used after --output\n", argv[i]); 2842cf2cd791Smrg if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); 2843a0d3b6eaSmrg for (dirind = 0; dirind < 4; dirind++) { 2844a0d3b6eaSmrg if (strcmp (direction[dirind], argv[i]) == 0) break; 2845a0d3b6eaSmrg } 2846a0d3b6eaSmrg if (dirind == 4) 2847cf2cd791Smrg argerr ("%s: invalid argument '%s'\n", argv[i-1], argv[i]); 2848cf2cd791Smrg config_output->rotation &= ~0xf; 2849cf2cd791Smrg config_output->rotation |= 1 << dirind; 2850cf2cd791Smrg config_output->changes |= changes_rotation; 2851a0d3b6eaSmrg continue; 2852a0d3b6eaSmrg } 2853a0d3b6eaSmrg if (!strcmp ("--reflect", argv[i]) || !strcmp ("--reflection", argv[i])) { 2854cf2cd791Smrg if (!config_output) argerr ("%s must be used after --output\n", argv[i]); 2855cf2cd791Smrg if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); 2856a0d3b6eaSmrg for (dirind = 0; dirind < 4; dirind++) { 2857a0d3b6eaSmrg if (strcmp (reflections[dirind], argv[i]) == 0) break; 2858a0d3b6eaSmrg } 2859a0d3b6eaSmrg if (dirind == 4) 2860cf2cd791Smrg argerr ("%s: invalid argument '%s'\n", argv[i-1], argv[i]); 2861cf2cd791Smrg config_output->rotation &= ~(RR_Reflect_X|RR_Reflect_Y); 2862cf2cd791Smrg config_output->rotation |= dirind * RR_Reflect_X; 2863cf2cd791Smrg config_output->changes |= changes_reflection; 2864a0d3b6eaSmrg continue; 2865a0d3b6eaSmrg } 2866a0d3b6eaSmrg if (!strcmp ("--left-of", argv[i])) { 2867cf2cd791Smrg if (!config_output) argerr ("%s must be used after --output\n", argv[i]); 2868cf2cd791Smrg if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); 2869cf2cd791Smrg config_output->relation = relation_left_of; 2870cf2cd791Smrg config_output->relative_to = argv[i]; 2871cf2cd791Smrg config_output->changes |= changes_relation; 2872a0d3b6eaSmrg continue; 2873a0d3b6eaSmrg } 2874a0d3b6eaSmrg if (!strcmp ("--right-of", argv[i])) { 2875cf2cd791Smrg if (!config_output) argerr ("%s must be used after --output\n", argv[i]); 2876cf2cd791Smrg if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); 2877cf2cd791Smrg config_output->relation = relation_right_of; 2878cf2cd791Smrg config_output->relative_to = argv[i]; 2879cf2cd791Smrg config_output->changes |= changes_relation; 2880a0d3b6eaSmrg continue; 2881a0d3b6eaSmrg } 2882a0d3b6eaSmrg if (!strcmp ("--above", argv[i])) { 2883cf2cd791Smrg if (!config_output) argerr ("%s must be used after --output\n", argv[i]); 2884cf2cd791Smrg if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); 2885cf2cd791Smrg config_output->relation = relation_above; 2886cf2cd791Smrg config_output->relative_to = argv[i]; 2887cf2cd791Smrg config_output->changes |= changes_relation; 2888a0d3b6eaSmrg continue; 2889a0d3b6eaSmrg } 2890a0d3b6eaSmrg if (!strcmp ("--below", argv[i])) { 2891cf2cd791Smrg if (!config_output) argerr ("%s must be used after --output\n", argv[i]); 2892cf2cd791Smrg if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); 2893cf2cd791Smrg config_output->relation = relation_below; 2894cf2cd791Smrg config_output->relative_to = argv[i]; 2895cf2cd791Smrg config_output->changes |= changes_relation; 2896a0d3b6eaSmrg continue; 2897a0d3b6eaSmrg } 2898a0d3b6eaSmrg if (!strcmp ("--same-as", argv[i])) { 2899cf2cd791Smrg if (!config_output) argerr ("%s must be used after --output\n", argv[i]); 2900cf2cd791Smrg if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); 2901cf2cd791Smrg config_output->relation = relation_same_as; 2902cf2cd791Smrg config_output->relative_to = argv[i]; 2903cf2cd791Smrg config_output->changes |= changes_relation; 2904a0d3b6eaSmrg continue; 2905a0d3b6eaSmrg } 290662df5ad0Smrg if (!strcmp ("--panning", argv[i])) { 290762df5ad0Smrg XRRPanning *pan; 2908cf2cd791Smrg if (!config_output) argerr ("%s must be used after --output\n", argv[i]); 2909cf2cd791Smrg if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); 2910cf2cd791Smrg pan = &config_output->panning; 291162df5ad0Smrg switch (sscanf (argv[i], "%dx%d+%d+%d/%dx%d+%d+%d/%d/%d/%d/%d", 291262df5ad0Smrg &pan->width, &pan->height, &pan->left, &pan->top, 291362df5ad0Smrg &pan->track_width, &pan->track_height, 291462df5ad0Smrg &pan->track_left, &pan->track_top, 291562df5ad0Smrg &pan->border_left, &pan->border_top, 291662df5ad0Smrg &pan->border_right, &pan->border_bottom)) { 291762df5ad0Smrg case 2: 291862df5ad0Smrg pan->left = pan->top = 0; 291962df5ad0Smrg /* fall through */ 292062df5ad0Smrg case 4: 292162df5ad0Smrg pan->track_left = pan->track_top = 292262df5ad0Smrg pan->track_width = pan->track_height = 0; 292362df5ad0Smrg /* fall through */ 292462df5ad0Smrg case 8: 292562df5ad0Smrg pan->border_left = pan->border_top = 292662df5ad0Smrg pan->border_right = pan->border_bottom = 0; 292762df5ad0Smrg /* fall through */ 292862df5ad0Smrg case 12: 292962df5ad0Smrg break; 293062df5ad0Smrg default: 2931cf2cd791Smrg argerr ("%s: invalid argument '%s'\n", argv[i-1], argv[i]); 293262df5ad0Smrg } 2933cf2cd791Smrg config_output->changes |= changes_panning; 293462df5ad0Smrg continue; 293562df5ad0Smrg } 293662df5ad0Smrg if (!strcmp ("--gamma", argv[i])) { 2937cf2cd791Smrg if (!config_output) argerr ("%s must be used after --output\n", argv[i]); 2938cf2cd791Smrg if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); 2939cf2cd791Smrg if (sscanf(argv[i], "%f:%f:%f", &config_output->gamma.red, 2940cf2cd791Smrg &config_output->gamma.green, &config_output->gamma.blue) != 3) 2941cf2cd791Smrg argerr ("%s: invalid argument '%s'\n", argv[i-1], argv[i]); 2942cf2cd791Smrg config_output->changes |= changes_gamma; 294362df5ad0Smrg setit_1_2 = True; 294462df5ad0Smrg continue; 294562df5ad0Smrg } 29468a16544fSmrg if (!strcmp ("--brightness", argv[i])) { 2947cf2cd791Smrg if (!config_output) argerr ("%s must be used after --output\n", argv[i]); 2948cf2cd791Smrg if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); 2949cf2cd791Smrg if (sscanf(argv[i], "%f", &config_output->brightness) != 1) 2950cf2cd791Smrg argerr ("%s: invalid argument '%s'\n", argv[i-1], argv[i]); 2951cf2cd791Smrg config_output->changes |= changes_gamma; 29528a16544fSmrg setit_1_2 = True; 29538a16544fSmrg continue; 29548a16544fSmrg } 295562df5ad0Smrg if (!strcmp ("--primary", argv[i])) { 2956cf2cd791Smrg if (!config_output) argerr ("%s must be used after --output\n", argv[i]); 2957cf2cd791Smrg config_output->changes |= changes_primary; 2958cf2cd791Smrg config_output->primary = True; 295962df5ad0Smrg setit_1_2 = True; 296062df5ad0Smrg continue; 296162df5ad0Smrg } 296262df5ad0Smrg if (!strcmp ("--noprimary", argv[i])) { 296362df5ad0Smrg no_primary = True; 296462df5ad0Smrg setit_1_2 = True; 296562df5ad0Smrg continue; 296662df5ad0Smrg } 2967a0d3b6eaSmrg if (!strcmp ("--set", argv[i])) { 2968a0d3b6eaSmrg output_prop_t *prop; 2969cf2cd791Smrg if (!config_output) argerr ("%s must be used after --output\n", argv[i]); 2970cf2cd791Smrg if (i+2 >= argc) argerr ("%s requires two arguments\n", argv[i]); 2971a0d3b6eaSmrg prop = malloc (sizeof (output_prop_t)); 2972cf2cd791Smrg prop->next = config_output->props; 2973cf2cd791Smrg config_output->props = prop; 2974cf2cd791Smrg prop->name = argv[++i]; 2975cf2cd791Smrg prop->value = argv[++i]; 2976a0d3b6eaSmrg propit = True; 2977cf2cd791Smrg config_output->changes |= changes_property; 2978a0d3b6eaSmrg setit_1_2 = True; 2979a0d3b6eaSmrg continue; 2980a0d3b6eaSmrg } 298162df5ad0Smrg if (!strcmp ("--scale", argv[i])) 298262df5ad0Smrg { 298362df5ad0Smrg double sx, sy; 2984cf2cd791Smrg if (!config_output) argerr ("%s must be used after --output\n", argv[i]); 2985cf2cd791Smrg if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); 298662df5ad0Smrg if (sscanf (argv[i], "%lfx%lf", &sx, &sy) != 2) 2987cf2cd791Smrg argerr ("failed to parse '%s' as a scaling factor\n", argv[i]); 2988cf2cd791Smrg init_transform (&config_output->transform); 2989cf2cd791Smrg config_output->transform.transform.matrix[0][0] = XDoubleToFixed (sx); 2990cf2cd791Smrg config_output->transform.transform.matrix[1][1] = XDoubleToFixed (sy); 2991cf2cd791Smrg config_output->transform.transform.matrix[2][2] = XDoubleToFixed (1.0); 299262df5ad0Smrg if (sx != 1 || sy != 1) 2993cf2cd791Smrg config_output->transform.filter = "bilinear"; 299462df5ad0Smrg else 2995cf2cd791Smrg config_output->transform.filter = "nearest"; 2996cf2cd791Smrg config_output->transform.nparams = 0; 2997cf2cd791Smrg config_output->transform.params = NULL; 2998cf2cd791Smrg config_output->changes |= changes_transform; 2999cf2cd791Smrg continue; 3000cf2cd791Smrg } 3001cf2cd791Smrg if (!strcmp ("--scale-from", argv[i])) 3002cf2cd791Smrg { 3003cf2cd791Smrg int w, h; 3004cf2cd791Smrg if (!config_output) argerr ("%s must be used after --output\n", argv[i]); 3005cf2cd791Smrg if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); 3006cf2cd791Smrg if (sscanf (argv[i], "%dx%d", &w, &h) != 2) 3007cf2cd791Smrg argerr ("failed to parse '%s' as a scale-from size\n", argv[i]); 3008cf2cd791Smrg if (w <=0 || h <= 0) 3009cf2cd791Smrg argerr ("--scale-from dimensions must be nonnegative\n"); 3010cf2cd791Smrg config_output->scale_from_w = w; 3011cf2cd791Smrg config_output->scale_from_h = h; 3012cf2cd791Smrg config_output->changes |= changes_transform; 301362df5ad0Smrg continue; 301462df5ad0Smrg } 301562df5ad0Smrg if (!strcmp ("--transform", argv[i])) { 301662df5ad0Smrg double transform[3][3]; 301762df5ad0Smrg int k, l; 3018cf2cd791Smrg if (!config_output) argerr ("%s must be used after --output\n", argv[i]); 3019cf2cd791Smrg if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); 3020cf2cd791Smrg init_transform (&config_output->transform); 302162df5ad0Smrg if (strcmp (argv[i], "none") != 0) 302262df5ad0Smrg { 302362df5ad0Smrg if (sscanf(argv[i], "%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf", 302462df5ad0Smrg &transform[0][0],&transform[0][1],&transform[0][2], 302562df5ad0Smrg &transform[1][0],&transform[1][1],&transform[1][2], 302662df5ad0Smrg &transform[2][0],&transform[2][1],&transform[2][2]) 302762df5ad0Smrg != 9) 3028cf2cd791Smrg argerr ("failed to parse '%s' as a transformation\n", argv[i]); 3029cf2cd791Smrg init_transform (&config_output->transform); 303062df5ad0Smrg for (k = 0; k < 3; k++) 303162df5ad0Smrg for (l = 0; l < 3; l++) { 3032cf2cd791Smrg config_output->transform.transform.matrix[k][l] = XDoubleToFixed (transform[k][l]); 303362df5ad0Smrg } 3034cf2cd791Smrg config_output->transform.filter = "bilinear"; 3035cf2cd791Smrg config_output->transform.nparams = 0; 3036cf2cd791Smrg config_output->transform.params = NULL; 303762df5ad0Smrg } 3038cf2cd791Smrg config_output->changes |= changes_transform; 303962df5ad0Smrg continue; 304062df5ad0Smrg } 3041a0d3b6eaSmrg if (!strcmp ("--off", argv[i])) { 3042cf2cd791Smrg if (!config_output) argerr ("%s must be used after --output\n", argv[i]); 3043cf2cd791Smrg set_name_xid (&config_output->mode, None); 3044cf2cd791Smrg set_name_xid (&config_output->crtc, None); 3045319fa471Smrg config_output->changes |= changes_mode | changes_crtc; 3046a0d3b6eaSmrg continue; 3047a0d3b6eaSmrg } 3048a0d3b6eaSmrg if (!strcmp ("--fb", argv[i])) { 3049cf2cd791Smrg if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); 3050a0d3b6eaSmrg if (sscanf (argv[i], "%dx%d", 3051a0d3b6eaSmrg &fb_width, &fb_height) != 2) 3052cf2cd791Smrg argerr ("failed to parse '%s' as a framebuffer size\n", argv[i]); 3053a0d3b6eaSmrg setit_1_2 = True; 30548a16544fSmrg action_requested = True; 3055a0d3b6eaSmrg continue; 3056a0d3b6eaSmrg } 3057a0d3b6eaSmrg if (!strcmp ("--fbmm", argv[i])) { 3058cf2cd791Smrg if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); 3059a0d3b6eaSmrg if (sscanf (argv[i], "%dx%d", 3060a0d3b6eaSmrg &fb_width_mm, &fb_height_mm) != 2) 3061cf2cd791Smrg argerr ("failed to parse '%s' as a physical size\n", argv[i]); 3062a0d3b6eaSmrg setit_1_2 = True; 30638a16544fSmrg action_requested = True; 3064a0d3b6eaSmrg continue; 3065a0d3b6eaSmrg } 3066a0d3b6eaSmrg if (!strcmp ("--dpi", argv[i])) { 3067c52f0396Smrg char *strtod_error; 3068cf2cd791Smrg if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); 3069c52f0396Smrg dpi = strtod(argv[i], &strtod_error); 3070c52f0396Smrg if (argv[i] == strtod_error) 3071a0d3b6eaSmrg { 3072a0d3b6eaSmrg dpi = 0.0; 3073cf2cd791Smrg dpi_output_name = argv[i]; 3074a0d3b6eaSmrg } 3075a0d3b6eaSmrg setit_1_2 = True; 30768a16544fSmrg action_requested = True; 3077a0d3b6eaSmrg continue; 3078a0d3b6eaSmrg } 3079a0d3b6eaSmrg if (!strcmp ("--auto", argv[i])) { 3080cf2cd791Smrg if (config_output) 3081a0d3b6eaSmrg { 3082cf2cd791Smrg config_output->automatic = True; 3083cf2cd791Smrg config_output->changes |= changes_automatic; 3084a0d3b6eaSmrg } 3085a0d3b6eaSmrg else 3086a0d3b6eaSmrg automatic = True; 3087a0d3b6eaSmrg setit_1_2 = True; 30888a16544fSmrg action_requested = True; 3089a0d3b6eaSmrg continue; 3090a0d3b6eaSmrg } 3091a0d3b6eaSmrg if (!strcmp ("--q12", argv[i])) 3092a0d3b6eaSmrg { 3093a0d3b6eaSmrg query_1_2 = True; 3094a0d3b6eaSmrg continue; 3095a0d3b6eaSmrg } 3096a0d3b6eaSmrg if (!strcmp ("--q1", argv[i])) 3097a0d3b6eaSmrg { 3098a0d3b6eaSmrg query_1 = True; 3099a0d3b6eaSmrg continue; 3100a0d3b6eaSmrg } 3101a0d3b6eaSmrg if (!strcmp ("--newmode", argv[i])) 3102a0d3b6eaSmrg { 3103f86b2e6cSmrg umode_t *m = calloc (1, sizeof (umode_t)); 3104c52f0396Smrg double clock; 3105a0d3b6eaSmrg 3106a0d3b6eaSmrg ++i; 3107cf2cd791Smrg if (i + 9 >= argc) 3108cf2cd791Smrg argerr ("failed to parse '%s' as a mode specification\n", argv[i]); 3109a0d3b6eaSmrg m->mode.name = argv[i]; 3110a0d3b6eaSmrg m->mode.nameLength = strlen (argv[i]); 3111a0d3b6eaSmrg i++; 3112c52f0396Smrg clock = check_strtod(argv[i++]); 3113a0d3b6eaSmrg m->mode.dotClock = clock * 1e6; 3114a0d3b6eaSmrg 3115c52f0396Smrg m->mode.width = check_strtol(argv[i++]); 3116c52f0396Smrg m->mode.hSyncStart = check_strtol(argv[i++]); 3117c52f0396Smrg m->mode.hSyncEnd = check_strtol(argv[i++]); 3118c52f0396Smrg m->mode.hTotal = check_strtol(argv[i++]); 3119c52f0396Smrg m->mode.height = check_strtol(argv[i++]); 3120c52f0396Smrg m->mode.vSyncStart = check_strtol(argv[i++]); 3121c52f0396Smrg m->mode.vSyncEnd = check_strtol(argv[i++]); 3122c52f0396Smrg m->mode.vTotal = check_strtol(argv[i++]); 3123a0d3b6eaSmrg m->mode.modeFlags = 0; 3124a0d3b6eaSmrg while (i < argc) { 3125a0d3b6eaSmrg int f; 3126a0d3b6eaSmrg 3127a0d3b6eaSmrg for (f = 0; mode_flags[f].string; f++) 3128a0d3b6eaSmrg if (!strcasecmp (mode_flags[f].string, argv[i])) 3129a0d3b6eaSmrg break; 3130a0d3b6eaSmrg 3131a0d3b6eaSmrg if (!mode_flags[f].string) 3132a0d3b6eaSmrg break; 3133a0d3b6eaSmrg m->mode.modeFlags |= mode_flags[f].flag; 3134a0d3b6eaSmrg i++; 3135a0d3b6eaSmrg } 3136a0d3b6eaSmrg m->next = umodes; 3137a0d3b6eaSmrg m->action = umode_create; 3138a0d3b6eaSmrg umodes = m; 3139a0d3b6eaSmrg modeit = True; 31408a16544fSmrg action_requested = True; 3141a0d3b6eaSmrg continue; 3142a0d3b6eaSmrg } 3143a0d3b6eaSmrg if (!strcmp ("--rmmode", argv[i])) 3144a0d3b6eaSmrg { 3145f86b2e6cSmrg umode_t *m = calloc (1, sizeof (umode_t)); 3146a0d3b6eaSmrg 3147cf2cd791Smrg if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); 3148a0d3b6eaSmrg set_name (&m->name, argv[i], name_string|name_xid); 3149a0d3b6eaSmrg m->action = umode_destroy; 3150a0d3b6eaSmrg m->next = umodes; 3151a0d3b6eaSmrg umodes = m; 3152a0d3b6eaSmrg modeit = True; 31538a16544fSmrg action_requested = True; 3154a0d3b6eaSmrg continue; 3155a0d3b6eaSmrg } 3156a0d3b6eaSmrg if (!strcmp ("--addmode", argv[i])) 3157a0d3b6eaSmrg { 3158f86b2e6cSmrg umode_t *m = calloc (1, sizeof (umode_t)); 3159a0d3b6eaSmrg 3160cf2cd791Smrg if (i+2 >= argc) argerr ("%s requires two arguments\n", argv[i]); 3161cf2cd791Smrg set_name (&m->output, argv[++i], name_string|name_xid); 3162cf2cd791Smrg set_name (&m->name, argv[++i], name_string|name_xid); 3163a0d3b6eaSmrg m->action = umode_add; 3164a0d3b6eaSmrg m->next = umodes; 3165a0d3b6eaSmrg umodes = m; 3166a0d3b6eaSmrg modeit = True; 31678a16544fSmrg action_requested = True; 3168a0d3b6eaSmrg continue; 3169a0d3b6eaSmrg } 3170a0d3b6eaSmrg if (!strcmp ("--delmode", argv[i])) 3171a0d3b6eaSmrg { 3172f86b2e6cSmrg umode_t *m = calloc (1, sizeof (umode_t)); 3173a0d3b6eaSmrg 3174cf2cd791Smrg if (i+2 >= argc) argerr ("%s requires two arguments\n", argv[i]); 3175cf2cd791Smrg set_name (&m->output, argv[++i], name_string|name_xid); 3176cf2cd791Smrg set_name (&m->name, argv[++i], name_string|name_xid); 3177a0d3b6eaSmrg m->action = umode_delete; 3178a0d3b6eaSmrg m->next = umodes; 3179a0d3b6eaSmrg umodes = m; 3180a0d3b6eaSmrg modeit = True; 31818a16544fSmrg action_requested = True; 3182a0d3b6eaSmrg continue; 3183a0d3b6eaSmrg } 3184cf2cd791Smrg if (!strcmp ("--listproviders", argv[i])) 3185cf2cd791Smrg { 3186cf2cd791Smrg list_providers = True; 3187cf2cd791Smrg action_requested = True; 3188cf2cd791Smrg continue; 3189cf2cd791Smrg } 3190cf2cd791Smrg if (!strcmp("--setprovideroutputsource", argv[i])) 3191cf2cd791Smrg { 3192cf2cd791Smrg if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); 3193cf2cd791Smrg set_name (&provider_name, argv[i], name_string|name_xid|name_index); 3194cf2cd791Smrg if (++i>=argc) 3195cf2cd791Smrg set_name_xid (&output_source_provider_name, 0); 3196cf2cd791Smrg else 3197cf2cd791Smrg set_name (&output_source_provider_name, argv[i], name_string|name_xid|name_index); 3198cf2cd791Smrg action_requested = True; 3199cf2cd791Smrg provsetoutsource = True; 3200cf2cd791Smrg continue; 3201cf2cd791Smrg } 3202cf2cd791Smrg if (!strcmp("--setprovideroffloadsink", argv[i])) 3203cf2cd791Smrg { 3204cf2cd791Smrg if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); 3205cf2cd791Smrg set_name (&provider_name, argv[i], name_string|name_xid|name_index); 3206cf2cd791Smrg if (++i>=argc) 3207cf2cd791Smrg set_name_xid (&offload_sink_provider_name, 0); 3208cf2cd791Smrg else 3209cf2cd791Smrg set_name (&offload_sink_provider_name, argv[i], name_string|name_xid|name_index); 3210cf2cd791Smrg action_requested = True; 3211cf2cd791Smrg provsetoffsink = True; 3212cf2cd791Smrg continue; 3213cf2cd791Smrg } 3214319fa471Smrg if (!strcmp("--listmonitors", argv[i])) 3215319fa471Smrg { 3216319fa471Smrg list_monitors = True; 3217319fa471Smrg action_requested = True; 3218319fa471Smrg continue; 3219319fa471Smrg } 3220319fa471Smrg if (!strcmp("--listactivemonitors", argv[i])) 3221319fa471Smrg { 3222319fa471Smrg list_active_monitors = True; 3223319fa471Smrg action_requested = True; 3224319fa471Smrg continue; 3225319fa471Smrg } 3226319fa471Smrg if (!strcmp("--setmonitor", argv[i])) 3227319fa471Smrg { 3228319fa471Smrg umonitor_t *m = calloc(1, sizeof (umonitor_t)), **l; 3229319fa471Smrg char *t; 3230319fa471Smrg char *o; 3231319fa471Smrg char *n; 3232319fa471Smrg char *geom; 3233319fa471Smrg 3234319fa471Smrg if (i+3 >= argc) argerr("%s requires three argument\n", argv[i]); 3235319fa471Smrg n = argv[++i]; 3236319fa471Smrg if (*n == '*') { 3237319fa471Smrg m->primary = True; 3238319fa471Smrg n++; 3239319fa471Smrg } 3240319fa471Smrg m->name = n; 3241319fa471Smrg m->set = True; 3242319fa471Smrg geom = argv[++i]; 3243319fa471Smrg 3244319fa471Smrg if (strncmp (geom, "auto", 4) != 0) { 3245319fa471Smrg if (sscanf(geom, "%d/%dx%d/%d+%d+%d", 3246319fa471Smrg &m->width, &m->mmwidth, &m->height, &m->mmheight, &m->x, &m->y) != 6) 3247319fa471Smrg argerr ("failed to parse '%s' as monitor geometry\n", argv[i]); 3248319fa471Smrg } 3249319fa471Smrg 3250319fa471Smrg o = argv[++i]; 3251319fa471Smrg if (strcmp(o, "none") != 0) { 3252319fa471Smrg printf ("output list %s\n", o); 3253319fa471Smrg for (; (t = strtok(o, ",")) != NULL; o = NULL) { 3254319fa471Smrg m->outputs = realloc(m->outputs, (m->noutput + 1) * sizeof (name_t)); 3255319fa471Smrg printf ("add monitor %s\n", t); 3256319fa471Smrg set_name(&m->outputs[m->noutput++], t, name_string|name_xid|name_index); 3257319fa471Smrg printf ("output name %s\n", m->outputs[m->noutput-1].string); 3258319fa471Smrg } 3259319fa471Smrg } 3260319fa471Smrg for (l = &umonitors; *l; l = &((*l)->next)); 3261319fa471Smrg *l = m; 3262319fa471Smrg action_requested = True; 3263319fa471Smrg monitorit = True; 3264319fa471Smrg continue; 3265319fa471Smrg } 3266319fa471Smrg if (!strcmp("--delmonitor", argv[i])) 3267319fa471Smrg { 3268319fa471Smrg umonitor_t *m = calloc(1, sizeof (umonitor_t)), **l; 3269319fa471Smrg 3270319fa471Smrg if (++i >= argc) argerr("%s requires an argument\n", argv[i-1]); 3271319fa471Smrg 3272319fa471Smrg m->name = argv[i]; 3273319fa471Smrg m->set = False; 3274319fa471Smrg for (l = &umonitors; *l; l = &((*l)->next)); 3275319fa471Smrg *l = m; 3276319fa471Smrg action_requested = True; 3277319fa471Smrg monitorit = True; 3278319fa471Smrg continue; 3279319fa471Smrg } 3280cf2cd791Smrg 3281cf2cd791Smrg argerr ("unrecognized option '%s'\n", argv[i]); 3282a0d3b6eaSmrg } 32838a16544fSmrg if (!action_requested) 32848a16544fSmrg query = True; 3285a0d3b6eaSmrg if (verbose) 3286a0d3b6eaSmrg { 3287a0d3b6eaSmrg query = True; 3288a0d3b6eaSmrg if (setit && !setit_1_2) 3289a0d3b6eaSmrg query_1 = True; 3290a0d3b6eaSmrg } 329162770414Smrg if (version) 329262770414Smrg printf("xrandr program version " VERSION "\n"); 3293a0d3b6eaSmrg 3294a0d3b6eaSmrg dpy = XOpenDisplay (display_name); 3295a0d3b6eaSmrg 3296a0d3b6eaSmrg if (dpy == NULL) { 3297a0d3b6eaSmrg fprintf (stderr, "Can't open display %s\n", XDisplayName(display_name)); 3298a0d3b6eaSmrg exit (1); 3299a0d3b6eaSmrg } 3300a0d3b6eaSmrg if (screen < 0) 3301a0d3b6eaSmrg screen = DefaultScreen (dpy); 3302a0d3b6eaSmrg if (screen >= ScreenCount (dpy)) { 3303a0d3b6eaSmrg fprintf (stderr, "Invalid screen number %d (display has %d)\n", 3304a0d3b6eaSmrg screen, ScreenCount (dpy)); 3305a0d3b6eaSmrg exit (1); 3306a0d3b6eaSmrg } 3307a0d3b6eaSmrg 3308a0d3b6eaSmrg root = RootWindow (dpy, screen); 3309a0d3b6eaSmrg 3310ea024c75Smrg if (!XRRQueryExtension (dpy, &event_base, &error_base) || 3311ea024c75Smrg !XRRQueryVersion (dpy, &major, &minor)) 3312a0d3b6eaSmrg { 3313a0d3b6eaSmrg fprintf (stderr, "RandR extension missing\n"); 3314a0d3b6eaSmrg exit (1); 3315a0d3b6eaSmrg } 3316a0d3b6eaSmrg if (major > 1 || (major == 1 && minor >= 2)) 3317a0d3b6eaSmrg has_1_2 = True; 331862df5ad0Smrg if (major > 1 || (major == 1 && minor >= 3)) 331962df5ad0Smrg has_1_3 = True; 3320cf2cd791Smrg if (major > 1 || (major == 1 && minor >= 4)) 3321cf2cd791Smrg has_1_4 = True; 3322319fa471Smrg if (major > 1 || (major == 1 && minor >= 5)) 3323319fa471Smrg has_1_5 = True; 3324a0d3b6eaSmrg if (has_1_2 && modeit) 3325a0d3b6eaSmrg { 3326a0d3b6eaSmrg umode_t *m; 3327a0d3b6eaSmrg 3328319fa471Smrg get_screen (True); 3329a0d3b6eaSmrg get_crtcs(); 3330a0d3b6eaSmrg get_outputs(); 3331a0d3b6eaSmrg 3332a0d3b6eaSmrg for (m = umodes; m; m = m->next) 3333a0d3b6eaSmrg { 3334a0d3b6eaSmrg XRRModeInfo *e; 3335a0d3b6eaSmrg output_t *o; 3336a0d3b6eaSmrg 3337a0d3b6eaSmrg switch (m->action) { 3338a0d3b6eaSmrg case umode_create: 3339a0d3b6eaSmrg XRRCreateMode (dpy, root, &m->mode); 3340a0d3b6eaSmrg break; 3341a0d3b6eaSmrg case umode_destroy: 3342a0d3b6eaSmrg e = find_mode (&m->name, 0); 3343a0d3b6eaSmrg if (!e) 3344a0d3b6eaSmrg fatal ("cannot find mode \"%s\"\n", m->name.string); 3345a0d3b6eaSmrg XRRDestroyMode (dpy, e->id); 3346a0d3b6eaSmrg break; 3347a0d3b6eaSmrg case umode_add: 3348a0d3b6eaSmrg o = find_output (&m->output); 3349a0d3b6eaSmrg if (!o) 3350a0d3b6eaSmrg fatal ("cannot find output \"%s\"\n", m->output.string); 3351a0d3b6eaSmrg e = find_mode (&m->name, 0); 3352a0d3b6eaSmrg if (!e) 3353a0d3b6eaSmrg fatal ("cannot find mode \"%s\"\n", m->name.string); 3354a0d3b6eaSmrg XRRAddOutputMode (dpy, o->output.xid, e->id); 3355a0d3b6eaSmrg break; 3356a0d3b6eaSmrg case umode_delete: 3357a0d3b6eaSmrg o = find_output (&m->output); 3358a0d3b6eaSmrg if (!o) 3359a0d3b6eaSmrg fatal ("cannot find output \"%s\"\n", m->output.string); 3360a0d3b6eaSmrg e = find_mode (&m->name, 0); 3361a0d3b6eaSmrg if (!e) 3362a0d3b6eaSmrg fatal ("cannot find mode \"%s\"\n", m->name.string); 3363a0d3b6eaSmrg XRRDeleteOutputMode (dpy, o->output.xid, e->id); 3364a0d3b6eaSmrg break; 3365a0d3b6eaSmrg } 3366a0d3b6eaSmrg } 3367319fa471Smrg if (!propit && !setit_1_2 && !monitorit) 3368a0d3b6eaSmrg { 3369a0d3b6eaSmrg XSync (dpy, False); 3370a0d3b6eaSmrg exit (0); 3371a0d3b6eaSmrg } 3372a0d3b6eaSmrg } 3373a0d3b6eaSmrg if (has_1_2 && propit) 3374a0d3b6eaSmrg { 3375cf2cd791Smrg output_t *output; 3376cf2cd791Smrg 3377319fa471Smrg get_screen (True); 3378a0d3b6eaSmrg get_crtcs(); 3379a0d3b6eaSmrg get_outputs(); 3380a0d3b6eaSmrg 3381cf2cd791Smrg for (output = all_outputs; output; output = output->next) 3382a0d3b6eaSmrg { 3383a0d3b6eaSmrg output_prop_t *prop; 3384a0d3b6eaSmrg 3385a0d3b6eaSmrg for (prop = output->props; prop; prop = prop->next) 3386a0d3b6eaSmrg { 3387a0d3b6eaSmrg Atom name = XInternAtom (dpy, prop->name, False); 3388a0d3b6eaSmrg Atom type; 3389558b030aSmrg int format = 0; 3390cf2cd791Smrg unsigned char *data, *malloced_data = NULL; 3391a0d3b6eaSmrg int nelements; 3392a0d3b6eaSmrg int int_value; 3393a0d3b6eaSmrg unsigned long ulong_value; 3394a0d3b6eaSmrg unsigned char *prop_data; 3395a0d3b6eaSmrg int actual_format; 3396a0d3b6eaSmrg unsigned long nitems, bytes_after; 3397a0d3b6eaSmrg Atom actual_type; 3398a0d3b6eaSmrg XRRPropertyInfo *propinfo; 3399a0d3b6eaSmrg 3400a0d3b6eaSmrg type = AnyPropertyType; 3401a0d3b6eaSmrg 3402a0d3b6eaSmrg if (XRRGetOutputProperty (dpy, output->output.xid, name, 3403a0d3b6eaSmrg 0, 100, False, False, 3404a0d3b6eaSmrg AnyPropertyType, 3405a0d3b6eaSmrg &actual_type, &actual_format, 3406a0d3b6eaSmrg &nitems, &bytes_after, &prop_data) == Success && 3407a0d3b6eaSmrg 3408a0d3b6eaSmrg (propinfo = XRRQueryOutputProperty(dpy, output->output.xid, 3409a0d3b6eaSmrg name))) 3410a0d3b6eaSmrg { 3411a0d3b6eaSmrg type = actual_type; 3412a0d3b6eaSmrg format = actual_format; 3413a0d3b6eaSmrg } 3414cf2cd791Smrg 3415cf2cd791Smrg malloced_data = property_values_from_string 3416cf2cd791Smrg (prop->value, type, actual_format, &nelements); 3417cf2cd791Smrg 3418cf2cd791Smrg if (malloced_data) 3419cf2cd791Smrg { 3420cf2cd791Smrg data = malloced_data; 3421cf2cd791Smrg type = actual_type; 3422cf2cd791Smrg format = actual_format; 3423cf2cd791Smrg } 3424cf2cd791Smrg else if (type == AnyPropertyType && 3425a0d3b6eaSmrg (sscanf (prop->value, "%d", &int_value) == 1 || 3426a0d3b6eaSmrg sscanf (prop->value, "0x%x", &int_value) == 1)) 3427a0d3b6eaSmrg { 3428a0d3b6eaSmrg type = XA_INTEGER; 3429a0d3b6eaSmrg ulong_value = int_value; 3430a0d3b6eaSmrg data = (unsigned char *) &ulong_value; 3431a0d3b6eaSmrg nelements = 1; 3432a0d3b6eaSmrg format = 32; 3433a0d3b6eaSmrg } 3434305217b6Smrg else if (type == XA_ATOM) 3435a0d3b6eaSmrg { 3436a0d3b6eaSmrg ulong_value = XInternAtom (dpy, prop->value, False); 3437a0d3b6eaSmrg data = (unsigned char *) &ulong_value; 3438a0d3b6eaSmrg nelements = 1; 3439a0d3b6eaSmrg } 3440305217b6Smrg else if (type == XA_STRING || type == AnyPropertyType) 3441a0d3b6eaSmrg { 3442a0d3b6eaSmrg type = XA_STRING; 3443a0d3b6eaSmrg data = (unsigned char *) prop->value; 3444a0d3b6eaSmrg nelements = strlen (prop->value); 3445a0d3b6eaSmrg format = 8; 3446a0d3b6eaSmrg } 344762df5ad0Smrg else 344862df5ad0Smrg continue; 3449a0d3b6eaSmrg XRRChangeOutputProperty (dpy, output->output.xid, 3450a0d3b6eaSmrg name, type, format, PropModeReplace, 3451a0d3b6eaSmrg data, nelements); 3452cf2cd791Smrg free (malloced_data); 3453a0d3b6eaSmrg } 3454a0d3b6eaSmrg } 3455a0d3b6eaSmrg if (!setit_1_2) 3456a0d3b6eaSmrg { 3457a0d3b6eaSmrg XSync (dpy, False); 3458a0d3b6eaSmrg exit (0); 3459a0d3b6eaSmrg } 3460a0d3b6eaSmrg } 3461cf2cd791Smrg if (provsetoutsource) 3462cf2cd791Smrg { 3463cf2cd791Smrg provider_t *provider, *source; 3464cf2cd791Smrg 3465cf2cd791Smrg if (!has_1_4) 3466cf2cd791Smrg fatal ("--setprovideroutputsource requires RandR 1.4\n"); 3467cf2cd791Smrg 3468319fa471Smrg get_screen (True); 3469cf2cd791Smrg get_providers (); 3470cf2cd791Smrg 3471cf2cd791Smrg provider = find_provider (&provider_name); 3472cf2cd791Smrg source = find_provider(&output_source_provider_name); 3473cf2cd791Smrg 34747936445dSmrg XRRSetProviderOutputSource(dpy, provider->provider.xid, source ? source->provider.xid : 0); 3475cf2cd791Smrg } 3476cf2cd791Smrg if (provsetoffsink) 3477cf2cd791Smrg { 3478cf2cd791Smrg provider_t *provider, *sink; 3479cf2cd791Smrg 3480cf2cd791Smrg if (!has_1_4) 3481cf2cd791Smrg fatal ("--setprovideroffloadsink requires RandR 1.4\n"); 3482cf2cd791Smrg 3483319fa471Smrg get_screen (True); 3484cf2cd791Smrg get_providers (); 3485cf2cd791Smrg 3486cf2cd791Smrg provider = find_provider (&provider_name); 3487cf2cd791Smrg sink = find_provider(&offload_sink_provider_name); 3488cf2cd791Smrg 34897936445dSmrg XRRSetProviderOffloadSink(dpy, provider->provider.xid, sink ? sink->provider.xid : 0); 3490cf2cd791Smrg } 3491a0d3b6eaSmrg if (setit_1_2) 3492a0d3b6eaSmrg { 3493319fa471Smrg get_screen (True); 3494a0d3b6eaSmrg get_crtcs (); 3495a0d3b6eaSmrg get_outputs (); 3496a0d3b6eaSmrg set_positions (); 3497a0d3b6eaSmrg set_screen_size (); 3498a0d3b6eaSmrg 3499a0d3b6eaSmrg pick_crtcs (); 3500a0d3b6eaSmrg 3501a0d3b6eaSmrg /* 3502a0d3b6eaSmrg * Assign outputs to crtcs 3503a0d3b6eaSmrg */ 3504a0d3b6eaSmrg set_crtcs (); 3505a0d3b6eaSmrg 3506a0d3b6eaSmrg /* 3507a0d3b6eaSmrg * Mark changing crtcs 3508a0d3b6eaSmrg */ 3509a0d3b6eaSmrg mark_changing_crtcs (); 3510a0d3b6eaSmrg 3511a0d3b6eaSmrg /* 3512a0d3b6eaSmrg * If an output was specified to track dpi, use it 3513a0d3b6eaSmrg */ 3514cf2cd791Smrg if (dpi_output_name) 3515a0d3b6eaSmrg { 3516cf2cd791Smrg output_t *dpi_output = find_output_by_name (dpi_output_name); 3517a0d3b6eaSmrg XRROutputInfo *output_info; 3518a0d3b6eaSmrg XRRModeInfo *mode_info; 3519cf2cd791Smrg if (!dpi_output) 3520cf2cd791Smrg fatal ("Cannot find output %s\n", dpi_output_name); 3521cf2cd791Smrg output_info = dpi_output->output_info; 3522cf2cd791Smrg mode_info = dpi_output->mode_info; 3523a0d3b6eaSmrg if (output_info && mode_info && output_info->mm_height) 3524a0d3b6eaSmrg { 3525a0d3b6eaSmrg /* 3526a0d3b6eaSmrg * When this output covers the whole screen, just use 3527a0d3b6eaSmrg * the known physical size 3528a0d3b6eaSmrg */ 3529a0d3b6eaSmrg if (fb_width == mode_info->width && 3530a0d3b6eaSmrg fb_height == mode_info->height) 3531a0d3b6eaSmrg { 3532a0d3b6eaSmrg fb_width_mm = output_info->mm_width; 3533a0d3b6eaSmrg fb_height_mm = output_info->mm_height; 3534a0d3b6eaSmrg } 3535a0d3b6eaSmrg else 3536a0d3b6eaSmrg { 3537a0d3b6eaSmrg dpi = (25.4 * mode_info->height) / output_info->mm_height; 3538a0d3b6eaSmrg } 3539a0d3b6eaSmrg } 3540a0d3b6eaSmrg } 3541a0d3b6eaSmrg 3542a0d3b6eaSmrg /* 3543a0d3b6eaSmrg * Compute physical screen size 3544a0d3b6eaSmrg */ 3545a0d3b6eaSmrg if (fb_width_mm == 0 || fb_height_mm == 0) 3546a0d3b6eaSmrg { 3547a0d3b6eaSmrg if (fb_width != DisplayWidth (dpy, screen) || 3548a0d3b6eaSmrg fb_height != DisplayHeight (dpy, screen) || dpi != 0.0) 3549a0d3b6eaSmrg { 3550a0d3b6eaSmrg if (dpi <= 0) 3551a0d3b6eaSmrg dpi = (25.4 * DisplayHeight (dpy, screen)) / DisplayHeightMM(dpy, screen); 3552a0d3b6eaSmrg 3553a0d3b6eaSmrg fb_width_mm = (25.4 * fb_width) / dpi; 3554a0d3b6eaSmrg fb_height_mm = (25.4 * fb_height) / dpi; 3555a0d3b6eaSmrg } 3556a0d3b6eaSmrg else 3557a0d3b6eaSmrg { 3558a0d3b6eaSmrg fb_width_mm = DisplayWidthMM (dpy, screen); 3559a0d3b6eaSmrg fb_height_mm = DisplayHeightMM (dpy, screen); 3560a0d3b6eaSmrg } 3561a0d3b6eaSmrg } 3562a0d3b6eaSmrg 356362df5ad0Smrg /* 356462df5ad0Smrg * Set panning 356562df5ad0Smrg */ 356662df5ad0Smrg set_panning (); 356762df5ad0Smrg 356862df5ad0Smrg /* 356962df5ad0Smrg * Set gamma on crtc's that belong to the outputs. 357062df5ad0Smrg */ 357162df5ad0Smrg set_gamma (); 357262df5ad0Smrg 3573a0d3b6eaSmrg /* 3574a0d3b6eaSmrg * Now apply all of the changes 3575a0d3b6eaSmrg */ 3576a0d3b6eaSmrg apply (); 3577a0d3b6eaSmrg 3578319fa471Smrg if (!monitorit) { 3579319fa471Smrg XSync (dpy, False); 3580319fa471Smrg exit (0); 3581319fa471Smrg } 3582319fa471Smrg } 3583319fa471Smrg if (monitorit) { 3584319fa471Smrg umonitor_t *u; 3585319fa471Smrg Atom name; 3586319fa471Smrg 3587319fa471Smrg if (!has_1_5) { 3588319fa471Smrg printf("RandR 1.5 not supported\n"); 3589319fa471Smrg exit(0); 3590319fa471Smrg } 3591319fa471Smrg 3592319fa471Smrg get_screen(True); 3593319fa471Smrg get_monitors(True); 3594319fa471Smrg get_crtcs(); 3595319fa471Smrg get_outputs(); 3596319fa471Smrg 3597319fa471Smrg for (u = umonitors; u; u = u->next) { 3598319fa471Smrg if (u->set) { 3599319fa471Smrg XRRMonitorInfo *m; 3600319fa471Smrg int o; 3601319fa471Smrg 3602319fa471Smrg name = XInternAtom(dpy, u->name, False); 3603319fa471Smrg m = XRRAllocateMonitor(dpy, u->noutput); 3604319fa471Smrg 3605319fa471Smrg m->name = name; 3606319fa471Smrg m->primary = u->primary; 3607319fa471Smrg m->x = u->x; 3608319fa471Smrg m->y = u->y; 3609319fa471Smrg m->width = u->width; 3610319fa471Smrg m->height = u->height; 3611319fa471Smrg m->mwidth = u->mmwidth; 3612319fa471Smrg m->mheight = u->mmheight; 3613319fa471Smrg for (o = 0; o < u->noutput; o++) { 3614319fa471Smrg output_t *output = find_output(&u->outputs[o]); 3615319fa471Smrg if (!output) 3616319fa471Smrg fatal("cannot find output\n"); 3617319fa471Smrg m->outputs[o] = output->output.xid; 3618319fa471Smrg } 3619319fa471Smrg 3620319fa471Smrg XRRSetMonitor(dpy, root, m); 3621319fa471Smrg 3622319fa471Smrg XRRFreeMonitors(m); 3623319fa471Smrg } else { 3624319fa471Smrg int m; 3625319fa471Smrg 3626319fa471Smrg name = XInternAtom(dpy, u->name, True); 3627319fa471Smrg if (!name) { 3628319fa471Smrg printf("No monitor named '%s'\n", u->name); 3629319fa471Smrg } else { 3630319fa471Smrg if (!monitors) 3631319fa471Smrg printf ("No monitors\n"); 3632319fa471Smrg else { 3633319fa471Smrg for (m = 0; m < monitors->n; m++) { 3634319fa471Smrg if (monitors->monitors[m].name == name) 3635319fa471Smrg break; 3636319fa471Smrg } 3637319fa471Smrg if (m == monitors->n) 3638319fa471Smrg printf("No monitor named '%s'\n", u->name); 3639319fa471Smrg else 3640319fa471Smrg XRRDeleteMonitor(dpy, root, name); 3641319fa471Smrg } 3642319fa471Smrg } 3643319fa471Smrg } 3644319fa471Smrg } 3645a0d3b6eaSmrg XSync (dpy, False); 3646a0d3b6eaSmrg exit (0); 3647a0d3b6eaSmrg } 3648a0d3b6eaSmrg if (query_1_2 || (query && has_1_2 && !query_1)) 3649a0d3b6eaSmrg { 3650a0d3b6eaSmrg output_t *output; 3651a0d3b6eaSmrg int m; 3652a0d3b6eaSmrg 3653a0d3b6eaSmrg#define ModeShown 0x80000000 3654a0d3b6eaSmrg 365562df5ad0Smrg get_screen (current); 3656a0d3b6eaSmrg get_crtcs (); 3657a0d3b6eaSmrg get_outputs (); 3658a0d3b6eaSmrg 3659a0d3b6eaSmrg printf ("Screen %d: minimum %d x %d, current %d x %d, maximum %d x %d\n", 3660a0d3b6eaSmrg screen, minWidth, minHeight, 3661a0d3b6eaSmrg DisplayWidth (dpy, screen), DisplayHeight(dpy, screen), 3662a0d3b6eaSmrg maxWidth, maxHeight); 3663a0d3b6eaSmrg 3664cf2cd791Smrg for (output = all_outputs; output; output = output->next) 3665a0d3b6eaSmrg { 3666a0d3b6eaSmrg XRROutputInfo *output_info = output->output_info; 3667cf2cd791Smrg crtc_t *cur_crtc = output->crtc_info; 3668cf2cd791Smrg XRRCrtcInfo *crtc_info = cur_crtc ? cur_crtc->crtc_info : NULL; 3669cf2cd791Smrg XRRModeInfo *cur_mode = output->mode_info; 3670a0d3b6eaSmrg Atom *props; 3671cf2cd791Smrg int j, nprop; 3672a0d3b6eaSmrg Bool *mode_shown; 3673a0d3b6eaSmrg Rotation rotations = output_rotations (output); 3674a0d3b6eaSmrg 3675a0d3b6eaSmrg printf ("%s %s", output_info->name, connection[output_info->connection]); 3676cf2cd791Smrg if (output->primary) { 3677cf2cd791Smrg printf(" primary"); 3678cf2cd791Smrg } 3679cf2cd791Smrg if (cur_mode) 3680a0d3b6eaSmrg { 368162df5ad0Smrg if (crtc_info) { 368262df5ad0Smrg printf (" %dx%d+%d+%d", 368362df5ad0Smrg crtc_info->width, crtc_info->height, 368462df5ad0Smrg crtc_info->x, crtc_info->y); 368562df5ad0Smrg } else { 368662df5ad0Smrg printf (" %dx%d+%d+%d", 3687cf2cd791Smrg cur_mode->width, cur_mode->height, output->x, 3688cf2cd791Smrg output->y); 368962df5ad0Smrg } 3690a0d3b6eaSmrg if (verbose) 3691cf2cd791Smrg printf (" (0x%x)", (int)cur_mode->id); 3692a0d3b6eaSmrg if (output->rotation != RR_Rotate_0 || verbose) 3693a0d3b6eaSmrg { 3694a0d3b6eaSmrg printf (" %s", 3695a0d3b6eaSmrg rotation_name (output->rotation)); 3696a0d3b6eaSmrg if (output->rotation & (RR_Reflect_X|RR_Reflect_Y)) 3697a0d3b6eaSmrg printf (" %s", reflection_name (output->rotation)); 3698a0d3b6eaSmrg } 3699a0d3b6eaSmrg } 3700a0d3b6eaSmrg if (rotations != RR_Rotate_0 || verbose) 3701a0d3b6eaSmrg { 3702a0d3b6eaSmrg Bool first = True; 3703a0d3b6eaSmrg printf (" ("); 3704a0d3b6eaSmrg for (i = 0; i < 4; i ++) { 3705a0d3b6eaSmrg if ((rotations >> i) & 1) { 3706a0d3b6eaSmrg if (!first) printf (" "); first = False; 3707a0d3b6eaSmrg printf("%s", direction[i]); 3708a0d3b6eaSmrg } 3709a0d3b6eaSmrg } 3710a0d3b6eaSmrg if (rotations & RR_Reflect_X) 3711a0d3b6eaSmrg { 3712a0d3b6eaSmrg if (!first) printf (" "); first = False; 3713a0d3b6eaSmrg printf ("x axis"); 3714a0d3b6eaSmrg } 3715a0d3b6eaSmrg if (rotations & RR_Reflect_Y) 3716a0d3b6eaSmrg { 3717558b030aSmrg if (!first) printf (" "); 3718a0d3b6eaSmrg printf ("y axis"); 3719a0d3b6eaSmrg } 3720a0d3b6eaSmrg printf (")"); 3721a0d3b6eaSmrg } 3722a0d3b6eaSmrg 3723cf2cd791Smrg if (cur_mode) 3724a0d3b6eaSmrg { 3725a0d3b6eaSmrg printf (" %dmm x %dmm", 372662df5ad0Smrg (int)output_info->mm_width, (int)output_info->mm_height); 372762df5ad0Smrg } 372862df5ad0Smrg 3729cf2cd791Smrg if (cur_crtc && cur_crtc->panning_info && 3730cf2cd791Smrg cur_crtc->panning_info->width > 0) 373162df5ad0Smrg { 3732cf2cd791Smrg XRRPanning *pan = cur_crtc->panning_info; 373362df5ad0Smrg printf (" panning %dx%d+%d+%d", 373462df5ad0Smrg pan->width, pan->height, pan->left, pan->top); 373562df5ad0Smrg if ((pan->track_width != 0 && 373662df5ad0Smrg (pan->track_left != pan->left || 373762df5ad0Smrg pan->track_width != pan->width || 373862df5ad0Smrg pan->border_left != 0 || 373962df5ad0Smrg pan->border_right != 0)) || 374062df5ad0Smrg (pan->track_height != 0 && 374162df5ad0Smrg (pan->track_top != pan->top || 374262df5ad0Smrg pan->track_height != pan->height || 374362df5ad0Smrg pan->border_top != 0 || 374462df5ad0Smrg pan->border_bottom != 0))) 374562df5ad0Smrg printf (" tracking %dx%d+%d+%d border %d/%d/%d/%d", 374662df5ad0Smrg pan->track_width, pan->track_height, 374762df5ad0Smrg pan->track_left, pan->track_top, 374862df5ad0Smrg pan->border_left, pan->border_top, 374962df5ad0Smrg pan->border_right, pan->border_bottom); 3750a0d3b6eaSmrg } 3751a0d3b6eaSmrg printf ("\n"); 3752a0d3b6eaSmrg 3753a0d3b6eaSmrg if (verbose) 3754a0d3b6eaSmrg { 375562df5ad0Smrg printf ("\tIdentifier: 0x%x\n", (int)output->output.xid); 375662df5ad0Smrg printf ("\tTimestamp: %d\n", (int)output_info->timestamp); 3757a0d3b6eaSmrg printf ("\tSubpixel: %s\n", order[output_info->subpixel_order]); 37588a16544fSmrg if (output->gamma.red != 0.0 && output->gamma.green != 0.0 && output->gamma.blue != 0.0) { 37598a16544fSmrg printf ("\tGamma: %#.2g:%#.2g:%#.2g\n", 37608a16544fSmrg output->gamma.red, output->gamma.green, output->gamma.blue); 37618a16544fSmrg printf ("\tBrightness: %#.2g\n", output->brightness); 37628a16544fSmrg } 3763a0d3b6eaSmrg printf ("\tClones: "); 3764a0d3b6eaSmrg for (j = 0; j < output_info->nclone; j++) 3765a0d3b6eaSmrg { 3766a0d3b6eaSmrg output_t *clone = find_output_by_xid (output_info->clones[j]); 3767a0d3b6eaSmrg 3768a0d3b6eaSmrg if (clone) printf (" %s", clone->output.string); 3769a0d3b6eaSmrg } 3770a0d3b6eaSmrg printf ("\n"); 3771a0d3b6eaSmrg if (output->crtc_info) 3772a0d3b6eaSmrg printf ("\tCRTC: %d\n", output->crtc_info->crtc.index); 3773a0d3b6eaSmrg printf ("\tCRTCs: "); 3774a0d3b6eaSmrg for (j = 0; j < output_info->ncrtc; j++) 3775a0d3b6eaSmrg { 3776a0d3b6eaSmrg crtc_t *crtc = find_crtc_by_xid (output_info->crtcs[j]); 3777a0d3b6eaSmrg if (crtc) 3778a0d3b6eaSmrg printf (" %d", crtc->crtc.index); 3779a0d3b6eaSmrg } 3780a0d3b6eaSmrg printf ("\n"); 378162df5ad0Smrg if (output->crtc_info && output->crtc_info->panning_info) { 378262df5ad0Smrg XRRPanning *pan = output->crtc_info->panning_info; 378362df5ad0Smrg printf ("\tPanning: %dx%d+%d+%d\n", 378462df5ad0Smrg pan->width, pan->height, pan->left, pan->top); 378562df5ad0Smrg printf ("\tTracking: %dx%d+%d+%d\n", 378662df5ad0Smrg pan->track_width, pan->track_height, 378762df5ad0Smrg pan->track_left, pan->track_top); 378862df5ad0Smrg printf ("\tBorder: %d/%d/%d/%d\n", 378962df5ad0Smrg pan->border_left, pan->border_top, 379062df5ad0Smrg pan->border_right, pan->border_bottom); 379162df5ad0Smrg } 379262df5ad0Smrg } 379362df5ad0Smrg if (verbose) 379462df5ad0Smrg { 379562df5ad0Smrg int x, y; 379662df5ad0Smrg 379762df5ad0Smrg printf ("\tTransform: "); 379862df5ad0Smrg for (y = 0; y < 3; y++) 379962df5ad0Smrg { 380062df5ad0Smrg for (x = 0; x < 3; x++) 380162df5ad0Smrg printf (" %f", XFixedToDouble (output->transform.transform.matrix[y][x])); 380262df5ad0Smrg if (y < 2) 380362df5ad0Smrg printf ("\n\t "); 380462df5ad0Smrg } 380562df5ad0Smrg if (output->transform.filter) 380662df5ad0Smrg printf ("\n\t filter: %s", output->transform.filter); 380762df5ad0Smrg printf ("\n"); 3808a0d3b6eaSmrg } 3809a0d3b6eaSmrg if (verbose || properties) 3810a0d3b6eaSmrg { 3811a0d3b6eaSmrg props = XRRListOutputProperties (dpy, output->output.xid, 3812a0d3b6eaSmrg &nprop); 3813a0d3b6eaSmrg for (j = 0; j < nprop; j++) { 3814a0d3b6eaSmrg unsigned char *prop; 3815a0d3b6eaSmrg int actual_format; 3816a0d3b6eaSmrg unsigned long nitems, bytes_after; 3817a0d3b6eaSmrg Atom actual_type; 3818a0d3b6eaSmrg XRRPropertyInfo *propinfo; 3819cf2cd791Smrg char *atom_name = XGetAtomName (dpy, props[j]); 38207936445dSmrg int k; 3821cf2cd791Smrg 3822a0d3b6eaSmrg XRRGetOutputProperty (dpy, output->output.xid, props[j], 3823a0d3b6eaSmrg 0, 100, False, False, 3824a0d3b6eaSmrg AnyPropertyType, 3825a0d3b6eaSmrg &actual_type, &actual_format, 3826a0d3b6eaSmrg &nitems, &bytes_after, &prop); 3827a0d3b6eaSmrg 3828a0d3b6eaSmrg propinfo = XRRQueryOutputProperty(dpy, output->output.xid, 3829a0d3b6eaSmrg props[j]); 3830a0d3b6eaSmrg 3831cf2cd791Smrg printf ("\t%s: ", atom_name); 3832a0d3b6eaSmrg 38337936445dSmrg print_output_property(atom_name, actual_format, 38347936445dSmrg actual_type, nitems, prop); 3835a0d3b6eaSmrg 3836cf2cd791Smrg if (propinfo->range && propinfo->num_values > 0) 3837cf2cd791Smrg { 3838cf2cd791Smrg printf ("\t\trange%s: ", 3839cf2cd791Smrg (propinfo->num_values == 2) ? "" : "s"); 3840cf2cd791Smrg for (k = 0; k < propinfo->num_values / 2; k++) 3841cf2cd791Smrg { 3842cf2cd791Smrg printf ("("); 38437936445dSmrg print_output_property_value (32, actual_type, 3844cf2cd791Smrg (unsigned char *) &(propinfo->values[k * 2])); 3845cf2cd791Smrg printf (", "); 38467936445dSmrg print_output_property_value (32, actual_type, 3847cf2cd791Smrg (unsigned char *) &(propinfo->values[k * 2 + 1])); 3848cf2cd791Smrg printf (")"); 3849f86b2e6cSmrg if (k < propinfo->num_values / 2 - 1) 3850f86b2e6cSmrg printf (", "); 3851cf2cd791Smrg } 3852cf2cd791Smrg printf ("\n"); 3853cf2cd791Smrg } 3854cf2cd791Smrg if (!propinfo->range && propinfo->num_values > 0) 3855cf2cd791Smrg { 3856cf2cd791Smrg printf ("\t\tsupported: "); 3857cf2cd791Smrg for (k = 0; k < propinfo->num_values; k++) 3858cf2cd791Smrg { 38597936445dSmrg print_output_property_value (32, actual_type, 3860cf2cd791Smrg (unsigned char *) &(propinfo->values[k])); 3861f86b2e6cSmrg if (k < propinfo->num_values - 1) 3862f86b2e6cSmrg printf (", "); 3863a0d3b6eaSmrg } 3864cf2cd791Smrg printf ("\n"); 3865a0d3b6eaSmrg } 3866a0d3b6eaSmrg 3867a0d3b6eaSmrg free(propinfo); 3868a0d3b6eaSmrg } 3869a0d3b6eaSmrg } 3870cf2cd791Smrg 3871a0d3b6eaSmrg if (verbose) 3872a0d3b6eaSmrg { 3873a0d3b6eaSmrg for (j = 0; j < output_info->nmode; j++) 3874a0d3b6eaSmrg { 3875a0d3b6eaSmrg XRRModeInfo *mode = find_mode_by_xid (output_info->modes[j]); 3876319fa471Smrg 3877319fa471Smrg print_verbose_mode (mode, mode == output->mode_info, 3878319fa471Smrg j < output_info->npreferred); 3879a0d3b6eaSmrg mode->modeFlags |= ModeShown; 3880a0d3b6eaSmrg } 3881a0d3b6eaSmrg } 3882a0d3b6eaSmrg else 3883a0d3b6eaSmrg { 3884a0d3b6eaSmrg mode_shown = calloc (output_info->nmode, sizeof (Bool)); 3885a0d3b6eaSmrg if (!mode_shown) fatal ("out of memory\n"); 3886a0d3b6eaSmrg for (j = 0; j < output_info->nmode; j++) 3887a0d3b6eaSmrg { 3888a0d3b6eaSmrg XRRModeInfo *jmode, *kmode; 3889cf2cd791Smrg int k; 3890a0d3b6eaSmrg 3891a0d3b6eaSmrg if (mode_shown[j]) continue; 3892a0d3b6eaSmrg 3893a0d3b6eaSmrg jmode = find_mode_by_xid (output_info->modes[j]); 3894a0d3b6eaSmrg printf (" "); 3895a0d3b6eaSmrg printf (" %-12s", jmode->name); 3896a0d3b6eaSmrg for (k = j; k < output_info->nmode; k++) 3897a0d3b6eaSmrg { 3898a0d3b6eaSmrg if (mode_shown[k]) continue; 3899a0d3b6eaSmrg kmode = find_mode_by_xid (output_info->modes[k]); 3900a0d3b6eaSmrg if (strcmp (jmode->name, kmode->name) != 0) continue; 3901a0d3b6eaSmrg mode_shown[k] = True; 3902a0d3b6eaSmrg kmode->modeFlags |= ModeShown; 39037936445dSmrg printf (" %6.2f", mode_refresh (kmode)); 3904a0d3b6eaSmrg if (kmode == output->mode_info) 3905a0d3b6eaSmrg printf ("*"); 3906a0d3b6eaSmrg else 3907a0d3b6eaSmrg printf (" "); 3908a0d3b6eaSmrg if (k < output_info->npreferred) 3909a0d3b6eaSmrg printf ("+"); 3910a0d3b6eaSmrg else 3911a0d3b6eaSmrg printf (" "); 3912a0d3b6eaSmrg } 3913a0d3b6eaSmrg printf ("\n"); 3914a0d3b6eaSmrg } 3915a0d3b6eaSmrg free (mode_shown); 3916a0d3b6eaSmrg } 3917a0d3b6eaSmrg } 3918a0d3b6eaSmrg for (m = 0; m < res->nmode; m++) 3919a0d3b6eaSmrg { 3920a0d3b6eaSmrg XRRModeInfo *mode = &res->modes[m]; 3921a0d3b6eaSmrg 3922a0d3b6eaSmrg if (!(mode->modeFlags & ModeShown)) 3923319fa471Smrg print_verbose_mode(mode, False, False); 3924a0d3b6eaSmrg } 3925a0d3b6eaSmrg exit (0); 3926a0d3b6eaSmrg } 3927cf2cd791Smrg if (list_providers) { 3928cf2cd791Smrg int k; 3929cf2cd791Smrg 3930cf2cd791Smrg if (!has_1_4) { 3931cf2cd791Smrg printf ("RandR 1.4 not supported\n"); 3932cf2cd791Smrg exit (0); 3933cf2cd791Smrg } 3934cf2cd791Smrg 3935cf2cd791Smrg get_screen (current); 3936cf2cd791Smrg get_providers (); 3937cf2cd791Smrg 3938cf2cd791Smrg if (providers) { 3939cf2cd791Smrg int j; 3940cf2cd791Smrg 3941cf2cd791Smrg printf("Providers: number : %d\n", num_providers); 3942cf2cd791Smrg 3943cf2cd791Smrg for (j = 0; j < num_providers; j++) { 3944cf2cd791Smrg provider_t *provider = &providers[j]; 3945cf2cd791Smrg XRRProviderInfo *info = provider->info; 3946cf2cd791Smrg 3947cf2cd791Smrg printf("Provider %d: id: 0x%x cap: 0x%x", j, (int)provider->provider.xid, info->capabilities); 3948cf2cd791Smrg for (k = 0; k < 4; k++) 3949cf2cd791Smrg if (info->capabilities & (1 << k)) 3950cf2cd791Smrg printf(", %s", capability_name(1<<k)); 3951cf2cd791Smrg 3952cf2cd791Smrg printf(" crtcs: %d outputs: %d associated providers: %d name:%s\n", info->ncrtcs, info->noutputs, info->nassociatedproviders, info->name); 3953cf2cd791Smrg } 3954cf2cd791Smrg } 3955cf2cd791Smrg } 3956319fa471Smrg if (list_monitors || list_active_monitors) { 3957319fa471Smrg 3958319fa471Smrg if (!has_1_5) { 3959319fa471Smrg printf("RandR 1.5 not supported\n"); 3960319fa471Smrg exit(0); 3961319fa471Smrg } 3962319fa471Smrg 3963319fa471Smrg get_screen(current); 3964319fa471Smrg get_monitors(list_active_monitors ? True : False); 3965319fa471Smrg get_crtcs(); 3966319fa471Smrg get_outputs(); 3967319fa471Smrg 3968319fa471Smrg if (monitors) { 3969319fa471Smrg int m, o; 3970319fa471Smrg 3971319fa471Smrg printf("Monitors: %d\n", monitors->n); 3972319fa471Smrg 3973319fa471Smrg for (m = 0; m < monitors->n; m++) { 3974319fa471Smrg printf (" %d: %s%s%s %d/%dx%d/%d+%d+%d ", 3975319fa471Smrg m, 3976319fa471Smrg monitors->monitors[m].automatic ? "+" : "", 3977319fa471Smrg monitors->monitors[m].primary ? "*" : "", 3978319fa471Smrg XGetAtomName(dpy, monitors->monitors[m].name), 3979319fa471Smrg monitors->monitors[m].width, 3980319fa471Smrg monitors->monitors[m].mwidth, 3981319fa471Smrg monitors->monitors[m].height, 3982319fa471Smrg monitors->monitors[m].mheight, 3983319fa471Smrg monitors->monitors[m].x, 3984319fa471Smrg monitors->monitors[m].y); 3985319fa471Smrg for (o = 0; o < monitors->monitors[m].noutput; o++) { 3986319fa471Smrg output_t *output = find_output_by_xid(monitors->monitors[m].outputs[o]); 3987319fa471Smrg if (output) 3988319fa471Smrg printf (" %s", output->output.string); 3989319fa471Smrg else 399035e1b5b7Sriastradh printf (" unknown output 0x%"PRIxMAX"\n", (uintmax_t) monitors->monitors[m].outputs[o]); 3991319fa471Smrg } 3992319fa471Smrg printf ("\n"); 3993319fa471Smrg } 3994319fa471Smrg } 3995319fa471Smrg } 3996cf2cd791Smrg 3997a0d3b6eaSmrg sc = XRRGetScreenInfo (dpy, root); 3998a0d3b6eaSmrg 3999a0d3b6eaSmrg if (sc == NULL) 4000a0d3b6eaSmrg exit (1); 4001a0d3b6eaSmrg 4002a0d3b6eaSmrg current_size = XRRConfigCurrentConfiguration (sc, ¤t_rotation); 4003a0d3b6eaSmrg 4004a0d3b6eaSmrg sizes = XRRConfigSizes(sc, &nsize); 4005a0d3b6eaSmrg 4006a0d3b6eaSmrg if (have_pixel_size) { 4007a0d3b6eaSmrg for (size = 0; size < nsize; size++) 4008a0d3b6eaSmrg { 4009a0d3b6eaSmrg if (sizes[size].width == width && sizes[size].height == height) 4010a0d3b6eaSmrg break; 4011a0d3b6eaSmrg } 4012a0d3b6eaSmrg if (size >= nsize) { 4013a0d3b6eaSmrg fprintf (stderr, 4014a0d3b6eaSmrg "Size %dx%d not found in available modes\n", width, height); 4015a0d3b6eaSmrg exit (1); 4016a0d3b6eaSmrg } 4017a0d3b6eaSmrg } 4018a0d3b6eaSmrg else if (size < 0) 4019a0d3b6eaSmrg size = current_size; 4020a0d3b6eaSmrg else if (size >= nsize) { 4021a0d3b6eaSmrg fprintf (stderr, 4022a0d3b6eaSmrg "Size index %d is too large, there are only %d sizes\n", 4023a0d3b6eaSmrg size, nsize); 4024a0d3b6eaSmrg exit (1); 4025a0d3b6eaSmrg } 4026a0d3b6eaSmrg 4027a0d3b6eaSmrg if (rot < 0) 4028a0d3b6eaSmrg { 4029a0d3b6eaSmrg for (rot = 0; rot < 4; rot++) 4030a0d3b6eaSmrg if (1 << rot == (current_rotation & 0xf)) 4031a0d3b6eaSmrg break; 4032a0d3b6eaSmrg } 4033a0d3b6eaSmrg 4034a0d3b6eaSmrg current_rate = XRRConfigCurrentRate (sc); 4035a0d3b6eaSmrg 4036a0d3b6eaSmrg if (rate < 0) 4037a0d3b6eaSmrg { 4038a0d3b6eaSmrg if (size == current_size) 4039a0d3b6eaSmrg rate = current_rate; 4040a0d3b6eaSmrg else 4041a0d3b6eaSmrg rate = 0; 4042a0d3b6eaSmrg } 4043a0d3b6eaSmrg else 4044a0d3b6eaSmrg { 4045a0d3b6eaSmrg rates = XRRConfigRates (sc, size, &nrate); 4046a0d3b6eaSmrg for (i = 0; i < nrate; i++) 4047a0d3b6eaSmrg if (rate == rates[i]) 4048a0d3b6eaSmrg break; 4049a0d3b6eaSmrg if (i == nrate) { 40507936445dSmrg fprintf (stderr, "Rate %.2f Hz not available for this size\n", rate); 4051a0d3b6eaSmrg exit (1); 4052a0d3b6eaSmrg } 4053a0d3b6eaSmrg } 4054a0d3b6eaSmrg 4055a0d3b6eaSmrg if (version) { 4056a0d3b6eaSmrg int major_version, minor_version; 4057a0d3b6eaSmrg XRRQueryVersion (dpy, &major_version, &minor_version); 4058a0d3b6eaSmrg printf("Server reports RandR version %d.%d\n", 4059a0d3b6eaSmrg major_version, minor_version); 4060a0d3b6eaSmrg } 4061a0d3b6eaSmrg 4062a0d3b6eaSmrg if (query || query_1) { 4063a0d3b6eaSmrg printf(" SZ: Pixels Physical Refresh\n"); 4064a0d3b6eaSmrg for (i = 0; i < nsize; i++) { 4065cf2cd791Smrg int j; 4066cf2cd791Smrg 4067a0d3b6eaSmrg printf ("%c%-2d %5d x %-5d (%4dmm x%4dmm )", 4068a0d3b6eaSmrg i == current_size ? '*' : ' ', 4069a0d3b6eaSmrg i, sizes[i].width, sizes[i].height, 4070a0d3b6eaSmrg sizes[i].mwidth, sizes[i].mheight); 4071a0d3b6eaSmrg rates = XRRConfigRates (sc, i, &nrate); 4072a0d3b6eaSmrg if (nrate) printf (" "); 4073a0d3b6eaSmrg for (j = 0; j < nrate; j++) 4074a0d3b6eaSmrg printf ("%c%-4d", 4075a0d3b6eaSmrg i == current_size && rates[j] == current_rate ? '*' : ' ', 4076a0d3b6eaSmrg rates[j]); 4077a0d3b6eaSmrg printf ("\n"); 4078a0d3b6eaSmrg } 4079a0d3b6eaSmrg } 4080a0d3b6eaSmrg 4081cf2cd791Smrg { 4082cf2cd791Smrg Rotation rotations = XRRConfigRotations(sc, ¤t_rotation); 4083a0d3b6eaSmrg 4084305217b6Smrg if (toggle_x && !(current_rotation & RR_Reflect_X)) reflection |= RR_Reflect_X; 4085305217b6Smrg if (toggle_y && !(current_rotation & RR_Reflect_Y)) reflection |= RR_Reflect_Y; 4086305217b6Smrg 4087cf2cd791Smrg if (query) { 4088cf2cd791Smrg printf("Current rotation - %s\n", 4089cf2cd791Smrg rotation_name (current_rotation)); 4090a0d3b6eaSmrg 4091cf2cd791Smrg printf("Current reflection - %s\n", 4092cf2cd791Smrg reflection_name (current_rotation)); 4093a0d3b6eaSmrg 4094cf2cd791Smrg printf ("Rotations possible - "); 4095cf2cd791Smrg for (i = 0; i < 4; i ++) { 4096cf2cd791Smrg if ((rotations >> i) & 1) printf("%s ", direction[i]); 4097cf2cd791Smrg } 4098cf2cd791Smrg printf ("\n"); 4099a0d3b6eaSmrg 4100cf2cd791Smrg printf ("Reflections possible - "); 4101cf2cd791Smrg if (rotations & (RR_Reflect_X|RR_Reflect_Y)) 4102cf2cd791Smrg { 4103cf2cd791Smrg if (rotations & RR_Reflect_X) printf ("X Axis "); 4104cf2cd791Smrg if (rotations & RR_Reflect_Y) printf ("Y Axis"); 4105cf2cd791Smrg } 4106cf2cd791Smrg else 4107cf2cd791Smrg printf ("none"); 4108cf2cd791Smrg printf ("\n"); 4109a0d3b6eaSmrg } 4110a0d3b6eaSmrg } 4111a0d3b6eaSmrg 4112a0d3b6eaSmrg if (verbose) { 4113a0d3b6eaSmrg printf("Setting size to %d, rotation to %s\n", size, direction[rot]); 4114a0d3b6eaSmrg 4115a0d3b6eaSmrg printf ("Setting reflection on "); 4116a0d3b6eaSmrg if (reflection) 4117a0d3b6eaSmrg { 4118a0d3b6eaSmrg if (reflection & RR_Reflect_X) printf ("X Axis "); 4119a0d3b6eaSmrg if (reflection & RR_Reflect_Y) printf ("Y Axis"); 4120a0d3b6eaSmrg } 4121a0d3b6eaSmrg else 4122a0d3b6eaSmrg printf ("neither axis"); 4123a0d3b6eaSmrg printf ("\n"); 4124a0d3b6eaSmrg } 4125a0d3b6eaSmrg 4126a0d3b6eaSmrg /* we should test configureNotify on the root window */ 4127a0d3b6eaSmrg XSelectInput (dpy, root, StructureNotifyMask); 4128a0d3b6eaSmrg 4129a0d3b6eaSmrg if (setit && !dryrun) XRRSelectInput (dpy, root, 4130a0d3b6eaSmrg RRScreenChangeNotifyMask); 4131cf2cd791Smrg if (setit && !dryrun) { 4132cf2cd791Smrg Rotation rotation = 1 << rot; 4133cf2cd791Smrg status = XRRSetScreenConfigAndRate (dpy, sc, root, (SizeID) size, 4134cf2cd791Smrg (Rotation) (rotation | reflection), 4135cf2cd791Smrg rate, CurrentTime); 4136cf2cd791Smrg } 4137a0d3b6eaSmrg 4138a0d3b6eaSmrg if (setit && !dryrun && status == RRSetConfigFailed) { 4139a0d3b6eaSmrg printf ("Failed to change the screen configuration!\n"); 4140a0d3b6eaSmrg ret = 1; 4141a0d3b6eaSmrg } 4142a0d3b6eaSmrg 4143a0d3b6eaSmrg if (verbose && setit && !dryrun && size != current_size) { 4144a0d3b6eaSmrg if (status == RRSetConfigSuccess) 4145a0d3b6eaSmrg { 4146a0d3b6eaSmrg Bool seen_screen = False; 4147a0d3b6eaSmrg while (!seen_screen) { 4148a0d3b6eaSmrg int spo; 4149a0d3b6eaSmrg XNextEvent(dpy, (XEvent *) &event); 4150a0d3b6eaSmrg 4151a0d3b6eaSmrg printf ("Event received, type = %d\n", event.type); 4152a0d3b6eaSmrg /* update Xlib's knowledge of the event */ 4153a0d3b6eaSmrg XRRUpdateConfiguration (&event); 4154a0d3b6eaSmrg if (event.type == ConfigureNotify) 4155a0d3b6eaSmrg printf("Received ConfigureNotify Event!\n"); 4156a0d3b6eaSmrg 4157a0d3b6eaSmrg switch (event.type - event_base) { 4158a0d3b6eaSmrg case RRScreenChangeNotify: 4159a0d3b6eaSmrg sce = (XRRScreenChangeNotifyEvent *) &event; 4160a0d3b6eaSmrg 4161a0d3b6eaSmrg printf("Got a screen change notify event!\n"); 4162a0d3b6eaSmrg printf(" window = %d\n root = %d\n size_index = %d\n rotation %d\n", 4163a0d3b6eaSmrg (int) sce->window, (int) sce->root, 4164a0d3b6eaSmrg sce->size_index, sce->rotation); 4165a0d3b6eaSmrg printf(" timestamp = %ld, config_timestamp = %ld\n", 4166a0d3b6eaSmrg sce->timestamp, sce->config_timestamp); 4167a0d3b6eaSmrg printf(" Rotation = %x\n", sce->rotation); 4168a0d3b6eaSmrg printf(" %d X %d pixels, %d X %d mm\n", 4169a0d3b6eaSmrg sce->width, sce->height, sce->mwidth, sce->mheight); 4170a0d3b6eaSmrg printf("Display width %d, height %d\n", 4171a0d3b6eaSmrg DisplayWidth(dpy, screen), DisplayHeight(dpy, screen)); 4172a0d3b6eaSmrg printf("Display widthmm %d, heightmm %d\n", 4173a0d3b6eaSmrg DisplayWidthMM(dpy, screen), DisplayHeightMM(dpy, screen)); 4174a0d3b6eaSmrg spo = sce->subpixel_order; 4175a0d3b6eaSmrg if ((spo < 0) || (spo > 5)) 4176a0d3b6eaSmrg printf ("Unknown subpixel order, value = %d\n", spo); 4177a0d3b6eaSmrg else printf ("new Subpixel rendering model is %s\n", order[spo]); 4178a0d3b6eaSmrg seen_screen = True; 4179a0d3b6eaSmrg break; 4180a0d3b6eaSmrg default: 4181a0d3b6eaSmrg if (event.type != ConfigureNotify) 4182a0d3b6eaSmrg printf("unknown event received, type = %d!\n", event.type); 4183a0d3b6eaSmrg } 4184a0d3b6eaSmrg } 4185a0d3b6eaSmrg } 4186a0d3b6eaSmrg } 4187a0d3b6eaSmrg XRRFreeScreenConfigInfo(sc); 4188a0d3b6eaSmrg return(ret); 4189a0d3b6eaSmrg} 4190