All pastes #637713 Raw Edit

compiz-manager script

public text v1 · immutable
#637713 ·published 2007-07-29 04:17 UTC
rendered paste body
#!/bin/bash
# Compiz manager 
# Copyright (c) 2007 Kristian Lyngstøl <kristian@bohemians.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
#
#
# Much of this code is based on Beryl code, also licensed under the GPL.
# This script will detect what options we need to pass to compiz to get it
# started, read a simple configuration file, and start a default
# plugin and possibly window decorator. 
# All of this should be possible to override in a configuration file.


# Todo:
#  - GUI, possibly in a second script.
#  - Testing on Xgl
#  - Configuration file sanity tests

#########################################################################
# You should NOT edit this, edit the configuration file instead.        #
# This is left for completness and if you need to modify the script.    #
# The generated configuration file should be equally documented.        #
#########################################################################

# Defaults
# Configuration file is based on XDG base dir. Set this to override the 
# defaults. Leave empty if in doubt. Use -v to see exactly what 
# configuration files compiz-manager looks for on your system.
#CONFIG="./compiz-managerrc"

# Set to yes to enable verbose (-v) by default. 
VERBOSE="no"

# Default arguments. Others are added to this, and the configuration can
# override ALL arguments. 
ARGS="--sm-disable --replace"

# Ditto for enviromental variables.
ENV=""

# Default plugins. Should probably be ini, gconf or ccp.
PLUGINS="ccp" 

# Defines the decorator and arguments. 
# Set it to empty to not use a decorator. 
DECORATOR="emerald" 
DECORATORARGS="--replace"

# Delay in seconds before we bring up the decorator(s)
# This avoids starting the decorator before the WM is up, 
# even if it shouldn't be a problem.
DELAY="5" 

# Set to "no" to pipe all decorator error messages to /dev/null
DECOERRORS="no" 

# Internal, used to process options. 
TASK="normal"

# No indirect by default
INDIRECT=1

# Echos the arguments if verbose
function verbose
{
	if [ "x$VERBOSE" = "xyes" ]; then 
		echo -ne "$*"
	fi
}

### System checks
# These are used for checking what hardware and software we're dealing with, 
# so we can decide what options to pass to compiz, if it's even possible to
# start compiz.

# Check wether the composite extension is present
function check_composite
{
	verbose "Checking for Composite extension: "
	if xdpyinfo -queryExtensions | grep -q Composite ; then
		verbose "present. \n";
		return 0;
	else
		verbose "not present. \n";
		return 1;
	fi
}

function check_xdamage
{
	verbose "Checking for XDamage extension: "
	if xdpyinfo -queryExtensions | grep -q DAMAGE ; then
		verbose "present. \n";
		return 0;
	else
		verbose "not present. \n";
		return 1;
	fi
}
# Check for existence if NV-GLX
function check_nvidia
{
	verbose "Checking for nVidia: "
	if xdpyinfo | grep -q NV-GLX ; then
		verbose "present. \n"
		return 0;
	else
		verbose "not present. \n"
		return 1;
	fi
}

# Detects if Xgl is running
function check_xgl
{
	verbose "Checking for Xgl: "
	if xvinfo | grep -q Xgl ; then
		verbose "present. \n"
		return 0;
	else
		verbose "not present. \n"
		return 1;
	fi
}

# Check for presence of FBConfig
function check_fbconfig
{
	verbose "Checking for FBConfig: "
	if glxinfo 2> /dev/null | grep -q GLX_SGIX_fbconfig ; then
		verbose "present. \n"
		return 0;
	else
		verbose "not present. \n"
		return 1;
	fi
}

# Check for TFP 
function check_tfp
{
	verbose "Checking for texture_from_pixmap: "
	if [ `glxinfo 2>/dev/null | grep GLX_EXT_texture_from_pixmap -c` -gt 2 ] ; then
		verbose "present. \n"
		return 0;
	else
		verbose "not present. \n"
		if [ "$INDIRECT" -eq 0 ]; then
			unset LIBGL_ALWAYS_INDIRECT
			INDIRECT=1
			return 1; 
		else
			verbose "Trying again with indirect rendering:\n";
			INDIRECT=0
			export LIBGL_ALWAYS_INDIRECT=1
			check_tfp;
			return $?
		fi
	fi
}

