#! /bin/bash
+###
+### X startup script
-xrdb -override $HOME/.Xdefaults
-: ${VNCSESSION=false}
+###--------------------------------------------------------------------------
+### Utility functions.
+
+## Progress indicators.
+info=yes
+info () {
+ case $info in yes) echo "- $*" >&2 ;; esac
+}
+
+run=yes
+run () {
+ local what=$1; shift
+ local bg=no
+
+ case $what in bg*) bg=yes what=${what#bg} ;; esac
+ info "run $what: $*"
+
+ case "$run,$bg" in
+ yes,no) "$@" ;;
+ yes,yes) "$@" & ;;
+ esac
+}
+
+## Program choice
+pick_program () {
+ local what=$1; shift
+ local choice=false
+ for i in "$@"; do
+ if type -t >/dev/null "$i"; then choice=$i; break; fi
+ done
+ info "pick $what = $choice"
+ echo "$choice"
+}
+
+###--------------------------------------------------------------------------
+### Parse arguments.
+
+vnc=no
+atomtag=
+start=yes
+wait=yes
+
+for opt; do
+ case "$opt" in
+ help)
+ cat <<EOF
+Options:
+ tag=TAG
+ [no]trace
+ [no]info
+ [no]run
+ [no]start
+ [no]wait
+ [no]vnc
+EOF
+ exit
+ ;;
+
+ tag=*) atomtag=/${opt#tag=} ;;
+ trace) set -x ;;
+ notrace) set +x ;;
+ info | run | start | wait | vnc) eval "$opt=yes" ;;
+ noinfo | norun | nostart | nowait | novnc) eval "${opt#no}=no" ;;
+
+ *) echo "unknown option $opt" >&2; exit 1 ;;
+ esac
+done
+
+###--------------------------------------------------------------------------
+### Iniitial settings.
+
+## Assume X sessions are secure.
export __mdw_sechost="`hostname`"
-# --- Do some fiddling ---
+## Obtain the screen dimensions.
+case ",$XWIDTH,$XHEIGHT," in
+ *,,*) eval $(xscsize -bx) ;;
+esac
+info "screen size = $XWIDTH x $XHEIGHT"
-cleanup=":"
-xset b 10 2000 50
-xset r rate 500 50
-xset m 1 1
-gnome-settings-daemon&
-mail-notification&
-$VNCSESSION || gkrellm&
-eval `xscsize -bx`
+initialize () {
+ ## Load the X resource database.
+ run init xrdb -override $HOME/.Xdefaults
-# --- Crank up ESD ---
+ ## Random xsettery.
+ run init xset b 10 2000 50
+ run init xset r rate 500 50
+ run init xset m 2 1
-if ! [ -r /tmp/.esd/socket ]; then
- esd -nobeeps -as 10&
- cleanup="$cleanup; kill $!"
-fi
+ ## Key mappings.
+ xmodmap -e 'keysym BackSpace = BackSpace BackSpace'
-# --- Start a nice window manager ---
+ ## Gnome settings.
+ case $vnc in no) run bginit gnome-settings-daemon ;; esac
+}
-enlightenment $EOPTS&
+###--------------------------------------------------------------------------
+### Start a window manager.
-# --- Crank up a screenlock program ---
+wm=$(pick_program window-manager enlightenment e16 twm)
+wmopts=""
+case "$wm,$vnc" in
+ enlightenment,yes | e16,yes)
+ wmopts="$eopts -econfdir $HOME/.enlightenment-vnc"
+ ;;
+esac
-if ! $VNCSESSION; then
- xscreensaver-command -exit
- xscreensaver -no-splash&
-fi
-gnome-panel&
+start-window-manager () {
+ run bginit $wm $wmopts
+}
+
+###--------------------------------------------------------------------------
+### Random useful clients.
+
+start-clients () {
+ ## Mail notification.
+ run bginit mail-notification
+
+ ## System monitor.
+ case $vnc in no) run bginit gkrellm ;; esac
-# --- Emacs window measurements ---
-#
-# Horizontal column pixel width = 492; window manager overhead = 34
-# Column character width = 82; Emacs magic overhead = -2
-# Vertical line pixel height = 13; misc overhead = 52
+ ## Screensaver.
+ case $vnc in
+ no)
+ run init xscreensaver-command -exit
+ run bginit xscreensaver -no-splash
+ ;;
+ esac
-emacs="noip emacs"
+ ## Panel.
+ case $vnc in no) run bginit gnome-panel ;; esac
+}
-# --- Xterm window measurements ---
-#
-# Window width is 504 (fixed).
-# Vertical line pixel height = 13; misc overhead = 23
+###--------------------------------------------------------------------------
+### Main screen layout.
-xterm="Eterm" xgeom=-geometry
+## Choose appropriate clients.
+emacs=$(pick_program emacs emacs22 emacs21 emacs)
+term=$(pick_program terminal pterm Eterm xterm)
-# --- GNOME stuff measurements ---
-#
-# GNOME panel width = 113
+## Emacs window measurements.
+case "$emacs" in
+ emacs21 | emacs)
+ e_colwd=492 e_hextra=34
+ e_colchars=82 e_cextra=-2
+ e_lineht=13 e_vextra=52
+ ;;
+ emacs22)
+ e_colwd=492 e_hextra=8
+ e_colchars=82 e_cextra=-6
+ e_lineht=13 e_vextra=46
+ ;;
+esac
+## Terminal window measurements.
+case "$term" in
+ pterm) t_wd=503 t_lineht=13 t_vextra=23 geom=-geometry;;
+ Eterm) t_wd=504 t_lineht=13 t_vextra=23 geom=-g;;
+ xterm) t_wd=507 t_lineht=13 t_vextra=27 geom=-geometry;;
+esac
+
+## GNOME stuff measurements.
declare -i xbound="XWIDTH - 113"
-# --- Choose a width for Emacs ---
-#
-# We'd like it to be as wide as possible, allowing for a column of xterms
-# down the right hand side. However, I'd prefer a double-width Emacs to a
-# single-width Emacs and xterms. If it's not going to work at all, a single
-# Emacs column will have to do. Also, there's a strange thing with Emacs21
-# and the toolbar, so we add on some rows which are later mysteriously
-# subtracted.
-
-declare -i ecols="(xbound - 504 - 34)/492"
-if (( ecols < 2 && xbound > 492 * 2 + 34 )); then
+## Choose a width for Emacs.
+##
+## We'd like it to be as wide as possible, allowing for a column of xterms
+## down the right hand side. However, I'd prefer a double-width Emacs to a
+## single-width Emacs and xterms. If it's not going to work at all, a single
+## Emacs column will have to do. Also, there's a strange thing with Emacs21
+## and the toolbar, so we add on some rows which are later mysteriously
+## subtracted.
+
+declare -i ecols="(xbound - t_wd - e_hextra)/e_colwd"
+if (( ecols < 2 && xbound > e_colwd * 2 + e_hextra )); then
ecols=2
elif (( ecols < 1 )); then
ecols=1
fi
-declare -i x="ecols * 492 + 34"
-$emacs -geometry $((ecols * 82 - 2))x$(((XHEIGHT - 52)/13))+0+0&
-
-# --- Now place some xterms ---
-#
-# A few smaller xterms are in general better than one great big one. 35
-# lines is a good height for most terminals. 25 lines is a minimum. The
-# strategy for doling out xterms into a column is to make as many 35-liners
-# as we can, until the remaining space would be too small for a 25-liner. If
-# we can get two 25s out of that then we do (largest first); otherwise just
-# make one big one. We stop at the end of a page, once we've made three
-# xterms.
-
-declare -i n=0 pgx=0 l h y ht
-declare -i hstd="35 * 13 + 23" hmin="25 * 13 + 23"
-while true; do
- if ((x + 504 > xbound)); then
- if ((n >= 3)); then break; fi
- x="pgx + XWIDTH" pgx="pgx + XWIDTH" xbound="xbound + XWIDTH"
- fi
- y=0 ht=XHEIGHT
- while ((ht - hstd >= hmin)); do
- $xterm -$xgeom 80x35+$x+$y&
- y="y + hstd" ht="ht - hstd" n="n + 1"
+declare -i \
+ emacsx="ecols * e_colchars + e_cextra" \
+ emacsy="(XHEIGHT - e_vextra)/e_lineht"
+
+start-emacs () {
+ run bgclients noip $emacs -geometry ${emacsx}x${emacsy}+0+0
+}
+
+## Now place some xterms.
+##
+## A few smaller xterms are in general better than one great big one. 35
+## lines is a good height for most terminals. 25 lines is a minimum. The
+## strategy for doling out xterms into a column is to make as many 35-liners
+## as we can, until the remaining space would be too small for a 25-liner.
+## If we can get two 25s out of that then we do (largest first); otherwise
+## just make one big one. We stop at the end of a page, once we've made
+## three xterms.
+
+start-xterms () {
+
+ ## Initialize some parameters.
+ declare -i x="ecols * e_colwd + e_hextra"
+ declare -i n=0 pgx=0 l h y ht
+ declare -i hstd="35 * t_lineht + t_vextra" hmin="25 * t_lineht + t_vextra"
+
+ ## Do the placement.
+ while :; do
+
+ ## Start a new iteration.
+ if ((x + t_wd > xbound)); then
+ if ((n >= 3)); then break; fi
+ x="pgx + XWIDTH" pgx="pgx + XWIDTH" xbound="xbound + XWIDTH"
+ fi
+
+ ## Make large xterms.
+ y=0 ht=XHEIGHT
+ while ((ht - hstd >= hmin)); do
+ run bgclients $term $geom 80x35+$x+$y
+ y="y + hstd" ht="ht - hstd" n="n + 1"
+ done
+
+ ## Fill the remaining space.
+ if ((ht >= 2 * hmin)); then h="ht - hmin"; else h=ht; fi
+ l="(h - t_vextra)/t_lineht" h="l * t_lineht + t_vextra"
+ run bgclients $term $geom 80x$l+$x+$y
+ y="y + h" ht="ht - h" n="n + 1"
+ if ((ht >= hmin)); then
+ run bgclients $term $geom 80x25+$x+$y
+ n="n + 1"
+ fi
+ x="x + t_wd"
done
- if ((ht >= 2 * hmin)); then h="ht - hmin"; else h=ht; fi
- l="(h - 23)/13" h="l * 13 + 23"
- $xterm -$xgeom 80x$l+$x+$y&
- y="y + h" ht="ht - h" n="n + 1"
- if ((ht >= hmin)); then
- $xterm -$xgeom 80x25+$x+$y&
- n="n + 1"
- fi
- x="x + 504"
-done
+}
+
+###--------------------------------------------------------------------------
+### Final waiting.
+
+atom=XINIT_COMMAND$atomtag
+
+xwait () {
+ while :; do
+ xatom delete $atom
+ info "waiting on $atom"
+ line=$(xatom wait $atom)
+ info "xatom: $line"
+
+ case "$line" in
+ :help)
+ xmsg -I -t "xinitrc help" -d "xinitrc commands" - <<EOF &
+:help
+:emacs :xterms :window-manager :clients
+:init
+:terminal
+! SHELL-COMMAND
+CLIENT
+EOF
+ ;;
+ :emacs | :xterms | :window-manager | :clients)
+ start-${line#:}
+ ;;
+ :terminal)
+ run bgclients $term
+ ;;
+ :init)
+ initialize
+ ;;
+ :exec)
+ info "restarting xinitrc"
+ exec "$0" wait nostart
+ ;;
+ :*)
+ xmsg -E -t "xinitrc error" "Unknown command \`$line'" &
+ ;;
+ !*)
+ eval "${line#!}"
+ ;;
+ *)
+ set -- $line
+ run bgclients "$@"
+ ;;
+ esac
+ done
+}
+
+###--------------------------------------------------------------------------
+### Actually start things up.
+
+case "$start" in
+ yes)
+ info "starting standard clients"
+ initialize
+ start-window-manager
+ start-clients
+ start-emacs
+ start-xterms
+ ;;
+ no)
+ info "not starting standard clients"
+ ;;
+esac
-# --- Wait for the world to end ---
+case "$wait" in
+ yes)
+ xwait
+ ;;
+ no)
+ info "not waiting before exit"
+ ;;
+esac
-xwait XWAIT_DIE:XWAIT_DIE_NOW
-eval "$cleanup"
+###----- That's all, folks --------------------------------------------------