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