#!/bin/sh
#
# Set wallpaper for awesome.
# Copyright (c) 2008 Julien Danjou <julien@danjou.info>
# 
# Derived from fbsetbg:
# Copyright (c) 2003-2004 Han Boetes <han@mijncomputer.nl>
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

# Portability notes:
# To guarantee this script works on all platforms that support awesome
# please keep the following restrictions in mind:
#
# - don't use if ! command;, use command; if [ $? -ne 0 ];
# - don't use [ -e file ] use [ -r file ]
# - don't use $(), use ``
# - don't use ~, use ${HOME}
# - don't use id -u or $UID, use whoami
# - don't use echo -e
# - getopts won't work on all platforms, but the config-file can
#   compensate for that.
# - various software like grep/sed/perl may be not present or not
#   the version you have. for example grep '\W' only works on gnu-grep.
#   Keep this in mind, use bare basic defaults.
# - Do _NOT_ suggest to use #!/bin/bash. Not everybody uses bash.

# TODO purheps: xprop -root _WIN_WORKSPACE
# _NET_CURRENT_DESKTOP

if [ -z "$XDG_CACHE_HOME" ]
then
    CONFIG_DIR="${HOME}/.cache/awesome"
else
    CONFIG_DIR="${XDG_CACHE_HOME}/awesome"
fi

# The wallpapersetter is selected in this order
wpsetters="${wpsetters:=Esetroot habak feh hsetroot chbg fvwm-root display qiv xv xsri xli xsetbg wmsetbg xsetroot}" # broken icewmbg'
lastwallpaper="${CONFIG_DIR}/lastwallpaper"


WHOAMI=`whoami`
[ "$WHOAMI" = root ] && PATH=/bin:/usr/bin/:/usr/local/bin:/usr/X11R6/bin

command="`basename \"$0\"`"


