xrandr.c revision c52f0396
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#ifdef HAVE_CONFIG_H 41#include "config.h" 42#endif 43 44#if RANDR_MAJOR > 1 || (RANDR_MAJOR == 1 && RANDR_MINOR >= 2) 45#define HAS_RANDR_1_2 1 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; 57 58static char *direction[5] = { 59 "normal", 60 "left", 61 "inverted", 62 "right", 63 "\n"}; 64 65static char *reflections[5] = { 66 "normal", 67 "x", 68 "y", 69 "xy", 70 "\n"}; 71 72/* subpixel order */ 73static char *order[6] = { 74 "unknown", 75 "horizontal rgb", 76 "horizontal bgr", 77 "vertical rgb", 78 "vertical bgr", 79 "no subpixels"}; 80 81static const struct { 82 char *string; 83 unsigned long flag; 84} mode_flags[] = { 85 { "+HSync", RR_HSyncPositive }, 86 { "-HSync", RR_HSyncNegative }, 87 { "+VSync", RR_VSyncPositive }, 88 { "-VSync", RR_VSyncNegative }, 89 { "Interlace", RR_Interlace }, 90 { "DoubleScan", RR_DoubleScan }, 91 { "CSync", RR_CSync }, 92 { "+CSync", RR_CSyncPositive }, 93 { "-CSync", RR_CSyncNegative }, 94 { NULL, 0 } 95}; 96 97static void 98usage(void) 99{ 100 fprintf(stderr, "usage: %s [options]\n", program_name); 101 fprintf(stderr, " where options are:\n"); 102 fprintf(stderr, " -display <display> or -d <display>\n"); 103 fprintf(stderr, " -help\n"); 104 fprintf(stderr, " -o <normal,inverted,left,right,0,1,2,3>\n"); 105 fprintf(stderr, " or --orientation <normal,inverted,left,right,0,1,2,3>\n"); 106 fprintf(stderr, " -q or --query\n"); 107 fprintf(stderr, " -s <size>/<width>x<height> or --size <size>/<width>x<height>\n"); 108 fprintf(stderr, " -r <rate> or --rate <rate> or --refresh <rate>\n"); 109 fprintf(stderr, " -v or --version\n"); 110 fprintf(stderr, " -x (reflect in x)\n"); 111 fprintf(stderr, " -y (reflect in y)\n"); 112 fprintf(stderr, " --screen <screen>\n"); 113 fprintf(stderr, " --verbose\n"); 114 fprintf(stderr, " --dryrun\n"); 115 fprintf(stderr, " --nograb\n"); 116#if HAS_RANDR_1_2 117 fprintf(stderr, " --prop or --properties\n"); 118 fprintf(stderr, " --fb <width>x<height>\n"); 119 fprintf(stderr, " --fbmm <width>x<height>\n"); 120 fprintf(stderr, " --dpi <dpi>/<output>\n"); 121#if 0 122 fprintf(stderr, " --clone\n"); 123 fprintf(stderr, " --extend\n"); 124#endif 125 fprintf(stderr, " --output <output>\n"); 126 fprintf(stderr, " --auto\n"); 127 fprintf(stderr, " --mode <mode>\n"); 128 fprintf(stderr, " --preferred\n"); 129 fprintf(stderr, " --pos <x>x<y>\n"); 130 fprintf(stderr, " --rate <rate> or --refresh <rate>\n"); 131 fprintf(stderr, " --reflect normal,x,y,xy\n"); 132 fprintf(stderr, " --rotate normal,inverted,left,right\n"); 133 fprintf(stderr, " --left-of <output>\n"); 134 fprintf(stderr, " --right-of <output>\n"); 135 fprintf(stderr, " --above <output>\n"); 136 fprintf(stderr, " --below <output>\n"); 137 fprintf(stderr, " --same-as <output>\n"); 138 fprintf(stderr, " --set <property> <value>\n"); 139 fprintf(stderr, " --scale <x>x<y>\n"); 140 fprintf(stderr, " --transform <a>,<b>,<c>,<d>,<e>,<f>,<g>,<h>,<i>\n"); 141 fprintf(stderr, " --off\n"); 142 fprintf(stderr, " --crtc <crtc>\n"); 143 fprintf(stderr, " --panning <w>x<h>[+<x>+<y>[/<track:w>x<h>+<x>+<y>[/<border:l>/<t>/<r>/<b>]]]\n"); 144 fprintf(stderr, " --gamma <r>:<g>:<b>\n"); 145 fprintf(stderr, " --primary\n"); 146 fprintf(stderr, " --noprimary\n"); 147 fprintf(stderr, " --newmode <name> <clock MHz>\n"); 148 fprintf(stderr, " <hdisp> <hsync-start> <hsync-end> <htotal>\n"); 149 fprintf(stderr, " <vdisp> <vsync-start> <vsync-end> <vtotal>\n"); 150 fprintf(stderr, " [+HSync] [-HSync] [+VSync] [-VSync]\n"); 151 fprintf(stderr, " --rmmode <name>\n"); 152 fprintf(stderr, " --addmode <output> <name>\n"); 153 fprintf(stderr, " --delmode <output> <name>\n"); 154#endif 155 156 exit(1); 157 /*NOTREACHED*/ 158} 159 160static void 161fatal (const char *format, ...) 162{ 163 va_list ap; 164 165 va_start (ap, format); 166 fprintf (stderr, "%s: ", program_name); 167 vfprintf (stderr, format, ap); 168 va_end (ap); 169 exit (1); 170 /*NOTREACHED*/ 171} 172 173static void 174warning (const char *format, ...) 175{ 176 va_list ap; 177 178 va_start (ap, format); 179 fprintf (stderr, "%s: ", program_name); 180 vfprintf (stderr, format, ap); 181 va_end (ap); 182} 183 184static char * 185rotation_name (Rotation rotation) 186{ 187 int i; 188 189 if ((rotation & 0xf) == 0) 190 return "normal"; 191 for (i = 0; i < 4; i++) 192 if (rotation & (1 << i)) 193 return direction[i]; 194 return "invalid rotation"; 195} 196 197static char * 198reflection_name (Rotation rotation) 199{ 200 rotation &= (RR_Reflect_X|RR_Reflect_Y); 201 switch (rotation) { 202 case 0: 203 return "none"; 204 case RR_Reflect_X: 205 return "X axis"; 206 case RR_Reflect_Y: 207 return "Y axis"; 208 case RR_Reflect_X|RR_Reflect_Y: 209 return "X and Y axis"; 210 } 211 return "invalid reflection"; 212} 213 214#if HAS_RANDR_1_2 215typedef enum _policy { 216 clone, extend 217} policy_t; 218 219typedef enum _relation { 220 left_of, right_of, above, below, same_as, 221} relation_t; 222 223typedef struct { 224 int x, y, width, height; 225} rectangle_t; 226 227typedef struct { 228 int x1, y1, x2, y2; 229} box_t; 230 231typedef struct { 232 int x, y; 233} point_t; 234 235typedef enum _changes { 236 changes_none = 0, 237 changes_crtc = (1 << 0), 238 changes_mode = (1 << 1), 239 changes_relation = (1 << 2), 240 changes_position = (1 << 3), 241 changes_rotation = (1 << 4), 242 changes_reflection = (1 << 5), 243 changes_automatic = (1 << 6), 244 changes_refresh = (1 << 7), 245 changes_property = (1 << 8), 246 changes_transform = (1 << 9), 247 changes_panning = (1 << 10), 248 changes_gamma = (1 << 11), 249 changes_primary = (1 << 12), 250} changes_t; 251 252typedef enum _name_kind { 253 name_none = 0, 254 name_string = (1 << 0), 255 name_xid = (1 << 1), 256 name_index = (1 << 2), 257 name_preferred = (1 << 3), 258} name_kind_t; 259 260typedef struct { 261 name_kind_t kind; 262 char *string; 263 XID xid; 264 int index; 265} name_t; 266 267typedef struct _crtc crtc_t; 268typedef struct _output output_t; 269typedef struct _transform transform_t; 270typedef struct _umode umode_t; 271typedef struct _output_prop output_prop_t; 272 273struct _transform { 274 XTransform transform; 275 char *filter; 276 int nparams; 277 XFixed *params; 278}; 279 280struct _crtc { 281 name_t crtc; 282 Bool changing; 283 XRRCrtcInfo *crtc_info; 284 285 XRRModeInfo *mode_info; 286 XRRPanning *panning_info; 287 int x; 288 int y; 289 Rotation rotation; 290 output_t **outputs; 291 int noutput; 292 transform_t current_transform, pending_transform; 293}; 294 295struct _output_prop { 296 struct _output_prop *next; 297 char *name; 298 char *value; 299}; 300 301struct _output { 302 struct _output *next; 303 304 changes_t changes; 305 306 output_prop_t *props; 307 308 name_t output; 309 XRROutputInfo *output_info; 310 311 name_t crtc; 312 crtc_t *crtc_info; 313 crtc_t *current_crtc_info; 314 315 name_t mode; 316 double refresh; 317 XRRModeInfo *mode_info; 318 319 name_t addmode; 320 321 relation_t relation; 322 char *relative_to; 323 324 int x, y; 325 Rotation rotation; 326 327 XRRPanning panning; 328 329 Bool automatic; 330 transform_t transform; 331 332 struct { 333 float red; 334 float green; 335 float blue; 336 } gamma; 337 338 Bool primary; 339 340 Bool found; 341}; 342 343typedef enum _umode_action { 344 umode_create, umode_destroy, umode_add, umode_delete 345} umode_action_t; 346 347 348struct _umode { 349 struct _umode *next; 350 351 umode_action_t action; 352 XRRModeInfo mode; 353 name_t output; 354 name_t name; 355}; 356 357static char *connection[3] = { 358 "connected", 359 "disconnected", 360 "unknown connection"}; 361 362#define OUTPUT_NAME 1 363 364#define CRTC_OFF 2 365#define CRTC_UNSET 3 366#define CRTC_INDEX 0x40000000 367 368#define MODE_NAME 1 369#define MODE_OFF 2 370#define MODE_UNSET 3 371#define MODE_PREF 4 372 373#define POS_UNSET -1 374 375static output_t *outputs = NULL; 376static output_t **outputs_tail = &outputs; 377static crtc_t *crtcs; 378static umode_t *umodes; 379static int num_crtcs; 380static XRRScreenResources *res; 381static int fb_width = 0, fb_height = 0; 382static int fb_width_mm = 0, fb_height_mm = 0; 383static double dpi = 0; 384static char *dpi_output = NULL; 385static Bool dryrun = False; 386static int minWidth, maxWidth, minHeight, maxHeight; 387static Bool has_1_2 = False; 388static Bool has_1_3 = False; 389 390static int 391mode_height (XRRModeInfo *mode_info, Rotation rotation) 392{ 393 switch (rotation & 0xf) { 394 case RR_Rotate_0: 395 case RR_Rotate_180: 396 return mode_info->height; 397 case RR_Rotate_90: 398 case RR_Rotate_270: 399 return mode_info->width; 400 default: 401 return 0; 402 } 403} 404 405static int 406mode_width (XRRModeInfo *mode_info, Rotation rotation) 407{ 408 switch (rotation & 0xf) { 409 case RR_Rotate_0: 410 case RR_Rotate_180: 411 return mode_info->width; 412 case RR_Rotate_90: 413 case RR_Rotate_270: 414 return mode_info->height; 415 default: 416 return 0; 417 } 418} 419 420static Bool 421transform_point (XTransform *transform, double *xp, double *yp) 422{ 423 double vector[3]; 424 double result[3]; 425 int i, j; 426 double v; 427 428 vector[0] = *xp; 429 vector[1] = *yp; 430 vector[2] = 1; 431 for (j = 0; j < 3; j++) 432 { 433 v = 0; 434 for (i = 0; i < 3; i++) 435 v += (XFixedToDouble (transform->matrix[j][i]) * vector[i]); 436 if (v > 32767 || v < -32767) 437 return False; 438 result[j] = v; 439 } 440 if (!result[2]) 441 return False; 442 for (j = 0; j < 2; j++) 443 vector[j] = result[j] / result[2]; 444 *xp = vector[0]; 445 *yp = vector[1]; 446 return True; 447} 448 449static void 450path_bounds (XTransform *transform, point_t *points, int npoints, box_t *box) 451{ 452 int i; 453 box_t point; 454 455 for (i = 0; i < npoints; i++) { 456 double x, y; 457 x = points[i].x; 458 y = points[i].y; 459 transform_point (transform, &x, &y); 460 point.x1 = floor (x); 461 point.y1 = floor (y); 462 point.x2 = ceil (x); 463 point.y2 = ceil (y); 464 if (i == 0) 465 *box = point; 466 else { 467 if (point.x1 < box->x1) box->x1 = point.x1; 468 if (point.y1 < box->y1) box->y1 = point.y1; 469 if (point.x2 > box->x2) box->x2 = point.x2; 470 if (point.y2 > box->y2) box->y2 = point.y2; 471 } 472 } 473} 474 475static void 476mode_geometry (XRRModeInfo *mode_info, Rotation rotation, 477 XTransform *transform, 478 box_t *bounds) 479{ 480 point_t rect[4]; 481 int width = mode_width (mode_info, rotation); 482 int height = mode_height (mode_info, rotation); 483 484 rect[0].x = 0; 485 rect[0].y = 0; 486 rect[1].x = width; 487 rect[1].y = 0; 488 rect[2].x = width; 489 rect[2].y = height; 490 rect[3].x = 0; 491 rect[3].y = height; 492 path_bounds (transform, rect, 4, bounds); 493} 494 495/* v refresh frequency in Hz */ 496static double 497mode_refresh (XRRModeInfo *mode_info) 498{ 499 double rate; 500 501 if (mode_info->hTotal && mode_info->vTotal) 502 rate = ((double) mode_info->dotClock / 503 ((double) mode_info->hTotal * (double) mode_info->vTotal)); 504 else 505 rate = 0; 506 return rate; 507} 508 509/* h sync frequency in Hz */ 510static double 511mode_hsync (XRRModeInfo *mode_info) 512{ 513 double rate; 514 515 if (mode_info->hTotal) 516 rate = (double) mode_info->dotClock / (double) mode_info->hTotal; 517 else 518 rate = 0; 519 return rate; 520} 521 522static void 523init_name (name_t *name) 524{ 525 name->kind = name_none; 526} 527 528static void 529set_name_string (name_t *name, char *string) 530{ 531 name->kind |= name_string; 532 name->string = string; 533} 534 535static void 536set_name_xid (name_t *name, XID xid) 537{ 538 name->kind |= name_xid; 539 name->xid = xid; 540} 541 542static void 543set_name_index (name_t *name, int index) 544{ 545 name->kind |= name_index; 546 name->index = index; 547} 548 549static void 550set_name_preferred (name_t *name) 551{ 552 name->kind |= name_preferred; 553} 554 555static void 556set_name_all (name_t *name, name_t *old) 557{ 558 if (old->kind & name_xid) 559 name->xid = old->xid; 560 if (old->kind & name_string) 561 name->string = old->string; 562 if (old->kind & name_index) 563 name->index = old->index; 564 name->kind |= old->kind; 565} 566 567static void 568set_name (name_t *name, char *string, name_kind_t valid) 569{ 570 unsigned int xid; /* don't make it XID (which is unsigned long): 571 scanf() takes unsigned int */ 572 int index; 573 574 if ((valid & name_xid) && sscanf (string, "0x%x", &xid) == 1) 575 set_name_xid (name, xid); 576 else if ((valid & name_index) && sscanf (string, "%d", &index) == 1) 577 set_name_index (name, index); 578 else if (valid & name_string) 579 set_name_string (name, string); 580 else 581 usage (); 582} 583 584static void 585init_transform (transform_t *transform) 586{ 587 int x; 588 memset (&transform->transform, '\0', sizeof (transform->transform)); 589 for (x = 0; x < 3; x++) 590 transform->transform.matrix[x][x] = XDoubleToFixed (1.0); 591 transform->filter = ""; 592 transform->nparams = 0; 593 transform->params = NULL; 594} 595 596static void 597set_transform (transform_t *dest, 598 XTransform *transform, 599 char *filter, 600 XFixed *params, 601 int nparams) 602{ 603 dest->transform = *transform; 604 dest->filter = strdup (filter); 605 dest->nparams = nparams; 606 dest->params = malloc (nparams * sizeof (XFixed)); 607 memcpy (dest->params, params, nparams * sizeof (XFixed)); 608} 609 610static void 611copy_transform (transform_t *dest, transform_t *src) 612{ 613 set_transform (dest, &src->transform, 614 src->filter, src->params, src->nparams); 615} 616 617static Bool 618equal_transform (transform_t *a, transform_t *b) 619{ 620 if (memcmp (&a->transform, &b->transform, sizeof (XTransform)) != 0) 621 return False; 622 if (strcmp (a->filter, b->filter) != 0) 623 return False; 624 if (a->nparams != b->nparams) 625 return False; 626 if (memcmp (a->params, b->params, a->nparams * sizeof (XFixed)) != 0) 627 return False; 628 return True; 629} 630 631static output_t * 632add_output (void) 633{ 634 output_t *output = calloc (1, sizeof (output_t)); 635 636 if (!output) 637 fatal ("out of memory\n"); 638 output->next = NULL; 639 output->found = False; 640 *outputs_tail = output; 641 outputs_tail = &output->next; 642 return output; 643} 644 645static output_t * 646find_output (name_t *name) 647{ 648 output_t *output; 649 650 for (output = outputs; output; output = output->next) 651 { 652 name_kind_t common = name->kind & output->output.kind; 653 654 if ((common & name_xid) && name->xid == output->output.xid) 655 break; 656 if ((common & name_string) && !strcmp (name->string, output->output.string)) 657 break; 658 if ((common & name_index) && name->index == output->output.index) 659 break; 660 } 661 return output; 662} 663 664static output_t * 665find_output_by_xid (RROutput output) 666{ 667 name_t output_name; 668 669 init_name (&output_name); 670 set_name_xid (&output_name, output); 671 return find_output (&output_name); 672} 673 674static output_t * 675find_output_by_name (char *name) 676{ 677 name_t output_name; 678 679 init_name (&output_name); 680 set_name_string (&output_name, name); 681 return find_output (&output_name); 682} 683 684static crtc_t * 685find_crtc (name_t *name) 686{ 687 int c; 688 crtc_t *crtc = NULL; 689 690 for (c = 0; c < num_crtcs; c++) 691 { 692 name_kind_t common; 693 694 crtc = &crtcs[c]; 695 common = name->kind & crtc->crtc.kind; 696 697 if ((common & name_xid) && name->xid == crtc->crtc.xid) 698 break; 699 if ((common & name_string) && !strcmp (name->string, crtc->crtc.string)) 700 break; 701 if ((common & name_index) && name->index == crtc->crtc.index) 702 break; 703 crtc = NULL; 704 } 705 return crtc; 706} 707 708static crtc_t * 709find_crtc_by_xid (RRCrtc crtc) 710{ 711 name_t crtc_name; 712 713 init_name (&crtc_name); 714 set_name_xid (&crtc_name, crtc); 715 return find_crtc (&crtc_name); 716} 717 718static XRRModeInfo * 719find_mode (name_t *name, double refresh) 720{ 721 int m; 722 XRRModeInfo *best = NULL; 723 double bestDist = 0; 724 725 for (m = 0; m < res->nmode; m++) 726 { 727 XRRModeInfo *mode = &res->modes[m]; 728 if ((name->kind & name_xid) && name->xid == mode->id) 729 { 730 best = mode; 731 break; 732 } 733 if ((name->kind & name_string) && !strcmp (name->string, mode->name)) 734 { 735 double dist; 736 737 if (refresh) 738 dist = fabs (mode_refresh (mode) - refresh); 739 else 740 dist = 0; 741 if (!best || dist < bestDist) 742 { 743 bestDist = dist; 744 best = mode; 745 } 746 break; 747 } 748 } 749 return best; 750} 751 752static XRRModeInfo * 753find_mode_by_xid (RRMode mode) 754{ 755 name_t mode_name; 756 757 init_name (&mode_name); 758 set_name_xid (&mode_name, mode); 759 return find_mode (&mode_name, 0); 760} 761 762#if 0 763static XRRModeInfo * 764find_mode_by_name (char *name) 765{ 766 name_t mode_name; 767 init_name (&mode_name); 768 set_name_string (&mode_name, name); 769 return find_mode (&mode_name, 0); 770} 771#endif 772 773static 774XRRModeInfo * 775find_mode_for_output (output_t *output, name_t *name) 776{ 777 XRROutputInfo *output_info = output->output_info; 778 int m; 779 XRRModeInfo *best = NULL; 780 double bestDist = 0; 781 782 for (m = 0; m < output_info->nmode; m++) 783 { 784 XRRModeInfo *mode; 785 786 mode = find_mode_by_xid (output_info->modes[m]); 787 if (!mode) continue; 788 if ((name->kind & name_xid) && name->xid == mode->id) 789 { 790 best = mode; 791 break; 792 } 793 if ((name->kind & name_string) && !strcmp (name->string, mode->name)) 794 { 795 double dist; 796 797 /* Stay away from doublescan modes unless refresh rate is specified. */ 798 if (!output->refresh && (mode->modeFlags & RR_DoubleScan)) 799 continue; 800 801 if (output->refresh) 802 dist = fabs (mode_refresh (mode) - output->refresh); 803 else 804 dist = 0; 805 if (!best || dist < bestDist) 806 { 807 bestDist = dist; 808 best = mode; 809 } 810 } 811 } 812 return best; 813} 814 815static XRRModeInfo * 816preferred_mode (output_t *output) 817{ 818 XRROutputInfo *output_info = output->output_info; 819 int m; 820 XRRModeInfo *best; 821 int bestDist; 822 823 best = NULL; 824 bestDist = 0; 825 for (m = 0; m < output_info->nmode; m++) 826 { 827 XRRModeInfo *mode_info = find_mode_by_xid (output_info->modes[m]); 828 int dist; 829 830 if (m < output_info->npreferred) 831 dist = 0; 832 else if (output_info->mm_height) 833 dist = (1000 * DisplayHeight(dpy, screen) / DisplayHeightMM(dpy, screen) - 834 1000 * mode_info->height / output_info->mm_height); 835 else 836 dist = DisplayHeight(dpy, screen) - mode_info->height; 837 838 if (dist < 0) dist = -dist; 839 if (!best || dist < bestDist) 840 { 841 best = mode_info; 842 bestDist = dist; 843 } 844 } 845 return best; 846} 847 848static Bool 849output_can_use_crtc (output_t *output, crtc_t *crtc) 850{ 851 XRROutputInfo *output_info = output->output_info; 852 int c; 853 854 for (c = 0; c < output_info->ncrtc; c++) 855 if (output_info->crtcs[c] == crtc->crtc.xid) 856 return True; 857 return False; 858} 859 860static Bool 861output_can_use_mode (output_t *output, XRRModeInfo *mode) 862{ 863 XRROutputInfo *output_info = output->output_info; 864 int m; 865 866 for (m = 0; m < output_info->nmode; m++) 867 if (output_info->modes[m] == mode->id) 868 return True; 869 return False; 870} 871 872static Bool 873crtc_can_use_rotation (crtc_t *crtc, Rotation rotation) 874{ 875 Rotation rotations = crtc->crtc_info->rotations; 876 Rotation dir = rotation & (RR_Rotate_0|RR_Rotate_90|RR_Rotate_180|RR_Rotate_270); 877 Rotation reflect = rotation & (RR_Reflect_X|RR_Reflect_Y); 878 if (((rotations & dir) != 0) && ((rotations & reflect) == reflect)) 879 return True; 880 return False; 881} 882 883#if 0 884static Bool 885crtc_can_use_transform (crtc_t *crtc, XTransform *transform) 886{ 887 int major, minor; 888 889 XRRQueryVersion (dpy, &major, &minor); 890 if (major > 1 || (major == 1 && minor >= 3)) 891 return True; 892 return False; 893} 894#endif 895 896/* 897 * Report only rotations that are supported by all crtcs 898 */ 899static Rotation 900output_rotations (output_t *output) 901{ 902 Bool found = False; 903 Rotation rotation = RR_Rotate_0; 904 XRROutputInfo *output_info = output->output_info; 905 int c; 906 907 for (c = 0; c < output_info->ncrtc; c++) 908 { 909 crtc_t *crtc = find_crtc_by_xid (output_info->crtcs[c]); 910 if (crtc) 911 { 912 if (!found) { 913 rotation = crtc->crtc_info->rotations; 914 found = True; 915 } else 916 rotation &= crtc->crtc_info->rotations; 917 } 918 } 919 return rotation; 920} 921 922static Bool 923output_can_use_rotation (output_t *output, Rotation rotation) 924{ 925 XRROutputInfo *output_info = output->output_info; 926 int c; 927 928 /* make sure all of the crtcs can use this rotation. 929 * yes, this is not strictly necessary, but it is 930 * simpler,and we expect most drivers to either 931 * support rotation everywhere or nowhere 932 */ 933 for (c = 0; c < output_info->ncrtc; c++) 934 { 935 crtc_t *crtc = find_crtc_by_xid (output_info->crtcs[c]); 936 if (crtc && !crtc_can_use_rotation (crtc, rotation)) 937 return False; 938 } 939 return True; 940} 941 942static Bool 943output_is_primary(output_t *output) 944{ 945 if (has_1_3) 946 return XRRGetOutputPrimary(dpy, root) == output->output.xid; 947 return False; 948} 949 950static void 951set_output_info (output_t *output, RROutput xid, XRROutputInfo *output_info) 952{ 953 /* sanity check output info */ 954 if (output_info->connection != RR_Disconnected && !output_info->nmode) 955 warning ("Output %s is not disconnected but has no modes\n", 956 output_info->name); 957 958 /* set output name and info */ 959 if (!(output->output.kind & name_xid)) 960 set_name_xid (&output->output, xid); 961 if (!(output->output.kind & name_string)) 962 set_name_string (&output->output, output_info->name); 963 output->output_info = output_info; 964 965 /* set crtc name and info */ 966 if (!(output->changes & changes_crtc)) 967 set_name_xid (&output->crtc, output_info->crtc); 968 969 if (output->crtc.kind == name_xid && output->crtc.xid == None) 970 output->crtc_info = NULL; 971 else 972 { 973 output->crtc_info = find_crtc (&output->crtc); 974 if (!output->crtc_info) 975 { 976 if (output->crtc.kind & name_xid) 977 fatal ("cannot find crtc 0x%x\n", output->crtc.xid); 978 if (output->crtc.kind & name_index) 979 fatal ("cannot find crtc %d\n", output->crtc.index); 980 } 981 if (!output_can_use_crtc (output, output->crtc_info)) 982 fatal ("output %s cannot use crtc 0x%x\n", output->output.string, 983 output->crtc_info->crtc.xid); 984 } 985 986 /* set mode name and info */ 987 if (!(output->changes & changes_mode)) 988 { 989 if (output->crtc_info) 990 set_name_xid (&output->mode, output->crtc_info->crtc_info->mode); 991 else 992 set_name_xid (&output->mode, None); 993 if (output->mode.xid) 994 { 995 output->mode_info = find_mode_by_xid (output->mode.xid); 996 if (!output->mode_info) 997 fatal ("server did not report mode 0x%x for output %s\n", 998 output->mode.xid, output->output.string); 999 } 1000 else 1001 output->mode_info = NULL; 1002 } 1003 else if (output->mode.kind == name_xid && output->mode.xid == None) 1004 output->mode_info = NULL; 1005 else 1006 { 1007 if (output->mode.kind == name_preferred) 1008 output->mode_info = preferred_mode (output); 1009 else 1010 output->mode_info = find_mode_for_output (output, &output->mode); 1011 if (!output->mode_info) 1012 { 1013 if (output->mode.kind & name_preferred) 1014 fatal ("cannot find preferred mode\n"); 1015 if (output->mode.kind & name_string) 1016 fatal ("cannot find mode %s\n", output->mode.string); 1017 if (output->mode.kind & name_xid) 1018 fatal ("cannot find mode 0x%x\n", output->mode.xid); 1019 } 1020 if (!output_can_use_mode (output, output->mode_info)) 1021 fatal ("output %s cannot use mode %s\n", output->output.string, 1022 output->mode_info->name); 1023 } 1024 1025 /* set position */ 1026 if (!(output->changes & changes_position)) 1027 { 1028 if (output->crtc_info) 1029 { 1030 output->x = output->crtc_info->crtc_info->x; 1031 output->y = output->crtc_info->crtc_info->y; 1032 } 1033 else 1034 { 1035 output->x = 0; 1036 output->y = 0; 1037 } 1038 } 1039 1040 /* set rotation */ 1041 if (!(output->changes & changes_rotation)) 1042 { 1043 output->rotation &= ~0xf; 1044 if (output->crtc_info) 1045 output->rotation |= (output->crtc_info->crtc_info->rotation & 0xf); 1046 else 1047 output->rotation = RR_Rotate_0; 1048 } 1049 if (!(output->changes & changes_reflection)) 1050 { 1051 output->rotation &= ~(RR_Reflect_X|RR_Reflect_Y); 1052 if (output->crtc_info) 1053 output->rotation |= (output->crtc_info->crtc_info->rotation & 1054 (RR_Reflect_X|RR_Reflect_Y)); 1055 } 1056 if (!output_can_use_rotation (output, output->rotation)) 1057 fatal ("output %s cannot use rotation \"%s\" reflection \"%s\"\n", 1058 output->output.string, 1059 rotation_name (output->rotation), 1060 reflection_name (output->rotation)); 1061 1062 /* set transformation */ 1063 if (!(output->changes & changes_transform)) 1064 { 1065 if (output->crtc_info) 1066 copy_transform (&output->transform, &output->crtc_info->current_transform); 1067 else 1068 init_transform (&output->transform); 1069 } 1070 1071 /* set primary */ 1072 if (!(output->changes & changes_primary)) 1073 output->primary = output_is_primary(output); 1074} 1075 1076static void 1077get_screen (Bool current) 1078{ 1079 if (!has_1_2) 1080 fatal ("Server RandR version before 1.2\n"); 1081 1082 XRRGetScreenSizeRange (dpy, root, &minWidth, &minHeight, 1083 &maxWidth, &maxHeight); 1084 1085 if (current) 1086 res = XRRGetScreenResourcesCurrent (dpy, root); 1087 else 1088 res = XRRGetScreenResources (dpy, root); 1089 if (!res) fatal ("could not get screen resources"); 1090} 1091 1092static void 1093get_crtcs (void) 1094{ 1095 int c; 1096 1097 num_crtcs = res->ncrtc; 1098 crtcs = calloc (num_crtcs, sizeof (crtc_t)); 1099 if (!crtcs) fatal ("out of memory\n"); 1100 1101 for (c = 0; c < res->ncrtc; c++) 1102 { 1103 XRRCrtcInfo *crtc_info = XRRGetCrtcInfo (dpy, res, res->crtcs[c]); 1104#if RANDR_MAJOR > 1 || RANDR_MINOR >= 3 1105 XRRCrtcTransformAttributes *attr; 1106#endif 1107 XRRPanning *panning_info = NULL; 1108 1109 if (has_1_3) { 1110 XRRPanning zero; 1111 memset(&zero, 0, sizeof(zero)); 1112 panning_info = XRRGetPanning (dpy, res, res->crtcs[c]); 1113 zero.timestamp = panning_info->timestamp; 1114 if (!memcmp(panning_info, &zero, sizeof(zero))) { 1115 Xfree(panning_info); 1116 panning_info = NULL; 1117 } 1118 } 1119 1120 set_name_xid (&crtcs[c].crtc, res->crtcs[c]); 1121 set_name_index (&crtcs[c].crtc, c); 1122 if (!crtc_info) fatal ("could not get crtc 0x%x information\n", res->crtcs[c]); 1123 crtcs[c].crtc_info = crtc_info; 1124 crtcs[c].panning_info = panning_info; 1125 if (crtc_info->mode == None) 1126 { 1127 crtcs[c].mode_info = NULL; 1128 crtcs[c].x = 0; 1129 crtcs[c].y = 0; 1130 crtcs[c].rotation = RR_Rotate_0; 1131 } 1132#if RANDR_MAJOR > 1 || RANDR_MINOR >= 3 1133 if (XRRGetCrtcTransform (dpy, res->crtcs[c], &attr) && attr) { 1134 set_transform (&crtcs[c].current_transform, 1135 &attr->currentTransform, 1136 attr->currentFilter, 1137 attr->currentParams, 1138 attr->currentNparams); 1139 XFree (attr); 1140 } 1141 else 1142#endif 1143 { 1144 init_transform (&crtcs[c].current_transform); 1145 } 1146 copy_transform (&crtcs[c].pending_transform, &crtcs[c].current_transform); 1147 } 1148} 1149 1150static void 1151crtc_add_output (crtc_t *crtc, output_t *output) 1152{ 1153 if (crtc->outputs) 1154 crtc->outputs = realloc (crtc->outputs, (crtc->noutput + 1) * sizeof (output_t *)); 1155 else 1156 { 1157 crtc->outputs = malloc (sizeof (output_t *)); 1158 crtc->x = output->x; 1159 crtc->y = output->y; 1160 crtc->rotation = output->rotation; 1161 crtc->mode_info = output->mode_info; 1162 copy_transform (&crtc->pending_transform, &output->transform); 1163 } 1164 if (!crtc->outputs) fatal ("out of memory\n"); 1165 crtc->outputs[crtc->noutput++] = output; 1166} 1167 1168static void 1169set_crtcs (void) 1170{ 1171 output_t *output; 1172 1173 for (output = outputs; output; output = output->next) 1174 { 1175 if (!output->mode_info) continue; 1176 crtc_add_output (output->crtc_info, output); 1177 } 1178} 1179 1180static void 1181set_panning (void) 1182{ 1183 output_t *output; 1184 1185 for (output = outputs; output; output = output->next) 1186 { 1187 if (! output->crtc_info) 1188 continue; 1189 if (! (output->changes & changes_panning)) 1190 continue; 1191 if (! output->crtc_info->panning_info) 1192 output->crtc_info->panning_info = malloc (sizeof(XRRPanning)); 1193 memcpy (output->crtc_info->panning_info, &output->panning, sizeof(XRRPanning)); 1194 output->crtc_info->changing = 1; 1195 } 1196} 1197 1198static void 1199set_gamma(void) 1200{ 1201 output_t *output; 1202 1203 for (output = outputs; output; output = output->next) { 1204 int i, size; 1205 crtc_t *crtc; 1206 XRRCrtcGamma *gamma; 1207 1208 if (!(output->changes & changes_gamma)) 1209 continue; 1210 1211 if (!output->crtc_info) { 1212 fatal("Need crtc to set gamma on.\n"); 1213 continue; 1214 } 1215 1216 crtc = output->crtc_info; 1217 1218 size = XRRGetCrtcGammaSize(dpy, crtc->crtc.xid); 1219 1220 if (!size) { 1221 fatal("Gamma size is 0.\n"); 1222 continue; 1223 } 1224 1225 gamma = XRRAllocGamma(size); 1226 if (!gamma) { 1227 fatal("Gamma allocation failed.\n"); 1228 continue; 1229 } 1230 1231 for (i = 0; i < size; i++) { 1232 if (output->gamma.red == 1.0) 1233 gamma->red[i] = i << 8; 1234 else 1235 gamma->red[i] = (CARD16)(pow((double)i/(double)(size - 1), 1236 (double)output->gamma.red) * (double)(size - 1) * 256); 1237 1238 if (output->gamma.green == 1.0) 1239 gamma->green[i] = i << 8; 1240 else 1241 gamma->green[i] = (CARD16)(pow((double)i/(double)(size - 1), 1242 (double)output->gamma.green) * (double)(size - 1) * 256); 1243 1244 if (output->gamma.blue == 1.0) 1245 gamma->blue[i] = i << 8; 1246 else 1247 gamma->blue[i] = (CARD16)(pow((double)i/(double)(size - 1), 1248 (double)output->gamma.blue) * (double)(size - 1) * 256); 1249 } 1250 1251 XRRSetCrtcGamma(dpy, crtc->crtc.xid, gamma); 1252 1253 free(gamma); 1254 } 1255} 1256 1257static void 1258set_primary(void) 1259{ 1260 output_t *output; 1261 1262 if (no_primary) { 1263 XRRSetOutputPrimary(dpy, root, None); 1264 } else { 1265 for (output = outputs; output; output = output->next) { 1266 if (!(output->changes & changes_primary)) 1267 continue; 1268 if (output->primary) 1269 XRRSetOutputPrimary(dpy, root, output->output.xid); 1270 } 1271 } 1272} 1273 1274static Status 1275crtc_disable (crtc_t *crtc) 1276{ 1277 if (verbose) 1278 printf ("crtc %d: disable\n", crtc->crtc.index); 1279 1280 if (dryrun) 1281 return RRSetConfigSuccess; 1282 return XRRSetCrtcConfig (dpy, res, crtc->crtc.xid, CurrentTime, 1283 0, 0, None, RR_Rotate_0, NULL, 0); 1284} 1285 1286static void 1287crtc_set_transform (crtc_t *crtc, transform_t *transform) 1288{ 1289 int major, minor; 1290 1291 XRRQueryVersion (dpy, &major, &minor); 1292 if (major > 1 || (major == 1 && minor >= 3)) 1293 XRRSetCrtcTransform (dpy, crtc->crtc.xid, 1294 &transform->transform, 1295 transform->filter, 1296 transform->params, 1297 transform->nparams); 1298} 1299 1300static Status 1301crtc_revert (crtc_t *crtc) 1302{ 1303 XRRCrtcInfo *crtc_info = crtc->crtc_info; 1304 1305 if (verbose) 1306 printf ("crtc %d: revert\n", crtc->crtc.index); 1307 1308 if (dryrun) 1309 return RRSetConfigSuccess; 1310 1311 if (!equal_transform (&crtc->current_transform, &crtc->pending_transform)) 1312 crtc_set_transform (crtc, &crtc->current_transform); 1313 return XRRSetCrtcConfig (dpy, res, crtc->crtc.xid, CurrentTime, 1314 crtc_info->x, crtc_info->y, 1315 crtc_info->mode, crtc_info->rotation, 1316 crtc_info->outputs, crtc_info->noutput); 1317} 1318 1319static Status 1320crtc_apply (crtc_t *crtc) 1321{ 1322 RROutput *rr_outputs; 1323 int o; 1324 Status s; 1325 RRMode mode = None; 1326 1327 if (!crtc->changing || !crtc->mode_info) 1328 return RRSetConfigSuccess; 1329 1330 rr_outputs = calloc (crtc->noutput, sizeof (RROutput)); 1331 if (!rr_outputs) 1332 return BadAlloc; 1333 for (o = 0; o < crtc->noutput; o++) 1334 rr_outputs[o] = crtc->outputs[o]->output.xid; 1335 mode = crtc->mode_info->id; 1336 if (verbose) { 1337 printf ("crtc %d: %12s %6.1f +%d+%d", crtc->crtc.index, 1338 crtc->mode_info->name, mode_refresh (crtc->mode_info), 1339 crtc->x, crtc->y); 1340 for (o = 0; o < crtc->noutput; o++) 1341 printf (" \"%s\"", crtc->outputs[o]->output.string); 1342 printf ("\n"); 1343 } 1344 1345 if (dryrun) 1346 s = RRSetConfigSuccess; 1347 else 1348 { 1349 if (!equal_transform (&crtc->current_transform, &crtc->pending_transform)) 1350 crtc_set_transform (crtc, &crtc->pending_transform); 1351 s = XRRSetCrtcConfig (dpy, res, crtc->crtc.xid, CurrentTime, 1352 crtc->x, crtc->y, mode, crtc->rotation, 1353 rr_outputs, crtc->noutput); 1354 if (s == RRSetConfigSuccess && crtc->panning_info) { 1355 if (has_1_3) 1356 s = XRRSetPanning (dpy, res, crtc->crtc.xid, crtc->panning_info); 1357 else 1358 fatal ("panning needs RandR 1.3\n"); 1359 } 1360 } 1361 free (rr_outputs); 1362 return s; 1363} 1364 1365static void 1366screen_revert (void) 1367{ 1368 if (verbose) 1369 printf ("screen %d: revert\n", screen); 1370 1371 if (dryrun) 1372 return; 1373 XRRSetScreenSize (dpy, root, 1374 DisplayWidth (dpy, screen), 1375 DisplayHeight (dpy, screen), 1376 DisplayWidthMM (dpy, screen), 1377 DisplayHeightMM (dpy, screen)); 1378} 1379 1380static void 1381screen_apply (void) 1382{ 1383 if (fb_width == DisplayWidth (dpy, screen) && 1384 fb_height == DisplayHeight (dpy, screen) && 1385 fb_width_mm == DisplayWidthMM (dpy, screen) && 1386 fb_height_mm == DisplayHeightMM (dpy, screen)) 1387 { 1388 return; 1389 } 1390 if (verbose) 1391 printf ("screen %d: %dx%d %dx%d mm %6.2fdpi\n", screen, 1392 fb_width, fb_height, fb_width_mm, fb_height_mm, dpi); 1393 if (dryrun) 1394 return; 1395 XRRSetScreenSize (dpy, root, fb_width, fb_height, 1396 fb_width_mm, fb_height_mm); 1397} 1398 1399static void 1400revert (void) 1401{ 1402 int c; 1403 1404 /* first disable all crtcs */ 1405 for (c = 0; c < res->ncrtc; c++) 1406 crtc_disable (&crtcs[c]); 1407 /* next reset screen size */ 1408 screen_revert (); 1409 /* now restore all crtcs */ 1410 for (c = 0; c < res->ncrtc; c++) 1411 crtc_revert (&crtcs[c]); 1412} 1413 1414/* 1415 * uh-oh, something bad happened in the middle of changing 1416 * the configuration. Revert to the previous configuration 1417 * and bail 1418 */ 1419static void 1420panic (Status s, crtc_t *crtc) 1421{ 1422 int c = crtc->crtc.index; 1423 char *message; 1424 1425 switch (s) { 1426 case RRSetConfigSuccess: message = "succeeded"; break; 1427 case BadAlloc: message = "out of memory"; break; 1428 case RRSetConfigFailed: message = "failed"; break; 1429 case RRSetConfigInvalidConfigTime: message = "invalid config time"; break; 1430 case RRSetConfigInvalidTime: message = "invalid time"; break; 1431 default: message = "unknown failure"; break; 1432 } 1433 1434 fprintf (stderr, "%s: Configure crtc %d %s\n", program_name, c, message); 1435 revert (); 1436 exit (1); 1437} 1438 1439static void 1440apply (void) 1441{ 1442 Status s; 1443 int c; 1444 1445 /* 1446 * Hold the server grabbed while messing with 1447 * the screen so that apps which notice the resize 1448 * event and ask for xinerama information from the server 1449 * receive up-to-date information 1450 */ 1451 if (grab_server) 1452 XGrabServer (dpy); 1453 1454 /* 1455 * Turn off any crtcs which are to be disabled or which are 1456 * larger than the target size 1457 */ 1458 for (c = 0; c < res->ncrtc; c++) 1459 { 1460 crtc_t *crtc = &crtcs[c]; 1461 XRRCrtcInfo *crtc_info = crtc->crtc_info; 1462 1463 /* if this crtc is already disabled, skip it */ 1464 if (crtc_info->mode == None) 1465 continue; 1466 1467 /* 1468 * If this crtc is to be left enabled, make 1469 * sure the old size fits then new screen 1470 */ 1471 if (crtc->mode_info) 1472 { 1473 XRRModeInfo *old_mode = find_mode_by_xid (crtc_info->mode); 1474 int x, y, w, h; 1475 box_t bounds; 1476 1477 if (!old_mode) 1478 panic (RRSetConfigFailed, crtc); 1479 1480 /* old position and size information */ 1481 mode_geometry (old_mode, crtc_info->rotation, 1482 &crtc->current_transform.transform, 1483 &bounds); 1484 1485 x = crtc_info->x + bounds.x1; 1486 y = crtc_info->y + bounds.y1; 1487 w = bounds.x2 - bounds.x1; 1488 h = bounds.y2 - bounds.y1; 1489 1490 /* if it fits, skip it */ 1491 if (x + w <= fb_width && y + h <= fb_height) 1492 continue; 1493 crtc->changing = True; 1494 } 1495 s = crtc_disable (crtc); 1496 if (s != RRSetConfigSuccess) 1497 panic (s, crtc); 1498 } 1499 1500 /* 1501 * Set the screen size 1502 */ 1503 screen_apply (); 1504 1505 /* 1506 * Set crtcs 1507 */ 1508 1509 for (c = 0; c < res->ncrtc; c++) 1510 { 1511 crtc_t *crtc = &crtcs[c]; 1512 1513 s = crtc_apply (crtc); 1514 if (s != RRSetConfigSuccess) 1515 panic (s, crtc); 1516 } 1517 1518 set_primary (); 1519 1520 /* 1521 * Release the server grab and let all clients 1522 * respond to the updated state 1523 */ 1524 if (grab_server) 1525 XUngrabServer (dpy); 1526} 1527 1528/* 1529 * Use current output state to complete the output list 1530 */ 1531static void 1532get_outputs (void) 1533{ 1534 int o; 1535 output_t *q; 1536 1537 for (o = 0; o < res->noutput; o++) 1538 { 1539 XRROutputInfo *output_info = XRRGetOutputInfo (dpy, res, res->outputs[o]); 1540 output_t *output; 1541 name_t output_name; 1542 if (!output_info) fatal ("could not get output 0x%x information\n", res->outputs[o]); 1543 set_name_xid (&output_name, res->outputs[o]); 1544 set_name_index (&output_name, o); 1545 set_name_string (&output_name, output_info->name); 1546 output = find_output (&output_name); 1547 if (!output) 1548 { 1549 output = add_output (); 1550 set_name_all (&output->output, &output_name); 1551 /* 1552 * When global --automatic mode is set, turn on connected but off 1553 * outputs, turn off disconnected but on outputs 1554 */ 1555 if (automatic) 1556 { 1557 switch (output_info->connection) { 1558 case RR_Connected: 1559 if (!output_info->crtc) { 1560 output->changes |= changes_automatic; 1561 output->automatic = True; 1562 } 1563 break; 1564 case RR_Disconnected: 1565 if (output_info->crtc) 1566 { 1567 output->changes |= changes_automatic; 1568 output->automatic = True; 1569 } 1570 break; 1571 } 1572 } 1573 } 1574 output->found = True; 1575 1576 /* 1577 * Automatic mode -- track connection state and enable/disable outputs 1578 * as necessary 1579 */ 1580 if (output->automatic) 1581 { 1582 switch (output_info->connection) { 1583 case RR_Connected: 1584 case RR_UnknownConnection: 1585 if ((!(output->changes & changes_mode))) 1586 { 1587 set_name_preferred (&output->mode); 1588 output->changes |= changes_mode; 1589 } 1590 break; 1591 case RR_Disconnected: 1592 if ((!(output->changes & changes_mode))) 1593 { 1594 set_name_xid (&output->mode, None); 1595 set_name_xid (&output->crtc, None); 1596 output->changes |= changes_mode; 1597 output->changes |= changes_crtc; 1598 } 1599 break; 1600 } 1601 } 1602 1603 set_output_info (output, res->outputs[o], output_info); 1604 } 1605 for (q = outputs; q; q = q->next) 1606 { 1607 if (!q->found) 1608 { 1609 fprintf(stderr, "warning: output %s not found; ignoring\n", 1610 q->output.string); 1611 } 1612 } 1613} 1614 1615static void 1616mark_changing_crtcs (void) 1617{ 1618 int c; 1619 1620 for (c = 0; c < num_crtcs; c++) 1621 { 1622 crtc_t *crtc = &crtcs[c]; 1623 int o; 1624 output_t *output; 1625 1626 /* walk old output list (to catch disables) */ 1627 for (o = 0; o < crtc->crtc_info->noutput; o++) 1628 { 1629 output = find_output_by_xid (crtc->crtc_info->outputs[o]); 1630 if (!output) fatal ("cannot find output 0x%x\n", 1631 crtc->crtc_info->outputs[o]); 1632 if (output->changes) 1633 crtc->changing = True; 1634 } 1635 /* walk new output list */ 1636 for (o = 0; o < crtc->noutput; o++) 1637 { 1638 output = crtc->outputs[o]; 1639 if (output->changes) 1640 crtc->changing = True; 1641 } 1642 } 1643} 1644 1645/* 1646 * Test whether 'crtc' can be used for 'output' 1647 */ 1648static Bool 1649check_crtc_for_output (crtc_t *crtc, output_t *output) 1650{ 1651 int c; 1652 int l; 1653 output_t *other; 1654 1655 for (c = 0; c < output->output_info->ncrtc; c++) 1656 if (output->output_info->crtcs[c] == crtc->crtc.xid) 1657 break; 1658 if (c == output->output_info->ncrtc) 1659 return False; 1660 for (other = outputs; other; other = other->next) 1661 { 1662 if (other == output) 1663 continue; 1664 1665 if (other->mode_info == NULL) 1666 continue; 1667 1668 if (other->crtc_info != crtc) 1669 continue; 1670 1671 /* see if the output connected to the crtc can clone to this output */ 1672 for (l = 0; l < output->output_info->nclone; l++) 1673 if (output->output_info->clones[l] == other->output.xid) 1674 break; 1675 /* not on the list, can't clone */ 1676 if (l == output->output_info->nclone) 1677 return False; 1678 } 1679 1680 if (crtc->noutput) 1681 { 1682 /* make sure the state matches */ 1683 if (crtc->mode_info != output->mode_info) 1684 return False; 1685 if (crtc->x != output->x) 1686 return False; 1687 if (crtc->y != output->y) 1688 return False; 1689 if (crtc->rotation != output->rotation) 1690 return False; 1691 if (!equal_transform (&crtc->current_transform, &output->transform)) 1692 return False; 1693 } 1694 else if (crtc->crtc_info->noutput) 1695 { 1696 /* make sure the state matches the already used state */ 1697 XRRModeInfo *mode = find_mode_by_xid (crtc->crtc_info->mode); 1698 1699 if (mode != output->mode_info) 1700 return False; 1701 if (crtc->crtc_info->x != output->x) 1702 return False; 1703 if (crtc->crtc_info->y != output->y) 1704 return False; 1705 if (crtc->crtc_info->rotation != output->rotation) 1706 return False; 1707 } 1708 return True; 1709} 1710 1711static crtc_t * 1712find_crtc_for_output (output_t *output) 1713{ 1714 int c; 1715 1716 for (c = 0; c < output->output_info->ncrtc; c++) 1717 { 1718 crtc_t *crtc; 1719 1720 crtc = find_crtc_by_xid (output->output_info->crtcs[c]); 1721 if (!crtc) fatal ("cannot find crtc 0x%x\n", output->output_info->crtcs[c]); 1722 1723 if (check_crtc_for_output (crtc, output)) 1724 return crtc; 1725 } 1726 return NULL; 1727} 1728 1729static void 1730set_positions (void) 1731{ 1732 output_t *output; 1733 Bool keep_going; 1734 Bool any_set; 1735 int min_x, min_y; 1736 1737 for (;;) 1738 { 1739 any_set = False; 1740 keep_going = False; 1741 for (output = outputs; output; output = output->next) 1742 { 1743 output_t *relation; 1744 name_t relation_name; 1745 1746 if (!(output->changes & changes_relation)) continue; 1747 1748 if (output->mode_info == NULL) continue; 1749 1750 init_name (&relation_name); 1751 set_name_string (&relation_name, output->relative_to); 1752 relation = find_output (&relation_name); 1753 if (!relation) fatal ("cannot find output \"%s\"\n", output->relative_to); 1754 1755 if (relation->mode_info == NULL) 1756 { 1757 output->x = 0; 1758 output->y = 0; 1759 output->changes |= changes_position; 1760 any_set = True; 1761 continue; 1762 } 1763 /* 1764 * Make sure the dependent object has been set in place 1765 */ 1766 if ((relation->changes & changes_relation) && 1767 !(relation->changes & changes_position)) 1768 { 1769 keep_going = True; 1770 continue; 1771 } 1772 1773 switch (output->relation) { 1774 case left_of: 1775 output->y = relation->y; 1776 output->x = relation->x - mode_width (output->mode_info, output->rotation); 1777 break; 1778 case right_of: 1779 output->y = relation->y; 1780 output->x = relation->x + mode_width (relation->mode_info, relation->rotation); 1781 break; 1782 case above: 1783 output->x = relation->x; 1784 output->y = relation->y - mode_height (output->mode_info, output->rotation); 1785 break; 1786 case below: 1787 output->x = relation->x; 1788 output->y = relation->y + mode_height (relation->mode_info, relation->rotation); 1789 break; 1790 case same_as: 1791 output->x = relation->x; 1792 output->y = relation->y; 1793 } 1794 output->changes |= changes_position; 1795 any_set = True; 1796 } 1797 if (!keep_going) 1798 break; 1799 if (!any_set) 1800 fatal ("loop in relative position specifications\n"); 1801 } 1802 1803 /* 1804 * Now normalize positions so the upper left corner of all outputs is at 0,0 1805 */ 1806 min_x = 32768; 1807 min_y = 32768; 1808 for (output = outputs; output; output = output->next) 1809 { 1810 if (output->mode_info == NULL) continue; 1811 1812 if (output->x < min_x) min_x = output->x; 1813 if (output->y < min_y) min_y = output->y; 1814 } 1815 if (min_x || min_y) 1816 { 1817 /* move all outputs */ 1818 for (output = outputs; output; output = output->next) 1819 { 1820 if (output->mode_info == NULL) continue; 1821 1822 output->x -= min_x; 1823 output->y -= min_y; 1824 output->changes |= changes_position; 1825 } 1826 } 1827} 1828 1829static void 1830set_screen_size (void) 1831{ 1832 output_t *output; 1833 Bool fb_specified = fb_width != 0 && fb_height != 0; 1834 1835 for (output = outputs; output; output = output->next) 1836 { 1837 XRRModeInfo *mode_info = output->mode_info; 1838 int x, y, w, h; 1839 box_t bounds; 1840 1841 if (!mode_info) continue; 1842 1843 mode_geometry (mode_info, output->rotation, 1844 &output->transform.transform, 1845 &bounds); 1846 x = output->x + bounds.x1; 1847 y = output->y + bounds.y1; 1848 w = bounds.x2 - bounds.x1; 1849 h = bounds.y2 - bounds.y1; 1850 /* make sure output fits in specified size */ 1851 if (fb_specified) 1852 { 1853 if (x + w > fb_width || y + h > fb_height) 1854 warning ("specified screen %dx%d not large enough for output %s (%dx%d+%d+%d)\n", 1855 fb_width, fb_height, output->output.string, w, h, x, y); 1856 } 1857 /* fit fb to output */ 1858 else 1859 { 1860 XRRPanning *pan; 1861 if (x + w > fb_width) 1862 fb_width = x + w; 1863 if (y + h > fb_height) 1864 fb_height = y + h; 1865 if (output->changes & changes_panning) 1866 pan = &output->panning; 1867 else 1868 pan = output->crtc_info ? output->crtc_info->panning_info : NULL; 1869 if (pan && pan->left + pan->width > fb_width) 1870 fb_width = pan->left + pan->width; 1871 if (pan && pan->top + pan->height > fb_height) 1872 fb_height = pan->top + pan->height; 1873 } 1874 } 1875 1876 if (fb_width > maxWidth || fb_height > maxHeight) 1877 fatal ("screen cannot be larger than %dx%d (desired size %dx%d)\n", 1878 maxWidth, maxHeight, fb_width, fb_height); 1879 if (fb_specified) 1880 { 1881 if (fb_width < minWidth || fb_height < minHeight) 1882 fatal ("screen must be at least %dx%d\n", minWidth, minHeight); 1883 } 1884 else 1885 { 1886 if (fb_width < minWidth) fb_width = minWidth; 1887 if (fb_height < minHeight) fb_height = minHeight; 1888 } 1889} 1890 1891#endif 1892 1893static void 1894disable_outputs (output_t *outputs) 1895{ 1896 while (outputs) 1897 { 1898 outputs->crtc_info = NULL; 1899 outputs = outputs->next; 1900 } 1901} 1902 1903/* 1904 * find the best mapping from output to crtc available 1905 */ 1906static int 1907pick_crtcs_score (output_t *outputs) 1908{ 1909 output_t *output; 1910 int best_score; 1911 int my_score; 1912 int score; 1913 crtc_t *best_crtc; 1914 int c; 1915 1916 if (!outputs) 1917 return 0; 1918 1919 output = outputs; 1920 outputs = outputs->next; 1921 /* 1922 * Score with this output disabled 1923 */ 1924 output->crtc_info = NULL; 1925 best_score = pick_crtcs_score (outputs); 1926 if (output->mode_info == NULL) 1927 return best_score; 1928 1929 best_crtc = NULL; 1930 /* 1931 * Now score with this output any valid crtc 1932 */ 1933 for (c = 0; c < output->output_info->ncrtc; c++) 1934 { 1935 crtc_t *crtc; 1936 1937 crtc = find_crtc_by_xid (output->output_info->crtcs[c]); 1938 if (!crtc) 1939 fatal ("cannot find crtc 0x%x\n", output->output_info->crtcs[c]); 1940 1941 /* reset crtc allocation for following outputs */ 1942 disable_outputs (outputs); 1943 if (!check_crtc_for_output (crtc, output)) 1944 continue; 1945 1946 my_score = 1000; 1947 /* slight preference for existing connections */ 1948 if (crtc == output->current_crtc_info) 1949 my_score++; 1950 1951 output->crtc_info = crtc; 1952 score = my_score + pick_crtcs_score (outputs); 1953 if (score > best_score) 1954 { 1955 best_crtc = crtc; 1956 best_score = score; 1957 } 1958 } 1959 if (output->crtc_info != best_crtc) 1960 output->crtc_info = best_crtc; 1961 /* 1962 * Reset other outputs based on this one using the best crtc 1963 */ 1964 (void) pick_crtcs_score (outputs); 1965 1966 return best_score; 1967} 1968 1969/* 1970 * Pick crtcs for any changing outputs that don't have one 1971 */ 1972static void 1973pick_crtcs (void) 1974{ 1975 output_t *output; 1976 1977 /* 1978 * First try to match up newly enabled outputs with spare crtcs 1979 */ 1980 for (output = outputs; output; output = output->next) 1981 { 1982 if (output->changes && output->mode_info) 1983 { 1984 if (output->crtc_info) { 1985 if (output->crtc_info->crtc_info->noutput > 0 && 1986 (output->crtc_info->crtc_info->noutput > 1 || 1987 output != find_output_by_xid (output->crtc_info->crtc_info->outputs[0]))) 1988 break; 1989 } else { 1990 output->crtc_info = find_crtc_for_output (output); 1991 if (!output->crtc_info) 1992 break; 1993 } 1994 } 1995 } 1996 /* 1997 * Everyone is happy 1998 */ 1999 if (!output) 2000 return; 2001 /* 2002 * When the simple way fails, see if there is a way 2003 * to swap crtcs around and make things work 2004 */ 2005 for (output = outputs; output; output = output->next) 2006 output->current_crtc_info = output->crtc_info; 2007 pick_crtcs_score (outputs); 2008 for (output = outputs; output; output = output->next) 2009 { 2010 if (output->mode_info && !output->crtc_info) 2011 fatal ("cannot find crtc for output %s\n", output->output.string); 2012 if (!output->changes && output->crtc_info != output->current_crtc_info) 2013 output->changes |= changes_crtc; 2014 } 2015} 2016 2017static int 2018check_strtol(char *s) 2019{ 2020 char *endptr; 2021 int result = strtol(s, &endptr, 10); 2022 if (s == endptr) 2023 usage(); 2024 return result; 2025} 2026 2027static int 2028check_strtod(char *s) 2029{ 2030 char *endptr; 2031 double result = strtod(s, &endptr); 2032 if (s == endptr) 2033 usage(); 2034 return result; 2035} 2036 2037int 2038main (int argc, char **argv) 2039{ 2040 XRRScreenSize *sizes; 2041 XRRScreenConfiguration *sc; 2042 int nsize; 2043 int nrate; 2044 short *rates; 2045 Status status = RRSetConfigFailed; 2046 int rot = -1; 2047 int query = 0; 2048 Rotation rotation, current_rotation, rotations; 2049 XEvent event; 2050 XRRScreenChangeNotifyEvent *sce; 2051 char *display_name = NULL; 2052 int i, j; 2053 SizeID current_size; 2054 short current_rate; 2055 double rate = -1; 2056 int size = -1; 2057 int dirind = 0; 2058 Bool setit = False; 2059 Bool version = False; 2060 int event_base, error_base; 2061 int reflection = 0; 2062 int width = 0, height = 0; 2063 Bool have_pixel_size = False; 2064 int ret = 0; 2065#if HAS_RANDR_1_2 2066 output_t *output = NULL; 2067 policy_t policy = clone; 2068 Bool setit_1_2 = False; 2069 Bool query_1_2 = False; 2070 Bool modeit = False; 2071 Bool propit = False; 2072 Bool query_1 = False; 2073 int major, minor; 2074 Bool current = False; 2075#endif 2076 2077 program_name = argv[0]; 2078 if (argc == 1) query = True; 2079 for (i = 1; i < argc; i++) { 2080 if (!strcmp ("-display", argv[i]) || !strcmp ("-d", argv[i])) { 2081 if (++i>=argc) usage (); 2082 display_name = argv[i]; 2083 continue; 2084 } 2085 if (!strcmp("-help", argv[i])) { 2086 usage(); 2087 continue; 2088 } 2089 if (!strcmp ("--verbose", argv[i])) { 2090 verbose = True; 2091 continue; 2092 } 2093 if (!strcmp ("--dryrun", argv[i])) { 2094 dryrun = True; 2095 verbose = True; 2096 continue; 2097 } 2098 if (!strcmp ("--nograb", argv[i])) { 2099 grab_server = False; 2100 continue; 2101 } 2102 if (!strcmp("--current", argv[i])) { 2103 current = True; 2104 /* if --current was the only arg, then query */ 2105 if (argc == 2) query = True; 2106 continue; 2107 } 2108 2109 if (!strcmp ("-s", argv[i]) || !strcmp ("--size", argv[i])) { 2110 if (++i>=argc) usage (); 2111 if (sscanf (argv[i], "%dx%d", &width, &height) == 2) { 2112 have_pixel_size = True; 2113 } else { 2114 size = check_strtol(argv[i]); 2115 if (size < 0) usage(); 2116 } 2117 setit = True; 2118 continue; 2119 } 2120 2121 if (!strcmp ("-r", argv[i]) || 2122 !strcmp ("--rate", argv[i]) || 2123 !strcmp ("--refresh", argv[i])) 2124 { 2125 if (++i>=argc) usage (); 2126 rate = check_strtod(argv[i]); 2127 setit = True; 2128#if HAS_RANDR_1_2 2129 if (output) 2130 { 2131 output->refresh = rate; 2132 output->changes |= changes_refresh; 2133 setit_1_2 = True; 2134 } 2135#endif 2136 continue; 2137 } 2138 2139 if (!strcmp ("-v", argv[i]) || !strcmp ("--version", argv[i])) { 2140 version = True; 2141 continue; 2142 } 2143 2144 if (!strcmp ("-x", argv[i])) { 2145 reflection |= RR_Reflect_X; 2146 setit = True; 2147 continue; 2148 } 2149 if (!strcmp ("-y", argv[i])) { 2150 reflection |= RR_Reflect_Y; 2151 setit = True; 2152 continue; 2153 } 2154 if (!strcmp ("--screen", argv[i])) { 2155 if (++i>=argc) usage (); 2156 screen = check_strtol(argv[i]); 2157 if (screen < 0) usage(); 2158 continue; 2159 } 2160 if (!strcmp ("-q", argv[i]) || !strcmp ("--query", argv[i])) { 2161 query = True; 2162 continue; 2163 } 2164 if (!strcmp ("-o", argv[i]) || !strcmp ("--orientation", argv[i])) { 2165 char *endptr; 2166 if (++i>=argc) usage (); 2167 dirind = strtol(argv[i], &endptr, 10); 2168 if (argv[i] == endptr) { 2169 for (dirind = 0; dirind < 4; dirind++) { 2170 if (strcmp (direction[dirind], argv[i]) == 0) break; 2171 } 2172 if ((dirind < 0) || (dirind > 3)) usage(); 2173 } 2174 rot = dirind; 2175 setit = True; 2176 continue; 2177 } 2178#if HAS_RANDR_1_2 2179 if (!strcmp ("--prop", argv[i]) || 2180 !strcmp ("--props", argv[i]) || 2181 !strcmp ("--madprops", argv[i]) || 2182 !strcmp ("--properties", argv[i])) 2183 { 2184 query_1_2 = True; 2185 properties = True; 2186 continue; 2187 } 2188 if (!strcmp ("--output", argv[i])) { 2189 if (++i >= argc) usage(); 2190 2191 output = find_output_by_name (argv[i]); 2192 if (!output) { 2193 output = add_output (); 2194 set_name (&output->output, argv[i], name_string|name_xid); 2195 } 2196 2197 setit_1_2 = True; 2198 continue; 2199 } 2200 if (!strcmp ("--crtc", argv[i])) { 2201 if (++i >= argc) usage(); 2202 if (!output) usage(); 2203 set_name (&output->crtc, argv[i], name_xid|name_index); 2204 output->changes |= changes_crtc; 2205 continue; 2206 } 2207 if (!strcmp ("--mode", argv[i])) { 2208 if (++i >= argc) usage(); 2209 if (!output) usage(); 2210 set_name (&output->mode, argv[i], name_string|name_xid); 2211 output->changes |= changes_mode; 2212 continue; 2213 } 2214 if (!strcmp ("--preferred", argv[i])) { 2215 if (!output) usage(); 2216 set_name_preferred (&output->mode); 2217 output->changes |= changes_mode; 2218 continue; 2219 } 2220 if (!strcmp ("--pos", argv[i])) { 2221 if (++i>=argc) usage (); 2222 if (!output) usage(); 2223 if (sscanf (argv[i], "%dx%d", 2224 &output->x, &output->y) != 2) 2225 usage (); 2226 output->changes |= changes_position; 2227 continue; 2228 } 2229 if (!strcmp ("--rotation", argv[i]) || !strcmp ("--rotate", argv[i])) { 2230 if (++i>=argc) usage (); 2231 if (!output) usage(); 2232 for (dirind = 0; dirind < 4; dirind++) { 2233 if (strcmp (direction[dirind], argv[i]) == 0) break; 2234 } 2235 if (dirind == 4) 2236 usage (); 2237 output->rotation &= ~0xf; 2238 output->rotation |= 1 << dirind; 2239 output->changes |= changes_rotation; 2240 continue; 2241 } 2242 if (!strcmp ("--reflect", argv[i]) || !strcmp ("--reflection", argv[i])) { 2243 if (++i>=argc) usage (); 2244 if (!output) usage(); 2245 for (dirind = 0; dirind < 4; dirind++) { 2246 if (strcmp (reflections[dirind], argv[i]) == 0) break; 2247 } 2248 if (dirind == 4) 2249 usage (); 2250 output->rotation &= ~(RR_Reflect_X|RR_Reflect_Y); 2251 output->rotation |= dirind * RR_Reflect_X; 2252 output->changes |= changes_reflection; 2253 continue; 2254 } 2255 if (!strcmp ("--left-of", argv[i])) { 2256 if (++i>=argc) usage (); 2257 if (!output) usage(); 2258 output->relation = left_of; 2259 output->relative_to = argv[i]; 2260 output->changes |= changes_relation; 2261 continue; 2262 } 2263 if (!strcmp ("--right-of", argv[i])) { 2264 if (++i>=argc) usage (); 2265 if (!output) usage(); 2266 output->relation = right_of; 2267 output->relative_to = argv[i]; 2268 output->changes |= changes_relation; 2269 continue; 2270 } 2271 if (!strcmp ("--above", argv[i])) { 2272 if (++i>=argc) usage (); 2273 if (!output) usage(); 2274 output->relation = above; 2275 output->relative_to = argv[i]; 2276 output->changes |= changes_relation; 2277 continue; 2278 } 2279 if (!strcmp ("--below", argv[i])) { 2280 if (++i>=argc) usage (); 2281 if (!output) usage(); 2282 output->relation = below; 2283 output->relative_to = argv[i]; 2284 output->changes |= changes_relation; 2285 continue; 2286 } 2287 if (!strcmp ("--same-as", argv[i])) { 2288 if (++i>=argc) usage (); 2289 if (!output) usage(); 2290 output->relation = same_as; 2291 output->relative_to = argv[i]; 2292 output->changes |= changes_relation; 2293 continue; 2294 } 2295 if (!strcmp ("--panning", argv[i])) { 2296 XRRPanning *pan; 2297 if (++i>=argc) usage (); 2298 if (!output) usage(); 2299 pan = &output->panning; 2300 switch (sscanf (argv[i], "%dx%d+%d+%d/%dx%d+%d+%d/%d/%d/%d/%d", 2301 &pan->width, &pan->height, &pan->left, &pan->top, 2302 &pan->track_width, &pan->track_height, 2303 &pan->track_left, &pan->track_top, 2304 &pan->border_left, &pan->border_top, 2305 &pan->border_right, &pan->border_bottom)) { 2306 case 2: 2307 pan->left = pan->top = 0; 2308 /* fall through */ 2309 case 4: 2310 pan->track_left = pan->track_top = 2311 pan->track_width = pan->track_height = 0; 2312 /* fall through */ 2313 case 8: 2314 pan->border_left = pan->border_top = 2315 pan->border_right = pan->border_bottom = 0; 2316 /* fall through */ 2317 case 12: 2318 break; 2319 default: 2320 usage (); 2321 } 2322 output->changes |= changes_panning; 2323 continue; 2324 } 2325 if (!strcmp ("--gamma", argv[i])) { 2326 if (!output) usage(); 2327 if (++i>=argc) usage (); 2328 if (sscanf(argv[i], "%f:%f:%f", &output->gamma.red, 2329 &output->gamma.green, &output->gamma.blue) != 3) 2330 usage (); 2331 output->changes |= changes_gamma; 2332 setit_1_2 = True; 2333 continue; 2334 } 2335 if (!strcmp ("--primary", argv[i])) { 2336 if (!output) usage(); 2337 output->changes |= changes_primary; 2338 output->primary = True; 2339 setit_1_2 = True; 2340 continue; 2341 } 2342 if (!strcmp ("--noprimary", argv[i])) { 2343 no_primary = True; 2344 setit_1_2 = True; 2345 continue; 2346 } 2347 if (!strcmp ("--set", argv[i])) { 2348 output_prop_t *prop; 2349 if (!output) usage(); 2350 prop = malloc (sizeof (output_prop_t)); 2351 prop->next = output->props; 2352 output->props = prop; 2353 if (++i>=argc) usage (); 2354 prop->name = argv[i]; 2355 if (++i>=argc) usage (); 2356 prop->value = argv[i]; 2357 propit = True; 2358 output->changes |= changes_property; 2359 setit_1_2 = True; 2360 continue; 2361 } 2362 if (!strcmp ("--scale", argv[i])) 2363 { 2364 double sx, sy; 2365 if (++i>=argc) usage(); 2366 if (sscanf (argv[i], "%lfx%lf", &sx, &sy) != 2) 2367 usage (); 2368 init_transform (&output->transform); 2369 output->transform.transform.matrix[0][0] = XDoubleToFixed (sx); 2370 output->transform.transform.matrix[1][1] = XDoubleToFixed (sy); 2371 output->transform.transform.matrix[2][2] = XDoubleToFixed (1.0); 2372 if (sx != 1 || sy != 1) 2373 output->transform.filter = "bilinear"; 2374 else 2375 output->transform.filter = "nearest"; 2376 output->transform.nparams = 0; 2377 output->transform.params = NULL; 2378 output->changes |= changes_transform; 2379 continue; 2380 } 2381 if (!strcmp ("--transform", argv[i])) { 2382 double transform[3][3]; 2383 int k, l; 2384 if (++i>=argc) usage (); 2385 init_transform (&output->transform); 2386 if (strcmp (argv[i], "none") != 0) 2387 { 2388 if (sscanf(argv[i], "%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf", 2389 &transform[0][0],&transform[0][1],&transform[0][2], 2390 &transform[1][0],&transform[1][1],&transform[1][2], 2391 &transform[2][0],&transform[2][1],&transform[2][2]) 2392 != 9) 2393 usage (); 2394 init_transform (&output->transform); 2395 for (k = 0; k < 3; k++) 2396 for (l = 0; l < 3; l++) { 2397 output->transform.transform.matrix[k][l] = XDoubleToFixed (transform[k][l]); 2398 } 2399 output->transform.filter = "bilinear"; 2400 output->transform.nparams = 0; 2401 output->transform.params = NULL; 2402 } 2403 output->changes |= changes_transform; 2404 continue; 2405 } 2406 if (!strcmp ("--off", argv[i])) { 2407 if (!output) usage(); 2408 set_name_xid (&output->mode, None); 2409 set_name_xid (&output->crtc, None); 2410 output->changes |= changes_mode; 2411 continue; 2412 } 2413 if (!strcmp ("--fb", argv[i])) { 2414 if (++i>=argc) usage (); 2415 if (sscanf (argv[i], "%dx%d", 2416 &fb_width, &fb_height) != 2) 2417 usage (); 2418 setit_1_2 = True; 2419 continue; 2420 } 2421 if (!strcmp ("--fbmm", argv[i])) { 2422 if (++i>=argc) usage (); 2423 if (sscanf (argv[i], "%dx%d", 2424 &fb_width_mm, &fb_height_mm) != 2) 2425 usage (); 2426 setit_1_2 = True; 2427 continue; 2428 } 2429 if (!strcmp ("--dpi", argv[i])) { 2430 char *strtod_error; 2431 if (++i>=argc) usage (); 2432 dpi = strtod(argv[i], &strtod_error); 2433 if (argv[i] == strtod_error) 2434 { 2435 dpi = 0.0; 2436 dpi_output = argv[i]; 2437 } 2438 setit_1_2 = True; 2439 continue; 2440 } 2441 if (!strcmp ("--clone", argv[i])) { 2442 policy = clone; 2443 setit_1_2 = True; 2444 continue; 2445 } 2446 if (!strcmp ("--extend", argv[i])) { 2447 policy = extend; 2448 setit_1_2 = True; 2449 continue; 2450 } 2451 if (!strcmp ("--auto", argv[i])) { 2452 if (output) 2453 { 2454 output->automatic = True; 2455 output->changes |= changes_automatic; 2456 } 2457 else 2458 automatic = True; 2459 setit_1_2 = True; 2460 continue; 2461 } 2462 if (!strcmp ("--q12", argv[i])) 2463 { 2464 query_1_2 = True; 2465 continue; 2466 } 2467 if (!strcmp ("--q1", argv[i])) 2468 { 2469 query_1 = True; 2470 continue; 2471 } 2472 if (!strcmp ("--newmode", argv[i])) 2473 { 2474 umode_t *m = malloc (sizeof (umode_t)); 2475 double clock; 2476 2477 ++i; 2478 if (i + 9 >= argc) usage (); 2479 m->mode.name = argv[i]; 2480 m->mode.nameLength = strlen (argv[i]); 2481 i++; 2482 clock = check_strtod(argv[i++]); 2483 m->mode.dotClock = clock * 1e6; 2484 2485 m->mode.width = check_strtol(argv[i++]); 2486 m->mode.hSyncStart = check_strtol(argv[i++]); 2487 m->mode.hSyncEnd = check_strtol(argv[i++]); 2488 m->mode.hTotal = check_strtol(argv[i++]); 2489 m->mode.height = check_strtol(argv[i++]); 2490 m->mode.vSyncStart = check_strtol(argv[i++]); 2491 m->mode.vSyncEnd = check_strtol(argv[i++]); 2492 m->mode.vTotal = check_strtol(argv[i++]); 2493 m->mode.modeFlags = 0; 2494 while (i < argc) { 2495 int f; 2496 2497 for (f = 0; mode_flags[f].string; f++) 2498 if (!strcasecmp (mode_flags[f].string, argv[i])) 2499 break; 2500 2501 if (!mode_flags[f].string) 2502 break; 2503 m->mode.modeFlags |= mode_flags[f].flag; 2504 i++; 2505 } 2506 m->next = umodes; 2507 m->action = umode_create; 2508 umodes = m; 2509 modeit = True; 2510 continue; 2511 } 2512 if (!strcmp ("--rmmode", argv[i])) 2513 { 2514 umode_t *m = malloc (sizeof (umode_t)); 2515 2516 if (++i>=argc) usage (); 2517 set_name (&m->name, argv[i], name_string|name_xid); 2518 m->action = umode_destroy; 2519 m->next = umodes; 2520 umodes = m; 2521 modeit = True; 2522 continue; 2523 } 2524 if (!strcmp ("--addmode", argv[i])) 2525 { 2526 umode_t *m = malloc (sizeof (umode_t)); 2527 2528 if (++i>=argc) usage (); 2529 set_name (&m->output, argv[i], name_string|name_xid); 2530 if (++i>=argc) usage(); 2531 set_name (&m->name, argv[i], name_string|name_xid); 2532 m->action = umode_add; 2533 m->next = umodes; 2534 umodes = m; 2535 modeit = True; 2536 continue; 2537 } 2538 if (!strcmp ("--delmode", argv[i])) 2539 { 2540 umode_t *m = malloc (sizeof (umode_t)); 2541 2542 if (++i>=argc) usage (); 2543 set_name (&m->output, argv[i], name_string|name_xid); 2544 if (++i>=argc) usage(); 2545 set_name (&m->name, argv[i], name_string|name_xid); 2546 m->action = umode_delete; 2547 m->next = umodes; 2548 umodes = m; 2549 modeit = True; 2550 continue; 2551 } 2552#endif 2553 usage(); 2554 } 2555 if (verbose) 2556 { 2557 query = True; 2558 if (setit && !setit_1_2) 2559 query_1 = True; 2560 } 2561 if (version) 2562 printf("xrandr program version " VERSION "\n"); 2563 2564 dpy = XOpenDisplay (display_name); 2565 2566 if (dpy == NULL) { 2567 fprintf (stderr, "Can't open display %s\n", XDisplayName(display_name)); 2568 exit (1); 2569 } 2570 if (screen < 0) 2571 screen = DefaultScreen (dpy); 2572 if (screen >= ScreenCount (dpy)) { 2573 fprintf (stderr, "Invalid screen number %d (display has %d)\n", 2574 screen, ScreenCount (dpy)); 2575 exit (1); 2576 } 2577 2578 root = RootWindow (dpy, screen); 2579 2580#if HAS_RANDR_1_2 2581 if (!XRRQueryVersion (dpy, &major, &minor)) 2582 { 2583 fprintf (stderr, "RandR extension missing\n"); 2584 exit (1); 2585 } 2586 if (major > 1 || (major == 1 && minor >= 2)) 2587 has_1_2 = True; 2588 if (major > 1 || (major == 1 && minor >= 3)) 2589 has_1_3 = True; 2590 2591 if (has_1_2 && modeit) 2592 { 2593 umode_t *m; 2594 2595 get_screen (current); 2596 get_crtcs(); 2597 get_outputs(); 2598 2599 for (m = umodes; m; m = m->next) 2600 { 2601 XRRModeInfo *e; 2602 output_t *o; 2603 2604 switch (m->action) { 2605 case umode_create: 2606 XRRCreateMode (dpy, root, &m->mode); 2607 break; 2608 case umode_destroy: 2609 e = find_mode (&m->name, 0); 2610 if (!e) 2611 fatal ("cannot find mode \"%s\"\n", m->name.string); 2612 XRRDestroyMode (dpy, e->id); 2613 break; 2614 case umode_add: 2615 o = find_output (&m->output); 2616 if (!o) 2617 fatal ("cannot find output \"%s\"\n", m->output.string); 2618 e = find_mode (&m->name, 0); 2619 if (!e) 2620 fatal ("cannot find mode \"%s\"\n", m->name.string); 2621 XRRAddOutputMode (dpy, o->output.xid, e->id); 2622 break; 2623 case umode_delete: 2624 o = find_output (&m->output); 2625 if (!o) 2626 fatal ("cannot find output \"%s\"\n", m->output.string); 2627 e = find_mode (&m->name, 0); 2628 if (!e) 2629 fatal ("cannot find mode \"%s\"\n", m->name.string); 2630 XRRDeleteOutputMode (dpy, o->output.xid, e->id); 2631 break; 2632 } 2633 } 2634 if (!setit_1_2) 2635 { 2636 XSync (dpy, False); 2637 exit (0); 2638 } 2639 } 2640 if (has_1_2 && propit) 2641 { 2642 2643 get_screen (current); 2644 get_crtcs(); 2645 get_outputs(); 2646 2647 for (output = outputs; output; output = output->next) 2648 { 2649 output_prop_t *prop; 2650 2651 for (prop = output->props; prop; prop = prop->next) 2652 { 2653 Atom name = XInternAtom (dpy, prop->name, False); 2654 Atom type; 2655 int format; 2656 unsigned char *data; 2657 int nelements; 2658 int int_value; 2659 unsigned long ulong_value; 2660 unsigned char *prop_data; 2661 int actual_format; 2662 unsigned long nitems, bytes_after; 2663 Atom actual_type; 2664 XRRPropertyInfo *propinfo; 2665 2666 type = AnyPropertyType; 2667 format=0; 2668 2669 if (XRRGetOutputProperty (dpy, output->output.xid, name, 2670 0, 100, False, False, 2671 AnyPropertyType, 2672 &actual_type, &actual_format, 2673 &nitems, &bytes_after, &prop_data) == Success && 2674 2675 (propinfo = XRRQueryOutputProperty(dpy, output->output.xid, 2676 name))) 2677 { 2678 type = actual_type; 2679 format = actual_format; 2680 } 2681 2682 if ((type == XA_INTEGER || type == AnyPropertyType) && 2683 (sscanf (prop->value, "%d", &int_value) == 1 || 2684 sscanf (prop->value, "0x%x", &int_value) == 1)) 2685 { 2686 type = XA_INTEGER; 2687 ulong_value = int_value; 2688 data = (unsigned char *) &ulong_value; 2689 nelements = 1; 2690 format = 32; 2691 } 2692 else if ((type == XA_ATOM)) 2693 { 2694 ulong_value = XInternAtom (dpy, prop->value, False); 2695 data = (unsigned char *) &ulong_value; 2696 nelements = 1; 2697 format = 32; 2698 } 2699 else if ((type == XA_STRING || type == AnyPropertyType)) 2700 { 2701 type = XA_STRING; 2702 data = (unsigned char *) prop->value; 2703 nelements = strlen (prop->value); 2704 format = 8; 2705 } 2706 else 2707 continue; 2708 XRRChangeOutputProperty (dpy, output->output.xid, 2709 name, type, format, PropModeReplace, 2710 data, nelements); 2711 } 2712 } 2713 if (!setit_1_2) 2714 { 2715 XSync (dpy, False); 2716 exit (0); 2717 } 2718 } 2719 if (setit_1_2) 2720 { 2721 get_screen (current); 2722 get_crtcs (); 2723 get_outputs (); 2724 set_positions (); 2725 set_screen_size (); 2726 2727 pick_crtcs (); 2728 2729 /* 2730 * Assign outputs to crtcs 2731 */ 2732 set_crtcs (); 2733 2734 /* 2735 * Mark changing crtcs 2736 */ 2737 mark_changing_crtcs (); 2738 2739 /* 2740 * If an output was specified to track dpi, use it 2741 */ 2742 if (dpi_output) 2743 { 2744 output_t *output = find_output_by_name (dpi_output); 2745 XRROutputInfo *output_info; 2746 XRRModeInfo *mode_info; 2747 if (!output) 2748 fatal ("Cannot find output %s\n", dpi_output); 2749 output_info = output->output_info; 2750 mode_info = output->mode_info; 2751 if (output_info && mode_info && output_info->mm_height) 2752 { 2753 /* 2754 * When this output covers the whole screen, just use 2755 * the known physical size 2756 */ 2757 if (fb_width == mode_info->width && 2758 fb_height == mode_info->height) 2759 { 2760 fb_width_mm = output_info->mm_width; 2761 fb_height_mm = output_info->mm_height; 2762 } 2763 else 2764 { 2765 dpi = (25.4 * mode_info->height) / output_info->mm_height; 2766 } 2767 } 2768 } 2769 2770 /* 2771 * Compute physical screen size 2772 */ 2773 if (fb_width_mm == 0 || fb_height_mm == 0) 2774 { 2775 if (fb_width != DisplayWidth (dpy, screen) || 2776 fb_height != DisplayHeight (dpy, screen) || dpi != 0.0) 2777 { 2778 if (dpi <= 0) 2779 dpi = (25.4 * DisplayHeight (dpy, screen)) / DisplayHeightMM(dpy, screen); 2780 2781 fb_width_mm = (25.4 * fb_width) / dpi; 2782 fb_height_mm = (25.4 * fb_height) / dpi; 2783 } 2784 else 2785 { 2786 fb_width_mm = DisplayWidthMM (dpy, screen); 2787 fb_height_mm = DisplayHeightMM (dpy, screen); 2788 } 2789 } 2790 2791 /* 2792 * Set panning 2793 */ 2794 set_panning (); 2795 2796 /* 2797 * Set gamma on crtc's that belong to the outputs. 2798 */ 2799 set_gamma (); 2800 2801 /* 2802 * Now apply all of the changes 2803 */ 2804 apply (); 2805 2806 XSync (dpy, False); 2807 exit (0); 2808 } 2809 if (query_1_2 || (query && has_1_2 && !query_1)) 2810 { 2811 output_t *output; 2812 int m; 2813 2814#define ModeShown 0x80000000 2815 2816 get_screen (current); 2817 get_crtcs (); 2818 get_outputs (); 2819 2820 printf ("Screen %d: minimum %d x %d, current %d x %d, maximum %d x %d\n", 2821 screen, minWidth, minHeight, 2822 DisplayWidth (dpy, screen), DisplayHeight(dpy, screen), 2823 maxWidth, maxHeight); 2824 2825 for (output = outputs; output; output = output->next) 2826 { 2827 XRROutputInfo *output_info = output->output_info; 2828 crtc_t *crtc = output->crtc_info; 2829 XRRCrtcInfo *crtc_info = crtc ? crtc->crtc_info : NULL; 2830 XRRModeInfo *mode = output->mode_info; 2831 Atom *props; 2832 int j, k, nprop; 2833 Bool *mode_shown; 2834 Rotation rotations = output_rotations (output); 2835 2836 printf ("%s %s", output_info->name, connection[output_info->connection]); 2837 if (mode) 2838 { 2839 if (crtc_info) { 2840 printf (" %dx%d+%d+%d", 2841 crtc_info->width, crtc_info->height, 2842 crtc_info->x, crtc_info->y); 2843 } else { 2844 printf (" %dx%d+%d+%d", 2845 mode->width, mode->height, output->x, output->y); 2846 } 2847 if (verbose) 2848 printf (" (0x%x)", (int)mode->id); 2849 if (output->rotation != RR_Rotate_0 || verbose) 2850 { 2851 printf (" %s", 2852 rotation_name (output->rotation)); 2853 if (output->rotation & (RR_Reflect_X|RR_Reflect_Y)) 2854 printf (" %s", reflection_name (output->rotation)); 2855 } 2856 } 2857 if (rotations != RR_Rotate_0 || verbose) 2858 { 2859 Bool first = True; 2860 printf (" ("); 2861 for (i = 0; i < 4; i ++) { 2862 if ((rotations >> i) & 1) { 2863 if (!first) printf (" "); first = False; 2864 printf("%s", direction[i]); 2865 first = False; 2866 } 2867 } 2868 if (rotations & RR_Reflect_X) 2869 { 2870 if (!first) printf (" "); first = False; 2871 printf ("x axis"); 2872 } 2873 if (rotations & RR_Reflect_Y) 2874 { 2875 if (!first) printf (" "); first = False; 2876 printf ("y axis"); 2877 } 2878 printf (")"); 2879 } 2880 2881 if (mode) 2882 { 2883 printf (" %dmm x %dmm", 2884 (int)output_info->mm_width, (int)output_info->mm_height); 2885 } 2886 2887 if (crtc && crtc->panning_info && crtc->panning_info->width > 0) 2888 { 2889 XRRPanning *pan = crtc->panning_info; 2890 printf (" panning %dx%d+%d+%d", 2891 pan->width, pan->height, pan->left, pan->top); 2892 if ((pan->track_width != 0 && 2893 (pan->track_left != pan->left || 2894 pan->track_width != pan->width || 2895 pan->border_left != 0 || 2896 pan->border_right != 0)) || 2897 (pan->track_height != 0 && 2898 (pan->track_top != pan->top || 2899 pan->track_height != pan->height || 2900 pan->border_top != 0 || 2901 pan->border_bottom != 0))) 2902 printf (" tracking %dx%d+%d+%d border %d/%d/%d/%d", 2903 pan->track_width, pan->track_height, 2904 pan->track_left, pan->track_top, 2905 pan->border_left, pan->border_top, 2906 pan->border_right, pan->border_bottom); 2907 } 2908 printf ("\n"); 2909 2910 if (verbose) 2911 { 2912 printf ("\tIdentifier: 0x%x\n", (int)output->output.xid); 2913 printf ("\tTimestamp: %d\n", (int)output_info->timestamp); 2914 printf ("\tSubpixel: %s\n", order[output_info->subpixel_order]); 2915 printf ("\tClones: "); 2916 for (j = 0; j < output_info->nclone; j++) 2917 { 2918 output_t *clone = find_output_by_xid (output_info->clones[j]); 2919 2920 if (clone) printf (" %s", clone->output.string); 2921 } 2922 printf ("\n"); 2923 if (output->crtc_info) 2924 printf ("\tCRTC: %d\n", output->crtc_info->crtc.index); 2925 printf ("\tCRTCs: "); 2926 for (j = 0; j < output_info->ncrtc; j++) 2927 { 2928 crtc_t *crtc = find_crtc_by_xid (output_info->crtcs[j]); 2929 if (crtc) 2930 printf (" %d", crtc->crtc.index); 2931 } 2932 printf ("\n"); 2933 if (output->crtc_info && output->crtc_info->panning_info) { 2934 XRRPanning *pan = output->crtc_info->panning_info; 2935 printf ("\tPanning: %dx%d+%d+%d\n", 2936 pan->width, pan->height, pan->left, pan->top); 2937 printf ("\tTracking: %dx%d+%d+%d\n", 2938 pan->track_width, pan->track_height, 2939 pan->track_left, pan->track_top); 2940 printf ("\tBorder: %d/%d/%d/%d\n", 2941 pan->border_left, pan->border_top, 2942 pan->border_right, pan->border_bottom); 2943 } 2944 } 2945 if (verbose) 2946 { 2947 int x, y; 2948 2949 printf ("\tTransform: "); 2950 for (y = 0; y < 3; y++) 2951 { 2952 for (x = 0; x < 3; x++) 2953 printf (" %f", XFixedToDouble (output->transform.transform.matrix[y][x])); 2954 if (y < 2) 2955 printf ("\n\t "); 2956 } 2957 if (output->transform.filter) 2958 printf ("\n\t filter: %s", output->transform.filter); 2959 printf ("\n"); 2960 } 2961 if (verbose || properties) 2962 { 2963 props = XRRListOutputProperties (dpy, output->output.xid, 2964 &nprop); 2965 for (j = 0; j < nprop; j++) { 2966 unsigned char *prop; 2967 int actual_format; 2968 unsigned long nitems, bytes_after; 2969 Atom actual_type; 2970 XRRPropertyInfo *propinfo; 2971 2972 XRRGetOutputProperty (dpy, output->output.xid, props[j], 2973 0, 100, False, False, 2974 AnyPropertyType, 2975 &actual_type, &actual_format, 2976 &nitems, &bytes_after, &prop); 2977 2978 propinfo = XRRQueryOutputProperty(dpy, output->output.xid, 2979 props[j]); 2980 2981 if (actual_type == XA_INTEGER && actual_format == 8) { 2982 int k; 2983 2984 printf("\t%s:\n", XGetAtomName (dpy, props[j])); 2985 for (k = 0; k < nitems; k++) { 2986 if (k % 16 == 0) 2987 printf ("\t\t"); 2988 printf("%02x", (unsigned char)prop[k]); 2989 if (k % 16 == 15) 2990 printf("\n"); 2991 } 2992 } else if (actual_type == XA_INTEGER && 2993 actual_format == 32) 2994 { 2995 printf("\t%s: ", XGetAtomName (dpy, props[j])); 2996 for (k = 0; k < nitems; k++) { 2997 if (k > 0) 2998 printf ("\n\t\t\t"); 2999 printf("%d (0x%08x)", 3000 (int)((INT32 *)prop)[k], (int)((INT32 *)prop)[k]); 3001 } 3002 3003 if (propinfo->range && propinfo->num_values > 0) { 3004 if (nitems > 1) 3005 printf ("\n\t\t"); 3006 printf("\trange%s: ", 3007 (propinfo->num_values == 2) ? "" : "s"); 3008 3009 for (k = 0; k < propinfo->num_values / 2; k++) 3010 printf(" (%d,%d)", (int)propinfo->values[k * 2], 3011 (int)propinfo->values[k * 2 + 1]); 3012 } 3013 3014 printf("\n"); 3015 } else if (actual_type == XA_ATOM && 3016 actual_format == 32) 3017 { 3018 printf("\t%s:", XGetAtomName (dpy, props[j])); 3019 for (k = 0; k < nitems; k++) { 3020 if (k > 0 && (k & 1) == 0) 3021 printf ("\n\t\t"); 3022 printf("\t%s", XGetAtomName (dpy, ((Atom *)prop)[k])); 3023 } 3024 3025 if (!propinfo->range && propinfo->num_values > 0) { 3026 printf("\n\t\tsupported:"); 3027 3028 for (k = 0; k < propinfo->num_values; k++) 3029 { 3030 printf(" %-12.12s", XGetAtomName (dpy, 3031 propinfo->values[k])); 3032 if (k % 4 == 3 && k < propinfo->num_values - 1) 3033 printf ("\n\t\t "); 3034 } 3035 } 3036 printf("\n"); 3037 } else if (actual_format == 8) { 3038 printf ("\t%s: %s%s\n", XGetAtomName (dpy, props[j]), 3039 prop, bytes_after ? "..." : ""); 3040 } else { 3041 char *type = actual_type ? XGetAtomName (dpy, actual_type) : "none"; 3042 printf ("\t%s: %s(%d) (format %d items %d) ????\n", 3043 XGetAtomName (dpy, props[j]), 3044 type, (int)actual_type, actual_format, (int)nitems); 3045 } 3046 3047 free(propinfo); 3048 } 3049 } 3050 3051 if (verbose) 3052 { 3053 for (j = 0; j < output_info->nmode; j++) 3054 { 3055 XRRModeInfo *mode = find_mode_by_xid (output_info->modes[j]); 3056 int f; 3057 3058 printf (" %s (0x%x) %6.1fMHz", 3059 mode->name, (int)mode->id, 3060 (double)mode->dotClock / 1000000.0); 3061 for (f = 0; mode_flags[f].flag; f++) 3062 if (mode->modeFlags & mode_flags[f].flag) 3063 printf (" %s", mode_flags[f].string); 3064 if (mode == output->mode_info) 3065 printf (" *current"); 3066 if (j < output_info->npreferred) 3067 printf (" +preferred"); 3068 printf ("\n"); 3069 printf (" h: width %4d start %4d end %4d total %4d skew %4d clock %6.1fKHz\n", 3070 mode->width, mode->hSyncStart, mode->hSyncEnd, 3071 mode->hTotal, mode->hSkew, mode_hsync (mode) / 1000); 3072 printf (" v: height %4d start %4d end %4d total %4d clock %6.1fHz\n", 3073 mode->height, mode->vSyncStart, mode->vSyncEnd, mode->vTotal, 3074 mode_refresh (mode)); 3075 mode->modeFlags |= ModeShown; 3076 } 3077 } 3078 else 3079 { 3080 mode_shown = calloc (output_info->nmode, sizeof (Bool)); 3081 if (!mode_shown) fatal ("out of memory\n"); 3082 for (j = 0; j < output_info->nmode; j++) 3083 { 3084 XRRModeInfo *jmode, *kmode; 3085 3086 if (mode_shown[j]) continue; 3087 3088 jmode = find_mode_by_xid (output_info->modes[j]); 3089 printf (" "); 3090 printf (" %-12s", jmode->name); 3091 for (k = j; k < output_info->nmode; k++) 3092 { 3093 if (mode_shown[k]) continue; 3094 kmode = find_mode_by_xid (output_info->modes[k]); 3095 if (strcmp (jmode->name, kmode->name) != 0) continue; 3096 mode_shown[k] = True; 3097 kmode->modeFlags |= ModeShown; 3098 printf (" %6.1f", mode_refresh (kmode)); 3099 if (kmode == output->mode_info) 3100 printf ("*"); 3101 else 3102 printf (" "); 3103 if (k < output_info->npreferred) 3104 printf ("+"); 3105 else 3106 printf (" "); 3107 } 3108 printf ("\n"); 3109 } 3110 free (mode_shown); 3111 } 3112 } 3113 for (m = 0; m < res->nmode; m++) 3114 { 3115 XRRModeInfo *mode = &res->modes[m]; 3116 3117 if (!(mode->modeFlags & ModeShown)) 3118 { 3119 printf (" %s (0x%x) %6.1fMHz\n", 3120 mode->name, (int)mode->id, 3121 (double)mode->dotClock / 1000000.0); 3122 printf (" h: width %4d start %4d end %4d total %4d skew %4d clock %6.1fKHz\n", 3123 mode->width, mode->hSyncStart, mode->hSyncEnd, 3124 mode->hTotal, mode->hSkew, mode_hsync (mode) / 1000); 3125 printf (" v: height %4d start %4d end %4d total %4d clock %6.1fHz\n", 3126 mode->height, mode->vSyncStart, mode->vSyncEnd, mode->vTotal, 3127 mode_refresh (mode)); 3128 } 3129 } 3130 exit (0); 3131 } 3132#endif 3133 3134 sc = XRRGetScreenInfo (dpy, root); 3135 3136 if (sc == NULL) 3137 exit (1); 3138 3139 current_size = XRRConfigCurrentConfiguration (sc, ¤t_rotation); 3140 3141 sizes = XRRConfigSizes(sc, &nsize); 3142 3143 if (have_pixel_size) { 3144 for (size = 0; size < nsize; size++) 3145 { 3146 if (sizes[size].width == width && sizes[size].height == height) 3147 break; 3148 } 3149 if (size >= nsize) { 3150 fprintf (stderr, 3151 "Size %dx%d not found in available modes\n", width, height); 3152 exit (1); 3153 } 3154 } 3155 else if (size < 0) 3156 size = current_size; 3157 else if (size >= nsize) { 3158 fprintf (stderr, 3159 "Size index %d is too large, there are only %d sizes\n", 3160 size, nsize); 3161 exit (1); 3162 } 3163 3164 if (rot < 0) 3165 { 3166 for (rot = 0; rot < 4; rot++) 3167 if (1 << rot == (current_rotation & 0xf)) 3168 break; 3169 } 3170 3171 current_rate = XRRConfigCurrentRate (sc); 3172 3173 if (rate < 0) 3174 { 3175 if (size == current_size) 3176 rate = current_rate; 3177 else 3178 rate = 0; 3179 } 3180 else 3181 { 3182 rates = XRRConfigRates (sc, size, &nrate); 3183 for (i = 0; i < nrate; i++) 3184 if (rate == rates[i]) 3185 break; 3186 if (i == nrate) { 3187 fprintf (stderr, "Rate %.1f Hz not available for this size\n", rate); 3188 exit (1); 3189 } 3190 } 3191 3192 if (version) { 3193 int major_version, minor_version; 3194 XRRQueryVersion (dpy, &major_version, &minor_version); 3195 printf("Server reports RandR version %d.%d\n", 3196 major_version, minor_version); 3197 } 3198 3199 if (query || query_1) { 3200 printf(" SZ: Pixels Physical Refresh\n"); 3201 for (i = 0; i < nsize; i++) { 3202 printf ("%c%-2d %5d x %-5d (%4dmm x%4dmm )", 3203 i == current_size ? '*' : ' ', 3204 i, sizes[i].width, sizes[i].height, 3205 sizes[i].mwidth, sizes[i].mheight); 3206 rates = XRRConfigRates (sc, i, &nrate); 3207 if (nrate) printf (" "); 3208 for (j = 0; j < nrate; j++) 3209 printf ("%c%-4d", 3210 i == current_size && rates[j] == current_rate ? '*' : ' ', 3211 rates[j]); 3212 printf ("\n"); 3213 } 3214 } 3215 3216 rotations = XRRConfigRotations(sc, ¤t_rotation); 3217 3218 rotation = 1 << rot ; 3219 if (query) { 3220 printf("Current rotation - %s\n", 3221 rotation_name (current_rotation)); 3222 3223 printf("Current reflection - %s\n", 3224 reflection_name (current_rotation)); 3225 3226 printf ("Rotations possible - "); 3227 for (i = 0; i < 4; i ++) { 3228 if ((rotations >> i) & 1) printf("%s ", direction[i]); 3229 } 3230 printf ("\n"); 3231 3232 printf ("Reflections possible - "); 3233 if (rotations & (RR_Reflect_X|RR_Reflect_Y)) 3234 { 3235 if (rotations & RR_Reflect_X) printf ("X Axis "); 3236 if (rotations & RR_Reflect_Y) printf ("Y Axis"); 3237 } 3238 else 3239 printf ("none"); 3240 printf ("\n"); 3241 } 3242 3243 if (verbose) { 3244 printf("Setting size to %d, rotation to %s\n", size, direction[rot]); 3245 3246 printf ("Setting reflection on "); 3247 if (reflection) 3248 { 3249 if (reflection & RR_Reflect_X) printf ("X Axis "); 3250 if (reflection & RR_Reflect_Y) printf ("Y Axis"); 3251 } 3252 else 3253 printf ("neither axis"); 3254 printf ("\n"); 3255 3256 if (reflection & RR_Reflect_X) printf("Setting reflection on X axis\n"); 3257 3258 if (reflection & RR_Reflect_Y) printf("Setting reflection on Y axis\n"); 3259 } 3260 3261 /* we should test configureNotify on the root window */ 3262 XSelectInput (dpy, root, StructureNotifyMask); 3263 3264 if (setit && !dryrun) XRRSelectInput (dpy, root, 3265 RRScreenChangeNotifyMask); 3266 if (setit && !dryrun) status = XRRSetScreenConfigAndRate (dpy, sc, 3267 root, 3268 (SizeID) size, (Rotation) (rotation | reflection), rate, CurrentTime); 3269 3270 XRRQueryExtension(dpy, &event_base, &error_base); 3271 3272 if (setit && !dryrun && status == RRSetConfigFailed) { 3273 printf ("Failed to change the screen configuration!\n"); 3274 ret = 1; 3275 } 3276 3277 if (verbose && setit && !dryrun && size != current_size) { 3278 if (status == RRSetConfigSuccess) 3279 { 3280 Bool seen_screen = False; 3281 while (!seen_screen) { 3282 int spo; 3283 XNextEvent(dpy, (XEvent *) &event); 3284 3285 printf ("Event received, type = %d\n", event.type); 3286 /* update Xlib's knowledge of the event */ 3287 XRRUpdateConfiguration (&event); 3288 if (event.type == ConfigureNotify) 3289 printf("Received ConfigureNotify Event!\n"); 3290 3291 switch (event.type - event_base) { 3292 case RRScreenChangeNotify: 3293 sce = (XRRScreenChangeNotifyEvent *) &event; 3294 3295 printf("Got a screen change notify event!\n"); 3296 printf(" window = %d\n root = %d\n size_index = %d\n rotation %d\n", 3297 (int) sce->window, (int) sce->root, 3298 sce->size_index, sce->rotation); 3299 printf(" timestamp = %ld, config_timestamp = %ld\n", 3300 sce->timestamp, sce->config_timestamp); 3301 printf(" Rotation = %x\n", sce->rotation); 3302 printf(" %d X %d pixels, %d X %d mm\n", 3303 sce->width, sce->height, sce->mwidth, sce->mheight); 3304 printf("Display width %d, height %d\n", 3305 DisplayWidth(dpy, screen), DisplayHeight(dpy, screen)); 3306 printf("Display widthmm %d, heightmm %d\n", 3307 DisplayWidthMM(dpy, screen), DisplayHeightMM(dpy, screen)); 3308 spo = sce->subpixel_order; 3309 if ((spo < 0) || (spo > 5)) 3310 printf ("Unknown subpixel order, value = %d\n", spo); 3311 else printf ("new Subpixel rendering model is %s\n", order[spo]); 3312 seen_screen = True; 3313 break; 3314 default: 3315 if (event.type != ConfigureNotify) 3316 printf("unknown event received, type = %d!\n", event.type); 3317 } 3318 } 3319 } 3320 } 3321 XRRFreeScreenConfigInfo(sc); 3322 return(ret); 3323} 3324