# Check for non power of two texture support
function check_npot_texture
{
	verbose "Checking for non power of two support: "
	if glxinfo | egrep -q '(GL_ARB_texture_non_power_of_two|GL_NV_texture_rectangle|GL_EXT_texture_rectangle|GL_ARB_texture_rectangle)' ; then
		verbose "present. \n"; 
		return 0;
	else
		verbose "Not present. \n"
		return 1;
	fi

}

function check_xsync
{
	verbose "Checking for XSync extension: ";
	if xdpyinfo -queryExtensions | grep -q SYNC ; then
		verbose "present. \n";
		return 0;
	else
		verbose "not present. \n" ;
	fi
}

# Counts how many screens we have, and the base value for DISPLAY=
# so we can easily start one decorator per screen
function check_multiscreen
{
	SCREENS=$(xdpyinfo | grep "screen #" | wc -l)
	verbose "Detected $SCREENS screen(s)\n";
	if [ "$SCREENS" == "1" ]; then return 0; fi;
	verbose "Multiscreen enviromental detection: \n"
	DISPLAYBASE=$(xdpyinfo | grep name\ of\ display | sed 's/.* display: *//' | sed 's/\..*//')
	verbose "\tDetected $DISPLAYBASE as the base of the DISPLAY variable\n";
	SCREENNUMBERS=$(xdpyinfo | grep "screen #" | sed -r 's/screen #(.):/\1/')
	for a in $SCREENNUMBERS ; do 
		MULTIDISPLAY[$a]=${DISPLAYBASE}.$a
		verbose "\tMULTIDISPLAY[$a] set to: ${MULTIDISPLAY[$a]}\n";
	done
}

function possible_check 
{
	if [ ! "$1" ]; then 
		echo "Fatal: Failed test: $2"; 
		return 1; 
	fi
	return 0;
}
# Returns true if we think it's actually possible to start compiz
function check_possible
{
	POSSIBLE="1"
	if ! possible_check "$TFP" "texture_from_pixmap support"; then return 1; fi
	if ! possible_check "$NPOT" "non-power-of-two texture support"; then return 1; fi
	if ! possible_check "$FBCONFIG" "FBConfig"; then return 1; fi
	if ! possible_check "$COMPOSITE" "Composite extension"; then return 1; fi
	if ! possible_check "$XDAMAGE" "XDamage extension"; then return 1; fi
	if ! possible_check "$XSYNC" "XSync extension"; then return 1; fi
	POSSIBLE="0";
	return 0;
}


### Work functions

# Builds a new-line seperated string of enviromental variables we might want
function build_env
{
	if [ $NVIDIA -eq 0 ]; then
		ENV="__GL_YIELD=NOTHING "
	fi
	if [ $INDIRECT -eq 0 ]; then
		ENV="$ENV LIBGL_ALWAYS_INDIRECT=1 "
	fi
}

# Builds the argument list
function build_args
{
	if [ $NVIDIA -eq 0 -a  $XGL -ne 0 -a $INDIRECT -ne 0 ]; then
		ARGS="--loose-binding "$ARGS
	fi
	if [ $INDIRECT -eq 0 ]; then
		ARGS="--indirect-rendering "$ARGS
	fi
}


# Prints usage
function usage
{
	echo "Usage: $0 [-r <env|args>] [-v]  [-h] [-i] [-f] [-d] [-w]"
	echo -e "-r\toutputs recommended values for either "
	echo -e "  \tenviromental variables, or arguments."
	echo -e "-v\tVerbose: Output the result of each individual test"
	echo -e "-h\tDisplay this message";
	echo -e "-i\tIgnore config file(s)";
	echo -e "-f\tForce; This overwrites your existing config file."
	echo -e "-d\tDry run: Do everything, but don't start."
	echo -e "-w\tOnly start window decorator(s). One per screen.";
	echo -e "Configuration"
	echo -e "$0 automatically stores configuration the first time you run it.";
	echo -e "You can use that to override checks, or pass custom arguments."
	echo -e "To re-write the configuration, you can either use -f, to get one"
	echo -e "based on your own settings, or -fi to create a fresh config."
}

