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