site: end of line message, adesklets is not dead.
[adesklets.git] / utils / adesklets_frontend.sh.in
blobf57e45eddf64f29512d00b87304c49ebf8c2195a
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_$(id -ru).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$(id -ru)_*.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 -s KILL $PIDS > /dev/null 2> /dev/null
97 # ------------------------------------------------------------------------------
98 # Detect potential fake root windows function
100 roots() {
101 local GEOM
102 GEOM=`xwininfo -root | sed -n '/geometry/{s/^.*geometry[ \t]*//;p}'`
103 local ID
104 if test $# -eq 0 ; then
105 ID="-root"
106 else
107 ID="-id $*"
108 echo $*
110 xwininfo $ID -tree | sed -n "/$GEOM/"'{s/^[ \t]*\(0x[0-9a-f]\+\).*/\1/;p}'
113 # ------------------------------------------------------------------------------
114 # Error handling function
116 error () {
117 test $# -gt 0 && echo "Error: $*" && echo
118 test $# -eq 0; exit
121 # Command line error handling function
123 usage () {
124 test $# -gt 0 && echo "Error: $*" && echo
125 if test "x$ADESKLETS_EMBEDDED" = "x" ; then
126 DESC='Usage: adesklets [OPTION]... [string_id]'
127 else
128 DESC='Possible options are:'
130 cat<<EOF
131 $DESC
133 Fake root window detection
134 --e16 Enlightenment 16, version 0.16.8 and later
135 --kde KDE >= 3.4.1 desktop detection
136 --nautilus Nautilus desktop detection
137 --rox ROX-Filer detection (incomplete)
138 --user Interactive detection (by user click)
139 --xfce4 Xfce4 desktop detection (tested on Xfce4 4.2.x,
140 with xfdesktop managing the icons)
141 --xffm Xffm desktop window detection (tested on xffm 4.3.3.1,
142 with xffm-deskview managing the icons)
144 --do-it-once When applicable, do not run the detection for each desklet,
145 but only once for all. Of course, desklets on multiple
146 screens will unlikely detect the right fake root window, but
147 it will speed things up for single screen settings.
148 Miscellany
149 -h,--help Print out this message and exit
150 -w progname Wait for at least one 'progname' instance to run under
151 the current user id (UID) before performing any further
152 action
153 -d delay Wait for a given delay (in seconds) before performing any
154 further action
155 -e editor Use an alternate editor for configuring the desklets; it
156 needs to be a standalone executable that does not need
157 a pseudo terminal
159 --polling FREQ Set frequency (in hertz) for polling the X server for events.
160 Lower values leads to less responsive, but less CPU hungry
161 desklets (Default: @X_POLLING_FREQ@ Hz)
163 if test "x$ADESKLETS_EMBEDDED" = "x" ; then
164 cat<<EOF
165 -v,--version Printout adesklets version
166 -k,--killall Kill all running, registered desklets
167 -c,--cleanup Remove all dead entries from \$HOME/.adesklets
168 (this implies \`--killall')
169 -i,--installer Invoke the desklet installer (requires Python)
170 -f script Execute command set from the \`script' file
172 If no \`string_id' is given, adesklets acts as a launcher (unless
173 the \`-f' switch is involved). Otherwise, adesklets acts as
174 an interpreter, if no \`-k' or \`-c' switch is used.
176 The most usual invokation of adesklets is the bare \`adesklets' command,
177 without arguments: it makes adesklets launch every registered desklets
178 from \$HOME/.adesklets, without any fake root window detection.
181 test $# -eq 0; exit
184 # ------------------------------------------------------------------------------
185 # Initial test
187 test -e $HOME/.adesklets && {
188 test -f $HOME/.adesklets || \
189 error "$HOME/.adesklets is not a configuration file; please remove it."
192 # ------------------------------------------------------------------------------
193 # Parse the command line.
195 SELF=$0
196 OPTS=
197 MODE=
198 DO_IT_ONCE=0
199 while test $# -gt 0 ; do
200 case "$1" in
201 --e16|--kde|--nautilus|--rox|--user|--xfce4|--xffm)
202 MODE=`echo $1 | sed 's/--//'`
204 --do-it-once)
205 DO_IT_ONCE=1
207 -h|--help)
208 usage
211 test $# -gt 1 || usage "no delay given after -d switch."
212 sleep $2 > /dev/null 2> /dev/null || \
213 usage "Invalid delay of \`$2' seconds given."
214 shift
217 test $# -gt 1 || usage "no progname given after -w switch."
218 while : ; do
219 test -z "`ps -u $(id -ru) -U $(id -ru) -o command | sed -n "/$2/p"`" || break
220 sleep 10
221 done
222 shift
225 test $# -gt 1 || usage "no editor given after -e switch."
226 ADESKLETS_EDITOR="$HOME/.adesklets_editor.sh"
227 echo '#! /bin/sh' > $ADESKLETS_EDITOR
228 echo "$2 &" >> $ADESKLETS_EDITOR
229 echo 'kill -9 $PPID' >> $ADESKLETS_EDITOR
230 chmod +x $ADESKLETS_EDITOR
231 test -x $ADESKLETS_EDITOR || usage "could not create editor wrapper"
232 export EDITOR="$ADESKLETS_EDITOR"
233 shift
235 -p|--polling)
236 test $# -gt 1 || usage "no polling frequency given after polling switch"
237 export ADESKLETS_POLLING="$2"
238 shift
240 -v|--version)
241 echo "adesklets @VERSION@"
242 echo "Written By Sylvain Fourmanoit <syfou@users.sourceforge.net>"
243 exit 0
245 -k|--killall)
246 kill_desklets
247 exit 0
249 -c|--cleanup)
250 # The cleanup routine assumes the file is EXACTLY formatted as
251 # it is output by the binary interpreter.
252 kill_desklets
253 LINE=
254 for DESKLET in `sed -n 's/^\[//;s/]$//;/^\//{=;p}' $HOME/.adesklets`
256 if test "$DESKLET" -gt 0 2> /dev/null ; then
257 ID=$DESKLET
258 else
259 test -x "$DESKLET" || LINE="$LINE $ID"
261 done
262 sed -i "`echo "$LINE" | sed 's/[0-9]\+/&,+1d;/g'`" $HOME/.adesklets
263 exit 0
265 -i|--installer)
266 shift
267 exec adesklets_installer $*
268 exit 1
271 test $# -gt 1 || usage "no file name given after -f switch."
272 test -r $2 || usage "could not read file \`$2'."
273 OPTS="-f $2"
274 shift
277 usage "invalid option \`$1'."
280 test "x$OPTS" = "x" || \
281 usage "invalid combination, \`$OPTS' and \`$1'."
282 OPTS="$1"
284 esac
285 shift
286 done
288 # ------------------------------------------------------------------------------
289 # Fake root window detection code
291 test "x$MODE" = "x" || ADESKLETS_MODE="$MODE"
292 test "x$ADESKLETS_MODE" = "x" || {
293 case "$ADESKLETS_MODE" in
294 xfce4|nautilus|e16)
295 # Identify the lead desktop window from root property,
296 # then find the last child with the proper dimension
297 # For now on, we take advantage from the "compatibility code"
298 # included in xfce4.
299 DESKTOP=`xprop -root | \
300 sed -n '/^NAUTILUS_DESKTOP_WINDOW_ID/{s/.* \(0x[0-9a-f]\+\)/\1/;p}'`
301 for ROOT in `roots $DESKTOP` ; do : ; done
302 ADESKLETS_ROOT=$ROOT
304 xffm)
305 # Get the first child of the last window named 'xffm-deskview'.
306 # The bet is on: how long before this changes?
307 DESKTOP=`xwininfo -root -tree | \
308 sed -n '/xffm-deskview/{s/[ \t]*\(0x[0-9a-f]\+\).*/\1/;p}' | \
309 sed -n '$p'`
310 ADESKLETS_ROOT=`xwininfo -id $DESKTOP -tree | \
311 sed -n '/^[ \t]*0x[0-9a-f]\+/{s/[ \t]*\(0x[0-9a-f]\+\).*/\1/;p}' | \
312 sed '1q'`
314 kde)
315 test "x`dcop kdesktop default isIconsEnabled`" = "xtrue" && {
316 # First, we need to sync. the real root pixmap
317 # with the desktop: the fake root window is using a
318 # ParentRelative backgroundPixmap, with the real image
319 # from one of its parent, but the root being empty.
320 # We are very lucky this work... But for how long?
321 test "x$MODE" = "x" || {
322 # Just do this at high level
323 for I in 0 1; do
324 dcop kdesktop default setIconsEnabled $I
325 done
327 # Detect the fake root window
328 for ROOT in `roots` ; do
329 ADESKLETS_ROOT=`xprop -id $ROOT | \
330 sed -n '/__SWM_VROOT/{s/.*\(0x[0-9a-f]\+\)/\1/;p}'`
331 test "x$ADESKLETS_ROOT" = "x" || break
332 done
335 rox)
336 # Find first full screen window with a Rox-Filer somewhere in
337 # its property
338 for ROOT in `roots` ; do
339 test "x`xprop -id $ROOT | sed -n '/ROX-Filer/p'`" = "x" || break
340 done
341 ADESKLETS_ROOT=$ROOT
343 user)
344 # In this special mode, the pseudo-root is determined
345 # interactively using xwininfo. Since xwininfo needs to
346 # grab the pointer, just make sure we serialize all calls
347 # using a lock.
348 lock
349 ADESKLETS_ROOT=`xwininfo | \
350 sed -n '/Window id/{s/.*Window id: \([^ ]*\) .*/\1/p}'`
351 unlock
354 error "unknown mode."
356 esac
357 test "$DO_IT_ONCE" -eq 0 && export ADESKLETS_MODE
358 export ADESKLETS_ROOT
361 # ------------------------------------------------------------------------------
362 # In case of launcher, just make preliminary FIFO cleanup
364 test "x$OPTS" = "x" && \
365 rm -f `ls @LOCKFILES_DIR@/*adesklets_fifo* 2>/dev/null` > /dev/null 2>&1
367 # ------------------------------------------------------------------------------
368 # Now, re-invoke the binary
370 export ADESKLETS_FRONTEND=1
371 exec adesklets $OPTS