# Functions
display_usage() {
    cat << EOF
Usage: $command [-u/-U [wallpapersetter]] [-fFcCtTaA] [-m #] /path/to/wallpaper
       $command [-u/-U [wallpapersetter]] [-fFcCtTaA] [-m #] -r/-R /path/to/wallpaperdirectory
       $command [-lhip]
Use \`\`$command -h'' for a complete help message.

EOF
}

display_help() {
    display_usage
    cat << EOF

Options:

    -f  Set fullscreen wallpaper (default).
    -c  Set centered wallpaper.
    -t  Set tiled wallpaper.
    -a  Set maximized wallpaper, preserving aspect.
        ( if your bgsetter doesn't support this
          we fall back to -f )
    -u  Use specified wallpapersetter, use no argument to forget.
    -r  set random wallpaper from a directory

    -F,-C,-T,-A,-U,-R same as lowercase but without remembering.

    -h  Display this help.

    -l  Set previous wallpaper.

    -i  Information about selected wallpaper command.

    -m  # Use montage to create a big image (image should
          fit screen size). Requires montage(1).
        # is the number of screen (columns in montage)
Files:

    \$XDG_CACHE_HOME/awesome/lastwallpaper     In this file the wallpaper you set
                                               will be stored, for the -l option.
Environment variables:
    wpsetters   Wallpapersetters to use.
                example:
                  wpsetters=feh awsetbg wallpaper.jpg

    DISPLAY     The display you want to set the wallpaper on.
                example:
                  DISPLAY=:0.0 awsetbg -l

EOF
}

find_it() {
    [ -n "$1" ] && which $1 1>/dev/null 2>&1
}

message() {
    extra_args="-default okay"
    if find_it gxmessage; then
        gxmessage $extra_args -center "$command: $@" &
    else
        xmessage $extra_args -center "$command: $@" &
    fi
}

remembercommand() {
    grep -vs "|${DISPLAY}$" ${lastwallpaper} > ${lastwallpaper}.tmp
    mv -f ${lastwallpaper}.tmp ${lastwallpaper}
    # Make dir/../../path/file.jpg work
    case $wallpaper in
        # no spaces allowed between the varname and '|'
        /*) echo $option $option2"|$wallpaper|$style|"$DISPLAY >> $lastwallpaper ;;
        *)  echo $option $option2"|$PWD/$wallpaper|$style|"$DISPLAY >> $lastwallpaper ;;
    esac
}

debugawsetbg() {
    echo
    echo $debugstory
    echo $sad_esetroot_story
    echo $sad_display_story
    exit 0
}

if [ $# -eq 0 ]; then
    message "no options given"
    display_usage
    exit 1
fi

# create directory and last wallpaper file 
if [ ! -d  "${CONFIG_DIR}" ]; then
        mkdir -p "${CONFIG_DIR}"
    touch ${lastwallpaper}
fi

unset debug setterfromcommandline
# Parse command-line options
while [ $# -gt 0 ]; do
    case "$1" in
        -u)
            if find_it "$2"; then
                grep -v wpsetters $lastwallpaper > ${lastwallpaper}.tmp
                echo "wpsetters $2" >> ${lastwallpaper}.tmp
                mv ${lastwallpaper}.tmp $lastwallpaper
                WPSETTER=$2
                setterfromcommandline=true
            elif [ -z "$2" ]; then
                grep -v wpsetters $lastwallpaper > ${lastwallpaper}.tmp
                mv ${lastwallpaper}.tmp $lastwallpaper
                message "wpsetter removed from historyfile"
                exit 0
            else
                message "Couldn't find \"$2\" for wallpapersetter"
                display_usage
                exit 1
            fi
            shift 2 ;;
        -U)
            if find_it "$2"; then
                WPSETTER=$2
                setterfromcommandline=true
            else
                message "Couldn't find \"$2\" for wallpapersetter"
                display_usage
                exit 1
            fi
            shift 2 ;;
        -i) debug=true
            break ;;
        -a) option='$aspect'
            shift ;;
        -f) option='$full'
            shift ;;
        -c) option='$center'
            shift ;;
        -t) option='$tile'
            shift ;;
        -A) option='$aspect'
            remember=false
            shift ;;
        -F) option='$full'
            remember=false
            shift ;;
        -C) option='$center'
            remember=false
            shift ;;
        -T) option='$tile'
            remember=false
            shift ;;
        -m)
            montage=`which montage`
            if test ! -z "$montage"; then
                shift
                cols="$1"; shift
                fns=""
                for i in `seq $cols`; do
                    fns="$fns $1";
                done;
                shift
                $montage $fns -geometry +0+0 -tile ${cols}x $CONFIG_DIR/montage.png
                wallpaper=$CONFIG_DIR/montage.png
            else
                shift
                echo "montage not found. Falling back to single image"
            fi
            ;;
        -r) option2=$option
            option=random
            wallpaper=$2 # in this case it's a dir
            break ;;
        -R) option2=$option
            option=random
            wallpaper=$2 # in this case it's a dir
            remember=false
            break ;;
        -l)
            if [ -r "$lastwallpaper" ]; then
                option=`grep "|${DISPLAY}$"    $lastwallpaper|cut -d'|' -f1`
                option2=`echo $option|cut -d' ' -f2`
                option=`echo $option|cut -d' ' -f1`
                wallpaper=`grep "|${DISPLAY}$" $lastwallpaper|cut -d'|' -f2`
                if [ -z "$wallpaper" ]; then
                    option=`grep "|${DISPLAY}.0$"    $lastwallpaper|cut -d'|' -f1`
                    option2=`echo $option|cut -d' ' -f2`
                    option=`echo $option|cut -d' ' -f1`
                    wallpaper=`grep "|${DISPLAY}.0$" $lastwallpaper|cut -d'|' -f2`
                fi
                if [ -z "$wallpaper" ]; then
                    message "No previous wallpaper recorded for display ${DISPLAY}"
                    exit 1
                fi
            else
                message "No previous wallpaper recorded for display ${DISPLAY}"
                exit 1
            fi
            remember=false
            break ;;
        -z)
            if [ -r "$lastwallpaper" ]; then
                option=`grep "|${DISPLAY}$"    $lastwallpaper|cut -d'|' -f1`
                option2=`echo $option|cut -d' ' -f2`
                option=`echo $option|cut -d' ' -f1`
                style=`grep "|${DISPLAY}$" $lastwallpaper|cut -d'|' -f3`
                wallpaper=`grep "|${DISPLAY}$" $lastwallpaper|cut -d'|' -f2`
                if [ -z "$wallpaper" ]; then
                    option=`grep "|${DISPLAY}.0$"    $lastwallpaper|cut -d'|' -f1`
                    option2=`echo $option|cut -d' ' -f2`
                    option=`echo $option|cut -d' ' -f1`
                    style=`grep "|${DISPLAY}.0$" $lastwallpaper|cut -d'|' -f3`
                    wallpaper=`grep "|${DISPLAY}.0$" $lastwallpaper|cut -d'|' -f2`
                fi
            fi
            if [ "$style" != "style" -a -n "$wallpaper" ]; then
                remember=false
                break
            fi
            style="style"
            shift ;;
        -Z)
            style="style"
            shift ;;
        -h) display_help ; exit 0 ;;
        --)
            message "$command doesn't recognize -- gnu-longopts."
            message 'Use $command -h for a help message.'
            display_usage
            exit 1 ;;
        -*)
            message "unrecognized option "\`"$1'"
            display_usage
            exit 1 ;;
        *)
            if [ "$option" = random ]; then
                option='$aspect'
            elif [ ! -r "$1" ]; then
                message "$1 isn't an existing wallpaper or a valid option."
                display_usage
                exit 1
            elif [ -z "$1" ]; then
                message 'No wallpaper to set'
                display_usage
                exit 1
            else
                wallpaper=$1
                break
            fi ;;
    esac
done

# Find the default wallpapersetter
if [ "$setterfromcommandline" != true ]; then
    if [ -r "$lastwallpaper" ]; then
        wpsetters="`awk '/wpsetters/ {print $2}' $lastwallpaper` $wpsetters"
    fi
    for wpsetter in $wpsetters; do
        if find_it $wpsetter; then
            case $wpsetter in
                Esetroot)
                    if ldd `which Esetroot`|grep libImlib 2>&1 > /dev/null; then
                        WPSETTER=$wpsetter
                        break
                    else
                        sad_esetroot_story="I also found Esetroot, but it doesn't have support for setting wallpapers. You need to install libimlib2 and rebuild Eterm to get it working."
                    fi
                    ;;
                display)
                    if find_it xwininfo; then
                        WPSETTER=$wpsetter
                        break
                    else
                        sad_display_story="I also found display, but I need xwininfo for querying the root window geometry."
                    fi
                    ;;
                *)
                    WPSETTER=$wpsetter
                    break
            esac
        fi
    done
fi

standardrant=\
"$WPSETTER doesn't set the wallpaper properly. Transparency for
awesome and apps like aterm and xchat won't work right with
it. Consider installing feh, Esetroot
(from Eterm) or fvwm-root (from FVWM) and I'll use them instead."

standardok=\
"$WPSETTER is a nice wallpapersetter. You won't have any problems."

case $WPSETTER in
    chbg)
        full='-once -mode maximize'
        tile='-once -mode tile'
        center='-once -mode center'
        aspect='-once -mode smart -max_grow 100 -max_size 100'
        debugstory="chbg supports all features but it doesn't report errors. I reported this bug to the chbg developers."
        ;;
    xsri)
        full='--center-x --center-y --scale-width=100 --scale-height=100'
        tile='--tile'
        center='--center-x --center-y --color=black'
        aspect='--center-x --center-y --scale-width=100 --scale-height=100 --keep-aspect --color=black'
        debugstory=$standardok
        ;;
    display)
        full="-sample `xwininfo -root 2> /dev/null|awk '/geom/{print $2}'` -window root"
        tile='-window root'
        center='-backdrop -window root'
        aspect="`xwininfo -root 2> /dev/null|grep geom` -window root"
        debugstory=$standardrant
        ;;
    Esetroot)
        full='-scale'
        tile=''
        center='-c'
        aspect='-fit'
        debugstory=$standardok
        ;;
    wmsetbg)
        full='-s -S'
        tile='-t'
        center='-b black -e'
        aspect='-b black -a -S'
        debugstory=$standardok
        ;;
    xsetbg)
        tile='-border black'
        center='-center -border black'
        aspect='-fullscreen -border black'
        full=$aspect #broken
        debugstory="xsetbg is actually xli. The fillscreen option (-f) is broken, defaults to (-a). $standardrant"
        ;;
    xli)
        tile='-onroot -quiet -border black'
        center='-center -onroot -quiet -border black'
        aspect='-fullscreen -onroot -quiet -border black'
        full=$aspect #broken
        debugstory="The fillscreen option (-f) is broken, defaults to (-a). $standardrant"
        ;;
    qiv)
        full='--root_s'
        tile='--root_t'
        center='--root'
        aspect='-m --root'
        debugstory=$standardrant
        ;;
    xv)
        full='-max -smooth -root -quit'
        tile='-root -quit'
        center='-rmode 5 -root -quit'
        aspect='-maxpect -smooth -root -quit'
        debugstory=$standardrant
        ;;
    feh)
        full='--bg-scale'
        tile='--bg-tile'
        center='--bg-center'
        aspect=$full
        debugstory=$standardok
        ;;
    hsetroot)
        full='-fill'
        tile='-tile'
        center='-center'
        aspect='-full'
        debugstory=$standardok
        ;;
    habak)
        full='-ms'
        tile=''
        center='-mC'
        aspect='-mS'
        debugstory=$standardok
        ;;
    fvwm-root)
        tile='-r'
        full=$tile
        center=$tile
        aspect=$tile
        debugstory="fvwm-root can retain and publish the Pixmap, thus
supports transparency. But only these image formats are supported:
XBM, XPM, PNG, SVG and it is rather limited with options."
        ;;
    icewmbg)
        tile='-s'
        full=$tile
        center=$tile
        aspect=$tile
        debugstory="icewmbg does support transparency, but only tiling. And I noticed odd
errormessages with aterm. Don't use it unless you have to."
        ;;
    xsetroot)
        tile='-solid'
        full=$tile
        center=$tile
        aspect=$tile
        debugstory="I can't find an app to set the wallpaper with. Using xsetroot to set
a solid background. If you want to have a background image you should install Esetroot or feh."
        wallpaper='#535d6c'
        ;;
    '')
        message \
"I can't find an app to set the wallpaper with. You can install one in
many many ways but I will give you some simple advice: install Eterm and
you're set. Eterm provides Esetroot and thats a great wallpaper setter. I
recommend you install the package provided by your distro."
        exit 1
        ;;
esac

if [ "$debug" = true ]; then
    debugawsetbg
    exit 0
fi

option=${option:='$full'}
option2=${option2:='$full'}


if [ -z "$DISPLAY" ]; then
    message "You are not connected to an X session\nPerhaps you should set the DISPLAY environment variable?"
    exit 1
fi


# random wallpaper code
if [ "$option" = random ]; then
    # Lets make one thing clear...
    wallpaperdir="$wallpaper"
    if [ -z "$wallpaperdir" ]; then
        message "No random wallpaper directory specified."
        exit 1
    fi
    if [ -d "$wallpaperdir" ]; then
        number_of_wallpapers=`ls "$wallpaperdir"|wc -l`
        if find_it random_number; then
            randomnumber=`random_number`
        # some shells don't support $RANDOM
        elif [ -z "$RANDOM" ]; then
            randomnumber=`(echo $$ ;time ps; w ; date )2>&1 | cksum | cut -f1 -d' '`
        else
            randomnumber="$RANDOM"
        fi
        wallpapernumber=`expr $randomnumber % $number_of_wallpapers + 1`
        #remember previous wallpaper
        if [ ! "$remember" = false ]; then
            remembercommand
        fi
        remember=false
        #set -x
        wallpaper="$wallpaperdir/`ls \"$wallpaperdir\"|sed -n ${wallpapernumber}p`"
        option=$option2 # have to choose something...
    else
        message "Invalid random wallpaper directory specified."
        exit 1
    fi
fi


if [ ! -r "$wallpaper" ] && [ $WPSETTER != "xsetroot" ]; then
    message "Can't find wallpaper $wallpaper"
    exit 1
fi


$WPSETTER `eval echo $option` "$wallpaper"
if [ $? -ne 0 -a "$WPSETTER" != "display" ] ||
   [ $? -ne 1 -a "$WPSETTER"  = "display" ]; then
    message "Something went wrong while setting the wallpaper.
Run '$WPSETTER "`eval echo $option` $wallpaper"' from an xterm to find out what."
    exit 1
fi


#remember previous wallpaper
if [ ! "$remember" = false ]; then
    remembercommand
fi