# Parses options
function parse_options
{
	while getopts "r:vhifdw" ARG
	do
		if [ "x$ARG" = "xr" ]; then
			TASK="RECOMMEND";
			if [ "x$OPTARG" = "xenv" ]; then
				REC="env";
			elif [ "x$OPTARG" = "xargs" ]; then
				REC="args"
			elif [ "x$OPTARG" = "xboth" ]; then
				REC="both"
			else
				echo "Invalid recommend argument"
				usage
				exit 1
			fi
		elif [ "x$ARG" = "xv" ]; then
			VERBOSE="yes"
		elif [ "x$ARG" = "xi" ]; then
			no_config
			IGNORECONFIG="yes"
		elif [ "x$ARG" = "xd" ]; then
			DRY="yes"
		elif [ "x$ARG" = "xf" ]; then
			FORCE="yes"
			FORCECONFIG="yes"
		elif [ "x$ARG" = "xw" ]; then
			TASK="WINDOWDECORATOR";
		else 
			usage
			exit 0
		fi
	done
}

# Store configuration
function store_config
{
	if [ -n "$IGNORECONFIG" ]; then
		if [ "x$FORCECONFIG" != "xyes" ]; then return; fi;
	fi
	if [ -z $CONFIG ]; then return ; fi
	if [ -f $CONFIG ]; then 
		if [ "x$FORCECONFIG" != "xyes" ]; then
			verbose "Not writing config; allready exists.\n";
			return 1;
		fi;
	fi;
	echo Writing configuration to: $CONFIG
	echo "# Autogenerated configuration"  > $CONFIG
	echo "# Generated:" `date` >> $CONFIG
	echo "# On $HOSTNAME by $USER" >> $CONFIG
	echo >> $CONFIG
	echo "# Behavior references: (yes/no)" >> $CONFIG
	echo "# Set this to \"yes\" to get the same result as if you ran compiz-manager with -v" >> $CONFIG
	echo "#VERBOSE=$VERBOSE" >> $CONFIG
	echo >> $CONFIG
	echo "# Plugins" >> $CONFIG
	echo "PLUGINS=\"$PLUGINS\"" >> $CONFIG
	echo "# Or, to append: " >> $CONFIG
	echo "# PLUGINS=\"\$PLUGINS <... >\"" >> $CONFIG
	echo >> $CONFIG
	echo "# Arguments, same as plugins to append" >> $CONFIG
	echo "# ARGS=\"\$ARGS <... >\"" >> $CONFIG
	echo "#ARGS=\"$ARGS\"" >>  $CONFIG
	echo >> $CONFIG
	echo "# Screen detection: " >> $CONFIG
	echo "SCREENS=$SCREENS" >> $CONFIG
	if [ -n "$SCREENNUMBERS" ]; then
		echo "SCREENNUMBERS=\"$SCREENNUMBERS\"" >> $CONFIG
		for a in ${SCREENNUMBERS}; do
			echo "MULTIDISPLAY[$a]=${MULTIDISPLAY[$a]}" >> $CONFIG
		done
	fi
	echo >> $CONFIG
	echo "# Decorator" >> $CONFIG
	echo "# Use \"unset DECORATOR\" or set DECORATOR=\"\" to not use one." >> $CONFIG
	echo "DECORATOR=\"$DECORATOR\"" >> $CONFIG
	echo "DECORATORARGS=\"$DECORATORARGS\"" >> $CONFIG
	echo "# Delay in seconds before the decorator is started." >> $CONFIG
	echo "DELAY=\"$DELAY\"" >> $CONFIG
	echo "# Set this to \"no\" to send all decorator errors to /dev/null" >> $CONFIG
	echo "DECOERRORS=\"$DECOERRORS\"" >> $CONFIG
	echo >> $CONFIG
	echo "# Values of 0 mean \"true\" (present), values of 1 means \"false\" (not present)" >> $CONFIG
	echo "# Checks: " >> $CONFIG
	echo NVIDIA=$NVIDIA >> $CONFIG
	echo FBCONFIG=$FBCONFIG >> $CONFIG
	echo XGL=$XGL >> $CONFIG
	echo TFP=$TFP >> $CONFIG
	echo NPOT=$NPOT >> $CONFIG
	echo COMPOSITE=$COMPOSITE >> $CONFIG
	echo XDAMAGE=$XDAMAGE >> $CONFIG
	echo POSSIBLE=$POSSIBLE >> $CONFIG
	echo XSYNC=$XSYNC >> $CONFIG
	echo INDIRECT=$INDIRECT >> $CONFIG
}

