blob: a503e2b349d9aa274a339a3663908d665bc724f1 [file] [log] [blame]
#!/bin/sh
#---------------------------------------------
# xdg-settings
#
# Utility script to get various settings from the desktop environment.
#
# Refer to the usage() function below for usage.
#
# Copyright 2009, Google Inc.
#
# LICENSE:
#
#---------------------------------------------
manualpage()
{
cat << _MANUALPAGE
_MANUALPAGE
}
usage()
{
cat << _USAGE
_USAGE
}
#@xdg-utils-common@
check_desktop_filename()
{
case "$1" in
*/*)
exit_failure_syntax "invalid application name"
;;
*.desktop)
return
;;
*)
exit_failure_syntax "invalid application name"
;;
esac
}
# {{{ default browser
# {{{ utility functions
# In order to remove an application from the automatically-generated list of
# applications for handling a given MIME type, the desktop environment may copy
# the global .desktop file into the user's .local directory, and remove that
# MIME type from its list. In that case, we must restore the MIME type to the
# application's list of MIME types before we can set it as the default for that
# MIME type. (We can't just delete the local version, since the user may have
# made other changes to it as well. So, tweak the existing file.)
# This function is hard-coded for text/html but it could be adapted if needed.
fix_local_desktop_file()
{
if test -z "$2" ; then
MIME="text/html"
else
MIME="$2"
fi
apps="${XDG_DATA_HOME:-$HOME/.local/share}/applications"
# No local desktop file?
[ ! -f "$apps/$1" ] && return
MIMETYPES="`grep "^MimeType=" "$apps/$1" | cut -d= -f 2-`"
case "$MIMETYPES" in
$MIME\;*|*\;$MIME\;*|*\;$MIME\;|*\;$MIME)
# Already has the mime-type? Great!
return 0
;;
esac
# Add the mime-type to the list
temp="`mktemp "$apps/$1.XXXXXX"`" || return
grep -v "^MimeType=" "$apps/$1" >> "$temp"
echo "MimeType=$MIME;$MIMETYPES" >> "$temp"
oldlines="`wc -l < "$apps/$1"`"
newlines="`wc -l < "$temp"`"
# The new file should have at least as many lines as the old.
if [ $oldlines -le $newlines ]; then
mv "$temp" "$apps/$1"
# This can take a little bit to get noticed.
sleep 4
else
rm -f "$temp"
return 1
fi
}
# }}} utility functions
# {{{ MIME utilities
xdg_mime_fixup()
{
# xdg-mime may use ktradertest, which will fork off a copy of kdeinit if
# one does not already exist. It will exit after about 15 seconds if no
# further processes need it around. But since it does not close its stdout,
# the shell (via grep) will wait around for kdeinit to exit. If we start a
# copy here, that copy will be used in xdg-mime and we will avoid waiting.
if [ "$DE" = kde -a -z "$XDG_MIME_FIXED" ]; then
ktradertest text/html Application > /dev/null 2>&1
# Only do this once, as we only need it once.
XDG_MIME_FIXED=yes
fi
}
get_browser_mime()
{
if test -z "$1" ; then
MIME="text/html"
else
MIME="$1"
fi
xdg_mime_fixup
xdg-mime query default "$MIME"
}
set_browser_mime()
{
xdg_mime_fixup
if test -z "$2" ; then
MIME="text/html"
else
MIME="$2"
fi
orig="`get_browser_mime $MIME`"
# Fixing the local desktop file can actually change the default browser all
# by itself, so we fix it only after querying to find the current default.
fix_local_desktop_file "$1" "$MIME" || return
mkdir -p "${XDG_DATA_HOME:-$HOME/.local/share}/applications"
xdg-mime default "$1" "$MIME" || return
if [ x"`get_browser_mime`" != x"$1" ]; then
# Put back the original value
xdg-mime default "$orig" "$MIME"
exit_failure_operation_failed
fi
}
# }}} MIME utilities
# {{{ KDE utilities
# Reads the KDE configuration setting, compensating for a bug in some versions of kreadconfig.
read_kde_config()
{
configfile="$1"
configsection="$2"
configkey="$3"
application="`kreadconfig --file $configfile --group $configsection --key $configkey`"
if [ x"$application" != x ]; then
echo "$application"
else
# kreadconfig in KDE 4 may not notice Key[$*]=... localized settings, so
# check by hand if it didn't find anything (oddly kwriteconfig works
# fine though).
configfile_dir=`kde${KDE_SESSION_VERSION}-config --path config | cut -d ':' -f 1`
configfile_path="$configfile_dir/$configfile"
[ ! -f "$configfile_path" ] && return
# This will only take the first value if there is more than one.
grep "^$configkey"'\[$[^]=]*\]=' "$configfile_path" | head -n 1 | cut -d= -f 2-
fi
}
# }}} KDE utilities
# {{{ KDE
# Resolves the KDE browser setting to a binary: if prefixed with !, simply removes it;
# otherwise, uses desktop_file_to_binary to get the binary out of the desktop file.
resolve_kde_browser()
{
[ -z "$browser" ] && return
case "$browser" in
!*)
echo "${browser#!}"
;;
*)
desktop_file_to_binary "$browser"
;;
esac
}
# Does the opposite of resolve_kde_browser: if prefixed with !, tries to find a desktop
# file corresponding to the binary, otherwise just returns the desktop file name.
resolve_kde_browser_desktop()
{
[ -z "$browser" ] && return
case "$browser" in
!*)
desktop="`binary_to_desktop_file "${browser#!}"`"
basename "$desktop"
;;
*)
echo "$browser"
;;
esac
}
read_kde_browser()
{
read_kde_config kdeglobals General BrowserApplication
}
get_browser_kde()
{
browser="`read_kde_browser`"
if [ x"$browser" = x ]; then
# No explicit default browser; KDE will use the MIME type text/html.
get_browser_mime
else
resolve_kde_browser_desktop
fi
}
check_browser_kde()
{
check="`desktop_file_to_binary "$1"`"
if [ -z "$check" ]; then
echo no
exit_success
fi
browser="`read_kde_browser`"
binary="`resolve_kde_browser`"
# Because KDE will use the handler for MIME type text/html if this value
# is empty, we allow either the empty string or a match to $check here.
if [ x"$binary" != x -a x"$binary" != x"$check" ]; then
echo no
exit_success
fi
browser="`get_browser_mime`"
binary="`desktop_file_to_binary "$browser"`"
if [ x"$binary" != x"$check" ]; then
echo no
exit_success
fi
echo yes
exit_success
}
set_browser_kde()
{
set_browser_mime "$1" || return
kwriteconfig --file kdeglobals --group General --key BrowserApplication "$1"
}
# }}} KDE
# {{{ GNOME
get_browser_gnome()
{
binary="`gconftool-2 --get /desktop/gnome/applications/browser/exec | first_word`"
if [ x"$binary" = x ]; then
# No default browser; GNOME might use the MIME type text/html.
get_browser_mime
else
# gconftool gives the binary (maybe with %s etc. afterward),
# but we want the desktop file name, not the binary. So, we
# have to find the desktop file to which it corresponds.
desktop="`binary_to_desktop_file "$binary"`"
basename "$desktop"
fi
}
check_browser_gnome()
{
check="`desktop_file_to_binary "$1"`"
if [ -z "$check" ]; then
echo no
exit_success
fi
binary="`gconftool-2 --get /desktop/gnome/applications/browser/exec | first_word`"
if [ x"$binary" != x"$check" ]; then
echo no
exit_success
fi
# Check HTTP and HTTPS, but not about: and unknown:.
for protocol in http https; do
binary="`gconftool-2 --get /desktop/gnome/url-handlers/$protocol/command | first_word`"
if [ x"$binary" != x"$check" ]; then
echo no
exit_success
fi
done
browser="`get_browser_mime`"
binary="`desktop_file_to_binary "$browser"`"
if [ x"$binary" != x"$check" ]; then
echo no
exit_success
fi
echo yes
exit_success
}
set_browser_gnome()
{
binary="`desktop_file_to_binary "$1"`"
[ "$binary" ] || exit_failure_file_missing
set_browser_mime "$1" || return
# Set the default browser.
gconftool-2 --type string --set /desktop/gnome/applications/browser/exec "$binary"
gconftool-2 --type bool --set /desktop/gnome/applications/browser/needs_term false
gconftool-2 --type bool --set /desktop/gnome/applications/browser/nremote true
# Set the handler for HTTP and HTTPS.
for protocol in http https; do
gconftool-2 --type string --set /desktop/gnome/url-handlers/$protocol/command "$binary %s"
gconftool-2 --type bool --set /desktop/gnome/url-handlers/$protocol/needs_terminal false
gconftool-2 --type bool --set /desktop/gnome/url-handlers/$protocol/enabled true
done
# Set the handler for about: and unknown URL types.
for protocol in about unknown; do
gconftool-2 --type string --set /desktop/gnome/url-handlers/$protocol/command "$binary %s"
done
}
# }}} GNOME
# {{{ GNOME 3.x
get_browser_gnome3()
{
get_browser_mime "x-scheme-handler/http"
}
check_browser_gnome3()
{
desktop="$1"
check="`desktop_file_to_binary "$1"`"
if [ -z "$check" ]; then
echo no
exit_success
fi
# Check HTTP and HTTPS, but not about: and unknown:.
for protocol in http https; do
browser="`get_browser_mime "x-scheme-handler/$protocol"`"
if [ x"$browser" != x"$desktop" ]; then
echo no
exit_success
fi
done
echo yes
exit_success
}
set_browser_gnome3()
{
binary="`desktop_file_to_binary "$1"`"
[ "$binary" ] || exit_failure_file_missing
set_browser_mime "$1" || return
# Set the default browser.
for protocol in http https about unknown; do
set_browser_mime "$1" "x-scheme-handler/$protocol" || return
done
}
# }}} GNOME 3.x
# {{{ xfce
get_browser_xfce()
{
search="${XDG_CONFIG_HOME:-$HOME/.config}:${XDG_CONFIG_DIRS:-/etc/xdg}"
IFS=:
for dir in $search; do
unset IFS
[ "$dir" -a -d "$dir/xfce4" ] || continue
file="$dir/xfce4/helpers.rc"
[ -r "$file" ] || continue
grep -q "^WebBrowser=" "$file" || continue
desktop="`grep "^WebBrowser=" "$file" | cut -d= -f 2-`"
echo "$desktop.desktop"
return
done
exit_failure_operation_failed
}
check_browser_xfce()
{
browser="`get_browser_xfce`"
if [ x"$browser" != x"$1" ]; then
echo no
exit_success
fi
echo yes
exit_success
}
check_xfce_desktop_file()
{
# Annoyingly, xfce wants its .desktop files in a separate directory instead
# of the standard locations, and requires a few custom tweaks to them:
# "Type" must be "X-XFCE-Helper"
# "X-XFCE-Category" must be "WebBrowser" (for web browsers, anyway)
# "X-XFCE-Commands" and "X-XFCE-CommandsWithParameter" must be set
search="${XDG_DATA_HOME:-$HOME/.local/share}:${XDG_DATA_DIRS:-/usr/local/share:/usr/share}"
IFS=:
for dir in $search; do
unset IFS
[ "$dir" -a -d "$dir/xfce4/helpers" ] || continue
file="$dir/xfce4/helpers/$1"
# We have the file, no need to create it.
[ -r "$file" ] && return
done
IFS=:
for dir in $search; do
unset IFS
[ "$dir" -a -d "$dir/applications" ] || continue
file="$dir/applications/$1"
if [ -r "$file" ]; then
# Found a file to convert.
target="${XDG_DATA_HOME:-$HOME/.local/share}/xfce4/helpers"
mkdir -p "$target"
grep -v "^Type=" "$file" > "$target/$1"
echo "Type=X-XFCE-Helper" >> "$target/$1"
echo "X-XFCE-Category=WebBrowser" >> "$target/$1"
# Change %F, %f, %U, and %u to "%s".
command="`grep -E "^Exec(\[[^]=]*])?=" "$file" | cut -d= -f 2- | sed -e 's/%[FfUu]/"%s"/g'`"
echo "X-XFCE-Commands=`echo "$command" | first_word`" >> "$target/$1"
echo "X-XFCE-CommandsWithParameter=$command" >> "$target/$1"
return
fi
done
return 1
}
set_browser_xfce()
{
check_xfce_desktop_file "$1" || exit_failure_operation_failed
helper_dir="${XDG_CONFIG_HOME:-$HOME/.config}/xfce4"
if [ ! -d "$helper_dir" ]; then
mkdir -p "$helper_dir" || exit_failure_operation_failed
fi
helpers_rc="$helper_dir/helpers.rc"
# Create the file if it does not exist to avoid special cases below.
if [ ! -r "$helpers_rc" ]; then
touch "$helpers_rc" || exit_failure_operation_failed
fi
temp="`mktemp "$helpers_rc.XXXXXX"`" || return
grep -v "^WebBrowser=" "$helpers_rc" >> "$temp"
echo "WebBrowser=${1%.desktop}" >> "$temp"
oldlines="`wc -l < "$helpers_rc"`"
newlines="`wc -l < "$temp"`"
# The new file should have at least as many lines as the old.
if [ $oldlines -le $newlines ]; then
mv "$temp" "$helpers_rc"
else
rm -f "$temp"
return 1
fi
}
# }}} xfce
# }}} default browser
# {{{ default url scheme handler
exit_unimplemented_default_handler()
{
exit_failure_operation_impossible "default-url-scheme-handler not implemented for $DE"
}
# {{{ KDE
# Recent versions of KDE support default scheme handler applications using the
# mime type of x-scheme-handler/scheme. Older versions will not support this
# but do have support for setting a default mail handler. There is also a
# system in KDE where .protocol files can be used, however this is not
# supported by this script. When reading a scheme handler we will use the
# default mail handler for the mailto scheme, otherwise we will use the mime
# type x-scheme-handler/scheme.
get_url_scheme_handler_kde()
{
if [ "$1" = "mailto" ]; then
handler="`read_kde_config emaildefaults PROFILE_Default EmailClient | first_word`"
echo "handler is $handler"
if [ x"$handler" != x ]; then
binary_to_desktop_file "$handler"
else
get_browser_mime "x-scheme-handler/$1"
fi
else
get_browser_mime "x-scheme-handler/$1"
fi
}
check_url_scheme_handler_kde()
{
check="`desktop_file_to_binary "$2"`"
if [ -z "$check" ]; then
echo no
exit_success
fi
if [ x"$1" = "mailto" ]; then
binary="`read_kde_config emaildefaults PROFILE_Default EmailClient`"
if [ x"$binary" != x"$check" ]; then
echo no
exit_success
fi
fi
handler="`get_browser_mime x-scheme-handler/$1`"
binary="`desktop_file_to_binary "$handler"`"
if [ x"$binary" != x"$check" ]; then
echo no
exit_success
fi
echo yes
exit_success
}
set_url_scheme_handler_kde()
{
set_browser_mime "$2" "x-scheme-handler/$1" || return
if [ "$1" = "mailto" ]; then
binary="`desktop_file_to_binary "$2"`"
kwriteconfig --file emaildefaults --group PROFILE_Default --key EmailClient "$binary"
fi
}
# }}} KDE
# {{{ GNOME
get_url_scheme_handler_gnome()
{
binary="`gconftool-2 --get /desktop/gnome/url-handlers/$1/command | first_word`"
if [ x"$binary" != x"" ]; then
# gconftool gives the binary (maybe with %s etc. afterward),
# but we want the desktop file name, not the binary. So, we
# have to find the desktop file to which it corresponds.
desktop="`binary_to_desktop_file "$binary"`"
basename "$desktop"
fi
}
check_url_scheme_handler_gnome()
{
check="`desktop_file_to_binary "$2"`"
if [ -z "$check" ]; then
echo no
exit_success
fi
binary="`gconftool-2 --get /desktop/gnome/url-handlers/$1/command | first_word`"
if [ x"$binary" != x"$check" ]; then
echo no
exit_success
fi
echo yes
exit_success
}
set_url_scheme_handler_gnome()
{
binary="`desktop_file_to_binary "$2"`"
[ "$binary" ] || exit_failure_file_missing
gconftool-2 --type string --set /desktop/gnome/url-handlers/$1/command "$binary %s"
gconftool-2 --type bool --set /desktop/gnome/url-handlers/$1/needs_terminal false
gconftool-2 --type bool --set /desktop/gnome/url-handlers/$1/enabled true
}
# }}} GNOME
# {{{ GNOME 3.x
get_url_scheme_handler_gnome3()
{
get_browser_mime "x-scheme-handler/$1"
}
check_url_scheme_handler_gnome3()
{
desktop="$2"
check="`desktop_file_to_binary "$2"`"
if [ -z "$check" ]; then
echo no
exit_success
fi
browser="`get_browser_mime "x-scheme-handler/$1"`"
if [ x"$browser" != x"$desktop" ]; then
echo no
exit_success
fi
echo yes
exit_success
}
set_url_scheme_handler_gnome3()
{
binary="`desktop_file_to_binary "$2"`"
[ "$binary" ] || exit_failure_file_missing
set_browser_mime "$2" || return
# Set the default browser.
set_browser_mime "$2" "x-scheme-handler/$1" || return
}
# }}} GNOME 3.x
# {{{ xfce
get_url_scheme_handler_xfce()
{
exit_unimplemented_default_handler "$1"
}
check_url_scheme_handler_xfce()
{
exit_unimplemented_default_handler "$1"
}
set_url_scheme_handler_xfce()
{
exit_unimplemented_default_handler "$1"
}
# }}} xfce
# }}} default protocol handler
dispatch_specific()
{
# The PROP comments in this function are used to generate the output of
# the --list option. The formatting is important. Make sure to line up the
# property descriptions with spaces so that it will look nice.
if [ x"$op" = x"get" ]; then
case "$parm" in
default-web-browser) # PROP: Default web browser
get_browser_$DE
;;
default-url-scheme-handler) # PROP: Default handler for URL scheme
get_url_scheme_handler_$DE "$1"
;;
*)
exit_failure_syntax
;;
esac
elif [ x"$op" = x"check" ]; then
case "$parm" in
default-web-browser)
check_desktop_filename "$1"
check_browser_$DE "$1"
;;
default-url-scheme-handler)
check_desktop_filename "$2"
check_url_scheme_handler_$DE "$1" "$2"
;;
*)
exit_failure_syntax
;;
esac
else # set
case "$parm" in
default-web-browser)
[ $# -eq 1 ] || exit_failure_syntax "unexpected/missing argument"
check_desktop_filename "$1"
set_browser_$DE "$1"
;;
default-url-scheme-handler)
[ $# -eq 2 ] || exit_failure_syntax "unexpected/missing argument"
check_desktop_filename "$2"
set_url_scheme_handler_$DE "$1" "$2"
;;
*)
exit_failure_syntax
;;
esac
fi
if [ $? -eq 0 ]; then
exit_success
else
exit_failure_operation_failed
fi
}
dispatch_generic()
{
# We only know how to get or check the default web browser.
[ x"$op" != x"get" -a x"$op" != x"check" ] && exit_failure_operation_impossible
[ x"$parm" != x"default-web-browser" ] && exit_failure_operation_impossible
# First look in $BROWSER
if [ x"$BROWSER" != x ]; then
binary="`which "${BROWSER%%:*}"`"
else
# Debian and Ubuntu (and others?) have x-www-browser.
binary="`which x-www-browser`"
fi
[ "$binary" ] || exit_failure_operation_failed
binary="`readlink -f "$binary"`"
[ "$binary" ] || exit_failure_operation_failed
if [ x"$op" = x"get" ]; then
desktop="`binary_to_desktop_file "$binary"`"
basename "$desktop"
else
# $op = "check"
check="`desktop_file_to_binary "$1"`"
if [ -z "$check" ]; then
echo no
exit_success
fi
if [ x"$binary" != x"$check" ]; then
echo no
exit_success
fi
echo yes
fi
exit_success
}
if [ x"$1" = x"--list" ]; then
echo "Known properties:"
# Extract the property names from dispatch_specific() above.
grep "^[ ]*[^)]*) # PROP:" "$0" | sed -e 's/^[ ]*\([^)]*\)) # PROP: \(.*\)$/ \1 \2/' | sort
exit_success
fi
[ x"$1" != x ] || exit_failure_syntax "no operation given"
[ x"$2" != x ] || exit_failure_syntax "no parameter name given"
[ x"$1" = x"get" -o x"$3" != x ] || exit_failure_syntax "no parameter value given"
op="$1"
parm="$2"
shift 2
if [ x"$op" != x"get" -a x"$op" != x"check" -a x"$op" != x"set" ]; then
exit_failure_syntax "invalid operation"
fi
detectDE
case "$DE" in
kde|gnome*|xfce)
dispatch_specific "$@"
;;
generic)
dispatch_generic "$@"
;;
*)
exit_failure_operation_impossible "unknown desktop environment"
;;
esac