#!/bin/sh
# -*- mode: shell-script; coding: utf-8 -*-
#
# add-gnome-keyboard-shortcut
#
# Script to add a a custom shortcut to GNOME Keyboard Shortcuts.
#
# Copyright (C) 2010-2015 Elmar Hoffmann
#
# 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
#

set -e

. /lib/elho/shell-tools

set +e

usage ()
{
    echo "Usage: $(basename -- "$0") [--verbose] [--debug] NAME ACTION BINDING"
}

commandline="$(getopt --name "$(basename -- "$0"): Error" \
    --options='?hvd' --longoptions='help,usage,verbose,debug' -- "$@")"
if [ $? -ne 0 ]; then
    usage
    exit 2
fi
set -e
eval set -- "${commandline}"
verbose=0
debug=0
while true; do
    case "$1" in
        -\?|-h|--help|--usage)
            usage
            exit
            ;;
        -v|--verbose)
            verbose=1
            ;;
        -d|--debug)
            debug=1
            ;;
        --)
            shift
            break
            ;;
        *)
            error "Invalid getopt(1) output."
            exit 1
            ;;
    esac
    shift
done
if [ $# -ne 3 ]; then
    usage
    exit 2
fi

name="$1"
action="$2"
binding="$3"

if [ "${verbose}" -eq 1 -o "${debug}" -eq 1 ]; then
    enable_verbose
fi
if [ "${debug}" -eq 1 ]; then
    enable_debug
fi

get_custom_keyboard_shortcut_basedir ()
{
    local desktop="$1"

    case "${desktop}" in
        gnome)
	    echo '/desktop/gnome/keybindings'
            ;;
        gnome3)
	    echo '/org/gnome/settings-daemon/plugins/media-keys/custom-keybindings'
            ;;
        mate)
	    echo '/org/mate/desktop/keybindings'
            ;;
        *)
            return 1
            ;;
    esac
}

list_custom_keyboard_shortcuts ()
{
    local desktop="$1"

    case "${desktop}" in
        gnome)
            gconftool-2 --all-dirs $(get_custom_keyboard_shortcut_basedir "${desktop}") \
		| sed --quiet \
		--expression='s,^[[:space:]]\+[^[:space:]]\+/\(custom[0-9]\+\),\1,gp'
            ;;
        gnome3|mate)
	    dconf list "$(get_custom_keyboard_shortcut_basedir "${desktop}")/" \
		| sed --quiet --expression='/^custom[0-9]\+/{s,/$,,g;p}'
            ;;
        *)
            return 1
            ;;
    esac
}

get_keyboard_shortcut_name ()
{
    local desktop="$1"
    local id="$2"

    local basedir="$(get_custom_keyboard_shortcut_basedir "${desktop}")"

    case "${desktop}" in
        gnome)
	if [ "$(gconftool-2 --get-type "${basedir}/${id}/name")" = 'string' ]
	then
	    gconftool-2 --get "${basedir}/${id}/name"
	else
	    return 1
	fi
            ;;
        gnome3|mate)
	    dconf read "${basedir}/${dir}/name" \
		| sed --expression="s/^'//;s/'\$//"
            ;;
        *)
            return 1
            ;;
    esac
}

set_keyboard_shortcut ()
{
    local desktop="$1"
    local id="$2"
    local name="$3"
    local action="$4"
    local binding="$5"

    local basedir="$(get_custom_keyboard_shortcut_basedir "${desktop}")"
    local actionname

    case "${desktop}" in
        gnome)
	    gconftool-2 --set "${basedir}/${id}/name" --type string "${name}"
	    gconftool-2 --set "${basedir}/${id}/action" --type string "${action}"
	    gconftool-2 --set "${basedir}/${id}/binding" --type string "${binding}"
            ;;
        gnome3|mate)
	    case "${desktop}" in
		gnome3)
		    actionname='command'

		    binding="$(echo "${binding}" \
			| sed --expression='s/<Control>/<Primary>/g')"
		    ;;
		mate)
		    actionname='action'
		    ;;
	    esac
	    dconf write "${basedir}/${id}/name" "'${name}'"
	    dconf write "${basedir}/${id}/${actionname}" "'${action}'"
	    dconf write "${basedir}/${id}/binding" "'${binding}'"

	    case "${desktop}" in
		gnome3)
		    # get array elements skipping leading dconf type annotation
		    local shortcuts="$(dconf read "${basedir}" \
			| sed --expression='s/^[^[]*\[//;s/\]$//')"
		    local newshortcuts

		    debug "Currently registered keyboard shortcuts: ${shortcuts}"
		    if [ -z "${shortcuts}" ]; then
			newshortcuts="'${basedir}/${id}/'"
		    else
			newshortcuts="${shortcuts},'${basedir}/${id}/'"
		    fi
		    debug "Newly registered keyboard shortcuts: ${newshortcuts}"
		    dconf write "${basedir}" "[${newshortcuts}]"
		    ;;
	    esac
            ;;
        *)
            return 1
            ;;
    esac
}

add_keyboard_shortcut ()
{
    local desktop="$1"

    local desktopname
    local tool

    case "${desktop}" in
        gnome)
	    desktopname='GNOME 2'
	    tool='gconftool-2'
            ;;
        gnome3)
	    desktopname='GNOME 3'
	    tool='dconf'
            ;;
        mate)
	    desktopname='MATE'
	    tool='dconf'
            ;;
        *)
            return 1
            ;;
    esac
    
    if ! which "${tool}" > /dev/null; then
	if [ "${verbose}" -eq 1 -o "${debug}" -eq 1 ]; then
	    warn "'${tool}' not installed, skipping ${desktopname} desktop..."
	fi
	return 0
    fi

    verbose "Adding keyboard shortcut for ${desktopname} desktop..."

    local basedir="$(get_custom_keyboard_shortcut_basedir "${desktop}")"
    local dirs="$(list_custom_keyboard_shortcuts "${desktop}" | sort)"

    debug "Existing keyboard shortcuts: $(print_args ${dirs})"

    # check whether keyboard shortcut with given name already exists
    for dir in ${dirs}; do
	if [ "$(get_keyboard_shortcut_name "${desktop}" "${dir}")" = "${name}" ]
	then
	    verbose "Keyboard shortcut '${dir}' named '${name}' already exists, skipping."
	    return
	fi
    done

    local next
    if [ -n "${dirs}" ]; then
	local last="$(echo "${dirs}" | sed --quiet --expression='$s/^custom//gp')"
	debug "Highest numbered existing custom keyboard shortcut: ${last}"

	next=$((${last} + 1))
    else
	next='0'
    fi

    local id="custom${next}"
    verbose "Adding keyboard shortcut '${id}' named '${name}'..."
    set_keyboard_shortcut  "${desktop}" "${id}" "${name}" "${action}" "${binding}"
}

for desktop in 'gnome' 'mate' 'gnome3'; do
    add_keyboard_shortcut "${desktop}"
done
