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