From 7f9b9fc892f65943bd7700620f3db75ad2b5e824 Mon Sep 17 00:00:00 2001 From: matthieu Date: Sat, 24 Nov 2007 16:58:12 +0000 Subject: [PATCH] xrandr 1.2.2 --- app/xrandr/Makefile.am | 2 +- app/xrandr/config.guess | 56 +- app/xrandr/config.sub | 47 +- app/xrandr/configure.ac | 4 +- app/xrandr/xrandr.c | 2958 ++++++++++++++++++++++++++++++++++----- app/xrandr/xrandr.man | 183 ++- 6 files changed, 2845 insertions(+), 405 deletions(-) diff --git a/app/xrandr/Makefile.am b/app/xrandr/Makefile.am index 178585d99..26c83b8c0 100644 --- a/app/xrandr/Makefile.am +++ b/app/xrandr/Makefile.am @@ -21,7 +21,7 @@ bin_PROGRAMS = xrandr -xrandr_CFLAGS = $(XRANDR_CFLAGS) +AM_CFLAGS = $(XRANDR_CFLAGS) xrandr_LDADD = $(XRANDR_LIBS) xrandr_SOURCES = \ diff --git a/app/xrandr/config.guess b/app/xrandr/config.guess index 917bbc50f..c38553dc7 100644 --- a/app/xrandr/config.guess +++ b/app/xrandr/config.guess @@ -3,7 +3,7 @@ # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. -timestamp='2005-07-08' +timestamp='2006-02-23' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by @@ -106,7 +106,7 @@ set_cc_for_build=' trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; : ${TMPDIR=/tmp} ; - { tmp=`(umask 077 && mktemp -d -q "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || + { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; @@ -206,6 +206,9 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:ekkoBSD:*:*) echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} exit ;; + *:SolidBSD:*:*) + echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} + exit ;; macppc:MirBSD:*:*) echo powerppc-unknown-mirbsd${UNAME_RELEASE} exit ;; @@ -764,7 +767,12 @@ EOF echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} exit ;; *:FreeBSD:*:*) - echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + case ${UNAME_MACHINE} in + pc98) + echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + *) + echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + esac exit ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin @@ -772,6 +780,9 @@ EOF i*:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit ;; + i*:MSYS_NT-*:*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit ;; i*:windows32*:*) # uname -m includes "-pc" on this system. echo ${UNAME_MACHINE}-mingw32 @@ -779,8 +790,11 @@ EOF i*:PW*:*) echo ${UNAME_MACHINE}-pc-pw32 exit ;; - x86:Interix*:[34]*) - echo i586-pc-interix${UNAME_RELEASE}|sed -e 's/\..*//' + x86:Interix*:[345]*) + echo i586-pc-interix${UNAME_RELEASE} + exit ;; + EM64T:Interix*:[345]*) + echo x86_64-unknown-interix${UNAME_RELEASE} exit ;; [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) echo i${UNAME_MACHINE}-pc-mks @@ -794,7 +808,7 @@ EOF i*:UWIN*:*) echo ${UNAME_MACHINE}-pc-uwin exit ;; - amd64:CYGWIN*:*:*) + amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) echo x86_64-unknown-cygwin exit ;; p*:CYGWIN*:*) @@ -851,7 +865,11 @@ EOF #endif #endif EOF - eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=` + eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' + /^CPU/{ + s: ::g + p + }'`" test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } ;; mips64:Linux:*:*) @@ -870,9 +888,16 @@ EOF #endif #endif EOF - eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=` + eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' + /^CPU/{ + s: ::g + p + }'`" test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } ;; + or32:Linux:*:*) + echo or32-unknown-linux-gnu + exit ;; ppc:Linux:*:*) echo powerpc-unknown-linux-gnu exit ;; @@ -916,6 +941,9 @@ EOF sparc:Linux:*:* | sparc64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; + vax:Linux:*:*) + echo ${UNAME_MACHINE}-dec-linux-gnu + exit ;; x86_64:Linux:*:*) echo x86_64-unknown-linux-gnu exit ;; @@ -961,7 +989,7 @@ EOF LIBC=gnulibc1 # endif #else - #ifdef __INTEL_COMPILER + #if defined(__INTEL_COMPILER) || defined(__PGI) || defined(__sun) LIBC=gnu #else LIBC=gnuaout @@ -971,7 +999,11 @@ EOF LIBC=dietlibc #endif EOF - eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=` + eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' + /^LIBC/{ + s: ::g + p + }'`" test x"${LIBC}" != x && { echo "${UNAME_MACHINE}-pc-linux-${LIBC}" exit @@ -1182,7 +1214,6 @@ EOF *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown case $UNAME_PROCESSOR in - *86) UNAME_PROCESSOR=i686 ;; unknown) UNAME_PROCESSOR=powerpc ;; esac echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} @@ -1261,6 +1292,9 @@ EOF i*86:skyos:*:*) echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' exit ;; + i*86:rdos:*:*) + echo ${UNAME_MACHINE}-pc-rdos + exit ;; esac #echo '(No uname command or uname output not recognized.)' 1>&2 diff --git a/app/xrandr/config.sub b/app/xrandr/config.sub index 1c366dfde..ad9f39571 100644 --- a/app/xrandr/config.sub +++ b/app/xrandr/config.sub @@ -3,7 +3,7 @@ # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. -timestamp='2005-07-08' +timestamp='2006-02-23' # This file is (in principle) common to ALL GNU software. # The presence of a machine in this file suggests that SOME GNU software @@ -119,8 +119,9 @@ esac # Here we must recognize all the valid KERNEL-OS combinations. maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in - nto-qnx* | linux-gnu* | linux-dietlibc | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | \ - kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | storm-chaos* | os2-emx* | rtmk-nova*) + nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \ + uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \ + storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; @@ -171,6 +172,10 @@ case $os in -hiux*) os=-hiuxwe2 ;; + -sco6) + os=-sco5v6 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; -sco5) os=-sco3.2v5 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` @@ -187,6 +192,10 @@ case $os in # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; + -sco5v6*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; -sco*) os=-sco3.2v2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` @@ -239,7 +248,7 @@ case $basic_machine in | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | i370 | i860 | i960 | ia64 \ | ip2k | iq2000 \ - | m32r | m32rle | m68000 | m68k | m88k | maxq | mcore \ + | m32r | m32rle | m68000 | m68k | m88k | maxq | mb | microblaze | mcore \ | mips | mipsbe | mipseb | mipsel | mipsle \ | mips16 \ | mips64 | mips64el \ @@ -257,8 +266,9 @@ case $basic_machine in | mipsisa64sr71k | mipsisa64sr71kel \ | mipstx39 | mipstx39el \ | mn10200 | mn10300 \ - | ms1 \ + | mt \ | msp430 \ + | nios | nios2 \ | ns16k | ns32k \ | or32 \ | pdp10 | pdp11 | pj | pjl \ @@ -286,6 +296,9 @@ case $basic_machine in ;; m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) ;; + ms1) + basic_machine=mt-unknown + ;; # We use `pc' rather than `unknown' # because (1) that's what they normally are, and @@ -336,8 +349,9 @@ case $basic_machine in | mipsisa64sr71k-* | mipsisa64sr71kel-* \ | mipstx39-* | mipstx39el-* \ | mmix-* \ - | ms1-* \ + | mt-* \ | msp430-* \ + | nios-* | nios2-* \ | none-* | np1-* | ns16k-* | ns32k-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ @@ -696,6 +710,9 @@ case $basic_machine in basic_machine=i386-pc os=-msdos ;; + ms1-*) + basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` + ;; mvs) basic_machine=i370-ibm os=-mvs @@ -803,6 +820,12 @@ case $basic_machine in pc532 | pc532-*) basic_machine=ns32k-pc532 ;; + pc98) + basic_machine=i386-pc + ;; + pc98-*) + basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; pentium | p5 | k5 | k6 | nexgen | viac3) basic_machine=i586-pc ;; @@ -859,6 +882,10 @@ case $basic_machine in basic_machine=i586-unknown os=-pw32 ;; + rdos) + basic_machine=i386-pc + os=-rdos + ;; rom68k) basic_machine=m68k-rom68k os=-coff @@ -1174,21 +1201,23 @@ case $os in | -aos* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ - | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* | -openbsd* \ + | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ + | -openbsd* | -solidbsd* \ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* \ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ - | -mingw32* | -linux-gnu* | -linux-uclibc* | -uxpv* | -beos* | -mpeix* | -udk* \ + | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \ + | -uxpv* | -beos* | -mpeix* | -udk* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ - | -skyos* | -haiku*) + | -skyos* | -haiku* | -rdos*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) diff --git a/app/xrandr/configure.ac b/app/xrandr/configure.ac index dc5fa8ed3..965e270c7 100644 --- a/app/xrandr/configure.ac +++ b/app/xrandr/configure.ac @@ -22,7 +22,7 @@ dnl dnl Process this file with autoconf to create configure. AC_PREREQ([2.57]) -AC_INIT(xrandr,[1.0.2], [https://bugs.freedesktop.org/enter_bug.cgi?product=xorg],xrandr) +AC_INIT(xrandr,[1.2.2], [https://bugs.freedesktop.org/enter_bug.cgi?product=xorg],xrandr) AM_INIT_AUTOMAKE([dist-bzip2]) AM_MAINTAINER_MODE @@ -32,7 +32,7 @@ AC_PROG_CC AC_PROG_INSTALL # Checks for pkg-config packages -PKG_CHECK_MODULES(XRANDR, xrandr xrender x11) +PKG_CHECK_MODULES(XRANDR, xrandr >= 1.2.0 xrender x11) AC_SUBST(XRANDR_CFLAGS) AC_SUBST(XRANDR_LIBS) diff --git a/app/xrandr/xrandr.c b/app/xrandr/xrandr.c index 09a9de682..c3bc6dce0 100644 --- a/app/xrandr/xrandr.c +++ b/app/xrandr/xrandr.c @@ -1,28 +1,27 @@ -/* $XdotOrg: app/xrandr/xrandr.c,v 1.6 2006/04/25 22:54:01 alanc Exp $ - * $XFree86: xc/programs/xrandr/xrandr.c,v 1.11 2002/10/14 18:01:43 keithp Exp $ - * +/* * Copyright © 2001 Keith Packard, member of The XFree86 Project, Inc. * Copyright © 2002 Hewlett Packard Company, Inc. + * Copyright © 2006 Intel Corporation * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that - * copyright notice and this permission notice appear in supporting - * documentation, and that the name of Keith Packard or HP not be used in - * advertising or publicity pertaining to distribution of the software without - * specific, written prior permission. Keith Packard and HP makes no - * representations about the suitability of this software for any purpose. It - * is provided "as is" without express or implied warranty. + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. * - * KEITH PACKARD and HP DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. * - * Blame Jim Gettys for any bugs; he wrote most of the client side code, + * Thanks to Jim Gettys who wrote most of the client side code, * and part of the server code for randr. */ @@ -30,369 +29,2634 @@ #include #include #include +#include #include #include /* we share subpixel information */ #include #include +#include +#include -static char *program_name; +#if RANDR_MAJOR > 1 || (RANDR_MAJOR == 1 && RANDR_MINOR >= 2) +#define HAS_RANDR_1_2 1 +#endif + +static char *program_name; +static Display *dpy; +static Window root; +static int screen = -1; +static Bool verbose = False; +static Bool automatic = False; +static Bool properties = False; static char *direction[5] = { - "normal", - "left", - "inverted", - "right", - "\n"}; + "normal", + "left", + "inverted", + "right", + "\n"}; + +static char *reflections[5] = { + "normal", + "x", + "y", + "xy", + "\n"}; /* subpixel order */ static char *order[6] = { - "unknown", - "horizontal rgb", - "horizontal bgr", - "vertical rgb", - "vertical bgr", - "no subpixels"}; + "unknown", + "horizontal rgb", + "horizontal bgr", + "vertical rgb", + "vertical bgr", + "no subpixels"}; +static const struct { + char *string; + unsigned long flag; +} mode_flags[] = { + { "+HSync", RR_HSyncPositive }, + { "-HSync", RR_HSyncNegative }, + { "+VSync", RR_VSyncPositive }, + { "-VSync", RR_VSyncNegative }, + { "Interlace", RR_Interlace }, + { "DoubleScan", RR_DoubleScan }, + { "CSync", RR_CSync }, + { "+CSync", RR_CSyncPositive }, + { "-CSync", RR_CSyncNegative }, + { NULL, 0 } +}; static void usage(void) { - fprintf(stderr, "usage: %s [options]\n", program_name); - fprintf(stderr, " where options are:\n"); - fprintf(stderr, " -display or -d \n"); - fprintf(stderr, " -help\n"); - fprintf(stderr, " -o \n"); - fprintf(stderr, " or --orientation \n"); - fprintf(stderr, " -q or --query\n"); - fprintf(stderr, " -s /x or --size /x\n"); - fprintf(stderr, " -r or --rate \n"); - fprintf(stderr, " -v or --version\n"); - fprintf(stderr, " -x (reflect in x)\n"); - fprintf(stderr, " -y (reflect in y)\n"); - fprintf(stderr, " --screen \n"); - fprintf(stderr, " --verbose\n"); - - exit(1); - /*NOTREACHED*/ + fprintf(stderr, "usage: %s [options]\n", program_name); + fprintf(stderr, " where options are:\n"); + fprintf(stderr, " -display or -d \n"); + fprintf(stderr, " -help\n"); + fprintf(stderr, " -o \n"); + fprintf(stderr, " or --orientation \n"); + fprintf(stderr, " -q or --query\n"); + fprintf(stderr, " -s /x or --size /x\n"); + fprintf(stderr, " -r or --rate or --refresh \n"); + fprintf(stderr, " -v or --version\n"); + fprintf(stderr, " -x (reflect in x)\n"); + fprintf(stderr, " -y (reflect in y)\n"); + fprintf(stderr, " --screen \n"); + fprintf(stderr, " --verbose\n"); + fprintf(stderr, " --dryrun\n"); +#if HAS_RANDR_1_2 + fprintf(stderr, " --prop or --properties\n"); + fprintf(stderr, " --fb x\n"); + fprintf(stderr, " --fbmm x\n"); + fprintf(stderr, " --dpi /\n"); +#if 0 + fprintf(stderr, " --clone\n"); + fprintf(stderr, " --extend\n"); +#endif + fprintf(stderr, " --output \n"); + fprintf(stderr, " --auto\n"); + fprintf(stderr, " --mode \n"); + fprintf(stderr, " --preferred\n"); + fprintf(stderr, " --pos x\n"); + fprintf(stderr, " --rate or --refresh \n"); + fprintf(stderr, " --reflect normal,x,y,xy\n"); + fprintf(stderr, " --rotate normal,inverted,left,right\n"); + fprintf(stderr, " --left-of \n"); + fprintf(stderr, " --right-of \n"); + fprintf(stderr, " --above \n"); + fprintf(stderr, " --below \n"); + fprintf(stderr, " --same-as \n"); + fprintf(stderr, " --set \n"); + fprintf(stderr, " --off\n"); + fprintf(stderr, " --crtc \n"); + fprintf(stderr, " --newmode \n"); + fprintf(stderr, " \n"); + fprintf(stderr, " \n"); + fprintf(stderr, " [+HSync] [-HSync] [+VSync] [-VSync]\n"); + fprintf(stderr, " --rmmode \n"); + fprintf(stderr, " --addmode \n"); + fprintf(stderr, " --delmode \n"); +#endif + + exit(1); + /*NOTREACHED*/ +} + +static void +fatal (const char *format, ...) +{ + va_list ap; + + va_start (ap, format); + fprintf (stderr, "%s: ", program_name); + vfprintf (stderr, format, ap); + va_end (ap); + exit (1); + /*NOTREACHED*/ +} + +static char * +rotation_name (Rotation rotation) +{ + int i; + + if ((rotation & 0xf) == 0) + return "normal"; + for (i = 0; i < 4; i++) + if (rotation & (1 << i)) + return direction[i]; + return "invalid rotation"; +} + +static char * +reflection_name (Rotation rotation) +{ + rotation &= (RR_Reflect_X|RR_Reflect_Y); + switch (rotation) { + case 0: + return "none"; + case RR_Reflect_X: + return "X axis"; + case RR_Reflect_Y: + return "Y axis"; + case RR_Reflect_X|RR_Reflect_Y: + return "X and Y axis"; + } + return "invalid reflection"; +} + +#if HAS_RANDR_1_2 +typedef enum _policy { + clone, extend +} policy_t; + +typedef enum _relation { + left_of, right_of, above, below, same_as, +} relation_t; + +typedef enum _changes { + changes_none = 0, + changes_crtc = (1 << 0), + changes_mode = (1 << 1), + changes_relation = (1 << 2), + changes_position = (1 << 3), + changes_rotation = (1 << 4), + changes_reflection = (1 << 5), + changes_automatic = (1 << 6), + changes_refresh = (1 << 7), + changes_property = (1 << 8), +} changes_t; + +typedef enum _name_kind { + name_none = 0, + name_string = (1 << 0), + name_xid = (1 << 1), + name_index = (1 << 2), + name_preferred = (1 << 3), +} name_kind_t; + +typedef struct { + name_kind_t kind; + char *string; + XID xid; + int index; +} name_t; + +typedef struct _crtc crtc_t; +typedef struct _output output_t; +typedef struct _umode umode_t; +typedef struct _output_prop output_prop_t; + +struct _crtc { + name_t crtc; + Bool changing; + XRRCrtcInfo *crtc_info; + + XRRModeInfo *mode_info; + int x; + int y; + Rotation rotation; + output_t **outputs; + int noutput; +}; + +struct _output_prop { + struct _output_prop *next; + char *name; + char *value; +}; + +struct _output { + struct _output *next; + + changes_t changes; + + output_prop_t *props; + + name_t output; + XRROutputInfo *output_info; + + name_t crtc; + crtc_t *crtc_info; + crtc_t *current_crtc_info; + + name_t mode; + float refresh; + XRRModeInfo *mode_info; + + name_t addmode; + + relation_t relation; + char *relative_to; + + int x, y; + Rotation rotation; + + Bool automatic; +}; + +typedef enum _umode_action { + umode_create, umode_destroy, umode_add, umode_delete +} umode_action_t; + + +struct _umode { + struct _umode *next; + + umode_action_t action; + XRRModeInfo mode; + name_t output; + name_t name; +}; + +static char *connection[3] = { + "connected", + "disconnected", + "unknown connection"}; + +#define OUTPUT_NAME 1 + +#define CRTC_OFF 2 +#define CRTC_UNSET 3 +#define CRTC_INDEX 0x40000000 + +#define MODE_NAME 1 +#define MODE_OFF 2 +#define MODE_UNSET 3 +#define MODE_PREF 4 + +#define POS_UNSET -1 + +static output_t *outputs = NULL; +static output_t **outputs_tail = &outputs; +static crtc_t *crtcs; +static umode_t *umodes; +static int num_crtcs; +static XRRScreenResources *res; +static int fb_width = 0, fb_height = 0; +static int fb_width_mm = 0, fb_height_mm = 0; +static float dpi = 0; +static char *dpi_output = NULL; +static Bool dryrun = False; +static int minWidth, maxWidth, minHeight, maxHeight; +static Bool has_1_2 = False; + +static int +mode_height (XRRModeInfo *mode_info, Rotation rotation) +{ + switch (rotation & 0xf) { + case RR_Rotate_0: + case RR_Rotate_180: + return mode_info->height; + case RR_Rotate_90: + case RR_Rotate_270: + return mode_info->width; + default: + return 0; + } +} + +static int +mode_width (XRRModeInfo *mode_info, Rotation rotation) +{ + switch (rotation & 0xf) { + case RR_Rotate_0: + case RR_Rotate_180: + return mode_info->width; + case RR_Rotate_90: + case RR_Rotate_270: + return mode_info->height; + default: + return 0; + } +} + +/* v refresh frequency in Hz */ +static float +mode_refresh (XRRModeInfo *mode_info) +{ + float rate; + + if (mode_info->hTotal && mode_info->vTotal) + rate = ((float) mode_info->dotClock / + ((float) mode_info->hTotal * (float) mode_info->vTotal)); + else + rate = 0; + return rate; +} + +/* h sync frequency in Hz */ +static float +mode_hsync (XRRModeInfo *mode_info) +{ + float rate; + + if (mode_info->hTotal) + rate = (float) mode_info->dotClock / (float) mode_info->hTotal; + else + rate = 0; + return rate; +} + +static void +init_name (name_t *name) +{ + name->kind = name_none; +} + +static void +set_name_string (name_t *name, char *string) +{ + name->kind |= name_string; + name->string = string; +} + +static void +set_name_xid (name_t *name, XID xid) +{ + name->kind |= name_xid; + name->xid = xid; +} + +static void +set_name_index (name_t *name, int index) +{ + name->kind |= name_index; + name->index = index; +} + +static void +set_name_preferred (name_t *name) +{ + name->kind |= name_preferred; +} + +static void +set_name_all (name_t *name, name_t *old) +{ + if (old->kind & name_xid) + name->xid = old->xid; + if (old->kind & name_string) + name->string = old->string; + if (old->kind & name_index) + name->index = old->index; + name->kind |= old->kind; +} + +static void +set_name (name_t *name, char *string, name_kind_t valid) +{ + XID xid; + int index; + + if ((valid & name_xid) && sscanf (string, "0x%x", &xid) == 1) + set_name_xid (name, xid); + else if ((valid & name_index) && sscanf (string, "%d", &index) == 1) + set_name_index (name, index); + else if (valid & name_string) + set_name_string (name, string); + else + usage (); +} + +static output_t * +add_output (void) +{ + output_t *output = calloc (1, sizeof (output_t)); + + if (!output) + fatal ("out of memory"); + output->next = NULL; + *outputs_tail = output; + outputs_tail = &output->next; + return output; +} + +static output_t * +find_output (name_t *name) +{ + output_t *output; + + for (output = outputs; output; output = output->next) + { + name_kind_t common = name->kind & output->output.kind; + + if ((common & name_xid) && name->xid == output->output.xid) + break; + if ((common & name_string) && !strcmp (name->string, output->output.string)) + break; + if ((common & name_index) && name->index == output->output.index) + break; + } + return output; +} + +static output_t * +find_output_by_xid (RROutput output) +{ + name_t output_name; + + init_name (&output_name); + set_name_xid (&output_name, output); + return find_output (&output_name); +} + +static output_t * +find_output_by_name (char *name) +{ + name_t output_name; + + init_name (&output_name); + set_name_string (&output_name, name); + return find_output (&output_name); +} + +static crtc_t * +find_crtc (name_t *name) +{ + int c; + crtc_t *crtc = NULL; + + for (c = 0; c < num_crtcs; c++) + { + name_kind_t common; + + crtc = &crtcs[c]; + common = name->kind & crtc->crtc.kind; + + if ((common & name_xid) && name->xid == crtc->crtc.xid) + break; + if ((common & name_string) && !strcmp (name->string, crtc->crtc.string)) + break; + if ((common & name_index) && name->index == crtc->crtc.index) + break; + crtc = NULL; + } + return crtc; +} + +static crtc_t * +find_crtc_by_xid (RRCrtc crtc) +{ + name_t crtc_name; + + init_name (&crtc_name); + set_name_xid (&crtc_name, crtc); + return find_crtc (&crtc_name); +} + +static XRRModeInfo * +find_mode (name_t *name, float refresh) +{ + int m; + XRRModeInfo *best = NULL; + float bestDist = 0; + + for (m = 0; m < res->nmode; m++) + { + XRRModeInfo *mode = &res->modes[m]; + if ((name->kind & name_xid) && name->xid == mode->id) + { + best = mode; + break; + } + if ((name->kind & name_string) && !strcmp (name->string, mode->name)) + { + float dist; + + if (refresh) + dist = fabs (mode_refresh (mode) - refresh); + else + dist = 0; + if (!best || dist < bestDist) + { + bestDist = dist; + best = mode; + } + break; + } + } + return best; +} + +static XRRModeInfo * +find_mode_by_xid (RRMode mode) +{ + name_t mode_name; + + init_name (&mode_name); + set_name_xid (&mode_name, mode); + return find_mode (&mode_name, 0); +} + +static XRRModeInfo * +find_mode_by_name (char *name) +{ + name_t mode_name; + init_name (&mode_name); + set_name_string (&mode_name, name); + return find_mode (&mode_name, 0); +} + +static +XRRModeInfo * +find_mode_for_output (output_t *output, name_t *name) +{ + XRROutputInfo *output_info = output->output_info; + int m; + XRRModeInfo *best = NULL; + float bestDist = 0; + + for (m = 0; m < output_info->nmode; m++) + { + XRRModeInfo *mode; + + mode = find_mode_by_xid (output_info->modes[m]); + if (!mode) continue; + if ((name->kind & name_xid) && name->xid == mode->id) + { + best = mode; + break; + } + if ((name->kind & name_string) && !strcmp (name->string, mode->name)) + { + float dist; + + if (output->refresh) + dist = fabs (mode_refresh (mode) - output->refresh); + else + dist = 0; + if (!best || dist < bestDist) + { + bestDist = dist; + best = mode; + } + } + } + return best; +} + +XRRModeInfo * +preferred_mode (output_t *output) +{ + XRROutputInfo *output_info = output->output_info; + int m; + XRRModeInfo *best; + int bestDist; + + best = NULL; + bestDist = 0; + for (m = 0; m < output_info->nmode; m++) + { + XRRModeInfo *mode_info = find_mode_by_xid (output_info->modes[m]); + int dist; + + if (m < output_info->npreferred) + dist = 0; + else if (output_info->mm_height) + dist = (1000 * DisplayHeight(dpy, screen) / DisplayHeightMM(dpy, screen) - + 1000 * mode_info->height / output_info->mm_height); + else + dist = DisplayHeight(dpy, screen) - mode_info->height; + + if (dist < 0) dist = -dist; + if (!best || dist < bestDist) + { + best = mode_info; + bestDist = dist; + } + } + return best; +} + +static Bool +output_can_use_crtc (output_t *output, crtc_t *crtc) +{ + XRROutputInfo *output_info = output->output_info; + int c; + + for (c = 0; c < output_info->ncrtc; c++) + if (output_info->crtcs[c] == crtc->crtc.xid) + return True; + return False; +} + +static Bool +output_can_use_mode (output_t *output, XRRModeInfo *mode) +{ + XRROutputInfo *output_info = output->output_info; + int m; + + for (m = 0; m < output_info->nmode; m++) + if (output_info->modes[m] == mode->id) + return True; + return False; +} + +static Bool +crtc_can_use_rotation (crtc_t *crtc, Rotation rotation) +{ + Rotation rotations = crtc->crtc_info->rotations; + Rotation dir = rotation & (RR_Rotate_0|RR_Rotate_90|RR_Rotate_180|RR_Rotate_270); + Rotation reflect = rotation & (RR_Reflect_X|RR_Reflect_Y); + if (((rotations & dir) != 0) && ((rotations & reflect) == reflect)) + return True; + return False; +} + +/* + * Report only rotations that are supported by all crtcs + */ +static Rotation +output_rotations (output_t *output) +{ + Bool found = False; + Rotation rotation = RR_Rotate_0; + XRROutputInfo *output_info = output->output_info; + int c; + + for (c = 0; c < output_info->ncrtc; c++) + { + crtc_t *crtc = find_crtc_by_xid (output_info->crtcs[c]); + if (crtc) + { + if (!found) { + rotation = crtc->crtc_info->rotations; + found = True; + } else + rotation &= crtc->crtc_info->rotations; + } + } + return rotation; +} + +static Bool +output_can_use_rotation (output_t *output, Rotation rotation) +{ + XRROutputInfo *output_info = output->output_info; + int c; + + /* make sure all of the crtcs can use this rotation. + * yes, this is not strictly necessary, but it is + * simpler,and we expect most drivers to either + * support rotation everywhere or nowhere + */ + for (c = 0; c < output_info->ncrtc; c++) + { + crtc_t *crtc = find_crtc_by_xid (output_info->crtcs[c]); + if (crtc && !crtc_can_use_rotation (crtc, rotation)) + return False; + } + return True; +} + +static void +set_output_info (output_t *output, RROutput xid, XRROutputInfo *output_info) +{ + /* sanity check output info */ + if (output_info->connection != RR_Disconnected && !output_info->nmode) + fatal ("Output %s is not disconnected but has no modes\n", + output_info->name); + + /* set output name and info */ + if (!(output->output.kind & name_xid)) + set_name_xid (&output->output, xid); + if (!(output->output.kind & name_string)) + set_name_string (&output->output, output_info->name); + output->output_info = output_info; + + /* set crtc name and info */ + if (!(output->changes & changes_crtc)) + set_name_xid (&output->crtc, output_info->crtc); + + if (output->crtc.kind == name_xid && output->crtc.xid == None) + output->crtc_info = NULL; + else + { + output->crtc_info = find_crtc (&output->crtc); + if (!output->crtc_info) + { + if (output->crtc.kind & name_xid) + fatal ("cannot find crtc 0x%x\n", output->crtc.xid); + if (output->crtc.kind & name_index) + fatal ("cannot find crtc %d\n", output->crtc.index); + } + if (!output_can_use_crtc (output, output->crtc_info)) + fatal ("output %s cannot use crtc 0x%x\n", output->output.string, + output->crtc_info->crtc.xid); + } + + /* set mode name and info */ + if (!(output->changes & changes_mode)) + { + if (output->crtc_info) + set_name_xid (&output->mode, output->crtc_info->crtc_info->mode); + else + set_name_xid (&output->mode, None); + if (output->mode.xid) + { + output->mode_info = find_mode_by_xid (output->mode.xid); + if (!output->mode_info) + fatal ("server did not report mode 0x%x for output %s\n", + output->mode.xid, output->output.string); + } + else + output->mode_info = NULL; + } + else if (output->mode.kind == name_xid && output->mode.xid == None) + output->mode_info = NULL; + else + { + if (output->mode.kind == name_preferred) + output->mode_info = preferred_mode (output); + else + output->mode_info = find_mode_for_output (output, &output->mode); + if (!output->mode_info) + { + if (output->mode.kind & name_preferred) + fatal ("cannot find preferred mode\n"); + if (output->mode.kind & name_string) + fatal ("cannot find mode %s\n", output->mode.string); + if (output->mode.kind & name_xid) + fatal ("cannot find mode 0x%x\n", output->mode.xid); + } + if (!output_can_use_mode (output, output->mode_info)) + fatal ("output %s cannot use mode %s\n", output->output.string, + output->mode_info->name); + } + + /* set position */ + if (!(output->changes & changes_position)) + { + if (output->crtc_info) + { + output->x = output->crtc_info->crtc_info->x; + output->y = output->crtc_info->crtc_info->y; + } + else + { + output->x = 0; + output->y = 0; + } + } + + /* set rotation */ + if (!(output->changes & changes_rotation)) + { + output->rotation &= ~0xf; + if (output->crtc_info) + output->rotation |= (output->crtc_info->crtc_info->rotation & 0xf); + else + output->rotation = RR_Rotate_0; + } + if (!(output->changes & changes_reflection)) + { + output->rotation &= ~(RR_Reflect_X|RR_Reflect_Y); + if (output->crtc_info) + output->rotation |= (output->crtc_info->crtc_info->rotation & + (RR_Reflect_X|RR_Reflect_Y)); + } + if (!output_can_use_rotation (output, output->rotation)) + fatal ("output %s cannot use rotation \"%s\" reflection \"%s\"\n", + output->output.string, + rotation_name (output->rotation), + reflection_name (output->rotation)); +} + +static void +get_screen (void) +{ + if (!has_1_2) + fatal ("Server RandR version before 1.2\n"); + + XRRGetScreenSizeRange (dpy, root, &minWidth, &minHeight, + &maxWidth, &maxHeight); + + res = XRRGetScreenResources (dpy, root); + if (!res) fatal ("could not get screen resources"); +} + +static void +get_crtcs (void) +{ + int c; + + num_crtcs = res->ncrtc; + crtcs = calloc (num_crtcs, sizeof (crtc_t)); + if (!crtcs) fatal ("out of memory"); + + for (c = 0; c < res->ncrtc; c++) + { + XRRCrtcInfo *crtc_info = XRRGetCrtcInfo (dpy, res, res->crtcs[c]); + set_name_xid (&crtcs[c].crtc, res->crtcs[c]); + set_name_index (&crtcs[c].crtc, c); + if (!crtc_info) fatal ("could not get crtc 0x%x information", res->crtcs[c]); + crtcs[c].crtc_info = crtc_info; + if (crtc_info->mode == None) + { + crtcs[c].mode_info = NULL; + crtcs[c].x = 0; + crtcs[c].y = 0; + crtcs[c].rotation = RR_Rotate_0; + } + } +} + +static void +crtc_add_output (crtc_t *crtc, output_t *output) +{ + if (crtc->outputs) + crtc->outputs = realloc (crtc->outputs, (crtc->noutput + 1) * sizeof (output_t *)); + else + { + crtc->outputs = malloc (sizeof (output_t *)); + crtc->x = output->x; + crtc->y = output->y; + crtc->rotation = output->rotation; + crtc->mode_info = output->mode_info; + } + if (!crtc->outputs) fatal ("out of memory"); + crtc->outputs[crtc->noutput++] = output; +} + +static void +set_crtcs (void) +{ + output_t *output; + + for (output = outputs; output; output = output->next) + { + if (!output->mode_info) continue; + crtc_add_output (output->crtc_info, output); + } +} + +static Status +crtc_disable (crtc_t *crtc) +{ + if (verbose) + printf ("crtc %d: disable\n", crtc->crtc.index); + + if (dryrun) + return RRSetConfigSuccess; + return XRRSetCrtcConfig (dpy, res, crtc->crtc.xid, CurrentTime, + 0, 0, None, RR_Rotate_0, NULL, 0); +} + +static Status +crtc_revert (crtc_t *crtc) +{ + XRRCrtcInfo *crtc_info = crtc->crtc_info; + + if (verbose) + printf ("crtc %d: revert\n", crtc->crtc.index); + + if (dryrun) + return RRSetConfigSuccess; + return XRRSetCrtcConfig (dpy, res, crtc->crtc.xid, CurrentTime, + crtc_info->x, crtc_info->y, + crtc_info->mode, crtc_info->rotation, + crtc_info->outputs, crtc_info->noutput); +} + +static Status +crtc_apply (crtc_t *crtc) +{ + RROutput *rr_outputs; + int o; + Status s; + RRMode mode = None; + + if (!crtc->changing || !crtc->mode_info) + return RRSetConfigSuccess; + + rr_outputs = calloc (crtc->noutput, sizeof (RROutput)); + if (!rr_outputs) + return BadAlloc; + for (o = 0; o < crtc->noutput; o++) + rr_outputs[o] = crtc->outputs[o]->output.xid; + mode = crtc->mode_info->id; + if (verbose) { + printf ("crtc %d: %12s %6.1f +%d+%d", crtc->crtc.index, + crtc->mode_info->name, mode_refresh (crtc->mode_info), + crtc->x, crtc->y); + for (o = 0; o < crtc->noutput; o++) + printf (" \"%s\"", crtc->outputs[o]->output.string); + printf ("\n"); + } + + if (dryrun) + s = RRSetConfigSuccess; + else + s = XRRSetCrtcConfig (dpy, res, crtc->crtc.xid, CurrentTime, + crtc->x, crtc->y, mode, crtc->rotation, + rr_outputs, crtc->noutput); + free (rr_outputs); + return s; +} + +static void +screen_revert (void) +{ + if (verbose) + printf ("screen %d: revert\n", screen); + + if (dryrun) + return; + XRRSetScreenSize (dpy, root, + DisplayWidth (dpy, screen), + DisplayHeight (dpy, screen), + DisplayWidthMM (dpy, screen), + DisplayHeightMM (dpy, screen)); +} + +static void +screen_apply (void) +{ + if (fb_width == DisplayWidth (dpy, screen) && + fb_height == DisplayHeight (dpy, screen) && + fb_width_mm == DisplayWidthMM (dpy, screen) && + fb_height_mm == DisplayHeightMM (dpy, screen)) + { + return; + } + if (verbose) + printf ("screen %d: %dx%d %dx%d mm %6.2fdpi\n", screen, + fb_width, fb_height, fb_width_mm, fb_height_mm, dpi); + if (dryrun) + return; + XRRSetScreenSize (dpy, root, fb_width, fb_height, + fb_width_mm, fb_height_mm); +} + +static void +revert (void) +{ + int c; + + /* first disable all crtcs */ + for (c = 0; c < res->ncrtc; c++) + crtc_disable (&crtcs[c]); + /* next reset screen size */ + screen_revert (); + /* now restore all crtcs */ + for (c = 0; c < res->ncrtc; c++) + crtc_revert (&crtcs[c]); +} + +/* + * uh-oh, something bad happened in the middle of changing + * the configuration. Revert to the previous configuration + * and bail + */ +static void +panic (Status s, crtc_t *crtc) +{ + int c = crtc->crtc.index; + char *message; + + switch (s) { + case RRSetConfigSuccess: message = "succeeded"; break; + case BadAlloc: message = "out of memory"; break; + case RRSetConfigFailed: message = "failed"; break; + case RRSetConfigInvalidConfigTime: message = "invalid config time"; break; + case RRSetConfigInvalidTime: message = "invalid time"; break; + default: message = "unknown failure"; break; + } + + fprintf (stderr, "%s: Configure crtc %d %s\n", program_name, c, message); + revert (); + exit (1); +} + +void +apply (void) +{ + Status s; + int c; + + /* + * Turn off any crtcs which are to be disabled or which are + * larger than the target size + */ + for (c = 0; c < res->ncrtc; c++) + { + crtc_t *crtc = &crtcs[c]; + XRRCrtcInfo *crtc_info = crtc->crtc_info; + + /* if this crtc is already disabled, skip it */ + if (crtc_info->mode == None) + continue; + + /* + * If this crtc is to be left enabled, make + * sure the old size fits then new screen + */ + if (crtc->mode_info) + { + XRRModeInfo *old_mode = find_mode_by_xid (crtc_info->mode); + int x, y, w, h; + + if (!old_mode) + panic (RRSetConfigFailed, crtc); + + /* old position and size information */ + x = crtc_info->x; + y = crtc_info->y; + w = mode_width (old_mode, crtc_info->rotation); + h = mode_height (old_mode, crtc_info->rotation); + + /* if it fits, skip it */ + if (x + w <= fb_width && y + h <= fb_height) + continue; + crtc->changing = True; + } + s = crtc_disable (crtc); + if (s != RRSetConfigSuccess) + panic (s, crtc); + } + + /* + * Hold the server grabbed while messing with + * the screen so that apps which notice the resize + * event and ask for xinerama information from the server + * receive up-to-date information + */ + XGrabServer (dpy); + + /* + * Set the screen size + */ + screen_apply (); + + /* + * Set crtcs + */ + + for (c = 0; c < res->ncrtc; c++) + { + crtc_t *crtc = &crtcs[c]; + + s = crtc_apply (crtc); + if (s != RRSetConfigSuccess) + panic (s, crtc); + } + /* + * Release the server grab and let all clients + * respond to the updated state + */ + XUngrabServer (dpy); +} + +/* + * Use current output state to complete the output list + */ +void +get_outputs (void) +{ + int o; + + for (o = 0; o < res->noutput; o++) + { + XRROutputInfo *output_info = XRRGetOutputInfo (dpy, res, res->outputs[o]); + output_t *output; + name_t output_name; + if (!output_info) fatal ("could not get output 0x%x information", res->outputs[o]); + set_name_xid (&output_name, res->outputs[o]); + set_name_index (&output_name, o); + set_name_string (&output_name, output_info->name); + output = find_output (&output_name); + if (!output) + { + output = add_output (); + set_name_all (&output->output, &output_name); + /* + * When global --automatic mode is set, turn on connected but off + * outputs, turn off disconnected but on outputs + */ + if (automatic) + { + switch (output_info->connection) { + case RR_Connected: + if (!output_info->crtc) { + output->changes |= changes_automatic; + output->automatic = True; + } + break; + case RR_Disconnected: + if (output_info->crtc) + { + output->changes |= changes_automatic; + output->automatic = True; + } + break; + } + } + } + + /* + * Automatic mode -- track connection state and enable/disable outputs + * as necessary + */ + if (output->automatic) + { + switch (output_info->connection) { + case RR_Connected: + case RR_UnknownConnection: + if ((!(output->changes & changes_mode))) + { + set_name_preferred (&output->mode); + output->changes |= changes_mode; + } + break; + case RR_Disconnected: + if ((!(output->changes & changes_mode))) + { + set_name_xid (&output->mode, None); + set_name_xid (&output->crtc, None); + output->changes |= changes_mode; + output->changes |= changes_crtc; + } + break; + } + } + + set_output_info (output, res->outputs[o], output_info); + } +} + +void +mark_changing_crtcs (void) +{ + int c; + + for (c = 0; c < num_crtcs; c++) + { + crtc_t *crtc = &crtcs[c]; + int o; + output_t *output; + + /* walk old output list (to catch disables) */ + for (o = 0; o < crtc->crtc_info->noutput; o++) + { + output = find_output_by_xid (crtc->crtc_info->outputs[o]); + if (!output) fatal ("cannot find output 0x%x\n", + crtc->crtc_info->outputs[o]); + if (output->changes) + crtc->changing = True; + } + /* walk new output list */ + for (o = 0; o < crtc->noutput; o++) + { + output = crtc->outputs[o]; + if (output->changes) + crtc->changing = True; + } + } +} + +/* + * Test whether 'crtc' can be used for 'output' + */ +Bool +check_crtc_for_output (crtc_t *crtc, output_t *output) +{ + int c; + int l; + output_t *other; + + for (c = 0; c < output->output_info->ncrtc; c++) + if (output->output_info->crtcs[c] == crtc->crtc.xid) + break; + if (c == output->output_info->ncrtc) + return False; + for (other = outputs; other; other = other->next) + { + if (other == output) + continue; + + if (other->mode_info == NULL) + continue; + + if (other->crtc_info != crtc) + continue; + + /* see if the output connected to the crtc can clone to this output */ + for (l = 0; l < output->output_info->nclone; l++) + if (output->output_info->clones[l] == other->output.xid) + break; + /* not on the list, can't clone */ + if (l == output->output_info->nclone) + return False; + } + + if (crtc->noutput) + { + /* make sure the state matches */ + if (crtc->mode_info != output->mode_info) + return False; + if (crtc->x != output->x) + return False; + if (crtc->y != output->y) + return False; + if (crtc->rotation != output->rotation) + return False; + } + return True; +} + +crtc_t * +find_crtc_for_output (output_t *output) +{ + int c; + + for (c = 0; c < output->output_info->ncrtc; c++) + { + crtc_t *crtc; + + crtc = find_crtc_by_xid (output->output_info->crtcs[c]); + if (!crtc) fatal ("cannot find crtc 0x%x\n", output->output_info->crtcs[c]); + + if (check_crtc_for_output (crtc, output)) + return crtc; + } + return NULL; +} + +static void +set_positions (void) +{ + output_t *output; + Bool keep_going; + Bool any_set; + int min_x, min_y; + + for (;;) + { + any_set = False; + keep_going = False; + for (output = outputs; output; output = output->next) + { + output_t *relation; + name_t relation_name; + + if (!(output->changes & changes_relation)) continue; + + if (output->mode_info == NULL) continue; + + init_name (&relation_name); + set_name_string (&relation_name, output->relative_to); + relation = find_output (&relation_name); + if (!relation) fatal ("cannot find output \"%s\"\n", output->relative_to); + + if (relation->mode_info == NULL) + { + output->x = 0; + output->y = 0; + output->changes |= changes_position; + any_set = True; + continue; + } + /* + * Make sure the dependent object has been set in place + */ + if ((relation->changes & changes_relation) && + !(relation->changes & changes_position)) + { + keep_going = True; + continue; + } + + switch (output->relation) { + case left_of: + output->y = relation->y; + output->x = relation->x - mode_width (output->mode_info, output->rotation); + break; + case right_of: + output->y = relation->y; + output->x = relation->x + mode_width (relation->mode_info, relation->rotation); + break; + case above: + output->x = relation->x; + output->y = relation->y - mode_height (output->mode_info, output->rotation); + break; + case below: + output->x = relation->x; + output->y = relation->y + mode_height (relation->mode_info, relation->rotation); + break; + case same_as: + output->x = relation->x; + output->y = relation->y; + } + output->changes |= changes_position; + any_set = True; + } + if (!keep_going) + break; + if (!any_set) + fatal ("loop in relative position specifications\n"); + } + + /* + * Now normalize positions so the upper left corner of all outputs is at 0,0 + */ + min_x = 32768; + min_y = 32768; + for (output = outputs; output; output = output->next) + { + if (output->mode_info == NULL) continue; + + if (output->x < min_x) min_x = output->x; + if (output->y < min_y) min_y = output->y; + } + if (min_x || min_y) + { + /* move all outputs */ + for (output = outputs; output; output = output->next) + { + if (output->mode_info == NULL) continue; + + output->x -= min_x; + output->y -= min_y; + output->changes |= changes_position; + } + } +} + +static void +set_screen_size (void) +{ + output_t *output; + Bool fb_specified = fb_width != 0 && fb_height != 0; + + for (output = outputs; output; output = output->next) + { + XRRModeInfo *mode_info = output->mode_info; + int x, y, w, h; + + if (!mode_info) continue; + + x = output->x; + y = output->y; + w = mode_width (mode_info, output->rotation); + h = mode_height (mode_info, output->rotation); + /* make sure output fits in specified size */ + if (fb_specified) + { + if (x + w > fb_width || y + h > fb_height) + fatal ("specified screen %dx%d not large enough for output %s (%dx%d+%d+%d)\n", + fb_width, fb_height, output->output.string, w, h, x, y); + } + /* fit fb to output */ + else + { + if (x + w > fb_width) fb_width = x + w; + if (y + h > fb_height) fb_height = y + h; + } + } + + if (fb_width > maxWidth || fb_height > maxHeight) + fatal ("screen cannot be larger than %dx%d (desired size %dx%d)\n", + maxWidth, maxHeight, fb_width, fb_height); + if (fb_specified) + { + if (fb_width < minWidth || fb_height < minHeight) + fatal ("screen must be at least %dx%d\n", minWidth, minHeight); + } + else + { + if (fb_width < minWidth) fb_width = minWidth; + if (fb_height < minHeight) fb_height = minHeight; + } +} + +#endif + +void +disable_outputs (output_t *outputs) +{ + while (outputs) + { + outputs->crtc_info = NULL; + outputs = outputs->next; + } +} + +/* + * find the best mapping from output to crtc available + */ +int +pick_crtcs_score (output_t *outputs) +{ + output_t *output; + int best_score; + int my_score; + int score; + crtc_t *best_crtc; + int c; + + if (!outputs) + return 0; + + output = outputs; + outputs = outputs->next; + /* + * Score with this output disabled + */ + output->crtc_info = NULL; + best_score = pick_crtcs_score (outputs); + if (output->mode_info == NULL) + return best_score; + + best_crtc = NULL; + /* + * Now score with this output any valid crtc + */ + for (c = 0; c < output->output_info->ncrtc; c++) + { + crtc_t *crtc; + + crtc = find_crtc_by_xid (output->output_info->crtcs[c]); + if (!crtc) + fatal ("cannot find crtc 0x%x\n", output->output_info->crtcs[c]); + + /* reset crtc allocation for following outputs */ + disable_outputs (outputs); + if (!check_crtc_for_output (crtc, output)) + continue; + + my_score = 1000; + /* slight preference for existing connections */ + if (crtc == output->current_crtc_info) + my_score++; + + output->crtc_info = crtc; + score = my_score + pick_crtcs_score (outputs); + if (score > best_score) + { + best_crtc = crtc; + best_score = score; + } + } + /* + * Reset other outputs based on this one using the best crtc + */ + if (output->crtc_info != best_crtc) + { + output->crtc_info = best_crtc; + (void) pick_crtcs_score (outputs); + } + return best_score; +} + +/* + * Pick crtcs for any changing outputs that don't have one + */ +void +pick_crtcs (void) +{ + output_t *output; + + /* + * First try to match up newly enabled outputs with spare crtcs + */ + for (output = outputs; output; output = output->next) + { + if (output->changes && output->mode_info && !output->crtc_info) + { + output->crtc_info = find_crtc_for_output (output); + if (!output->crtc_info) + break; + } + } + /* + * Everyone is happy + */ + if (!output) + return; + /* + * When the simple way fails, see if there is a way + * to swap crtcs around and make things work + */ + for (output = outputs; output; output = output->next) + output->current_crtc_info = output->crtc_info; + pick_crtcs_score (outputs); + for (output = outputs; output; output = output->next) + { + if (output->mode_info && !output->crtc_info) + fatal ("cannot find crtc for output %s\n", output->output.string); + if (!output->changes && output->crtc_info != output->current_crtc_info) + output->changes |= changes_crtc; + } } int main (int argc, char **argv) { - Display *dpy; - XRRScreenSize *sizes; - XRRScreenConfiguration *sc; - int nsize; - int nrate; - short *rates; - Window root; - Status status = RRSetConfigFailed; - int rot = -1; - int verbose = 0, query = 0; - Rotation rotation, current_rotation, rotations; - XEvent event; - XRRScreenChangeNotifyEvent *sce; - char *display_name = NULL; - int i, j; - SizeID current_size; - short current_rate; - int rate = -1; - int size = -1; - int dirind = 0; - int setit = 0; - int screen = -1; - int version = 0; - int event_base, error_base; - int reflection = 0; - int width = 0, height = 0; - int have_pixel_size = 0; - int ret = 0; + XRRScreenSize *sizes; + XRRScreenConfiguration *sc; + int nsize; + int nrate; + short *rates; + Status status = RRSetConfigFailed; + int rot = -1; + int query = 0; + Rotation rotation, current_rotation, rotations; + XEvent event; + XRRScreenChangeNotifyEvent *sce; + char *display_name = NULL; + int i, j; + SizeID current_size; + short current_rate; + float rate = -1; + int size = -1; + int dirind = 0; + Bool setit = False; + Bool version = False; + int event_base, error_base; + int reflection = 0; + int width = 0, height = 0; + Bool have_pixel_size = False; + int ret = 0; +#if HAS_RANDR_1_2 + output_t *output = NULL; + policy_t policy = clone; + Bool setit_1_2 = False; + Bool query_1_2 = False; + Bool modeit = False; + Bool propit = False; + Bool query_1 = False; + int major, minor; +#endif - program_name = argv[0]; - if (argc == 1) query = 1; - for (i = 1; i < argc; i++) { - if (!strcmp ("-display", argv[i]) || !strcmp ("-d", argv[i])) { - if (++i>=argc) usage (); - display_name = argv[i]; - continue; - } - if (!strcmp("-help", argv[i])) { - usage(); - continue; - } - if (!strcmp ("--verbose", argv[i])) { - verbose = 1; - continue; - } - - if (!strcmp ("-s", argv[i]) || !strcmp ("--size", argv[i])) { - if (++i>=argc) usage (); - if (sscanf (argv[i], "%dx%d", &width, &height) == 2) - have_pixel_size = 1; - else { - size = atoi (argv[i]); - if (size < 0) usage(); - } - setit = 1; - continue; - } - - if (!strcmp ("-r", argv[i]) || !strcmp ("--rate", argv[i])) { - if (++i>=argc) usage (); - rate = atoi (argv[i]); - if (rate < 0) usage(); - setit = 1; - continue; - } - - if (!strcmp ("-v", argv[i]) || !strcmp ("--version", argv[i])) { - version = 1; - continue; - } - - if (!strcmp ("-x", argv[i])) { - reflection |= RR_Reflect_X; - setit = 1; - continue; - } - if (!strcmp ("-y", argv[i])) { - reflection |= RR_Reflect_Y; - setit = 1; - continue; - } - if (!strcmp ("--screen", argv[i])) { - if (++i>=argc) usage (); - screen = atoi (argv[i]); - if (screen < 0) usage(); - continue; - } - if (!strcmp ("-q", argv[i]) || !strcmp ("--query", argv[i])) { - query = 1; - continue; - } - if (!strcmp ("-o", argv[i]) || !strcmp ("--orientation", argv[i])) { - char *endptr; - if (++i>=argc) usage (); - dirind = strtol(argv[i], &endptr, 0); - if (*endptr != '\0') { - for (dirind = 0; dirind < 4; dirind++) { - if (strcmp (direction[dirind], argv[i]) == 0) break; + program_name = argv[0]; + if (argc == 1) query = True; + for (i = 1; i < argc; i++) { + if (!strcmp ("-display", argv[i]) || !strcmp ("-d", argv[i])) { + if (++i>=argc) usage (); + display_name = argv[i]; + continue; } - if ((dirind < 0) || (dirind > 3)) usage(); - } - rot = dirind; - setit = 1; - continue; + if (!strcmp("-help", argv[i])) { + usage(); + continue; + } + if (!strcmp ("--verbose", argv[i])) { + verbose = True; + continue; + } + if (!strcmp ("--dryrun", argv[i])) { + dryrun = True; + verbose = True; + continue; + } + + if (!strcmp ("-s", argv[i]) || !strcmp ("--size", argv[i])) { + if (++i>=argc) usage (); + if (sscanf (argv[i], "%dx%d", &width, &height) == 2) + have_pixel_size = True; + else { + size = atoi (argv[i]); + if (size < 0) usage(); + } + setit = True; + continue; + } + + if (!strcmp ("-r", argv[i]) || + !strcmp ("--rate", argv[i]) || + !strcmp ("--refresh", argv[i])) + { + if (++i>=argc) usage (); + if (sscanf (argv[i], "%f", &rate) != 1) + usage (); + setit = True; +#if HAS_RANDR_1_2 + if (output) + { + output->refresh = rate; + output->changes |= changes_refresh; + setit_1_2 = True; + } +#endif + continue; + } + + if (!strcmp ("-v", argv[i]) || !strcmp ("--version", argv[i])) { + version = True; + continue; + } + + if (!strcmp ("-x", argv[i])) { + reflection |= RR_Reflect_X; + setit = True; + continue; + } + if (!strcmp ("-y", argv[i])) { + reflection |= RR_Reflect_Y; + setit = True; + continue; + } + if (!strcmp ("--screen", argv[i])) { + if (++i>=argc) usage (); + screen = atoi (argv[i]); + if (screen < 0) usage(); + continue; + } + if (!strcmp ("-q", argv[i]) || !strcmp ("--query", argv[i])) { + query = True; + continue; + } + if (!strcmp ("-o", argv[i]) || !strcmp ("--orientation", argv[i])) { + char *endptr; + if (++i>=argc) usage (); + dirind = strtol(argv[i], &endptr, 0); + if (*endptr != '\0') { + for (dirind = 0; dirind < 4; dirind++) { + if (strcmp (direction[dirind], argv[i]) == 0) break; + } + if ((dirind < 0) || (dirind > 3)) usage(); + } + rot = dirind; + setit = True; + continue; + } +#if HAS_RANDR_1_2 + if (!strcmp ("--prop", argv[i]) || !strcmp ("--properties", argv[i])) + { + query_1_2 = True; + properties = True; + continue; + } + if (!strcmp ("--output", argv[i])) { + if (++i >= argc) usage(); + output = add_output (); + + set_name (&output->output, argv[i], name_string|name_xid); + + setit_1_2 = True; + continue; + } + if (!strcmp ("--crtc", argv[i])) { + if (++i >= argc) usage(); + if (!output) usage(); + set_name (&output->crtc, argv[i], name_xid|name_index); + output->changes |= changes_crtc; + continue; + } + if (!strcmp ("--mode", argv[i])) { + if (++i >= argc) usage(); + if (!output) usage(); + set_name (&output->mode, argv[i], name_string|name_xid); + output->changes |= changes_mode; + continue; + } + if (!strcmp ("--preferred", argv[i])) { + if (!output) usage(); + set_name_preferred (&output->mode); + output->changes |= changes_mode; + continue; + } + if (!strcmp ("--pos", argv[i])) { + if (++i>=argc) usage (); + if (!output) usage(); + if (sscanf (argv[i], "%dx%d", + &output->x, &output->y) != 2) + usage (); + output->changes |= changes_position; + continue; + } + if (!strcmp ("--rotation", argv[i]) || !strcmp ("--rotate", argv[i])) { + if (++i>=argc) usage (); + if (!output) usage(); + for (dirind = 0; dirind < 4; dirind++) { + if (strcmp (direction[dirind], argv[i]) == 0) break; + } + if (dirind == 4) + usage (); + output->rotation &= ~0xf; + output->rotation |= 1 << dirind; + output->changes |= changes_rotation; + continue; + } + if (!strcmp ("--reflect", argv[i]) || !strcmp ("--reflection", argv[i])) { + if (++i>=argc) usage (); + if (!output) usage(); + for (dirind = 0; dirind < 4; dirind++) { + if (strcmp (reflections[dirind], argv[i]) == 0) break; + } + if (dirind == 4) + usage (); + output->rotation &= ~(RR_Reflect_X|RR_Reflect_Y); + output->rotation |= dirind * RR_Reflect_X; + output->changes |= changes_reflection; + continue; + } + if (!strcmp ("--left-of", argv[i])) { + if (++i>=argc) usage (); + if (!output) usage(); + output->relation = left_of; + output->relative_to = argv[i]; + output->changes |= changes_relation; + continue; + } + if (!strcmp ("--right-of", argv[i])) { + if (++i>=argc) usage (); + if (!output) usage(); + output->relation = right_of; + output->relative_to = argv[i]; + output->changes |= changes_relation; + continue; + } + if (!strcmp ("--above", argv[i])) { + if (++i>=argc) usage (); + if (!output) usage(); + output->relation = above; + output->relative_to = argv[i]; + output->changes |= changes_relation; + continue; + } + if (!strcmp ("--below", argv[i])) { + if (++i>=argc) usage (); + if (!output) usage(); + output->relation = below; + output->relative_to = argv[i]; + output->changes |= changes_relation; + continue; + } + if (!strcmp ("--same-as", argv[i])) { + if (++i>=argc) usage (); + if (!output) usage(); + output->relation = same_as; + output->relative_to = argv[i]; + output->changes |= changes_relation; + continue; + } + if (!strcmp ("--set", argv[i])) { + output_prop_t *prop; + if (!output) usage(); + prop = malloc (sizeof (output_prop_t)); + prop->next = output->props; + output->props = prop; + if (++i>=argc) usage (); + prop->name = argv[i]; + if (++i>=argc) usage (); + prop->value = argv[i]; + propit = True; + output->changes |= changes_property; + setit_1_2 = True; + continue; + } + if (!strcmp ("--off", argv[i])) { + if (!output) usage(); + set_name_xid (&output->mode, None); + set_name_xid (&output->crtc, None); + output->changes |= changes_mode; + continue; + } + if (!strcmp ("--fb", argv[i])) { + if (++i>=argc) usage (); + if (sscanf (argv[i], "%dx%d", + &fb_width, &fb_height) != 2) + usage (); + setit_1_2 = True; + continue; + } + if (!strcmp ("--fbmm", argv[i])) { + if (++i>=argc) usage (); + if (sscanf (argv[i], "%dx%d", + &fb_width_mm, &fb_height_mm) != 2) + usage (); + setit_1_2 = True; + continue; + } + if (!strcmp ("--dpi", argv[i])) { + if (++i>=argc) usage (); + if (sscanf (argv[i], "%f", &dpi) != 1) + { + dpi = 0.0; + dpi_output = argv[i]; + } + setit_1_2 = True; + continue; + } + if (!strcmp ("--clone", argv[i])) { + policy = clone; + setit_1_2 = True; + continue; + } + if (!strcmp ("--extend", argv[i])) { + policy = extend; + setit_1_2 = True; + continue; + } + if (!strcmp ("--auto", argv[i])) { + if (output) + { + output->automatic = True; + output->changes |= changes_automatic; + } + else + automatic = True; + setit_1_2 = True; + continue; + } + if (!strcmp ("--q12", argv[i])) + { + query_1_2 = True; + continue; + } + if (!strcmp ("--q1", argv[i])) + { + query_1 = True; + continue; + } + if (!strcmp ("--newmode", argv[i])) + { + umode_t *m = malloc (sizeof (umode_t)); + float clock; + + ++i; + if (i + 9 >= argc) usage (); + m->mode.name = argv[i]; + m->mode.nameLength = strlen (argv[i]); + i++; + if (sscanf (argv[i++], "%f", &clock) != 1) + usage (); + m->mode.dotClock = clock * 1e6; + + if (sscanf (argv[i++], "%d", &m->mode.width) != 1) usage(); + if (sscanf (argv[i++], "%d", &m->mode.hSyncStart) != 1) usage(); + if (sscanf (argv[i++], "%d", &m->mode.hSyncEnd) != 1) usage(); + if (sscanf (argv[i++], "%d", &m->mode.hTotal) != 1) usage(); + if (sscanf (argv[i++], "%d", &m->mode.height) != 1) usage(); + if (sscanf (argv[i++], "%d", &m->mode.vSyncStart) != 1) usage(); + if (sscanf (argv[i++], "%d", &m->mode.vSyncEnd) != 1) usage(); + if (sscanf (argv[i++], "%d", &m->mode.vTotal) != 1) usage(); + m->mode.modeFlags = 0; + while (i < argc) { + int f; + + for (f = 0; mode_flags[f].string; f++) + if (!strcasecmp (mode_flags[f].string, argv[i])) + break; + + if (!mode_flags[f].string) + break; + m->mode.modeFlags |= mode_flags[f].flag; + i++; + } + m->next = umodes; + m->action = umode_create; + umodes = m; + modeit = True; + continue; + } + if (!strcmp ("--rmmode", argv[i])) + { + umode_t *m = malloc (sizeof (umode_t)); + + if (++i>=argc) usage (); + set_name (&m->name, argv[i], name_string|name_xid); + m->action = umode_destroy; + m->next = umodes; + umodes = m; + modeit = True; + continue; + } + if (!strcmp ("--addmode", argv[i])) + { + umode_t *m = malloc (sizeof (umode_t)); + + if (++i>=argc) usage (); + set_name (&m->output, argv[i], name_string|name_xid); + if (++i>=argc) usage(); + set_name (&m->name, argv[i], name_string|name_xid); + m->action = umode_add; + m->next = umodes; + umodes = m; + modeit = True; + continue; + } + if (!strcmp ("--delmode", argv[i])) + { + umode_t *m = malloc (sizeof (umode_t)); + + if (++i>=argc) usage (); + set_name (&m->output, argv[i], name_string|name_xid); + if (++i>=argc) usage(); + set_name (&m->name, argv[i], name_string|name_xid); + m->action = umode_delete; + m->next = umodes; + umodes = m; + modeit = True; + continue; + } +#endif + usage(); } - usage(); - } - if (verbose) query = 1; - - dpy = XOpenDisplay (display_name); - - if (dpy == NULL) { - fprintf (stderr, "Can't open display %s\n", XDisplayName(display_name)); - exit (1); - } - if (screen < 0) - screen = DefaultScreen (dpy); - if (screen >= ScreenCount (dpy)) { - fprintf (stderr, "Invalid screen number %d (display has %d)\n", - screen, ScreenCount (dpy)); - exit (1); - } - - root = RootWindow (dpy, screen); - - sc = XRRGetScreenInfo (dpy, root); - - if (sc == NULL) - exit (1); - - current_size = XRRConfigCurrentConfiguration (sc, ¤t_rotation); - - sizes = XRRConfigSizes(sc, &nsize); - - if (have_pixel_size) { - for (size = 0; size < nsize; size++) + if (verbose) { - if (sizes[size].width == width && sizes[size].height == height) - break; - } - if (size >= nsize) { - fprintf (stderr, - "Size %dx%d not found in available modes\n", width, height); - exit (1); - } - } - else if (size < 0) - size = current_size; - - if (rot < 0) - { - for (rot = 0; rot < 4; rot++) - if (1 << rot == (current_rotation & 0xf)) - break; - } - - current_rate = XRRConfigCurrentRate (sc); - - if (rate < 0) - { - if (size == current_size) - rate = current_rate; - else - rate = 0; - } - else - { - rates = XRRConfigRates (sc, size, &nrate); - for (i = 0; i < nrate; i++) - if (rate == rates[i]) - break; - if (i == nrate) { - fprintf (stderr, "Rate %d not available for this size\n", rate); - exit (1); - } - } - - if (version) { - int major_version, minor_version; - XRRQueryVersion (dpy, &major_version, &minor_version); - printf("Server reports RandR version %d.%d\n", - major_version, minor_version); - } - - if (query) { - printf(" SZ: Pixels Physical Refresh\n"); - for (i = 0; i < nsize; i++) { - printf ("%c%-2d %5d x %-5d (%4dmm x%4dmm )", - i == current_size ? '*' : ' ', - i, sizes[i].width, sizes[i].height, - sizes[i].mwidth, sizes[i].mheight); - rates = XRRConfigRates (sc, i, &nrate); - if (nrate) printf (" "); - for (j = 0; j < nrate; j++) - printf ("%c%-4d", - i == current_size && rates[j] == current_rate ? '*' : ' ', - rates[j]); - printf ("\n"); - } - } - - rotations = XRRConfigRotations(sc, ¤t_rotation); - - rotation = 1 << rot ; - if (query) { - for (i = 0; i < 4; i ++) { - if ((current_rotation >> i) & 1) - printf("Current rotation - %s\n", direction[i]); + query = True; + if (setit && !setit_1_2) + query_1 = True; } - printf("Current reflection - "); - if (current_rotation & (RR_Reflect_X|RR_Reflect_Y)) + dpy = XOpenDisplay (display_name); + + if (dpy == NULL) { + fprintf (stderr, "Can't open display %s\n", XDisplayName(display_name)); + exit (1); + } + if (screen < 0) + screen = DefaultScreen (dpy); + if (screen >= ScreenCount (dpy)) { + fprintf (stderr, "Invalid screen number %d (display has %d)\n", + screen, ScreenCount (dpy)); + exit (1); + } + + root = RootWindow (dpy, screen); + +#if HAS_RANDR_1_2 + if (!XRRQueryVersion (dpy, &major, &minor)) { - if (current_rotation & RR_Reflect_X) printf ("X Axis "); - if (current_rotation & RR_Reflect_Y) printf ("Y Axis"); + fprintf (stderr, "RandR extension missing\n"); + exit (1); } - else - printf ("none"); - printf ("\n"); - - - printf ("Rotations possible - "); - for (i = 0; i < 4; i ++) { - if ((rotations >> i) & 1) printf("%s ", direction[i]); - } - printf ("\n"); - - printf ("Reflections possible - "); - if (rotations & (RR_Reflect_X|RR_Reflect_Y)) - { - if (rotations & RR_Reflect_X) printf ("X Axis "); - if (rotations & RR_Reflect_Y) printf ("Y Axis"); - } - else - printf ("none"); - printf ("\n"); - } - - if (verbose) { - printf("Setting size to %d, rotation to %s\n", size, direction[rot]); - - printf ("Setting reflection on "); - if (reflection) - { - if (reflection & RR_Reflect_X) printf ("X Axis "); - if (reflection & RR_Reflect_Y) printf ("Y Axis"); - } - else - printf ("neither axis"); - printf ("\n"); - - if (reflection & RR_Reflect_X) printf("Setting reflection on X axis\n"); - - if (reflection & RR_Reflect_Y) printf("Setting reflection on Y axis\n"); - } - - /* we should test configureNotify on the root window */ - XSelectInput (dpy, root, StructureNotifyMask); - - if (setit) XRRSelectInput (dpy, root, - RRScreenChangeNotifyMask); - if (setit) status = XRRSetScreenConfigAndRate (dpy, sc, - DefaultRootWindow (dpy), - (SizeID) size, (Rotation) (rotation | reflection), rate, CurrentTime); - - XRRQueryExtension(dpy, &event_base, &error_base); - - if (setit && status == RRSetConfigFailed) { - printf ("Failed to change the screen configuration!\n"); - ret = 1; - } - - if (verbose && setit) { - if (status == RRSetConfigSuccess) - { - while (1) { - int spo; - XNextEvent(dpy, (XEvent *) &event); + if (major > 1 || (major == 1 && minor >= 2)) + has_1_2 = True; - printf ("Event received, type = %d\n", event.type); - /* update Xlib's knowledge of the event */ - XRRUpdateConfiguration (&event); - if (event.type == ConfigureNotify) - printf("Received ConfigureNotify Event!\n"); + if (has_1_2 && modeit) + { + umode_t *m; - switch (event.type - event_base) { - case RRScreenChangeNotify: - sce = (XRRScreenChangeNotifyEvent *) &event; + get_screen (); + get_crtcs(); + get_outputs(); + + for (m = umodes; m; m = m->next) + { + XRRModeInfo *e; + output_t *o; + + switch (m->action) { + case umode_create: + XRRCreateMode (dpy, root, &m->mode); + break; + case umode_destroy: + e = find_mode (&m->name, 0); + if (!e) + fatal ("cannot find mode \"%s\"\n", m->name.string); + XRRDestroyMode (dpy, e->id); + break; + case umode_add: + o = find_output (&m->output); + if (!o) + fatal ("cannot find output \"%s\"\n", m->output.string); + e = find_mode (&m->name, 0); + if (!e) + fatal ("cannot find mode \"%s\"\n", m->name.string); + XRRAddOutputMode (dpy, o->output.xid, e->id); + break; + case umode_delete: + o = find_output (&m->output); + if (!o) + fatal ("cannot find output \"%s\"\n", m->output.string); + e = find_mode (&m->name, 0); + if (!e) + fatal ("cannot find mode \"%s\"\n", m->name.string); + XRRDeleteOutputMode (dpy, o->output.xid, e->id); + break; + } + } + if (!setit_1_2) + { + XSync (dpy, False); + exit (0); + } + } + if (has_1_2 && propit) + { + + get_screen (); + get_crtcs(); + get_outputs(); + + for (output = outputs; output; output = output->next) + { + output_prop_t *prop; - printf("Got a screen change notify event!\n"); - printf(" window = %d\n root = %d\n size_index = %d\n rotation %d\n", - (int) sce->window, (int) sce->root, - sce->size_index, sce->rotation); - printf(" timestamp = %ld, config_timestamp = %ld\n", - sce->timestamp, sce->config_timestamp); - printf(" Rotation = %x\n", sce->rotation); - printf(" %d X %d pixels, %d X %d mm\n", - sce->width, sce->height, sce->mwidth, sce->mheight); - printf("Display width %d, height %d\n", - DisplayWidth(dpy, screen), DisplayHeight(dpy, screen)); - printf("Display widthmm %d, heightmm %d\n", - DisplayWidthMM(dpy, screen), DisplayHeightMM(dpy, screen)); - spo = sce->subpixel_order; - if ((spo < 0) || (spo > 5)) - printf ("Unknown subpixel order, value = %d\n", spo); - else printf ("new Subpixel rendering model is %s\n", order[spo]); - break; - default: - if (event.type != ConfigureNotify) - printf("unknown event received, type = %d!\n", event.type); + for (prop = output->props; prop; prop = prop->next) + { + Atom name = XInternAtom (dpy, prop->name, False); + Atom type; + int format; + unsigned char *data; + int nelements; + int int_value; + unsigned long ulong_value; + unsigned char *prop_data; + int actual_format; + unsigned long nitems, bytes_after; + Atom actual_type; + XRRPropertyInfo *propinfo; + + type = AnyPropertyType; + format=0; + + if (XRRGetOutputProperty (dpy, output->output.xid, name, + 0, 100, False, False, + AnyPropertyType, + &actual_type, &actual_format, + &nitems, &bytes_after, &prop_data) == Success && + + (propinfo = XRRQueryOutputProperty(dpy, output->output.xid, + name))) + { + type = actual_type; + format = actual_format; + } + + if ((type == XA_INTEGER || type == AnyPropertyType) && + (sscanf (prop->value, "%d", &int_value) == 1 || + sscanf (prop->value, "0x%x", &int_value) == 1)) + { + type = XA_INTEGER; + ulong_value = int_value; + data = (unsigned char *) &ulong_value; + nelements = 1; + format = 32; + } + else if ((type == XA_ATOM)) + { + ulong_value = XInternAtom (dpy, prop->value, False); + data = (unsigned char *) &ulong_value; + nelements = 1; + format = 32; + } + else if ((type == XA_STRING || type == AnyPropertyType)) + { + type = XA_STRING; + data = (unsigned char *) prop->value; + nelements = strlen (prop->value); + format = 8; + } + XRRChangeOutputProperty (dpy, output->output.xid, + name, type, format, PropModeReplace, + data, nelements); + } } + if (!setit_1_2) + { + XSync (dpy, False); + exit (0); } - } - } - XRRFreeScreenConfigInfo(sc); - return(ret); + } + if (setit_1_2) + { + get_screen (); + get_crtcs (); + get_outputs (); + set_positions (); + set_screen_size (); + + pick_crtcs (); + + /* + * Assign outputs to crtcs + */ + set_crtcs (); + + /* + * Mark changing crtcs + */ + mark_changing_crtcs (); + + /* + * If an output was specified to track dpi, use it + */ + if (dpi_output) + { + output_t *output = find_output_by_name (dpi_output); + XRROutputInfo *output_info; + XRRModeInfo *mode_info; + if (!output) + fatal ("Cannot find output %s\n", dpi_output); + output_info = output->output_info; + mode_info = output->mode_info; + if (output_info && mode_info && output_info->mm_height) + { + /* + * When this output covers the whole screen, just use + * the known physical size + */ + if (fb_width == mode_info->width && + fb_height == mode_info->height) + { + fb_width_mm = output_info->mm_width; + fb_height_mm = output_info->mm_height; + } + else + { + dpi = (25.4 * mode_info->height) / output_info->mm_height; + } + } + } + + /* + * Compute physical screen size + */ + if (fb_width_mm == 0 || fb_height_mm == 0) + { + if (fb_width != DisplayWidth (dpy, screen) || + fb_height != DisplayHeight (dpy, screen) || dpi != 0.0) + { + if (dpi <= 0) + dpi = (25.4 * DisplayHeight (dpy, screen)) / DisplayHeightMM(dpy, screen); + + fb_width_mm = (25.4 * fb_width) / dpi; + fb_height_mm = (25.4 * fb_height) / dpi; + } + else + { + fb_width_mm = DisplayWidthMM (dpy, screen); + fb_height_mm = DisplayHeightMM (dpy, screen); + } + } + + /* + * Now apply all of the changes + */ + apply (); + + XSync (dpy, False); + exit (0); + } + if (query_1_2 || (query && has_1_2 && !query_1)) + { + output_t *output; + int m; + +#define ModeShown 0x80000000 + + get_screen (); + get_crtcs (); + get_outputs (); + + printf ("Screen %d: minimum %d x %d, current %d x %d, maximum %d x %d\n", + screen, minWidth, minHeight, + DisplayWidth (dpy, screen), DisplayHeight(dpy, screen), + maxWidth, maxHeight); + + for (output = outputs; output; output = output->next) + { + XRROutputInfo *output_info = output->output_info; + XRRModeInfo *mode = output->mode_info; + Atom *props; + int j, k, nprop; + Bool *mode_shown; + Rotation rotations = output_rotations (output); + + printf ("%s %s", output_info->name, connection[output_info->connection]); + if (mode) + { + printf (" %dx%d+%d+%d", + mode_width (mode, output->rotation), + mode_height (mode, output->rotation), + output->x, output->y); + if (verbose) + printf (" (0x%x)", mode->id); + if (output->rotation != RR_Rotate_0 || verbose) + { + printf (" %s", + rotation_name (output->rotation)); + if (output->rotation & (RR_Reflect_X|RR_Reflect_Y)) + printf (" %s", reflection_name (output->rotation)); + } + } + if (rotations != RR_Rotate_0 || verbose) + { + Bool first = True; + printf (" ("); + for (i = 0; i < 4; i ++) { + if ((rotations >> i) & 1) { + if (!first) printf (" "); first = False; + printf("%s", direction[i]); + first = False; + } + } + if (rotations & RR_Reflect_X) + { + if (!first) printf (" "); first = False; + printf ("x axis"); + } + if (rotations & RR_Reflect_Y) + { + if (!first) printf (" "); first = False; + printf ("y axis"); + } + printf (")"); + } + + if (mode) + { + printf (" %dmm x %dmm", + output_info->mm_width, output_info->mm_height); + } + printf ("\n"); + + if (verbose) + { + printf ("\tIdentifier: 0x%x\n", output->output.xid); + printf ("\tTimestamp: %d\n", output_info->timestamp); + printf ("\tSubpixel: %s\n", order[output_info->subpixel_order]); + printf ("\tClones: "); + for (j = 0; j < output_info->nclone; j++) + { + output_t *clone = find_output_by_xid (output_info->clones[j]); + + if (clone) printf (" %s", clone->output.string); + } + printf ("\n"); + if (output->crtc_info) + printf ("\tCRTC: %d\n", output->crtc_info->crtc.index); + printf ("\tCRTCs: "); + for (j = 0; j < output_info->ncrtc; j++) + { + crtc_t *crtc = find_crtc_by_xid (output_info->crtcs[j]); + if (crtc) + printf (" %d", crtc->crtc.index); + } + printf ("\n"); + } + if (verbose || properties) + { + props = XRRListOutputProperties (dpy, output->output.xid, + &nprop); + for (j = 0; j < nprop; j++) { + unsigned char *prop; + int actual_format; + unsigned long nitems, bytes_after; + Atom actual_type; + XRRPropertyInfo *propinfo; + + XRRGetOutputProperty (dpy, output->output.xid, props[j], + 0, 100, False, False, + AnyPropertyType, + &actual_type, &actual_format, + &nitems, &bytes_after, &prop); + + propinfo = XRRQueryOutputProperty(dpy, output->output.xid, + props[j]); + + if (actual_type == XA_INTEGER && actual_format == 8) { + int k; + + printf("\t%s:\n", XGetAtomName (dpy, props[j])); + for (k = 0; k < nitems; k++) { + if (k % 16 == 0) + printf ("\t\t"); + printf("%02x", (unsigned char)prop[k]); + if (k % 16 == 15) + printf("\n"); + } + } else if (actual_type == XA_INTEGER && + actual_format == 32) + { + printf("\t%s: %d (0x%08x)", + XGetAtomName (dpy, props[j]), + *(INT32 *)prop, *(INT32 *)prop); + + if (propinfo->range && propinfo->num_values > 0) { + printf(" range%s: ", + (propinfo->num_values == 2) ? "" : "s"); + + for (k = 0; k < propinfo->num_values / 2; k++) + printf(" (%d,%d)", propinfo->values[k * 2], + propinfo->values[k * 2 + 1]); + } + + printf("\n"); + } else if (actual_type == XA_ATOM && + actual_format == 32) + { + printf("\t%s: %s", + XGetAtomName (dpy, props[j]), + XGetAtomName (dpy, *(Atom *)prop)); + + if (!propinfo->range && propinfo->num_values > 0) { + printf("\n\t\tsupported:"); + + for (k = 0; k < propinfo->num_values; k++) + { + printf(" %-12.12s", XGetAtomName (dpy, + propinfo->values[k])); + if (k % 4 == 3 && k < propinfo->num_values - 1) + printf ("\n\t\t "); + } + } + printf("\n"); + + } else if (actual_format == 8) { + printf ("\t\t%s: %s%s\n", XGetAtomName (dpy, props[j]), + prop, bytes_after ? "..." : ""); + } else { + printf ("\t\t%s: ????\n", XGetAtomName (dpy, props[j])); + } + + free(propinfo); + } + } + + if (verbose) + { + for (j = 0; j < output_info->nmode; j++) + { + XRRModeInfo *mode = find_mode_by_xid (output_info->modes[j]); + int f; + + printf (" %s (0x%x) %6.1fMHz", + mode->name, mode->id, + (float)mode->dotClock / 1000000.0); + for (f = 0; mode_flags[f].flag; f++) + if (mode->modeFlags & mode_flags[f].flag) + printf (" %s", mode_flags[f].string); + printf ("\n"); + printf (" h: width %4d start %4d end %4d total %4d skew %4d clock %6.1fKHz\n", + mode->width, mode->hSyncStart, mode->hSyncEnd, + mode->hTotal, mode->hSkew, mode_hsync (mode) / 1000); + printf (" v: height %4d start %4d end %4d total %4d clock %6.1fHz\n", + mode->height, mode->vSyncStart, mode->vSyncEnd, mode->vTotal, + mode_refresh (mode)); + mode->modeFlags |= ModeShown; + } + } + else + { + mode_shown = calloc (output_info->nmode, sizeof (Bool)); + if (!mode_shown) fatal ("out of memory\n"); + for (j = 0; j < output_info->nmode; j++) + { + XRRModeInfo *jmode, *kmode; + + if (mode_shown[j]) continue; + + jmode = find_mode_by_xid (output_info->modes[j]); + printf (" "); + printf (" %-12s", jmode->name); + for (k = j; k < output_info->nmode; k++) + { + if (mode_shown[k]) continue; + kmode = find_mode_by_xid (output_info->modes[k]); + if (strcmp (jmode->name, kmode->name) != 0) continue; + mode_shown[k] = True; + kmode->modeFlags |= ModeShown; + printf (" %6.1f", mode_refresh (kmode)); + if (kmode == output->mode_info) + printf ("*"); + else + printf (" "); + if (k < output_info->npreferred) + printf ("+"); + else + printf (" "); + } + printf ("\n"); + } + free (mode_shown); + } + } + for (m = 0; m < res->nmode; m++) + { + XRRModeInfo *mode = &res->modes[m]; + + if (!(mode->modeFlags & ModeShown)) + { + printf (" %s (0x%x) %6.1fMHz\n", + mode->name, mode->id, + (float)mode->dotClock / 1000000.0); + printf (" h: width %4d start %4d end %4d total %4d skew %4d clock %6.1fKHz\n", + mode->width, mode->hSyncStart, mode->hSyncEnd, + mode->hTotal, mode->hSkew, mode_hsync (mode) / 1000); + printf (" v: height %4d start %4d end %4d total %4d clock %6.1fHz\n", + mode->height, mode->vSyncStart, mode->vSyncEnd, mode->vTotal, + mode_refresh (mode)); + } + } + exit (0); + } +#endif + + sc = XRRGetScreenInfo (dpy, root); + + if (sc == NULL) + exit (1); + + current_size = XRRConfigCurrentConfiguration (sc, ¤t_rotation); + + sizes = XRRConfigSizes(sc, &nsize); + + if (have_pixel_size) { + for (size = 0; size < nsize; size++) + { + if (sizes[size].width == width && sizes[size].height == height) + break; + } + if (size >= nsize) { + fprintf (stderr, + "Size %dx%d not found in available modes\n", width, height); + exit (1); + } + } + else if (size < 0) + size = current_size; + else if (size >= nsize) { + fprintf (stderr, + "Size index %d is too large, there are only %d sizes\n", + size, nsize); + exit (1); + } + + if (rot < 0) + { + for (rot = 0; rot < 4; rot++) + if (1 << rot == (current_rotation & 0xf)) + break; + } + + current_rate = XRRConfigCurrentRate (sc); + + if (rate < 0) + { + if (size == current_size) + rate = current_rate; + else + rate = 0; + } + else + { + rates = XRRConfigRates (sc, size, &nrate); + for (i = 0; i < nrate; i++) + if (rate == rates[i]) + break; + if (i == nrate) { + fprintf (stderr, "Rate %.1f Hz not available for this size\n", rate); + exit (1); + } + } + + if (version) { + int major_version, minor_version; + XRRQueryVersion (dpy, &major_version, &minor_version); + printf("Server reports RandR version %d.%d\n", + major_version, minor_version); + } + + if (query || query_1) { + printf(" SZ: Pixels Physical Refresh\n"); + for (i = 0; i < nsize; i++) { + printf ("%c%-2d %5d x %-5d (%4dmm x%4dmm )", + i == current_size ? '*' : ' ', + i, sizes[i].width, sizes[i].height, + sizes[i].mwidth, sizes[i].mheight); + rates = XRRConfigRates (sc, i, &nrate); + if (nrate) printf (" "); + for (j = 0; j < nrate; j++) + printf ("%c%-4d", + i == current_size && rates[j] == current_rate ? '*' : ' ', + rates[j]); + printf ("\n"); + } + } + + rotations = XRRConfigRotations(sc, ¤t_rotation); + + rotation = 1 << rot ; + if (query) { + printf("Current rotation - %s\n", + rotation_name (current_rotation)); + + printf("Current reflection - %s\n", + reflection_name (current_rotation)); + + printf ("Rotations possible - "); + for (i = 0; i < 4; i ++) { + if ((rotations >> i) & 1) printf("%s ", direction[i]); + } + printf ("\n"); + + printf ("Reflections possible - "); + if (rotations & (RR_Reflect_X|RR_Reflect_Y)) + { + if (rotations & RR_Reflect_X) printf ("X Axis "); + if (rotations & RR_Reflect_Y) printf ("Y Axis"); + } + else + printf ("none"); + printf ("\n"); + } + + if (verbose) { + printf("Setting size to %d, rotation to %s\n", size, direction[rot]); + + printf ("Setting reflection on "); + if (reflection) + { + if (reflection & RR_Reflect_X) printf ("X Axis "); + if (reflection & RR_Reflect_Y) printf ("Y Axis"); + } + else + printf ("neither axis"); + printf ("\n"); + + if (reflection & RR_Reflect_X) printf("Setting reflection on X axis\n"); + + if (reflection & RR_Reflect_Y) printf("Setting reflection on Y axis\n"); + } + + /* we should test configureNotify on the root window */ + XSelectInput (dpy, root, StructureNotifyMask); + + if (setit && !dryrun) XRRSelectInput (dpy, root, + RRScreenChangeNotifyMask); + if (setit && !dryrun) status = XRRSetScreenConfigAndRate (dpy, sc, + DefaultRootWindow (dpy), + (SizeID) size, (Rotation) (rotation | reflection), rate, CurrentTime); + + XRRQueryExtension(dpy, &event_base, &error_base); + + if (setit && !dryrun && status == RRSetConfigFailed) { + printf ("Failed to change the screen configuration!\n"); + ret = 1; + } + + if (verbose && setit && !dryrun && size != current_size) { + if (status == RRSetConfigSuccess) + { + Bool seen_screen = False; + while (!seen_screen) { + int spo; + XNextEvent(dpy, (XEvent *) &event); + + printf ("Event received, type = %d\n", event.type); + /* update Xlib's knowledge of the event */ + XRRUpdateConfiguration (&event); + if (event.type == ConfigureNotify) + printf("Received ConfigureNotify Event!\n"); + + switch (event.type - event_base) { + case RRScreenChangeNotify: + sce = (XRRScreenChangeNotifyEvent *) &event; + + printf("Got a screen change notify event!\n"); + printf(" window = %d\n root = %d\n size_index = %d\n rotation %d\n", + (int) sce->window, (int) sce->root, + sce->size_index, sce->rotation); + printf(" timestamp = %ld, config_timestamp = %ld\n", + sce->timestamp, sce->config_timestamp); + printf(" Rotation = %x\n", sce->rotation); + printf(" %d X %d pixels, %d X %d mm\n", + sce->width, sce->height, sce->mwidth, sce->mheight); + printf("Display width %d, height %d\n", + DisplayWidth(dpy, screen), DisplayHeight(dpy, screen)); + printf("Display widthmm %d, heightmm %d\n", + DisplayWidthMM(dpy, screen), DisplayHeightMM(dpy, screen)); + spo = sce->subpixel_order; + if ((spo < 0) || (spo > 5)) + printf ("Unknown subpixel order, value = %d\n", spo); + else printf ("new Subpixel rendering model is %s\n", order[spo]); + seen_screen = True; + break; + default: + if (event.type != ConfigureNotify) + printf("unknown event received, type = %d!\n", event.type); + } + } + } + } + XRRFreeScreenConfigInfo(sc); + return(ret); } diff --git a/app/xrandr/xrandr.man b/app/xrandr/xrandr.man index 2e1d1147a..3780dd881 100644 --- a/app/xrandr/xrandr.man +++ b/app/xrandr/xrandr.man @@ -26,49 +26,162 @@ xrandr \- primitive command line interface to RandR extension .SH SYNOPSIS .B "xrandr" -[-help] [-display \fIdisplay\fP] -[-o \fIorientation\fP] -[-q] [-v] -[-s \fIsize\fP] -[-x] [-y] -[--screen \fIsnum\fP] -[--verbose] +[\-help] [\-display \fIdisplay\fP] +[\-q] [\-v] +[\-\-verbose] +[\-\-screen \fIsnum\fP] +.br +.B RandR version 1.2 options +.br +[\-\-prop] +[\-\-fb x] +[\-\-fbmm x] +[\-\-dpi ] +.br +.B Per-output options +.br +[\-\-output ] +[\-\-auto] +[\-\-mode ] +[\-\-preferred] +[\-\-pos x] +[\-\-rate ] +[\-\-reflect \fIreflection\fP] +[\-\-rotate \fIorientation\fP] +[\-\-left\-of \] +[\-\-right\-of \] +[\-\-above \] +[\-\-below \] +[\-\-same-as \] +[\-\-set ] +[\-\-off] +[\-\-crtc ] +[\-\-newmode \fImode\fP] +[\-\-rmmode ] +[\-\-addmode ] +[\-\-delmode ] +.br +.B RandR version 1.0 and version 1.1 options +.br +[\-o \fIorientation\fP] +[\-s \fIsize\fP] +[\-x] [\-y] .SH DESCRIPTION .I Xrandr -is used to set the screen size, orientation and/or reflection. -The -.I -s -option is a small integer index used to specify which size the screen should be set to. -To find out what sizes are available, use the -.I -q -option, which reports the sizes available, the current rotation, and -the possible rotations and reflections. -The default size is the first size specified in the list. -The -.I -o -option is used to specify the orientation of the screen, -and can be one of -\fI"normal inverted left right 0 1 2 3"\fP. +is used to set the size, orientation and/or reflection of the outputs for a +screen. It can also set the screen size. +There are a few global options; the rest modify a particular output and +follow the specification of that output on the command line. +.IP \-\-help +Print out a summary of the usage and exit. +.IP \-v +Print out the RandR version reported by the X server and exit. +.IP \-\-verbose +causes xrandr to be more verbose. When used with \-q (or without other +options), xrandr will display more information about the server state. When +used along with options that reconfigure the system, progress will be +reported while executing the configuration changes. +.IP \-q +When this option is present, or when no configuration changes are requested, +xrandr will display the current state of the system. +.IP "\-screen \fIsnum\fP" +This option selects which screen to manipulate. Note this refers to the X +screen abstraction, not the monitor (or output). +.SH "RandR version 1.2 options" +These options are only available for X server supporting RandR version 1.2 +or newer. +.IP \-\-prop +This option causes xrandr to display the contents of properties for each +output. \-\-verbose also enables \-\-prop. +.IP "\-\-fb x" +Reconfigures the screen to the specified size. All configured monitors must +fit within this size. When this option is not provided, xrandr computes the +smallest screen size that will hold the set of configured outputs; this +option provides a way to override that behaviour. +.IP "\-\-fbmm x" +Sets the reported values for the physical size of the screen. Normally, +xrandr resets the reported physical size values to keep the DPI constant. +This overrides that computation. +.IP "\-\-dpi " +This also sets the reported physical size values of the screen, it uses the +specified DPI value to compute an appropriate physical size using whatever +pixel size will be set. .PP -The -.I -x -option instructs the server to reflect the screen on the X axis. -The -.I -y -option instructs the server to reflect the screen on the Y axis. -Reflection is applied after rotation. +.B "Per-output options" +.IP "\-\-output " +Selects an output to reconfigure. Use either the name of the output or the +XID. +.IP \-\-auto +For connected but disabled outputs, this will enable them using their +preferred mode (or, something close to 96dpi if they have no preferred +mode). For disconnected but enabled outputs, this will disable them. +.IP "\-\-mode " +This selects a mode. Use either the name or the XID for +.IP "\-\-preferred" +This selects the same mode as \-\-auto, but it doesn't automatically enable or +disable the output. +.IP "\-\-pos x" +Position the output within the screen using pixel coordinates. +.IP "\-\-rate " +This marks a preference for refresh rates close to the specified value, when +multiple modes have the same name, this will select the one with the nearest +refresh rate. +.IP "\-\-reflect \fIreflection\fP" +Reflection can be one of 'normal' 'x', 'y' or 'xy'. This causes the output +contents to be reflected across the specified axes. +.IP "\-\-rotate \fIrotation\fP" +Rotation can be one of 'normal', 'left', 'right' or 'inverted'. This causes +the output contents to be rotated in the specified direction. +.IP "\-\-left\-of, \-\-right\-of, \-\-above, \-\-below, \-\-same-as " +Use one of these options to position the output relative to the position of +another output. This allows convenient tiling of outputs within the screen. +The position is always computed relative to the new position of the other +output, so it is not valid to say \-\-output a \-\-left\-of b \-\-output +b \-\-left\-of a. +.IP "\-\-set " +Sets an output property. Integer properties may be specified as a valid +(see \-\-prop) decimal or hexadecimal (with a leading 0x) value. Atom properties +may be set to any of the valid atoms (see \-\-prop). String properties may be +set to any value. +.IP "\-\-off" +Disables the output. +.IP "\-\-crtc " +Uses the specified crtc (either as an index in the list of CRTCs or XID). +In normal usage, this option is not required as xrandr tries to make +sensible choices about which crtc to use with each output. When that fails +for some reason, this option can override the normal selection. +.IP "\-\-newmode \fImode\fP" +New modelines can be added to the server and then associated with outputs. +This option does the former. The \fImode\fP is specified using the ModeLine +syntax for xorg.conf: hdisp hsyncstart hsyncend htotal vdisp vsyncstart +vsyncend vtotal \fIflags\fP. \fIflags\fP can be zero or more of +HSync, +-HSync, +VSync, -VSync, Interlace, DoubleScan, CSync, +CSync, -CSync. +.IP "\-\-rmmode " +This removes a mode from the server if it is otherwise unused. +.IP "\-\-addmode " +Add a mode to the set of valid modes for an output. +.IP "\-\-delmode " +Remove a mode from the set of valid modes for an output. .PP -The -.I -help -option prints out a usage summary. -The -.I --verbose -option tells you what xrandr is doing, selects for events, and tells you -when events are received to enable debugging. +.SH "RandR version 1.1 options" +These options are available for X servers supporting RandR version 1.1 or +older. They are still valid for newer X servers, but they don't interact +sensibly with version 1.2 options on the same command line. +.IP "\-s or \-s x" +This sets the screen size, either matching by size or using the index into +the list of available sizes. +.IP "\-o \fIrotation\fP" +This specifies the orientation of the screen, +and can be one of normal, inverted, left or right. +.IP \-x +Reflect across the X axis. +.IP \-y +Reflect across the Y axis. .SH "SEE ALSO" Xrandr(3) .SH AUTHORS Keith Packard, +Open Source Technology Center, Intel Corporation. and Jim Gettys, Cambridge Research Laboratory, HP Labs, HP.