Site: add link to Jean Baptiste Favre and Xavier Janer web sites
[adesklets.git] / utils / adesklets_frontend.sh.in
blobab59c3a33473a7291d1185254e855820d80b3f55
1 #! /bin/sh
2 # adesklets - Shell script frontend for the adesklets interpreter
3 # ------------------------------------------------------------------------------
4 # Copyright (C) 2005, 2006 Sylvain Fourmanoit <syfou@users.sourceforge.net>
6 # Permission is hereby granted, free of charge, to any person obtaining a copy
7 # of this software and associated documentation files (the "Software"), to
8 # deal in the Software without restriction, including without limitation the
9 # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 # sell copies of the Software, and to permit persons to whom the Software is
11 # furnished to do so, subject to the following conditions:
13 # The above copyright notice and this permission notice shall be included in
14 # all copies of the Software and its documentation and acknowledgment shall be
15 # given in the documentation and software packages that this Software was
16 # used.
18 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 # THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
22 # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 # ------------------------------------------------------------------------------
25 # This is the shell script frontend for the adesklets interpreter, introduced
26 # in adesklets 0.4.11. It serves a couple simple purposes:
28 # - Bring all the fake-root windows detection code out of the binary
29 # interpreter, and detect them from a front-end. It makes it far simpler
30 # and quicker to adapt to new situations, as this code is no longer written
31 # in C, but in a sh-compatible scripting form. Hopefully, in this new format,
32 # people will be able to contribute new detection routines for specific
33 # Window Manager easily.
35 # - Print out a couple of warnings to hopefully prevent some people that
36 # would not read the fourth chapter from the manual from not invoking
37 # adesklets right.
39 # - Add a couple of functionalities, such as configuration file cleanup, and
40 # desklets killing.
42 # PORTABILITY NOTICE:
43 # ===================
45 # This shell script was made to comply with the POSIX 1003.2 and 1003.2a
46 # specification for the shell, and not use any vendor-specific extension
47 # for any program invoked. It has been tested on both BASH 3.00.16 and NetBSD
48 # ash 1.6.1 on a variety of platforms. It also uses some low-level, fairly
49 # common utilities or builtin, all also described in POSIX, namely:
51 # 1) a Streaming EDitor (sed). It as been tested on GNU sed 4.0.9, and FreeBSD
52 # 4.9 sed
53 # 2) test, conforming to POSIX 1003.2
54 # 3) mkdir and rmdir
55 # 4) sleep
56 # 5) kill
57 # 6) ls
58 # 7) ps (only for the -w switch)
60 # The xprop and xwinfinfo programs can also be used, if a given fake-root
61 # window detection routine is explicitely invoked. Both XFree86 and X.org
62 # implementations of these utilities have been tested. Window Manager specific
63 # detection will also potentially need WM specific programs:
65 # kde: need consolde dcop client
67 # ------------------------------------------------------------------------------
68 # Lock/unlock function
69 # Based on the fact that creating a directory is atomic
71 LOCKFILE=@LOCKFILES_DIR@/adesklets_frontend_$UID.lock
73 lock() {
74 while : ; do
75 mkdir $LOCKFILE > /dev/null 2> /dev/null && break
76 sleep .2
77 done
80 unlock() {
81 rmdir $LOCKFILE > /dev/null 2> /dev/null
84 # ------------------------------------------------------------------------------
85 # Kill all desklets function
87 kill_desklets() {
88 LOCK=`ls @LOCKFILES_DIR@/adesklets_uid$UID_*.lock 2> /dev/null`
89 test "x$LOCK" = "x" || {
90 PIDS=`cat $LOCK`
91 kill $PIDS > /dev/null 2> /dev/null
92 sleep 1
93 kill -9 $PIDS > /dev/null 2> /dev/null
97 # ------------------------------------------------------------------------------
98 # Detect potential fake root windows function
100 roots() {
101 local GEOM=`xwininfo -root | sed -n '/geometry/{s/^.*geometry[ \t]*//;p}'`
102 local ID
103 if test $# -eq 0 ; then
104 ID="-root"
105 else
106 ID="-id $*"
107 echo $*
109 xwininfo $ID -tree | sed -n "/$GEOM/"'{s/^[ \t]*\(0x[0-9a-f]\+\).*/\1/;p}'
112 # ------------------------------------------------------------------------------
113 # Error handling function
115 error () {
116 test $# -gt 0 && echo "Error: $*" && echo
117 test $# -eq 0; exit
120 # Command line error handling function
122 usage () {
123 test $# -gt 0 && echo "Error: $*" && echo
124 if test "x$ADESKLETS_EMBEDDED" = "x" ; then
125 DESC='Usage: adesklets [OPTION]... [string_id]'
126 else
127 DESC='Possible options are:'
129 cat<<EOF
130 $DESC
132 Fake root window detection
133 --e16 Enlightenment 16, version 0.16.8 and later
134 --kde KDE >= 3.4.1 desktop detection
135 --nautilus Nautilus desktop detection
136 --rox ROX-Filer detection (incomplete)
137 --user Interactive detection (by user click)
138 --xfce4 Xfce4 desktop detection (tested on Xfce4 4.2.x,
139 with xfdesktop managing the icons)
140 --xffm Xffm desktop window detection (tested on xffm 4.3.3.1,
141 with xffm-deskview managing the icons)
143 --do-it-once When applicable, do not run the detection for each desklet,
144 but only once for all. Of course, desklets on multiple
145 screens will unlikely detect the right fake root window, but
146 it will speed things up for single screen settings.
147 Miscellany
148 -h,--help Print out this message and exit
149 -w progname Wait for at least one 'progname' instance to run under
150 the current user id (UID) before performing any further
151 action
152 -d delay Wait for a given delay (in seconds) before performing any
153 further action
154 -e editor Use an alternate editor for configuring the desklets; it
155 needs to be a standalone executable that does not need
156 a pseudo terminal
158 if test "x$ADESKLETS_EMBEDDED" = "x" ; then
159 cat<<EOF
160 -v,--version Printout adesklets version
161 -k,--killall Kill all running, registered desklets
162 -c,--cleanup Remove all dead entries from \$HOME/.adesklets
163 (this implies \`--killall')
164 -i,--installer Invoke the desklet installer (requires Python)
165 -f script Execute command set from the \`script' file
167 If no \`string_id' is given, adesklets acts as a launcher (unless
168 the \`-f' switch is involved). Otherwise, adesklets acts as
169 an interpreter, if no \`-k' or \`-c' switch is used.
171 The most usual invokation of adesklets is the bare \`adesklets' command,
172 without arguments: it makes adesklets launch every registered desklets
173 from \$HOME/.adesklets, without any fake root window detection.
176 test $# -eq 0; exit
179 # ------------------------------------------------------------------------------
180 # Initial test
182 test -e $HOME/.adesklets && {
183 test -f $HOME/.adesklets || \
184 error "$HOME/.adesklets is not a configuration file; please remove it."
187 # ------------------------------------------------------------------------------
188 # Parse the command line.
190 SELF=$0
191 OPTS=
192 MODE=
193 DO_IT_ONCE=0
194 while test $# -gt 0 ; do
195 case "$1" in
196 --e16|--kde|--nautilus|--rox|--user|--xfce4|--xffm)
197 MODE=`echo $1 | sed 's/--//'`
199 --do-it-once)
200 DO_IT_ONCE=1
202 -h|--help)
203 usage
206 test $# -gt 1 || usage "no delay given after -d switch."
207 sleep $2 > /dev/null 2> /dev/null || \
208 usage "Invalid delay of \`$2' seconds given."
209 shift
212 test $# -gt 1 || usage "no progname given after -w switch."
213 while : ; do
214 test -z "`ps -u $UID -U $UID -o comm | sed -n "/$2/p"`" || break
215 sleep 10
216 done
217 shift
220 test $# -gt 1 || usage "no editor given after -e switch."
221 ADESKLETS_EDITOR="$HOME/.adesklets_editor.sh"
222 echo '#! /bin/sh' > $ADESKLETS_EDITOR
223 echo "$2 &" >> $ADESKLETS_EDITOR
224 echo 'kill -9 $PPID' >> $ADESKLETS_EDITOR
225 chmod +x $ADESKLETS_EDITOR
226 test -x $ADESKLETS_EDITOR || usage "could not create editor wrapper"
227 export EDITOR="$ADESKLETS_EDITOR"
228 shift
230 -v|--version)
231 echo "adesklets @VERSION@"
232 echo "Written By Sylvain Fourmanoit <syfou@users.sourceforge.net>"
233 exit 0
235 -k|--killall)
236 kill_desklets
237 exit 0
239 -c|--cleanup)
240 # The cleanup routine assumes the file is EXACTLY formatted as
241 # it is output by the binary interpreter.
242 kill_desklets
243 LINE=
244 for DESKLET in `sed -n 's/^\[//;s/]$//;/^\//{=;p}' $HOME/.adesklets`
246 if test "$DESKLET" -gt 0 2> /dev/null ; then
247 ID=$DESKLET
248 else
249 test -x "$DESKLET" || LINE="$LINE $ID"
251 done
252 sed -i "`echo "$LINE" | sed 's/[0-9]\+/&,+1d;/g'`" $HOME/.adesklets
253 exit 0
255 -i|--installer)
256 shift
257 exec adesklets_installer $*
258 exit 1
261 test $# -gt 1 || usage "no file name given after -f switch."
262 test -r $2 || usage "could not read file \`$2'."
263 OPTS="-f $2"
264 shift
267 usage "invalid option \`$1'."
270 test "x$OPTS" = "x" || \
271 usage "invalid combination, \`$OPTS' and \`$1'."
272 OPTS="$1"
274 esac
275 shift
276 done
278 # ------------------------------------------------------------------------------
279 # Fake root window detection code
281 test "x$MODE" = "x" || ADESKLETS_MODE="$MODE"
282 test "x$ADESKLETS_MODE" = "x" || {
283 case "$ADESKLETS_MODE" in
284 xfce4|nautilus|e16)
285 # Identify the lead desktop window from root property,
286 # then find the last child with the proper dimension
287 # For now on, we take advantage from the "compatibility code"
288 # included in xfce4.
289 DESKTOP=`xprop -root | \
290 sed -n '/^NAUTILUS_DESKTOP_WINDOW_ID/{s/.* \(0x[0-9a-f]\+\)/\1/;p}'`
291 for ROOT in `roots $DESKTOP` ; do : ; done
292 ADESKLETS_ROOT=$ROOT
294 xffm)
295 # Get the first child of the last window named 'xffm-deskview'.
296 # The bet is on: how long before this changes?
297 DESKTOP=`xwininfo -root -tree | \
298 sed -n '/xffm-deskview/{s/[ \t]*\(0x[0-9a-f]\+\).*/\1/;p}' | \
299 sed -n '$p'`
300 ADESKLETS_ROOT=`xwininfo -id $DESKTOP -tree | \
301 sed -n '/^[ \t]*0x[0-9a-f]\+/{s/[ \t]*\(0x[0-9a-f]\+\).*/\1/;p}' | \
302 sed '1q'`
304 kde)
305 test "x`dcop kdesktop default isIconsEnabled`" = "xtrue" && {
306 # First, we need to sync. the real root pixmap
307 # with the desktop: the fake root window is using a
308 # ParentRelative backgroundPixmap, with the real image
309 # from one of its parent, but the root being empty.
310 # We are very lucky this work... But for how long?
311 test "x$MODE" = "x" || {
312 # Just do this at high level
313 for I in 0 1; do
314 dcop kdesktop default setIconsEnabled $I
315 done
317 # Detect the fake root window
318 for ROOT in `roots` ; do
319 ADESKLETS_ROOT=`xprop -id $ROOT | \
320 sed -n '/__SWM_VROOT/{s/.*\(0x[0-9a-f]\+\)/\1/;p}'`
321 test "x$ADESKLETS_ROOT" = "x" || break
322 done
325 rox)
326 # Find first full screen window with a Rox-Filer somewhere in
327 # its property
328 for ROOT in `roots` ; do
329 test "x`xprop -id $ROOT | sed -n '/ROX-Filer/p'`" = "x" || break
330 done
331 ADESKLETS_ROOT=$ROOT
333 user)
334 # In this special mode, the pseudo-root is determined
335 # interactively using xwininfo. Since xwininfo needs to
336 # grab the pointer, just make sure we serialize all calls
337 # using a lock.
338 lock
339 ADESKLETS_ROOT=`xwininfo | \
340 sed -n '/Window id/{s/.*Window id: \([^ ]*\) .*/\1/p}'`
341 unlock
344 error "unknown mode."
346 esac
347 test "$DO_IT_ONCE" -eq 0 && export ADESKLETS_MODE
348 export ADESKLETS_ROOT
351 # ------------------------------------------------------------------------------
352 # In case of launcher, just make preliminary FIFO cleanup
354 test "x$OPTS" = "x" && \
355 rm -f `ls @LOCKFILES_DIR@/*adesklets_fifo* 2>/dev/null` > /dev/null 2>&1
357 # ------------------------------------------------------------------------------
358 # Now, re-invoke the binary
360 export ADESKLETS_FRONTEND=1
361 exec adesklets $OPTS