You are not logged in.
Hi folks.
As stated I'm looking for smart ways to determine whether some arbitrary program should be executed inside an xterm/Konsole/Terminal/whatever. I'm currently using dmenu plus the oneliner below to fire up mutt & friends. It works fine like this but somehow I don't like the idea of using ldd. So if anyone can think of other (more elegant) solutions, I'd be glad to see them. Otherwise just consider this post a hint ![]()
#!/bin/sh
ldd $(which $1) | grep -q '\(libX11\|libxcb\)\.so' && exec "$@" || exec Terminal -x "$@"Offline
Less elegantly, you could just manually make a list of the programs that don't need to be run in a terminal. And then update the list when needed. This would also give you more full control. Why make a script guess if you already know the answer.
Offline
@csn that's a nice approach.
I think that approach should work well in practice.
There are some exceptions (like: I know you can link vim against libX11 to give it clipboard integration, but it's still a terminal app), maybe you could put all exceptions in an array (and the interesting part is, you don't even need to track if an exception needs terminal or not, because you can just make the inverse decision, so an array containing program names would suffice - although that wouldn't be very robust.. recompile vim with different flags and things could break)
Last edited by Dieter@be (2010-11-02 20:46:18)
< Daenyth> and he works prolifically
4 8 15 16 23 42
Offline
Offline
btw you can make the grep a tiny bit prettier:
egrep -q '(libX11|libxcb)\.so'< Daenyth> and he works prolifically
4 8 15 16 23 42
Offline
Hmm, this approach runs commands like `mpc toggle` in a terminal.
There are obviously a whole bunch of scripts and tools which don't link to X, but because of them being non-interactive they don't need to be spawned in a terminal.
I thought of checking for linking against ncurses to check if they need to be run in a terminal, but then you don't match commandline programs that don't use ncurses (like ssh or other interactive scripts).
I wonder if there is a way to check if there is a way to properly check if apps spawn X clients. (before running them, of course), you can do something like
strings `which $app` | grep windowbut that's not waterproof (you need to check for a specific call, but then you need to support multiple toolkits, and shellscripts can contain the string as well....)
< Daenyth> and he works prolifically
4 8 15 16 23 42
Offline
Right, which is why I (meanwhile) extended that oneliner into a little script that also does blacklisting as suggested by lotuskip. Posting it here, in case anyone's interested.
By the way, that's a problem every launcher has. The well known launchers from GNOME, etc. just do white listing by letting the user specify which programs should be started in a terminal. It actually never occured to me to simply do the reverse.
I guess in the end it really depends on your usage pattern what works better for you. Personally, I tend to prefer launching things in a terminal by default because I happen to use many text mode apps. Also, sometimes I make a typo in dmenu and press <Return> too fast and then some program starts running (or failing) in the background and I'd have to switch VT to look at its stdout/stderr.
But apart from that, the checking-for-linkage approach is hackish anyway and doesn't work for static binaries (not an issue in practice unless your distribution happens to be `sta.li', but it's wrong nevertheless). I did a bit of reading on this and it appears there's currently no clean, generic solution that doesn't involve hacking the kernel.
#!/bin/bash
# list of programs to treat specially
PROGLIST=(chromium gimp)
# specify how to obtain the command line that will be run. the default value
# makes this script suitable as a replacement for `dmenu_run'
#CMDLINE="$@"
CMDLINE=$(dmenu_path | dmenu ${1+"$@"})
# command to execute your favourite terminal
#TERMCMD='xterm -title %s -e %s'
TERMCMD='Terminal --title %s --hold --execute %s'
# path to ld.so
LD=/lib/ld-linux-x86-64.so.2
[ -z "$CMDLINE" ] && exit 0
prog=$(which $(echo "$CMDLINE" | cut -d ' ' -f 1))
title=$(basename "$prog")
listed() {
for name in "${PROGLIST[@]}"; do
if [ "$1" = "$name" -o "$1" = "$(which "$name")" ]; then
return 0
fi
done
return 1
}
prog_type() {
local progtype
if listed "$1"; then
progtype=listed
elif "$LD" --verify "$1"; then
if "$LD" --list "$1" | egrep -q '(libX11|libxcb)\.so'; then
progtype=gui
else
progtype=text
fi
else
progtype=other
fi
printf '%s' "$progtype"
}
declare exe
case "$(prog_type "$prog")" in
listed|gui)
exe="$CMDLINE"
;;
text|*)
exe=$(printf "$TERMCMD" "$title" "$CMDLINE")
;;
esac
exec $exe
exit 0Last edited by csn (2010-11-21 13:08:55)
Offline
hmm.. I decided to make the user decide explicitly any time an unknown app is run, and remember the choice for later.
this gives 100% accuracy while still being simple and fairly non-invasive.
Here's my code (there's some history code in there which you might want to ignore)
#!/bin/bash
TERM="urxvt -e sh -c"
CACHE=${XDG_CACHE_HOME:-$HOME/.cache}/dmenu-recent-apps
mkdir -p ${XDG_CACHE_HOME:-$HOME/.cache}
CONFIG=${XDG_CONFIG_HOME:-$HOME/.config}/dmenu
mkdir -p $CONFIG
touch $CONFIG/apps-term
touch $CONFIG/apps-bg
MOST_USED=`sort $CACHE 2>/dev/null | uniq -c | sort -rn | colrm 1 8`
RUN=`(echo "$MOST_USED"; dmenu_path | grep -vxF "$MOST_USED") | dmenu -p Execute: "$@"` || exit
(echo $RUN; head -n 99 $CACHE 2>/dev/null) > $CACHE.$$
mv $CACHE.$$ $CACHE
# figure out how to run the command based on the first word. Note that this does not support
# a bg/term decision based on further arguments (although you could easily add that)
word0=${RUN%% *}
match="^$word0$"
while ! grep -q $match $CONFIG/apps-term $CONFIG/apps-bg
do
type=$(echo -e "term\nbg" | dmenu -p type)
[ $type = bg -o $type = term ] || continue
echo $word0 >> $CONFIG/apps-$type
done
grep -q $match $CONFIG/apps-term && exec $TERM $RUN
grep -q $match $CONFIG/apps-bg && exec $RUNLast edited by Dieter@be (2010-11-21 13:58:15)
< Daenyth> and he works prolifically
4 8 15 16 23 42
Offline