#!/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-2019 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

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

set +e
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


list_custom_keyboard_shortcuts ()
{
    case "${XDG_CURRENT_DESKTOP}" in
        GNOME)
	    gsettings get "${KEYBINDING_SCHEMA}" custom-keybindings \
		| sed --expression='s/^@[[:alnum:]]* //;s/^\[//;s/\]$//;s/, /\n/g' \
		| sed --expression="s/^'//;s/'$//"
            ;;
        MATE)
	    dconf list '/org/mate/desktop/keybindings/' \
		| sed --quiet --expression='/^custom[0-9]\+/{s,/$,,g;p}'
            ;;
        *)
            return 1
            ;;
    esac
}

get_keyboard_shortcut_name ()
{
    local id="$1"

    case "${XDG_CURRENT_DESKTOP}" in
        GNOME)
	    gsettings get "${KEYBINDING_SCHEMA}.custom-keybinding:${id}" name \
		| sed --expression="s/^'//;s/'\$//"
            ;;
        MATE)
	    local dir="$(echo "${id}" | sed --expression='s,^/,,;s,/$,,')"
	    dconf read "${KEYBINDING_PATH}/${dir}/name" \
		| sed --expression="s/^'//;s/'\$//"
            ;;
        *)
            return 1
            ;;
    esac
}

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

    case "${XDG_CURRENT_DESKTOP}" in
	GNOME)
	    local path="${KEYBINDING_PATH}${id}/"

	    # Map binding to GNOME 3 syntax
	    binding="$(echo "${binding}" \
		| sed --expression='s/<Control>/<Primary>/g')"

	    # add shortcut
	    gsettings set "${KEYBINDING_SCHEMA}.custom-keybinding:${path}" name "'${name}'"
	    gsettings set "${KEYBINDING_SCHEMA}.custom-keybinding:${path}" command "'${action}'"
	    gsettings set "${KEYBINDING_SCHEMA}.custom-keybinding:${path}" binding "'${binding}'"

	    # update array of shortcuts
	    local shortcuts="$(list_custom_keyboard_shortcuts)"
	    local newshortcuts

	    debug "Currently registered keyboard shortcuts: $(printf "'%s'" ${shortcuts})"
	    if [ -z "${shortcuts}" ]; then
		newshortcuts="'${path}'"
	    else
		newshortcuts="$(printf "'%s'" ${shortcuts}),'${path}'"
	    fi
	    debug "Newly registered keyboard shortcuts: ${newshortcuts}"
	    gsettings set "${KEYBINDING_SCHEMA}" custom-keybindings "[${newshortcuts}]"
	    ;;
	MATE)
	    dconf write "${KEYBINDING_PATH}/${id}/name" "'${name}'"
	    dconf write "${KEYBINDING_PATH}/${id}/action" "'${action}'"
	    dconf write "${KEYBINDING_PATH}/${id}/binding" "'${binding}'"
	    ;;
    esac
}

add_keyboard_shortcut ()
{
    local dirs="$(list_custom_keyboard_shortcuts)"

    if [ -n "${dirs}" ]; then
	debug "Existing keyboard shortcuts: $(print_args $(basename --multiple ${dirs}))"
    fi

    # check whether keyboard shortcut with given name already exists
    # and find next number to be used for its name, if not
    local next='0'
    local last=''
    for dir in ${dirs}; do
	if [ "$(get_keyboard_shortcut_name "${dir}")" = "${name}" ]
	then
	    verbose "Keyboard shortcut '${dir}' named '${name}' already exists, skipping."
	    return
	fi

	local key="$(basename "${dir}")"
	local num="$(echo "${key}" | sed --quiet --expression='$s/^custom\([[:digit:]]\+\)/\1/gp')"
	if [ -n "${num}" -a "${num}" -ge "${next}" ]; then
	    next=$((${num} + 1))
	    last="${num}"
	fi
    done

    debug "Highest numbered existing custom keyboard shortcut: ${last}"

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

case "${XDG_CURRENT_DESKTOP}" in
    GNOME)
	KEYBINDING_SCHEMA='org.gnome.settings-daemon.plugins.media-keys'
	KEYBINDING_PATH='/org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/'
	;;
    MATE)
	KEYBINDING_PATH='/org/mate/desktop/keybindings'
        ;;
    '')
	error 'Unable to detect esktop environment: XDG_CURRENT_DESKTOP not set'
	exit 1
        ;;
    *)
	error "Desktop environment '${XDG_CURRENT_DESKTOP}' not supported!"
	exit 1
        ;;
esac

verbose "Adding keyboard shortcut for ${XDG_CURRENT_DESKTOP} desktop..."
add_keyboard_shortcut
