diff --git a/debian/changelog b/debian/changelog index 21d9516..ad3806f 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +xbase-clients (1:7.2.ds2-1) experimental; urgency=low + + * Update to xrandr 1.2.0. + + -- Julien Cristau Mon, 19 Feb 2007 09:59:14 +0100 + xbase-clients (1:7.2.ds1-2) experimental; urgency=low * Build-dep on libpng12-dev instead of libpng-dev. xcursorgen requires diff --git a/xrandr/Makefile.am b/xrandr/Makefile.am index 178585d..26c83b8 100644 --- a/xrandr/Makefile.am +++ b/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/xrandr/Makefile.in b/xrandr/Makefile.in index 0fdd314..07e5dd8 100644 --- a/xrandr/Makefile.in +++ b/xrandr/Makefile.in @@ -62,8 +62,7 @@ bin_PROGRAMS = xrandr$(EXEEXT) DIST_COMMON = README $(am__configure_deps) $(srcdir)/Makefile.am \ $(srcdir)/Makefile.in $(srcdir)/config.h.in \ $(top_srcdir)/configure AUTHORS COPYING ChangeLog INSTALL NEWS \ - compile config.guess config.sub depcomp install-sh missing \ - mkinstalldirs + compile config.guess config.sub depcomp install-sh missing subdir = . ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac @@ -71,13 +70,13 @@ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ configure.lineno configure.status.lineno -mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +mkinstalldirs = $(install_sh) -d CONFIG_HEADER = config.h CONFIG_CLEAN_FILES = am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(appmandir)" binPROGRAMS_INSTALL = $(INSTALL_PROGRAM) PROGRAMS = $(bin_PROGRAMS) -am_xrandr_OBJECTS = xrandr-xrandr.$(OBJEXT) +am_xrandr_OBJECTS = xrandr.$(OBJEXT) xrandr_OBJECTS = $(am_xrandr_OBJECTS) am__DEPENDENCIES_1 = xrandr_DEPENDENCIES = $(am__DEPENDENCIES_1) @@ -212,7 +211,7 @@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ -xrandr_CFLAGS = $(XRANDR_CFLAGS) +AM_CFLAGS = $(XRANDR_CFLAGS) xrandr_LDADD = $(XRANDR_LIBS) xrandr_SOURCES = \ xrandr.c @@ -331,7 +330,7 @@ mostlyclean-compile: distclean-compile: -rm -f *.tab.c -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xrandr-xrandr.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xrandr.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ @@ -346,20 +345,6 @@ distclean-compile: @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` - -xrandr-xrandr.o: xrandr.c -@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(xrandr_CFLAGS) $(CFLAGS) -MT xrandr-xrandr.o -MD -MP -MF "$(DEPDIR)/xrandr-xrandr.Tpo" -c -o xrandr-xrandr.o `test -f 'xrandr.c' || echo '$(srcdir)/'`xrandr.c; \ -@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/xrandr-xrandr.Tpo" "$(DEPDIR)/xrandr-xrandr.Po"; else rm -f "$(DEPDIR)/xrandr-xrandr.Tpo"; exit 1; fi -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='xrandr.c' object='xrandr-xrandr.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(xrandr_CFLAGS) $(CFLAGS) -c -o xrandr-xrandr.o `test -f 'xrandr.c' || echo '$(srcdir)/'`xrandr.c - -xrandr-xrandr.obj: xrandr.c -@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(xrandr_CFLAGS) $(CFLAGS) -MT xrandr-xrandr.obj -MD -MP -MF "$(DEPDIR)/xrandr-xrandr.Tpo" -c -o xrandr-xrandr.obj `if test -f 'xrandr.c'; then $(CYGPATH_W) 'xrandr.c'; else $(CYGPATH_W) '$(srcdir)/xrandr.c'; fi`; \ -@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/xrandr-xrandr.Tpo" "$(DEPDIR)/xrandr-xrandr.Po"; else rm -f "$(DEPDIR)/xrandr-xrandr.Tpo"; exit 1; fi -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='xrandr.c' object='xrandr-xrandr.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(xrandr_CFLAGS) $(CFLAGS) -c -o xrandr-xrandr.obj `if test -f 'xrandr.c'; then $(CYGPATH_W) 'xrandr.c'; else $(CYGPATH_W) '$(srcdir)/xrandr.c'; fi` uninstall-info-am: install-appmanDATA: $(appman_DATA) @$(NORMAL_INSTALL) diff --git a/xrandr/configure b/xrandr/configure index 4d0388f..b54ca86 100755 --- a/xrandr/configure +++ b/xrandr/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.61 for xrandr 1.0.2. +# Generated by GNU Autoconf 2.61 for xrandr 1.2.0. # # Report bugs to . # @@ -574,8 +574,8 @@ SHELL=${CONFIG_SHELL-/bin/sh} # Identity of this package. PACKAGE_NAME='xrandr' PACKAGE_TARNAME='xrandr' -PACKAGE_VERSION='1.0.2' -PACKAGE_STRING='xrandr 1.0.2' +PACKAGE_VERSION='1.2.0' +PACKAGE_STRING='xrandr 1.2.0' PACKAGE_BUGREPORT='https://bugs.freedesktop.org/enter_bug.cgi?product=xorg' ac_subst_vars='SHELL @@ -1194,7 +1194,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures xrandr 1.0.2 to adapt to many kinds of systems. +\`configure' configures xrandr 1.2.0 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1264,7 +1264,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of xrandr 1.0.2:";; + short | recursive ) echo "Configuration of xrandr 1.2.0:";; esac cat <<\_ACEOF @@ -1359,7 +1359,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -xrandr configure 1.0.2 +xrandr configure 1.2.0 generated by GNU Autoconf 2.61 Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, @@ -1373,7 +1373,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by xrandr $as_me 1.0.2, which was +It was created by xrandr $as_me 1.2.0, which was generated by GNU Autoconf 2.61. Invocation command line was $ $0 $@ @@ -2043,7 +2043,7 @@ fi # Define the identity of the package. PACKAGE='xrandr' - VERSION='1.0.2' + VERSION='1.2.0' cat >>confdefs.h <<_ACEOF @@ -3522,12 +3522,12 @@ if test -n "$PKG_CONFIG"; then pkg_cv_XRANDR_CFLAGS="$XRANDR_CFLAGS" else if test -n "$PKG_CONFIG" && \ - { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"xrandr xrender x11\"") >&5 - ($PKG_CONFIG --exists --print-errors "xrandr xrender x11") 2>&5 + { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"xrandr >= 1.2.0 xrender x11\"") >&5 + ($PKG_CONFIG --exists --print-errors "xrandr >= 1.2.0 xrender x11") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then - pkg_cv_XRANDR_CFLAGS=`$PKG_CONFIG --cflags "xrandr xrender x11" 2>/dev/null` + pkg_cv_XRANDR_CFLAGS=`$PKG_CONFIG --cflags "xrandr >= 1.2.0 xrender x11" 2>/dev/null` else pkg_failed=yes fi @@ -3540,12 +3540,12 @@ if test -n "$PKG_CONFIG"; then pkg_cv_XRANDR_LIBS="$XRANDR_LIBS" else if test -n "$PKG_CONFIG" && \ - { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"xrandr xrender x11\"") >&5 - ($PKG_CONFIG --exists --print-errors "xrandr xrender x11") 2>&5 + { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"xrandr >= 1.2.0 xrender x11\"") >&5 + ($PKG_CONFIG --exists --print-errors "xrandr >= 1.2.0 xrender x11") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then - pkg_cv_XRANDR_LIBS=`$PKG_CONFIG --libs "xrandr xrender x11" 2>/dev/null` + pkg_cv_XRANDR_LIBS=`$PKG_CONFIG --libs "xrandr >= 1.2.0 xrender x11" 2>/dev/null` else pkg_failed=yes fi @@ -3564,14 +3564,14 @@ else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then - XRANDR_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "xrandr xrender x11"` + XRANDR_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "xrandr >= 1.2.0 xrender x11"` else - XRANDR_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "xrandr xrender x11"` + XRANDR_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "xrandr >= 1.2.0 xrender x11"` fi # Put the nasty error message in config.log where it belongs echo "$XRANDR_PKG_ERRORS" >&5 - { { echo "$as_me:$LINENO: error: Package requirements (xrandr xrender x11) were not met: + { { echo "$as_me:$LINENO: error: Package requirements (xrandr >= 1.2.0 xrender x11) were not met: $XRANDR_PKG_ERRORS @@ -3582,7 +3582,7 @@ Alternatively, you may set the environment variables XRANDR_CFLAGS and XRANDR_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details. " >&5 -echo "$as_me: error: Package requirements (xrandr xrender x11) were not met: +echo "$as_me: error: Package requirements (xrandr >= 1.2.0 xrender x11) were not met: $XRANDR_PKG_ERRORS @@ -4216,7 +4216,7 @@ exec 6>&1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by xrandr $as_me 1.0.2, which was +This file was extended by xrandr $as_me 1.2.0, which was generated by GNU Autoconf 2.61. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -4269,7 +4269,7 @@ Report bugs to ." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF ac_cs_version="\\ -xrandr config.status 1.0.2 +xrandr config.status 1.2.0 configured by $0, generated by GNU Autoconf 2.61, with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\" diff --git a/xrandr/configure.ac b/xrandr/configure.ac index dc5fa8e..ae7d2f2 100644 --- a/xrandr/configure.ac +++ b/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.0], [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/xrandr/mkinstalldirs b/xrandr/mkinstalldirs deleted file mode 100755 index 259dbfc..0000000 --- a/xrandr/mkinstalldirs +++ /dev/null @@ -1,158 +0,0 @@ -#! /bin/sh -# mkinstalldirs --- make directory hierarchy - -scriptversion=2005-06-29.22 - -# Original author: Noah Friedman -# Created: 1993-05-16 -# Public domain. -# -# This file is maintained in Automake, please report -# bugs to or send patches to -# . - -errstatus=0 -dirmode= - -usage="\ -Usage: mkinstalldirs [-h] [--help] [--version] [-m MODE] DIR ... - -Create each directory DIR (with mode MODE, if specified), including all -leading file name components. - -Report bugs to ." - -# process command line arguments -while test $# -gt 0 ; do - case $1 in - -h | --help | --h*) # -h for help - echo "$usage" - exit $? - ;; - -m) # -m PERM arg - shift - test $# -eq 0 && { echo "$usage" 1>&2; exit 1; } - dirmode=$1 - shift - ;; - --version) - echo "$0 $scriptversion" - exit $? - ;; - --) # stop option processing - shift - break - ;; - -*) # unknown option - echo "$usage" 1>&2 - exit 1 - ;; - *) # first non-opt arg - break - ;; - esac -done - -for file -do - if test -d "$file"; then - shift - else - break - fi -done - -case $# in - 0) exit 0 ;; -esac - -# Solaris 8's mkdir -p isn't thread-safe. If you mkdir -p a/b and -# mkdir -p a/c at the same time, both will detect that a is missing, -# one will create a, then the other will try to create a and die with -# a "File exists" error. This is a problem when calling mkinstalldirs -# from a parallel make. We use --version in the probe to restrict -# ourselves to GNU mkdir, which is thread-safe. -case $dirmode in - '') - if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then - echo "mkdir -p -- $*" - exec mkdir -p -- "$@" - else - # On NextStep and OpenStep, the `mkdir' command does not - # recognize any option. It will interpret all options as - # directories to create, and then abort because `.' already - # exists. - test -d ./-p && rmdir ./-p - test -d ./--version && rmdir ./--version - fi - ;; - *) - if mkdir -m "$dirmode" -p --version . >/dev/null 2>&1 && - test ! -d ./--version; then - echo "mkdir -m $dirmode -p -- $*" - exec mkdir -m "$dirmode" -p -- "$@" - else - # Clean up after NextStep and OpenStep mkdir. - for d in ./-m ./-p ./--version "./$dirmode"; - do - test -d $d && rmdir $d - done - fi - ;; -esac - -for file -do - case $file in - /*) pathcomp=/ ;; - *) pathcomp= ;; - esac - oIFS=$IFS - IFS=/ - set fnord $file - shift - IFS=$oIFS - - for d - do - test "x$d" = x && continue - - pathcomp=$pathcomp$d - case $pathcomp in - -*) pathcomp=./$pathcomp ;; - esac - - if test ! -d "$pathcomp"; then - echo "mkdir $pathcomp" - - mkdir "$pathcomp" || lasterr=$? - - if test ! -d "$pathcomp"; then - errstatus=$lasterr - else - if test ! -z "$dirmode"; then - echo "chmod $dirmode $pathcomp" - lasterr= - chmod "$dirmode" "$pathcomp" || lasterr=$? - - if test ! -z "$lasterr"; then - errstatus=$lasterr - fi - fi - fi - fi - - pathcomp=$pathcomp/ - done -done - -exit $errstatus - -# Local Variables: -# mode: shell-script -# sh-indentation: 2 -# eval: (add-hook 'write-file-hooks 'time-stamp) -# time-stamp-start: "scriptversion=" -# time-stamp-format: "%:y-%02m-%02d.%02H" -# time-stamp-end: "$" -# End: diff --git a/xrandr/xrandr.c b/xrandr/xrandr.c index 09a9de6..7425263 100644 --- a/xrandr/xrandr.c +++ b/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,2162 @@ #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 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, " --off\n"); + fprintf(stderr, " --crtc \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"; + } +} + +#if HAS_RANDR_1_2 +typedef enum _policy { + clone, extend +} policy_t; + +typedef enum _relation { + left_of, right_of, above, below +} 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_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; + +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 { + struct _output *next; + + changes_t changes; + + name_t output; + XRROutputInfo *output_info; + + name_t crtc; + crtc_t *crtc_info; + + name_t mode; + float refresh; + XRRModeInfo *mode_info; + + relation_t relation; + char *relative_to; + + int x, y; + Rotation rotation; + + Bool automatic; +}; + +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 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_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) +{ + XRRCrtcInfo *crtc_info = crtc->crtc_info; + + 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"); + + 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; + } + } +} + +crtc_t * +find_crtc_for_output (output_t *output) +{ + int c; + + for (c = 0; c < output->output_info->ncrtc; c++) + { + crtc_t *crtc; + int l, o; + output_t *other; + + crtc = find_crtc_by_xid (output->output_info->crtcs[c]); + if (!crtc) fatal ("cannot find crtc 0x%x\n", output->output_info->crtcs[c]); + + 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) break; + } + if (other) continue; + + + if (crtc->noutput) + { + /* make sure the state matches */ + if (crtc->mode_info != output->mode_info) continue; + if (crtc->x != output->x) continue; + if (crtc->y != output->y) continue; + if (crtc->rotation != output->rotation) continue; + } + 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; + + 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; + } + 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 + 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; + char *crtc; + policy_t policy = clone; + Bool setit_1_2 = False; + Bool query_1_2 = 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 ("--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; + } + 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; + } +#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 (setit_1_2) + { + XRROutputInfo *output_info; + XRRCrtcInfo *crtc_info; + XRRCrtcInfo *crtc_cur; + XRRModeInfo *mode_info; + RROutput *crtc_outputs; + int n_crtc_output; + int c, o, m; + int om, sm; - switch (event.type - event_base) { - case RRScreenChangeNotify: - sce = (XRRScreenChangeNotifyEvent *) &event; + get_screen (); + get_crtcs (); + get_outputs (); + set_positions (); + set_screen_size (); - 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); + /* + * Pick crtcs for any changing outputs that don't have one + */ + 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) + fatal ("cannot find crtc for output %s\n", output->output.string); + } } + + /* + * 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; + } + } } - } - } - XRRFreeScreenConfigInfo(sc); - return(ret); + + /* + * 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; + + 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 (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); + + 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_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]); + + 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)); + } + } + 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; + 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); + } + } + 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; + + 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) { + 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/xrandr/xrandr.man b/xrandr/xrandr.man index 2e1d114..228ec94 100644 --- a/xrandr/xrandr.man +++ b/xrandr/xrandr.man @@ -27,48 +27,137 @@ xrandr \- primitive command line interface to RandR extension .SH SYNOPSIS .B "xrandr" [-help] [-display \fIdisplay\fP] -[-o \fIorientation\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 \] +[--off] +[--crtc ] +.br +.B RandR version 1.0 and version 1.1 options +.br +[-o \fIorientation\fP] [-s \fIsize\fP] [-x] [-y] -[--screen \fIsnum\fP] -[--verbose] .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 xx" +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 " +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 "--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. .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 server supporting RandR version 1.1 or +older. They are still valid for newer X servers, but they don't +.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.