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