xrandr.c revision f86b2e6c
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%s", program_name, 101 " where options are:\n" 102 " --display <display> or -d <display>\n" 103 " --help\n" 104 " -o <normal,inverted,left,right,0,1,2,3>\n" 105 " or --orientation <normal,inverted,left,right,0,1,2,3>\n" 106 " -q or --query\n" 107 " -s <size>/<width>x<height> or --size <size>/<width>x<height>\n" 108 " -r <rate> or --rate <rate> or --refresh <rate>\n" 109 " -v or --version\n" 110 " -x (reflect in x)\n" 111 " -y (reflect in y)\n" 112 " --screen <screen>\n" 113 " --verbose\n" 114 " --current\n" 115 " --dryrun\n" 116 " --nograb\n" 117 " --prop or --properties\n" 118 " --fb <width>x<height>\n" 119 " --fbmm <width>x<height>\n" 120 " --dpi <dpi>/<output>\n" 121 " --output <output>\n" 122 " --auto\n" 123 " --mode <mode>\n" 124 " --preferred\n" 125 " --pos <x>x<y>\n" 126 " --rate <rate> or --refresh <rate>\n" 127 " --reflect normal,x,y,xy\n" 128 " --rotate normal,inverted,left,right\n" 129 " --left-of <output>\n" 130 " --right-of <output>\n" 131 " --above <output>\n" 132 " --below <output>\n" 133 " --same-as <output>\n" 134 " --set <property> <value>\n" 135 " --scale <x>x<y>\n" 136 " --scale-from <w>x<h>\n" 137 " --transform <a>,<b>,<c>,<d>,<e>,<f>,<g>,<h>,<i>\n" 138 " --off\n" 139 " --crtc <crtc>\n" 140 " --panning <w>x<h>[+<x>+<y>[/<track:w>x<h>+<x>+<y>[/<border:l>/<t>/<r>/<b>]]]\n" 141 " --gamma <r>:<g>:<b>\n" 142 " --primary\n" 143 " --noprimary\n" 144 " --newmode <name> <clock MHz>\n" 145 " <hdisp> <hsync-start> <hsync-end> <htotal>\n" 146 " <vdisp> <vsync-start> <vsync-end> <vtotal>\n" 147 " [flags...]\n" 148 " Valid flags: +HSync -HSync +VSync -VSync\n" 149 " +CSync -CSync CSync Interlace DoubleScan\n" 150 " --rmmode <name>\n" 151 " --addmode <output> <name>\n" 152 " --delmode <output> <name>\n" 153 " --listproviders\n" 154 " --setprovideroutputsource <prov-xid> <source-xid>\n" 155 " --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 const 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 ("--display", argv[i]) || 2514 !strcmp ("-d", argv[i])) { 2515 if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); 2516 display_name = argv[i]; 2517 continue; 2518 } 2519 if (!strcmp("-help", argv[i]) || !strcmp("--help", argv[i])) { 2520 usage(); 2521 exit(0); 2522 } 2523 if (!strcmp ("--verbose", argv[i])) { 2524 verbose = True; 2525 continue; 2526 } 2527 if (!strcmp ("--dryrun", argv[i])) { 2528 dryrun = True; 2529 verbose = True; 2530 continue; 2531 } 2532 if (!strcmp ("--nograb", argv[i])) { 2533 grab_server = False; 2534 continue; 2535 } 2536 if (!strcmp("--current", argv[i])) { 2537 current = True; 2538 continue; 2539 } 2540 2541 if (!strcmp ("-s", argv[i]) || !strcmp ("--size", argv[i])) { 2542 if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); 2543 if (sscanf (argv[i], "%dx%d", &width, &height) == 2) { 2544 have_pixel_size = True; 2545 } else { 2546 size = check_strtol(argv[i]); 2547 if (size < 0) argerr ("--size argument must be nonnegative\n"); 2548 } 2549 setit = True; 2550 action_requested = True; 2551 continue; 2552 } 2553 2554 if (!strcmp ("-r", argv[i]) || 2555 !strcmp ("--rate", argv[i]) || 2556 !strcmp ("--refresh", argv[i])) 2557 { 2558 if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); 2559 rate = check_strtod(argv[i]); 2560 setit = True; 2561 if (config_output) 2562 { 2563 config_output->refresh = rate; 2564 config_output->changes |= changes_refresh; 2565 setit_1_2 = True; 2566 } 2567 action_requested = True; 2568 continue; 2569 } 2570 2571 if (!strcmp ("-v", argv[i]) || !strcmp ("--version", argv[i])) { 2572 version = True; 2573 action_requested = True; 2574 continue; 2575 } 2576 2577 if (!strcmp ("-x", argv[i])) { 2578 reflection |= RR_Reflect_X; 2579 setit = True; 2580 action_requested = True; 2581 continue; 2582 } 2583 if (!strcmp ("-y", argv[i])) { 2584 reflection |= RR_Reflect_Y; 2585 setit = True; 2586 action_requested = True; 2587 continue; 2588 } 2589 if (!strcmp ("--screen", argv[i])) { 2590 if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); 2591 screen = check_strtol(argv[i]); 2592 if (screen < 0) argerr ("--screen argument must be nonnegative\n"); 2593 continue; 2594 } 2595 if (!strcmp ("-q", argv[i]) || !strcmp ("--query", argv[i])) { 2596 query = True; 2597 continue; 2598 } 2599 if (!strcmp ("-o", argv[i]) || !strcmp ("--orientation", argv[i])) { 2600 char *endptr; 2601 if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); 2602 dirind = strtol(argv[i], &endptr, 10); 2603 if (argv[i] == endptr) { 2604 for (dirind = 0; dirind < 4; dirind++) { 2605 if (strcmp (direction[dirind], argv[i]) == 0) break; 2606 } 2607 } 2608 if ((dirind < 0) || (dirind > 3)) 2609 argerr ("%s: invalid argument '%s'\n", argv[i-1], argv[i]); 2610 rot = dirind; 2611 setit = True; 2612 action_requested = True; 2613 continue; 2614 } 2615 if (!strcmp ("--prop", argv[i]) || 2616 !strcmp ("--props", argv[i]) || 2617 !strcmp ("--madprops", argv[i]) || 2618 !strcmp ("--properties", argv[i])) 2619 { 2620 query_1_2 = True; 2621 properties = True; 2622 action_requested = True; 2623 continue; 2624 } 2625 if (!strcmp ("--output", argv[i])) { 2626 if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); 2627 2628 config_output = find_output_by_name (argv[i]); 2629 if (!config_output) { 2630 config_output = add_output (); 2631 set_name (&config_output->output, argv[i], name_string|name_xid); 2632 } 2633 2634 setit_1_2 = True; 2635 action_requested = True; 2636 continue; 2637 } 2638 if (!strcmp ("--crtc", argv[i])) { 2639 if (!config_output) argerr ("%s must be used after --output\n", argv[i]); 2640 if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); 2641 set_name (&config_output->crtc, argv[i], name_xid|name_index); 2642 config_output->changes |= changes_crtc; 2643 continue; 2644 } 2645 if (!strcmp ("--mode", argv[i])) { 2646 if (!config_output) argerr ("%s must be used after --output\n", argv[i]); 2647 if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); 2648 set_name (&config_output->mode, argv[i], name_string|name_xid); 2649 config_output->changes |= changes_mode; 2650 continue; 2651 } 2652 if (!strcmp ("--preferred", argv[i])) { 2653 if (!config_output) argerr ("%s must be used after --output\n", argv[i]); 2654 set_name_preferred (&config_output->mode); 2655 config_output->changes |= changes_mode; 2656 continue; 2657 } 2658 if (!strcmp ("--pos", argv[i])) { 2659 if (!config_output) argerr ("%s must be used after --output\n", argv[i]); 2660 if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); 2661 if (sscanf (argv[i], "%dx%d", 2662 &config_output->x, &config_output->y) != 2) 2663 argerr ("failed to parse '%s' as a position\n", argv[i]); 2664 config_output->changes |= changes_position; 2665 continue; 2666 } 2667 if (!strcmp ("--rotation", argv[i]) || !strcmp ("--rotate", argv[i])) { 2668 if (!config_output) argerr ("%s must be used after --output\n", argv[i]); 2669 if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); 2670 for (dirind = 0; dirind < 4; dirind++) { 2671 if (strcmp (direction[dirind], argv[i]) == 0) break; 2672 } 2673 if (dirind == 4) 2674 argerr ("%s: invalid argument '%s'\n", argv[i-1], argv[i]); 2675 config_output->rotation &= ~0xf; 2676 config_output->rotation |= 1 << dirind; 2677 config_output->changes |= changes_rotation; 2678 continue; 2679 } 2680 if (!strcmp ("--reflect", argv[i]) || !strcmp ("--reflection", argv[i])) { 2681 if (!config_output) argerr ("%s must be used after --output\n", argv[i]); 2682 if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); 2683 for (dirind = 0; dirind < 4; dirind++) { 2684 if (strcmp (reflections[dirind], argv[i]) == 0) break; 2685 } 2686 if (dirind == 4) 2687 argerr ("%s: invalid argument '%s'\n", argv[i-1], argv[i]); 2688 config_output->rotation &= ~(RR_Reflect_X|RR_Reflect_Y); 2689 config_output->rotation |= dirind * RR_Reflect_X; 2690 config_output->changes |= changes_reflection; 2691 continue; 2692 } 2693 if (!strcmp ("--left-of", argv[i])) { 2694 if (!config_output) argerr ("%s must be used after --output\n", argv[i]); 2695 if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); 2696 config_output->relation = relation_left_of; 2697 config_output->relative_to = argv[i]; 2698 config_output->changes |= changes_relation; 2699 continue; 2700 } 2701 if (!strcmp ("--right-of", argv[i])) { 2702 if (!config_output) argerr ("%s must be used after --output\n", argv[i]); 2703 if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); 2704 config_output->relation = relation_right_of; 2705 config_output->relative_to = argv[i]; 2706 config_output->changes |= changes_relation; 2707 continue; 2708 } 2709 if (!strcmp ("--above", argv[i])) { 2710 if (!config_output) argerr ("%s must be used after --output\n", argv[i]); 2711 if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); 2712 config_output->relation = relation_above; 2713 config_output->relative_to = argv[i]; 2714 config_output->changes |= changes_relation; 2715 continue; 2716 } 2717 if (!strcmp ("--below", argv[i])) { 2718 if (!config_output) argerr ("%s must be used after --output\n", argv[i]); 2719 if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); 2720 config_output->relation = relation_below; 2721 config_output->relative_to = argv[i]; 2722 config_output->changes |= changes_relation; 2723 continue; 2724 } 2725 if (!strcmp ("--same-as", argv[i])) { 2726 if (!config_output) argerr ("%s must be used after --output\n", argv[i]); 2727 if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); 2728 config_output->relation = relation_same_as; 2729 config_output->relative_to = argv[i]; 2730 config_output->changes |= changes_relation; 2731 continue; 2732 } 2733 if (!strcmp ("--panning", argv[i])) { 2734 XRRPanning *pan; 2735 if (!config_output) argerr ("%s must be used after --output\n", argv[i]); 2736 if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); 2737 pan = &config_output->panning; 2738 switch (sscanf (argv[i], "%dx%d+%d+%d/%dx%d+%d+%d/%d/%d/%d/%d", 2739 &pan->width, &pan->height, &pan->left, &pan->top, 2740 &pan->track_width, &pan->track_height, 2741 &pan->track_left, &pan->track_top, 2742 &pan->border_left, &pan->border_top, 2743 &pan->border_right, &pan->border_bottom)) { 2744 case 2: 2745 pan->left = pan->top = 0; 2746 /* fall through */ 2747 case 4: 2748 pan->track_left = pan->track_top = 2749 pan->track_width = pan->track_height = 0; 2750 /* fall through */ 2751 case 8: 2752 pan->border_left = pan->border_top = 2753 pan->border_right = pan->border_bottom = 0; 2754 /* fall through */ 2755 case 12: 2756 break; 2757 default: 2758 argerr ("%s: invalid argument '%s'\n", argv[i-1], argv[i]); 2759 } 2760 config_output->changes |= changes_panning; 2761 continue; 2762 } 2763 if (!strcmp ("--gamma", argv[i])) { 2764 if (!config_output) argerr ("%s must be used after --output\n", argv[i]); 2765 if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); 2766 if (sscanf(argv[i], "%f:%f:%f", &config_output->gamma.red, 2767 &config_output->gamma.green, &config_output->gamma.blue) != 3) 2768 argerr ("%s: invalid argument '%s'\n", argv[i-1], argv[i]); 2769 config_output->changes |= changes_gamma; 2770 setit_1_2 = True; 2771 continue; 2772 } 2773 if (!strcmp ("--brightness", argv[i])) { 2774 if (!config_output) argerr ("%s must be used after --output\n", argv[i]); 2775 if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); 2776 if (sscanf(argv[i], "%f", &config_output->brightness) != 1) 2777 argerr ("%s: invalid argument '%s'\n", argv[i-1], argv[i]); 2778 config_output->changes |= changes_gamma; 2779 setit_1_2 = True; 2780 continue; 2781 } 2782 if (!strcmp ("--primary", argv[i])) { 2783 if (!config_output) argerr ("%s must be used after --output\n", argv[i]); 2784 config_output->changes |= changes_primary; 2785 config_output->primary = True; 2786 setit_1_2 = True; 2787 continue; 2788 } 2789 if (!strcmp ("--noprimary", argv[i])) { 2790 no_primary = True; 2791 setit_1_2 = True; 2792 continue; 2793 } 2794 if (!strcmp ("--set", argv[i])) { 2795 output_prop_t *prop; 2796 if (!config_output) argerr ("%s must be used after --output\n", argv[i]); 2797 if (i+2 >= argc) argerr ("%s requires two arguments\n", argv[i]); 2798 prop = malloc (sizeof (output_prop_t)); 2799 prop->next = config_output->props; 2800 config_output->props = prop; 2801 prop->name = argv[++i]; 2802 prop->value = argv[++i]; 2803 propit = True; 2804 config_output->changes |= changes_property; 2805 setit_1_2 = True; 2806 continue; 2807 } 2808 if (!strcmp ("--scale", argv[i])) 2809 { 2810 double sx, sy; 2811 if (!config_output) argerr ("%s must be used after --output\n", argv[i]); 2812 if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); 2813 if (sscanf (argv[i], "%lfx%lf", &sx, &sy) != 2) 2814 argerr ("failed to parse '%s' as a scaling factor\n", argv[i]); 2815 init_transform (&config_output->transform); 2816 config_output->transform.transform.matrix[0][0] = XDoubleToFixed (sx); 2817 config_output->transform.transform.matrix[1][1] = XDoubleToFixed (sy); 2818 config_output->transform.transform.matrix[2][2] = XDoubleToFixed (1.0); 2819 if (sx != 1 || sy != 1) 2820 config_output->transform.filter = "bilinear"; 2821 else 2822 config_output->transform.filter = "nearest"; 2823 config_output->transform.nparams = 0; 2824 config_output->transform.params = NULL; 2825 config_output->changes |= changes_transform; 2826 continue; 2827 } 2828 if (!strcmp ("--scale-from", argv[i])) 2829 { 2830 int w, h; 2831 if (!config_output) argerr ("%s must be used after --output\n", argv[i]); 2832 if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); 2833 if (sscanf (argv[i], "%dx%d", &w, &h) != 2) 2834 argerr ("failed to parse '%s' as a scale-from size\n", argv[i]); 2835 if (w <=0 || h <= 0) 2836 argerr ("--scale-from dimensions must be nonnegative\n"); 2837 config_output->scale_from_w = w; 2838 config_output->scale_from_h = h; 2839 config_output->changes |= changes_transform; 2840 continue; 2841 } 2842 if (!strcmp ("--transform", argv[i])) { 2843 double transform[3][3]; 2844 int k, l; 2845 if (!config_output) argerr ("%s must be used after --output\n", argv[i]); 2846 if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); 2847 init_transform (&config_output->transform); 2848 if (strcmp (argv[i], "none") != 0) 2849 { 2850 if (sscanf(argv[i], "%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf", 2851 &transform[0][0],&transform[0][1],&transform[0][2], 2852 &transform[1][0],&transform[1][1],&transform[1][2], 2853 &transform[2][0],&transform[2][1],&transform[2][2]) 2854 != 9) 2855 argerr ("failed to parse '%s' as a transformation\n", argv[i]); 2856 init_transform (&config_output->transform); 2857 for (k = 0; k < 3; k++) 2858 for (l = 0; l < 3; l++) { 2859 config_output->transform.transform.matrix[k][l] = XDoubleToFixed (transform[k][l]); 2860 } 2861 config_output->transform.filter = "bilinear"; 2862 config_output->transform.nparams = 0; 2863 config_output->transform.params = NULL; 2864 } 2865 config_output->changes |= changes_transform; 2866 continue; 2867 } 2868 if (!strcmp ("--off", argv[i])) { 2869 if (!config_output) argerr ("%s must be used after --output\n", argv[i]); 2870 set_name_xid (&config_output->mode, None); 2871 set_name_xid (&config_output->crtc, None); 2872 config_output->changes |= changes_mode; 2873 continue; 2874 } 2875 if (!strcmp ("--fb", argv[i])) { 2876 if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); 2877 if (sscanf (argv[i], "%dx%d", 2878 &fb_width, &fb_height) != 2) 2879 argerr ("failed to parse '%s' as a framebuffer size\n", argv[i]); 2880 setit_1_2 = True; 2881 action_requested = True; 2882 continue; 2883 } 2884 if (!strcmp ("--fbmm", argv[i])) { 2885 if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); 2886 if (sscanf (argv[i], "%dx%d", 2887 &fb_width_mm, &fb_height_mm) != 2) 2888 argerr ("failed to parse '%s' as a physical size\n", argv[i]); 2889 setit_1_2 = True; 2890 action_requested = True; 2891 continue; 2892 } 2893 if (!strcmp ("--dpi", argv[i])) { 2894 char *strtod_error; 2895 if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); 2896 dpi = strtod(argv[i], &strtod_error); 2897 if (argv[i] == strtod_error) 2898 { 2899 dpi = 0.0; 2900 dpi_output_name = argv[i]; 2901 } 2902 setit_1_2 = True; 2903 action_requested = True; 2904 continue; 2905 } 2906 if (!strcmp ("--auto", argv[i])) { 2907 if (config_output) 2908 { 2909 config_output->automatic = True; 2910 config_output->changes |= changes_automatic; 2911 } 2912 else 2913 automatic = True; 2914 setit_1_2 = True; 2915 action_requested = True; 2916 continue; 2917 } 2918 if (!strcmp ("--q12", argv[i])) 2919 { 2920 query_1_2 = True; 2921 continue; 2922 } 2923 if (!strcmp ("--q1", argv[i])) 2924 { 2925 query_1 = True; 2926 continue; 2927 } 2928 if (!strcmp ("--newmode", argv[i])) 2929 { 2930 umode_t *m = calloc (1, sizeof (umode_t)); 2931 double clock; 2932 2933 ++i; 2934 if (i + 9 >= argc) 2935 argerr ("failed to parse '%s' as a mode specification\n", argv[i]); 2936 m->mode.name = argv[i]; 2937 m->mode.nameLength = strlen (argv[i]); 2938 i++; 2939 clock = check_strtod(argv[i++]); 2940 m->mode.dotClock = clock * 1e6; 2941 2942 m->mode.width = check_strtol(argv[i++]); 2943 m->mode.hSyncStart = check_strtol(argv[i++]); 2944 m->mode.hSyncEnd = check_strtol(argv[i++]); 2945 m->mode.hTotal = check_strtol(argv[i++]); 2946 m->mode.height = check_strtol(argv[i++]); 2947 m->mode.vSyncStart = check_strtol(argv[i++]); 2948 m->mode.vSyncEnd = check_strtol(argv[i++]); 2949 m->mode.vTotal = check_strtol(argv[i++]); 2950 m->mode.modeFlags = 0; 2951 while (i < argc) { 2952 int f; 2953 2954 for (f = 0; mode_flags[f].string; f++) 2955 if (!strcasecmp (mode_flags[f].string, argv[i])) 2956 break; 2957 2958 if (!mode_flags[f].string) 2959 break; 2960 m->mode.modeFlags |= mode_flags[f].flag; 2961 i++; 2962 } 2963 m->next = umodes; 2964 m->action = umode_create; 2965 umodes = m; 2966 modeit = True; 2967 action_requested = True; 2968 continue; 2969 } 2970 if (!strcmp ("--rmmode", argv[i])) 2971 { 2972 umode_t *m = calloc (1, sizeof (umode_t)); 2973 2974 if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); 2975 set_name (&m->name, argv[i], name_string|name_xid); 2976 m->action = umode_destroy; 2977 m->next = umodes; 2978 umodes = m; 2979 modeit = True; 2980 action_requested = True; 2981 continue; 2982 } 2983 if (!strcmp ("--addmode", argv[i])) 2984 { 2985 umode_t *m = calloc (1, sizeof (umode_t)); 2986 2987 if (i+2 >= argc) argerr ("%s requires two arguments\n", argv[i]); 2988 set_name (&m->output, argv[++i], name_string|name_xid); 2989 set_name (&m->name, argv[++i], name_string|name_xid); 2990 m->action = umode_add; 2991 m->next = umodes; 2992 umodes = m; 2993 modeit = True; 2994 action_requested = True; 2995 continue; 2996 } 2997 if (!strcmp ("--delmode", argv[i])) 2998 { 2999 umode_t *m = calloc (1, sizeof (umode_t)); 3000 3001 if (i+2 >= argc) argerr ("%s requires two arguments\n", argv[i]); 3002 set_name (&m->output, argv[++i], name_string|name_xid); 3003 set_name (&m->name, argv[++i], name_string|name_xid); 3004 m->action = umode_delete; 3005 m->next = umodes; 3006 umodes = m; 3007 modeit = True; 3008 action_requested = True; 3009 continue; 3010 } 3011 if (!strcmp ("--listproviders", argv[i])) 3012 { 3013 list_providers = True; 3014 action_requested = True; 3015 continue; 3016 } 3017 if (!strcmp("--setprovideroutputsource", argv[i])) 3018 { 3019 if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); 3020 set_name (&provider_name, argv[i], name_string|name_xid|name_index); 3021 if (++i>=argc) 3022 set_name_xid (&output_source_provider_name, 0); 3023 else 3024 set_name (&output_source_provider_name, argv[i], name_string|name_xid|name_index); 3025 action_requested = True; 3026 provsetoutsource = True; 3027 continue; 3028 } 3029 if (!strcmp("--setprovideroffloadsink", argv[i])) 3030 { 3031 if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]); 3032 set_name (&provider_name, argv[i], name_string|name_xid|name_index); 3033 if (++i>=argc) 3034 set_name_xid (&offload_sink_provider_name, 0); 3035 else 3036 set_name (&offload_sink_provider_name, argv[i], name_string|name_xid|name_index); 3037 action_requested = True; 3038 provsetoffsink = True; 3039 continue; 3040 } 3041 3042 argerr ("unrecognized option '%s'\n", argv[i]); 3043 } 3044 if (!action_requested) 3045 query = True; 3046 if (verbose) 3047 { 3048 query = True; 3049 if (setit && !setit_1_2) 3050 query_1 = True; 3051 } 3052 if (version) 3053 printf("xrandr program version " VERSION "\n"); 3054 3055 dpy = XOpenDisplay (display_name); 3056 3057 if (dpy == NULL) { 3058 fprintf (stderr, "Can't open display %s\n", XDisplayName(display_name)); 3059 exit (1); 3060 } 3061 if (screen < 0) 3062 screen = DefaultScreen (dpy); 3063 if (screen >= ScreenCount (dpy)) { 3064 fprintf (stderr, "Invalid screen number %d (display has %d)\n", 3065 screen, ScreenCount (dpy)); 3066 exit (1); 3067 } 3068 3069 root = RootWindow (dpy, screen); 3070 3071 if (!XRRQueryExtension (dpy, &event_base, &error_base) || 3072 !XRRQueryVersion (dpy, &major, &minor)) 3073 { 3074 fprintf (stderr, "RandR extension missing\n"); 3075 exit (1); 3076 } 3077 if (major > 1 || (major == 1 && minor >= 2)) 3078 has_1_2 = True; 3079 if (major > 1 || (major == 1 && minor >= 3)) 3080 has_1_3 = True; 3081 if (major > 1 || (major == 1 && minor >= 4)) 3082 has_1_4 = True; 3083 3084 if (has_1_2 && modeit) 3085 { 3086 umode_t *m; 3087 3088 get_screen (current); 3089 get_crtcs(); 3090 get_outputs(); 3091 3092 for (m = umodes; m; m = m->next) 3093 { 3094 XRRModeInfo *e; 3095 output_t *o; 3096 3097 switch (m->action) { 3098 case umode_create: 3099 XRRCreateMode (dpy, root, &m->mode); 3100 break; 3101 case umode_destroy: 3102 e = find_mode (&m->name, 0); 3103 if (!e) 3104 fatal ("cannot find mode \"%s\"\n", m->name.string); 3105 XRRDestroyMode (dpy, e->id); 3106 break; 3107 case umode_add: 3108 o = find_output (&m->output); 3109 if (!o) 3110 fatal ("cannot find output \"%s\"\n", m->output.string); 3111 e = find_mode (&m->name, 0); 3112 if (!e) 3113 fatal ("cannot find mode \"%s\"\n", m->name.string); 3114 XRRAddOutputMode (dpy, o->output.xid, e->id); 3115 break; 3116 case umode_delete: 3117 o = find_output (&m->output); 3118 if (!o) 3119 fatal ("cannot find output \"%s\"\n", m->output.string); 3120 e = find_mode (&m->name, 0); 3121 if (!e) 3122 fatal ("cannot find mode \"%s\"\n", m->name.string); 3123 XRRDeleteOutputMode (dpy, o->output.xid, e->id); 3124 break; 3125 } 3126 } 3127 if (!setit_1_2) 3128 { 3129 XSync (dpy, False); 3130 exit (0); 3131 } 3132 } 3133 if (has_1_2 && propit) 3134 { 3135 output_t *output; 3136 3137 get_screen (current); 3138 get_crtcs(); 3139 get_outputs(); 3140 3141 for (output = all_outputs; output; output = output->next) 3142 { 3143 output_prop_t *prop; 3144 3145 for (prop = output->props; prop; prop = prop->next) 3146 { 3147 Atom name = XInternAtom (dpy, prop->name, False); 3148 Atom type; 3149 int format = 0; 3150 unsigned char *data, *malloced_data = NULL; 3151 int nelements; 3152 int int_value; 3153 unsigned long ulong_value; 3154 unsigned char *prop_data; 3155 int actual_format; 3156 unsigned long nitems, bytes_after; 3157 Atom actual_type; 3158 XRRPropertyInfo *propinfo; 3159 3160 type = AnyPropertyType; 3161 3162 if (XRRGetOutputProperty (dpy, output->output.xid, name, 3163 0, 100, False, False, 3164 AnyPropertyType, 3165 &actual_type, &actual_format, 3166 &nitems, &bytes_after, &prop_data) == Success && 3167 3168 (propinfo = XRRQueryOutputProperty(dpy, output->output.xid, 3169 name))) 3170 { 3171 type = actual_type; 3172 format = actual_format; 3173 } 3174 3175 malloced_data = property_values_from_string 3176 (prop->value, type, actual_format, &nelements); 3177 3178 if (malloced_data) 3179 { 3180 data = malloced_data; 3181 type = actual_type; 3182 format = actual_format; 3183 } 3184 else if (type == AnyPropertyType && 3185 (sscanf (prop->value, "%d", &int_value) == 1 || 3186 sscanf (prop->value, "0x%x", &int_value) == 1)) 3187 { 3188 type = XA_INTEGER; 3189 ulong_value = int_value; 3190 data = (unsigned char *) &ulong_value; 3191 nelements = 1; 3192 format = 32; 3193 } 3194 else if ((type == XA_ATOM)) 3195 { 3196 ulong_value = XInternAtom (dpy, prop->value, False); 3197 data = (unsigned char *) &ulong_value; 3198 nelements = 1; 3199 } 3200 else if ((type == XA_STRING || type == AnyPropertyType)) 3201 { 3202 type = XA_STRING; 3203 data = (unsigned char *) prop->value; 3204 nelements = strlen (prop->value); 3205 format = 8; 3206 } 3207 else 3208 continue; 3209 XRRChangeOutputProperty (dpy, output->output.xid, 3210 name, type, format, PropModeReplace, 3211 data, nelements); 3212 free (malloced_data); 3213 } 3214 } 3215 if (!setit_1_2) 3216 { 3217 XSync (dpy, False); 3218 exit (0); 3219 } 3220 } 3221 if (provsetoutsource) 3222 { 3223 provider_t *provider, *source; 3224 3225 if (!has_1_4) 3226 fatal ("--setprovideroutputsource requires RandR 1.4\n"); 3227 3228 get_screen (current); 3229 get_providers (); 3230 3231 provider = find_provider (&provider_name); 3232 source = find_provider(&output_source_provider_name); 3233 3234 XRRSetProviderOutputSource(dpy, provider->provider.xid, source->provider.xid); 3235 } 3236 if (provsetoffsink) 3237 { 3238 provider_t *provider, *sink; 3239 3240 if (!has_1_4) 3241 fatal ("--setprovideroffloadsink requires RandR 1.4\n"); 3242 3243 get_screen (current); 3244 get_providers (); 3245 3246 provider = find_provider (&provider_name); 3247 sink = find_provider(&offload_sink_provider_name); 3248 3249 XRRSetProviderOffloadSink(dpy, provider->provider.xid, sink->provider.xid); 3250 } 3251 if (setit_1_2) 3252 { 3253 get_screen (current); 3254 get_crtcs (); 3255 get_outputs (); 3256 set_positions (); 3257 set_screen_size (); 3258 3259 pick_crtcs (); 3260 3261 /* 3262 * Assign outputs to crtcs 3263 */ 3264 set_crtcs (); 3265 3266 /* 3267 * Mark changing crtcs 3268 */ 3269 mark_changing_crtcs (); 3270 3271 /* 3272 * If an output was specified to track dpi, use it 3273 */ 3274 if (dpi_output_name) 3275 { 3276 output_t *dpi_output = find_output_by_name (dpi_output_name); 3277 XRROutputInfo *output_info; 3278 XRRModeInfo *mode_info; 3279 if (!dpi_output) 3280 fatal ("Cannot find output %s\n", dpi_output_name); 3281 output_info = dpi_output->output_info; 3282 mode_info = dpi_output->mode_info; 3283 if (output_info && mode_info && output_info->mm_height) 3284 { 3285 /* 3286 * When this output covers the whole screen, just use 3287 * the known physical size 3288 */ 3289 if (fb_width == mode_info->width && 3290 fb_height == mode_info->height) 3291 { 3292 fb_width_mm = output_info->mm_width; 3293 fb_height_mm = output_info->mm_height; 3294 } 3295 else 3296 { 3297 dpi = (25.4 * mode_info->height) / output_info->mm_height; 3298 } 3299 } 3300 } 3301 3302 /* 3303 * Compute physical screen size 3304 */ 3305 if (fb_width_mm == 0 || fb_height_mm == 0) 3306 { 3307 if (fb_width != DisplayWidth (dpy, screen) || 3308 fb_height != DisplayHeight (dpy, screen) || dpi != 0.0) 3309 { 3310 if (dpi <= 0) 3311 dpi = (25.4 * DisplayHeight (dpy, screen)) / DisplayHeightMM(dpy, screen); 3312 3313 fb_width_mm = (25.4 * fb_width) / dpi; 3314 fb_height_mm = (25.4 * fb_height) / dpi; 3315 } 3316 else 3317 { 3318 fb_width_mm = DisplayWidthMM (dpy, screen); 3319 fb_height_mm = DisplayHeightMM (dpy, screen); 3320 } 3321 } 3322 3323 /* 3324 * Set panning 3325 */ 3326 set_panning (); 3327 3328 /* 3329 * Set gamma on crtc's that belong to the outputs. 3330 */ 3331 set_gamma (); 3332 3333 /* 3334 * Now apply all of the changes 3335 */ 3336 apply (); 3337 3338 XSync (dpy, False); 3339 exit (0); 3340 } 3341 if (query_1_2 || (query && has_1_2 && !query_1)) 3342 { 3343 output_t *output; 3344 int m; 3345 3346#define ModeShown 0x80000000 3347 3348 get_screen (current); 3349 get_crtcs (); 3350 get_outputs (); 3351 3352 printf ("Screen %d: minimum %d x %d, current %d x %d, maximum %d x %d\n", 3353 screen, minWidth, minHeight, 3354 DisplayWidth (dpy, screen), DisplayHeight(dpy, screen), 3355 maxWidth, maxHeight); 3356 3357 for (output = all_outputs; output; output = output->next) 3358 { 3359 XRROutputInfo *output_info = output->output_info; 3360 crtc_t *cur_crtc = output->crtc_info; 3361 XRRCrtcInfo *crtc_info = cur_crtc ? cur_crtc->crtc_info : NULL; 3362 XRRModeInfo *cur_mode = output->mode_info; 3363 Atom *props; 3364 int j, nprop; 3365 Bool *mode_shown; 3366 Rotation rotations = output_rotations (output); 3367 3368 printf ("%s %s", output_info->name, connection[output_info->connection]); 3369 if (output->primary) { 3370 printf(" primary"); 3371 } 3372 if (cur_mode) 3373 { 3374 if (crtc_info) { 3375 printf (" %dx%d+%d+%d", 3376 crtc_info->width, crtc_info->height, 3377 crtc_info->x, crtc_info->y); 3378 } else { 3379 printf (" %dx%d+%d+%d", 3380 cur_mode->width, cur_mode->height, output->x, 3381 output->y); 3382 } 3383 if (verbose) 3384 printf (" (0x%x)", (int)cur_mode->id); 3385 if (output->rotation != RR_Rotate_0 || verbose) 3386 { 3387 printf (" %s", 3388 rotation_name (output->rotation)); 3389 if (output->rotation & (RR_Reflect_X|RR_Reflect_Y)) 3390 printf (" %s", reflection_name (output->rotation)); 3391 } 3392 } 3393 if (rotations != RR_Rotate_0 || verbose) 3394 { 3395 Bool first = True; 3396 printf (" ("); 3397 for (i = 0; i < 4; i ++) { 3398 if ((rotations >> i) & 1) { 3399 if (!first) printf (" "); first = False; 3400 printf("%s", direction[i]); 3401 } 3402 } 3403 if (rotations & RR_Reflect_X) 3404 { 3405 if (!first) printf (" "); first = False; 3406 printf ("x axis"); 3407 } 3408 if (rotations & RR_Reflect_Y) 3409 { 3410 if (!first) printf (" "); 3411 printf ("y axis"); 3412 } 3413 printf (")"); 3414 } 3415 3416 if (cur_mode) 3417 { 3418 printf (" %dmm x %dmm", 3419 (int)output_info->mm_width, (int)output_info->mm_height); 3420 } 3421 3422 if (cur_crtc && cur_crtc->panning_info && 3423 cur_crtc->panning_info->width > 0) 3424 { 3425 XRRPanning *pan = cur_crtc->panning_info; 3426 printf (" panning %dx%d+%d+%d", 3427 pan->width, pan->height, pan->left, pan->top); 3428 if ((pan->track_width != 0 && 3429 (pan->track_left != pan->left || 3430 pan->track_width != pan->width || 3431 pan->border_left != 0 || 3432 pan->border_right != 0)) || 3433 (pan->track_height != 0 && 3434 (pan->track_top != pan->top || 3435 pan->track_height != pan->height || 3436 pan->border_top != 0 || 3437 pan->border_bottom != 0))) 3438 printf (" tracking %dx%d+%d+%d border %d/%d/%d/%d", 3439 pan->track_width, pan->track_height, 3440 pan->track_left, pan->track_top, 3441 pan->border_left, pan->border_top, 3442 pan->border_right, pan->border_bottom); 3443 } 3444 printf ("\n"); 3445 3446 if (verbose) 3447 { 3448 printf ("\tIdentifier: 0x%x\n", (int)output->output.xid); 3449 printf ("\tTimestamp: %d\n", (int)output_info->timestamp); 3450 printf ("\tSubpixel: %s\n", order[output_info->subpixel_order]); 3451 if (output->gamma.red != 0.0 && output->gamma.green != 0.0 && output->gamma.blue != 0.0) { 3452 printf ("\tGamma: %#.2g:%#.2g:%#.2g\n", 3453 output->gamma.red, output->gamma.green, output->gamma.blue); 3454 printf ("\tBrightness: %#.2g\n", output->brightness); 3455 } 3456 printf ("\tClones: "); 3457 for (j = 0; j < output_info->nclone; j++) 3458 { 3459 output_t *clone = find_output_by_xid (output_info->clones[j]); 3460 3461 if (clone) printf (" %s", clone->output.string); 3462 } 3463 printf ("\n"); 3464 if (output->crtc_info) 3465 printf ("\tCRTC: %d\n", output->crtc_info->crtc.index); 3466 printf ("\tCRTCs: "); 3467 for (j = 0; j < output_info->ncrtc; j++) 3468 { 3469 crtc_t *crtc = find_crtc_by_xid (output_info->crtcs[j]); 3470 if (crtc) 3471 printf (" %d", crtc->crtc.index); 3472 } 3473 printf ("\n"); 3474 if (output->crtc_info && output->crtc_info->panning_info) { 3475 XRRPanning *pan = output->crtc_info->panning_info; 3476 printf ("\tPanning: %dx%d+%d+%d\n", 3477 pan->width, pan->height, pan->left, pan->top); 3478 printf ("\tTracking: %dx%d+%d+%d\n", 3479 pan->track_width, pan->track_height, 3480 pan->track_left, pan->track_top); 3481 printf ("\tBorder: %d/%d/%d/%d\n", 3482 pan->border_left, pan->border_top, 3483 pan->border_right, pan->border_bottom); 3484 } 3485 } 3486 if (verbose) 3487 { 3488 int x, y; 3489 3490 printf ("\tTransform: "); 3491 for (y = 0; y < 3; y++) 3492 { 3493 for (x = 0; x < 3; x++) 3494 printf (" %f", XFixedToDouble (output->transform.transform.matrix[y][x])); 3495 if (y < 2) 3496 printf ("\n\t "); 3497 } 3498 if (output->transform.filter) 3499 printf ("\n\t filter: %s", output->transform.filter); 3500 printf ("\n"); 3501 } 3502 if (verbose || properties) 3503 { 3504 props = XRRListOutputProperties (dpy, output->output.xid, 3505 &nprop); 3506 for (j = 0; j < nprop; j++) { 3507 unsigned char *prop; 3508 int actual_format; 3509 unsigned long nitems, bytes_after; 3510 Atom actual_type; 3511 XRRPropertyInfo *propinfo; 3512 char *atom_name = XGetAtomName (dpy, props[j]); 3513 Bool is_edid = strcmp (atom_name, "EDID") == 0; 3514 int bytes_per_item, k; 3515 3516 XRRGetOutputProperty (dpy, output->output.xid, props[j], 3517 0, 100, False, False, 3518 AnyPropertyType, 3519 &actual_type, &actual_format, 3520 &nitems, &bytes_after, &prop); 3521 3522 propinfo = XRRQueryOutputProperty(dpy, output->output.xid, 3523 props[j]); 3524 3525 bytes_per_item = actual_format / 8; 3526 3527 printf ("\t%s: ", atom_name); 3528 3529 if (is_edid) 3530 { 3531 printf ("\n\t\t"); 3532 } 3533 3534 for (k = 0; k < nitems; k++) 3535 { 3536 if (k != 0) 3537 { 3538 if ((k % 16) == 0) 3539 { 3540 printf ("\n\t\t"); 3541 } 3542 } 3543 print_output_property_value (is_edid, actual_format, 3544 actual_type, 3545 prop + (k * bytes_per_item)); 3546 if (!is_edid) 3547 { 3548 printf (" "); 3549 } 3550 } 3551 printf ("\n"); 3552 3553 if (propinfo->range && propinfo->num_values > 0) 3554 { 3555 printf ("\t\trange%s: ", 3556 (propinfo->num_values == 2) ? "" : "s"); 3557 for (k = 0; k < propinfo->num_values / 2; k++) 3558 { 3559 printf ("("); 3560 print_output_property_value (False, 32, actual_type, 3561 (unsigned char *) &(propinfo->values[k * 2])); 3562 printf (", "); 3563 print_output_property_value (False, 32, actual_type, 3564 (unsigned char *) &(propinfo->values[k * 2 + 1])); 3565 printf (")"); 3566 if (k < propinfo->num_values / 2 - 1) 3567 printf (", "); 3568 } 3569 printf ("\n"); 3570 } 3571 if (!propinfo->range && propinfo->num_values > 0) 3572 { 3573 printf ("\t\tsupported: "); 3574 for (k = 0; k < propinfo->num_values; k++) 3575 { 3576 print_output_property_value (False, 32, actual_type, 3577 (unsigned char *) &(propinfo->values[k])); 3578 if (k < propinfo->num_values - 1) 3579 printf (", "); 3580 } 3581 printf ("\n"); 3582 } 3583 3584 free(propinfo); 3585 } 3586 } 3587 3588 if (verbose) 3589 { 3590 for (j = 0; j < output_info->nmode; j++) 3591 { 3592 XRRModeInfo *mode = find_mode_by_xid (output_info->modes[j]); 3593 int f; 3594 3595 printf (" %s (0x%x) %6.1fMHz", 3596 mode->name, (int)mode->id, 3597 (double)mode->dotClock / 1000000.0); 3598 for (f = 0; mode_flags[f].flag; f++) 3599 if (mode->modeFlags & mode_flags[f].flag) 3600 printf (" %s", mode_flags[f].string); 3601 if (mode == output->mode_info) 3602 printf (" *current"); 3603 if (j < output_info->npreferred) 3604 printf (" +preferred"); 3605 printf ("\n"); 3606 printf (" h: width %4d start %4d end %4d total %4d skew %4d clock %6.1fKHz\n", 3607 mode->width, mode->hSyncStart, mode->hSyncEnd, 3608 mode->hTotal, mode->hSkew, mode_hsync (mode) / 1000); 3609 printf (" v: height %4d start %4d end %4d total %4d clock %6.1fHz\n", 3610 mode->height, mode->vSyncStart, mode->vSyncEnd, mode->vTotal, 3611 mode_refresh (mode)); 3612 mode->modeFlags |= ModeShown; 3613 } 3614 } 3615 else 3616 { 3617 mode_shown = calloc (output_info->nmode, sizeof (Bool)); 3618 if (!mode_shown) fatal ("out of memory\n"); 3619 for (j = 0; j < output_info->nmode; j++) 3620 { 3621 XRRModeInfo *jmode, *kmode; 3622 int k; 3623 3624 if (mode_shown[j]) continue; 3625 3626 jmode = find_mode_by_xid (output_info->modes[j]); 3627 printf (" "); 3628 printf (" %-12s", jmode->name); 3629 for (k = j; k < output_info->nmode; k++) 3630 { 3631 if (mode_shown[k]) continue; 3632 kmode = find_mode_by_xid (output_info->modes[k]); 3633 if (strcmp (jmode->name, kmode->name) != 0) continue; 3634 mode_shown[k] = True; 3635 kmode->modeFlags |= ModeShown; 3636 printf (" %6.1f", mode_refresh (kmode)); 3637 if (kmode == output->mode_info) 3638 printf ("*"); 3639 else 3640 printf (" "); 3641 if (k < output_info->npreferred) 3642 printf ("+"); 3643 else 3644 printf (" "); 3645 } 3646 printf ("\n"); 3647 } 3648 free (mode_shown); 3649 } 3650 } 3651 for (m = 0; m < res->nmode; m++) 3652 { 3653 XRRModeInfo *mode = &res->modes[m]; 3654 3655 if (!(mode->modeFlags & ModeShown)) 3656 { 3657 printf (" %s (0x%x) %6.1fMHz\n", 3658 mode->name, (int)mode->id, 3659 (double)mode->dotClock / 1000000.0); 3660 printf (" h: width %4d start %4d end %4d total %4d skew %4d clock %6.1fKHz\n", 3661 mode->width, mode->hSyncStart, mode->hSyncEnd, 3662 mode->hTotal, mode->hSkew, mode_hsync (mode) / 1000); 3663 printf (" v: height %4d start %4d end %4d total %4d clock %6.1fHz\n", 3664 mode->height, mode->vSyncStart, mode->vSyncEnd, mode->vTotal, 3665 mode_refresh (mode)); 3666 } 3667 } 3668 exit (0); 3669 } 3670 if (list_providers) { 3671 int k; 3672 3673 if (!has_1_4) { 3674 printf ("RandR 1.4 not supported\n"); 3675 exit (0); 3676 } 3677 3678 get_screen (current); 3679 get_providers (); 3680 3681 if (providers) { 3682 int j; 3683 3684 printf("Providers: number : %d\n", num_providers); 3685 3686 for (j = 0; j < num_providers; j++) { 3687 provider_t *provider = &providers[j]; 3688 XRRProviderInfo *info = provider->info; 3689 3690 printf("Provider %d: id: 0x%x cap: 0x%x", j, (int)provider->provider.xid, info->capabilities); 3691 for (k = 0; k < 4; k++) 3692 if (info->capabilities & (1 << k)) 3693 printf(", %s", capability_name(1<<k)); 3694 3695 printf(" crtcs: %d outputs: %d associated providers: %d name:%s\n", info->ncrtcs, info->noutputs, info->nassociatedproviders, info->name); 3696 } 3697 } 3698 } 3699 3700 sc = XRRGetScreenInfo (dpy, root); 3701 3702 if (sc == NULL) 3703 exit (1); 3704 3705 current_size = XRRConfigCurrentConfiguration (sc, ¤t_rotation); 3706 3707 sizes = XRRConfigSizes(sc, &nsize); 3708 3709 if (have_pixel_size) { 3710 for (size = 0; size < nsize; size++) 3711 { 3712 if (sizes[size].width == width && sizes[size].height == height) 3713 break; 3714 } 3715 if (size >= nsize) { 3716 fprintf (stderr, 3717 "Size %dx%d not found in available modes\n", width, height); 3718 exit (1); 3719 } 3720 } 3721 else if (size < 0) 3722 size = current_size; 3723 else if (size >= nsize) { 3724 fprintf (stderr, 3725 "Size index %d is too large, there are only %d sizes\n", 3726 size, nsize); 3727 exit (1); 3728 } 3729 3730 if (rot < 0) 3731 { 3732 for (rot = 0; rot < 4; rot++) 3733 if (1 << rot == (current_rotation & 0xf)) 3734 break; 3735 } 3736 3737 current_rate = XRRConfigCurrentRate (sc); 3738 3739 if (rate < 0) 3740 { 3741 if (size == current_size) 3742 rate = current_rate; 3743 else 3744 rate = 0; 3745 } 3746 else 3747 { 3748 rates = XRRConfigRates (sc, size, &nrate); 3749 for (i = 0; i < nrate; i++) 3750 if (rate == rates[i]) 3751 break; 3752 if (i == nrate) { 3753 fprintf (stderr, "Rate %.1f Hz not available for this size\n", rate); 3754 exit (1); 3755 } 3756 } 3757 3758 if (version) { 3759 int major_version, minor_version; 3760 XRRQueryVersion (dpy, &major_version, &minor_version); 3761 printf("Server reports RandR version %d.%d\n", 3762 major_version, minor_version); 3763 } 3764 3765 if (query || query_1) { 3766 printf(" SZ: Pixels Physical Refresh\n"); 3767 for (i = 0; i < nsize; i++) { 3768 int j; 3769 3770 printf ("%c%-2d %5d x %-5d (%4dmm x%4dmm )", 3771 i == current_size ? '*' : ' ', 3772 i, sizes[i].width, sizes[i].height, 3773 sizes[i].mwidth, sizes[i].mheight); 3774 rates = XRRConfigRates (sc, i, &nrate); 3775 if (nrate) printf (" "); 3776 for (j = 0; j < nrate; j++) 3777 printf ("%c%-4d", 3778 i == current_size && rates[j] == current_rate ? '*' : ' ', 3779 rates[j]); 3780 printf ("\n"); 3781 } 3782 } 3783 3784 { 3785 Rotation rotations = XRRConfigRotations(sc, ¤t_rotation); 3786 3787 if (query) { 3788 printf("Current rotation - %s\n", 3789 rotation_name (current_rotation)); 3790 3791 printf("Current reflection - %s\n", 3792 reflection_name (current_rotation)); 3793 3794 printf ("Rotations possible - "); 3795 for (i = 0; i < 4; i ++) { 3796 if ((rotations >> i) & 1) printf("%s ", direction[i]); 3797 } 3798 printf ("\n"); 3799 3800 printf ("Reflections possible - "); 3801 if (rotations & (RR_Reflect_X|RR_Reflect_Y)) 3802 { 3803 if (rotations & RR_Reflect_X) printf ("X Axis "); 3804 if (rotations & RR_Reflect_Y) printf ("Y Axis"); 3805 } 3806 else 3807 printf ("none"); 3808 printf ("\n"); 3809 } 3810 } 3811 3812 if (verbose) { 3813 printf("Setting size to %d, rotation to %s\n", size, direction[rot]); 3814 3815 printf ("Setting reflection on "); 3816 if (reflection) 3817 { 3818 if (reflection & RR_Reflect_X) printf ("X Axis "); 3819 if (reflection & RR_Reflect_Y) printf ("Y Axis"); 3820 } 3821 else 3822 printf ("neither axis"); 3823 printf ("\n"); 3824 3825 if (reflection & RR_Reflect_X) printf("Setting reflection on X axis\n"); 3826 3827 if (reflection & RR_Reflect_Y) printf("Setting reflection on Y axis\n"); 3828 } 3829 3830 /* we should test configureNotify on the root window */ 3831 XSelectInput (dpy, root, StructureNotifyMask); 3832 3833 if (setit && !dryrun) XRRSelectInput (dpy, root, 3834 RRScreenChangeNotifyMask); 3835 if (setit && !dryrun) { 3836 Rotation rotation = 1 << rot; 3837 status = XRRSetScreenConfigAndRate (dpy, sc, root, (SizeID) size, 3838 (Rotation) (rotation | reflection), 3839 rate, CurrentTime); 3840 } 3841 3842 if (setit && !dryrun && status == RRSetConfigFailed) { 3843 printf ("Failed to change the screen configuration!\n"); 3844 ret = 1; 3845 } 3846 3847 if (verbose && setit && !dryrun && size != current_size) { 3848 if (status == RRSetConfigSuccess) 3849 { 3850 Bool seen_screen = False; 3851 while (!seen_screen) { 3852 int spo; 3853 XNextEvent(dpy, (XEvent *) &event); 3854 3855 printf ("Event received, type = %d\n", event.type); 3856 /* update Xlib's knowledge of the event */ 3857 XRRUpdateConfiguration (&event); 3858 if (event.type == ConfigureNotify) 3859 printf("Received ConfigureNotify Event!\n"); 3860 3861 switch (event.type - event_base) { 3862 case RRScreenChangeNotify: 3863 sce = (XRRScreenChangeNotifyEvent *) &event; 3864 3865 printf("Got a screen change notify event!\n"); 3866 printf(" window = %d\n root = %d\n size_index = %d\n rotation %d\n", 3867 (int) sce->window, (int) sce->root, 3868 sce->size_index, sce->rotation); 3869 printf(" timestamp = %ld, config_timestamp = %ld\n", 3870 sce->timestamp, sce->config_timestamp); 3871 printf(" Rotation = %x\n", sce->rotation); 3872 printf(" %d X %d pixels, %d X %d mm\n", 3873 sce->width, sce->height, sce->mwidth, sce->mheight); 3874 printf("Display width %d, height %d\n", 3875 DisplayWidth(dpy, screen), DisplayHeight(dpy, screen)); 3876 printf("Display widthmm %d, heightmm %d\n", 3877 DisplayWidthMM(dpy, screen), DisplayHeightMM(dpy, screen)); 3878 spo = sce->subpixel_order; 3879 if ((spo < 0) || (spo > 5)) 3880 printf ("Unknown subpixel order, value = %d\n", spo); 3881 else printf ("new Subpixel rendering model is %s\n", order[spo]); 3882 seen_screen = True; 3883 break; 3884 default: 3885 if (event.type != ConfigureNotify) 3886 printf("unknown event received, type = %d!\n", event.type); 3887 } 3888 } 3889 } 3890 } 3891 XRRFreeScreenConfigInfo(sc); 3892 return(ret); 3893} 3894