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