####
# Execute checks, if necesarry. 
function check_everything
{
	if [ -z "$NVIDIA" ]; then
		check_nvidia
		NVIDIA=$?
	else
		verbose "Skipping nVidia check, using stored value.\n"
	fi
	if [ -z "$XGL" ]; then
		check_xgl
		XGL=$?
	else
		verbose "Skipping Xgl check, using stored value.\n"
	fi

	if [ -z "$FBCONFIG" ]; then
		check_fbconfig
		FBCONFIG=$?
	else
		verbose "Skipping FBConfig check, using stored value.\n"
	fi
	if [ -z "$TFP" ]; then
		check_tfp
		TFP=$?
	else
		verbose "Skipping texture_from_pixmap check, using stored value.\n"
	fi
	if [ -z "$NPOT" ]; then
		check_npot_texture
		NPOT=$?
	else
		verbose "Skipping non-power-of-two texture check, using stored value.\n"
	fi

	if [ -z "$COMPOSITE" ]; then
		check_composite
		COMPOSITE=$?
	else
		verbose "Skipping Composite extension check, using stored value.\n"
	fi

	if [ -z "$XDAMAGE" ]; then
		check_xdamage
		XDAMAGE=$?
	else
		verbose "Skipping Damage extension check, using stored value.\n"
	fi

	if [ -z "$XSYNC" ]; then 
		check_xsync
		XSYNC=$?
	else
		verbose "Skipping XSync extension check, using stored value.\n";
	fi

	if [ -z "$SCREENS" ]; then
		check_multiscreen
	else
		verbose "Skipping screen detection check, using stored value.\n";
	fi
}

###
# Check if a directory exists; creates it if it doesn't, returns false if the
# path isn't a directory. 
function require_dir
{
	if ! [ -a "$1" ]; then 
		verbose "Creating directory $1\n";
		mkdir $1;
	fi
	if [ ! -d $1 ]; then
		echo "Warning: $1 exists but isn't a directory.";
		return 1;
	fi
	return 0;
}


#### 
# Configuration handeling
# We attempt to follow the XDG basedir spec here;
# We can read both a global config, and a local one.
# The configuration file is extremly simple, as it's just a bash script.
# It might be a good idea to improve that a bit, specially with security 
# in mind, an general errors.

# No config, so unset and possibly warn. (Might do more later) 
function no_config
{
	if [ -n "$1" ]; then
		echo "$1";
	fi
	unset CONFIG
}

function get_config_name
{
	if [ -n "$CONFIG" ]; then 
		return 0;
	fi

	if [ -z "$XDG_CONFIG_HOME" ]; then
		if ! require_dir "$HOME/.config" ; then
			no_config "Don't know how to treat config files. Ignoring them."
		else
			CONFIG="$HOME/.config/compiz-managerrc"
		fi
	else
		if ! require_dir "$XDG_CONFIG_HOME" ; then
			no_config "Don't know how to treat config files. Ignoring them."
		else
			CONFIG="$XDG_CONFIG_HOME/compiz-managerrc"
		fi
	fi
}

function parse_config 
{
	if [ -z "$XDG_CONFIG_DIRS" ]; then
		XDG_CONFIG_DIRS="/etc/xdg/";
	fi

	verbose "Looking for configuration file(s): \n"
	oldIFS=$IFS
	IFS=":";
	for a in $XDG_CONFIG_DIRS; do
		if [ -f "$a/compiz-managerrc" ]; then
			verbose "\t Loading ${a}/compiz-managerrc\n"; 
			. $a/compiz-managerrc;
		else
			verbose "\t Not found: ${a}/compiz-managerrc\n";
		fi
	done
	IFS=$oldIFS
	if [ -n "$CONFIG" ]; then 
		if [ -f "$CONFIG" ]; then 
			verbose "\t Loading $CONFIG\n"
			. $CONFIG ; 
		else
			verbose "\t Not found: \"$CONFIG\"\n";
		fi
	fi 
}

###
# Let's get this show started!
function start_compiz
{
	###
	# No need to continue if we've determined it's not possible to start anyway
	if [ $POSSIBLE != "0" ]; then
		echo "Checks indicate that it's impossible to start compiz on your system."
		exit 1;
	else
		verbose "Checks indicate compiz should work on your system\n"
	fi;
	verbose "Exporting: $ENV \n"
	export $ENV
	verbose Executing: compiz $ARGS $PLUGINS "\n"
	if [ "x$DRY" = "xyes" ]; then exit 0; fi
	compiz $ARGS $PLUGINS
}

####
# Starts one decorator per screen
function start_decorators
{
	if [ -z "$DECORATOR" ]; then return 1; fi
	if [ "$SCREENS" == "1" ]; then 
		verbose "Starting delayed decorator in the background: "
		verbose "sleep $DELAY && $DECORATOR $DECORATORARGS &\n" 
		if [ "x$DRY" = "xyes" ]; then return 0; fi
			if [ "$DECOERRORS" = "no" ]; then
				sleep $DELAY && $DECORATOR $DECORATORARGS 2>/dev/null &
			else
				sleep $DELAY && $DECORATOR $DECORATORARGS &
			fi
		return 0;
	fi
	verbose "Starting decorators for all screens: \n"
	for a in $SCREENNUMBERS; do
		verbose "\t Screen $a: "
		verbose "sleep $DELAY && DISPLAY=${MULTIDISPLAY[$a]} $DECORATOR $DECORATORARGS\n"
		if [ "x$DRY" != "xyes" ]; then  
			if [ "$DECOERRORS" = "no" ]; then
				sleep $DELAY && DISPLAY=${MULTIDISPLAY[$a]} $DECORATOR $DECORATORARGS 2>/dev/null &
			else
				sleep $DELAY && DISPLAY=${MULTIDISPLAY[$a]} $DECORATOR $DECORATORARGS &
			fi

		fi
	done	
}

####################
# Execution begins here.
# First get options, check for configuration
# Check everything if necesarry, build the enviroment and arguments
# and eventually select a task.

parse_options $*

# We need this even when ignoring, or we won't know where to store force
# configuration files
get_config_name 

if [ -z "$IGNORECONFIG" ]; then parse_config
else verbose "Ignoring configuration files as you requested\n"; fi
if [ -z "$NOCHECKS" ]; then check_everything; fi

### 
# This is the master-test, it has to be done last.
if [ -z "$POSSIBLE" ]; then check_possible 
else verbose "Skipping \"possible\" test, using stored value.\n"; fi

####
# Builds the enviromental variables list and argument list based
# on the result of the checks
build_env
build_args

case "$TASK" in
	RECOMMEND)
		if [ "x$REC"  = "xenv" ]; then
			echo -e $ENV;
		elif [ "x$REC" = "xargs" ]; then
			echo -e $ARGS
		elif [ "x$REC" = "xboth" ]; then
			echo -e $ARGS $PLUGINS
			echo -e $ENV
		fi
		if [ $POSSIBLE != "0" ]; then return 1; fi
		;;
	WINDOWDECORATOR)
		echo "start window decorator here..."
		start_decorators
		;;
	*)
		store_config
		start_decorators
		start_compiz
	;;
esac