Commit | Line | Data |
---|---|---|
f617db13 | 1 | #! /bin/bash |
8e08f814 MW |
2 | ### |
3 | ### X startup script | |
f617db13 | 4 | |
8e08f814 MW |
5 | ###-------------------------------------------------------------------------- |
6 | ### Utility functions. | |
f617db13 | 7 | |
8e08f814 MW |
8 | ## Progress indicators. |
9 | info=yes | |
10 | info () { | |
11 | case $info in yes) echo "- $*" >&2 ;; esac | |
12 | } | |
f617db13 | 13 | |
8e08f814 MW |
14 | run=yes |
15 | run () { | |
16 | local what=$1; shift | |
17 | local bg=no | |
f617db13 | 18 | |
8e08f814 MW |
19 | case $what in bg*) bg=yes what=${what#bg} ;; esac |
20 | info "run $what: $*" | |
f617db13 | 21 | |
8e08f814 MW |
22 | case "$run,$bg" in |
23 | yes,no) "$@" ;; | |
24 | yes,yes) "$@" & ;; | |
25 | esac | |
26 | } | |
eebca092 | 27 | |
74bd743a MW |
28 | manage () { |
29 | local when=$(date +%s) now | |
30 | local fail=0 rc report | |
31 | ||
32 | while :; do | |
33 | "$@"; rc=$? | |
34 | case $rc in | |
35 | 0) info "manage $1: successful exit"; break ;; | |
36 | 143) info "manage $1: terminated"; break ;; | |
37 | esac | |
38 | now=$(date +%s) | |
39 | report="rc = $rc" | |
40 | if (( $now - $when > 5 )); then | |
41 | fail=0 | |
42 | else | |
43 | report="$report, early failure" | |
44 | fail=$(( $fail + 1 )) | |
45 | if (( $fail >= 5 )); then | |
46 | info "manage $1: exit ($report), giving up after $fail failures" | |
47 | break | |
48 | fi | |
49 | fi | |
50 | info "manage $1: exit ($report), restarting" | |
51 | when=$now | |
52 | done | |
53 | } | |
54 | ||
8e08f814 | 55 | ## Program choice |
eebca092 | 56 | pick_program () { |
8e08f814 MW |
57 | local what=$1; shift |
58 | local choice=false | |
eebca092 | 59 | for i in "$@"; do |
8e08f814 | 60 | if type -t >/dev/null "$i"; then choice=$i; break; fi |
eebca092 | 61 | done |
8e08f814 MW |
62 | info "pick $what = $choice" |
63 | echo "$choice" | |
eebca092 MW |
64 | } |
65 | ||
8e08f814 MW |
66 | ###-------------------------------------------------------------------------- |
67 | ### Parse arguments. | |
f617db13 | 68 | |
8e08f814 MW |
69 | vnc=no |
70 | atomtag= | |
71 | start=yes | |
72 | wait=yes | |
f617db13 | 73 | |
8e08f814 MW |
74 | for opt; do |
75 | case "$opt" in | |
76 | help) | |
77 | cat <<EOF | |
78 | Options: | |
79 | tag=TAG | |
80 | [no]trace | |
81 | [no]info | |
82 | [no]run | |
83 | [no]start | |
84 | [no]wait | |
85 | [no]vnc | |
86 | EOF | |
87 | exit | |
88 | ;; | |
f617db13 | 89 | |
8e08f814 MW |
90 | tag=*) atomtag=/${opt#tag=} ;; |
91 | trace) set -x ;; | |
92 | notrace) set +x ;; | |
93 | info | run | start | wait | vnc) eval "$opt=yes" ;; | |
94 | noinfo | norun | nostart | nowait | novnc) eval "${opt#no}=no" ;; | |
95 | ||
96 | *) echo "unknown option $opt" >&2; exit 1 ;; | |
97 | esac | |
98 | done | |
99 | ||
27b6787d MW |
100 | ###-------------------------------------------------------------------------- |
101 | ### Preliminary hook. | |
102 | ||
103 | if [ -r $HOME/.xinitrc-prehook ]; then | |
104 | . $HOME/.xinitrc-prehook | |
105 | fi | |
106 | ||
8e08f814 MW |
107 | ###-------------------------------------------------------------------------- |
108 | ### Iniitial settings. | |
109 | ||
110 | ## Assume X sessions are secure. | |
b617a6a0 | 111 | export __mdw_sechost="$(hostname)" |
8e08f814 | 112 | |
dad76b5d MW |
113 | ## Tell things that XFCE is in charge. This is the most desktoppy thing that |
114 | ## I run, so it's not entirely wrong. | |
115 | : ${XDG_CURRENT_DESKTOP=XFCE}; export XDG_CURRENT_DESKTOP | |
116 | ||
8e08f814 MW |
117 | ## Obtain the screen dimensions. |
118 | case ",$XWIDTH,$XHEIGHT," in | |
b8d36c3c | 119 | *,,*) eval $(xscsize -bx; xscsize -bmx) ;; |
8e08f814 | 120 | esac |
b8d36c3c MW |
121 | case ",$XNSCR," in |
122 | ,,) | |
fc504d29 | 123 | XNSCR=1 XSCR0_X=0 XSCR0_Y=0 XSCR0_WIDTH=$XWIDTH XSCR0_HEIGHT=$XHEIGHT |
b8d36c3c MW |
124 | ;; |
125 | esac | |
126 | i=0; while (( i < XNSCR )); do | |
127 | eval "x=\$XSCR${i}_X y=\$XSCR${i}_Y | |
128 | wd=\$XSCR${i}_WIDTH ht=\$XSCR${i}_HEIGHT" | |
129 | info "screen #$i = ${wd}x${ht}+${x}+${y}" | |
130 | i=$(( i + 1 )) | |
131 | done | |
8e08f814 MW |
132 | |
133 | initialize () { | |
134 | ## Load the X resource database. | |
135 | run init xrdb -override $HOME/.Xdefaults | |
136 | ||
137 | ## Random xsettery. | |
8ab9747e | 138 | run init xset b 5 2000 50 |
8e08f814 MW |
139 | run init xset r rate 500 50 |
140 | run init xset m 2 1 | |
141 | ||
f4450ac9 | 142 | ## Key mappings. |
cd38b61d MW |
143 | xmodmap $HOME/.xmodmap |
144 | if [ -r $HOME/.xmodmap-local ]; then | |
145 | xmodmap $HOME/.xmodmap-local | |
146 | fi | |
8e08f814 MW |
147 | } |
148 | ||
149 | ###-------------------------------------------------------------------------- | |
150 | ### Start a window manager. | |
151 | ||
6f6bd6da | 152 | wm=$(pick_program window-manager e16 compiz enlightenment e17 twm) |
8e08f814 MW |
153 | wmopts="" |
154 | case "$wm,$vnc" in | |
155 | enlightenment,yes | e16,yes) | |
156 | wmopts="$eopts -econfdir $HOME/.enlightenment-vnc" | |
157 | ;; | |
158 | esac | |
159 | ||
16ee7a8c | 160 | start-e16 () { |
74bd743a | 161 | run bginit manage $wm $wmopts |
16ee7a8c MW |
162 | win=nil |
163 | for i in $(seq 10); do | |
b35a9c36 | 164 | sleep 1 |
16ee7a8c MW |
165 | if eesh version >/dev/null 2>&1; then |
166 | win=t | |
167 | break | |
168 | fi | |
16ee7a8c MW |
169 | done |
170 | case $win in | |
171 | t) | |
172 | info "$wm started ok" | |
173 | run init xsetroot -cursor_name left_ptr | |
174 | ;; | |
175 | nil) | |
176 | info "$wm failed to start!" | |
177 | ;; | |
178 | esac | |
179 | } | |
180 | ||
181 | start-window-manager () { | |
182 | case $(type -t start-$wm || echo "not-found") in | |
183 | function) | |
184 | start-$wm $wmopts | |
185 | ;; | |
186 | *) | |
74bd743a | 187 | run bginit manage $wm $wmopts |
16ee7a8c MW |
188 | ;; |
189 | esac | |
8e08f814 MW |
190 | } |
191 | ||
192 | ###-------------------------------------------------------------------------- | |
193 | ### Random useful clients. | |
194 | ||
54951353 MW |
195 | start-clients-local () { :; } |
196 | ||
8e08f814 | 197 | start-clients () { |
2e60c7f3 | 198 | |
5587cf4f | 199 | ## Gnome session. |
d83c96c9 MW |
200 | case "$vnc,$(xfce4-session --version 2>&1),$(gnome-session --version 2>&1)" |
201 | in | |
202 | no,xfce4-session*) | |
203 | run bginit xfce4-session | |
204 | ;; | |
205 | no,*,gnome-session\ 2.3[2-9].* | \ | |
206 | no,*,gnome-session\ 2.4[0-9].* | \ | |
207 | no,*,gnome-session\ 2.[1-9][0-9][0-9]*) | |
2e60c7f3 MW |
208 | run bginit gnome-session --session mdw |
209 | ;; | |
d83c96c9 | 210 | no,*,gnome-session*) |
2e60c7f3 MW |
211 | run bginit gnome-session |
212 | ;; | |
213 | esac | |
54951353 MW |
214 | |
215 | ## Local clients. | |
216 | start-clients-local | |
8e08f814 MW |
217 | } |
218 | ||
219 | ###-------------------------------------------------------------------------- | |
220 | ### Main screen layout. | |
f617db13 | 221 | |
8e08f814 | 222 | ## Choose appropriate clients. |
722f9bbc | 223 | emacs=$(pick_program emacs \ |
94fbb577 MW |
224 | emacs24-lucid emacs23-lucid emacs24 emacs23 emacs22 emacs21 \ |
225 | emacs-lucid emacs) | |
8e08f814 | 226 | term=$(pick_program terminal pterm Eterm xterm) |
f617db13 | 227 | |
9b6762e9 MW |
228 | ## If we fell back to an unversioned Emacs binary, then figure out what |
229 | ## version it actually is. | |
230 | case $emacs in | |
231 | emacs | emacs-lucid) | |
232 | set -- $($emacs --version | head -n1) | |
233 | e_ver=emacs${3%%.*}${emacs#emacs} | |
234 | ;; | |
235 | *) | |
236 | e_ver=$emacs | |
237 | ;; | |
238 | esac | |
239 | info emacs-version = $e_ver | |
240 | ||
8e08f814 | 241 | ## Emacs window measurements. |
35f728b2 | 242 | ## |
58ccc65c MW |
243 | ## e_colsz = width of a column in characters (from `emacs-width' metaconfig) |
244 | ## e_charwd = width of a character in pixels (assume `6x13') | |
245 | ## e_colextra = additional per-column overhead in pixels | |
246 | ## e_colextrachars = additional per-column overhead in character units | |
35f728b2 MW |
247 | ## e_colwd = basic width of a column in pixels |
248 | ## e_hextra = extra horizontal width in pixels | |
249 | ## Width of an N-column Emacs frame in pixels will be | |
250 | ## N*e_colwd + e_hextra | |
251 | ## e_colchars = width of a column in Emacs `-geometry' units | |
252 | ## e_cextra = extra horizontal width in Emacs `-geometry' units | |
253 | ## So an N-column frame should be reported to Emacs as being | |
254 | ## N*e_colchars + e_cextra geometry units wide | |
255 | ## e_lineht = height of a character line in pixels | |
256 | ## e_vextra = number of additional vertical cruft pixels | |
257 | ## So an N-line Emacs frame takes N*e_lineht + e_vextra pixels | |
46e40566 MW |
258 | e_colsz=$(mdw-conf emacs-width 77) e_charwd=6 |
259 | e_colextra=30 e_colextrachars=5 e_lineht=13 | |
9b6762e9 | 260 | case "$e_ver" in |
22e3f287 MW |
261 | emacs21 | emacs) e_hextra=34 e_cextra=-2 e_vextra=52 ;; |
262 | emacs22 | emacs23) e_hextra=8 e_cextra=-6 e_vextra=46 ;; | |
263 | emacs24) e_hextra=5 e_cextra=-6 e_vextra=42 ;; | |
264 | emacs23-lucid) e_hextra=7 e_cextra=-6 e_vextra=48 ;; | |
265 | emacs24-lucid) e_hextra=7 e_cextra=-5 e_vextra=48 ;; | |
85bbf8d3 | 266 | esac |
46e40566 MW |
267 | e_colwd=$(( e_colsz*e_charwd + e_colextra )) |
268 | e_colchars=$(( e_colsz + e_colextrachars )) | |
f617db13 | 269 | |
8e08f814 | 270 | ## Terminal window measurements. |
35f728b2 MW |
271 | ## |
272 | ## t_wd = the window width, in pixels | |
273 | ## t_lineht, t_vextra = height parameters: if the window is N lines high, | |
274 | ## then it will be N*t_lineht + t_vextra pixels high | |
85bbf8d3 | 275 | case "$term" in |
b906a1f9 MW |
276 | pterm) |
277 | ## The pterm width differs according to whether it's linked against Gtk 2 | |
278 | ## or 3. Let's find out... | |
279 | case $(ldd $(command -v pterm) | grep libgtk) in | |
280 | libgtk-2*) t_wd=504 ;; | |
281 | *) t_wd=500 ;; | |
282 | esac | |
283 | t_lineht=13 t_vextra=23 geom=-geometry;; | |
85bbf8d3 MW |
284 | Eterm) t_wd=504 t_lineht=13 t_vextra=23 geom=-g;; |
285 | xterm) t_wd=507 t_lineht=13 t_vextra=27 geom=-geometry;; | |
286 | esac | |
f617db13 | 287 | |
8e08f814 | 288 | ## GNOME stuff measurements. |
6c3d0b23 | 289 | declare -i panelwd=64 xbound=$(( XWIDTH - panelwd )) |
f617db13 | 290 | |
8e08f814 MW |
291 | ## Choose a width for Emacs. |
292 | ## | |
30ab13b5 MW |
293 | ## We're going to make a single frame of Emacs, which will be automatically |
294 | ## divvied into columns; the rest of the space will be tiled with xterms. If | |
295 | ## we have multiple screens, then Emacs can have the first screen and we'll | |
296 | ## fill the rest with terminals. Otherwise, we'll try to have N columns of | |
297 | ## Emacs, and N - 1 columns of xterms; if that doesn't work, we'll make do | |
298 | ## with N - 2 columns of xterms. | |
299 | ## | |
300 | ## So, let W be the available width; let E and T be the widths of an Emacs | |
301 | ## column (e_colwd) and terminal (t_wd), respectively, and let E0 be the | |
302 | ## additive width of Emacs's existence (e_hextra). If we have more than one | |
303 | ## screen, then instead, let T be zero. To start out, then, we let N = 1 + | |
304 | ## floor((W - E - E0)/(E + T)). If W - E0 - (N + 1) E - (N - 1)*T >= 0, then | |
305 | ## we increase N by one. | |
b8d36c3c MW |
306 | declare -i lim=XSCR0_WIDTH |
307 | if (( lim > xbound )); then lim=xbound; fi | |
30ab13b5 MW |
308 | declare -i twd=t_wd; if (( XNSCR > 1 )); then twd=0; fi |
309 | declare -i ecols=$(( (lim - e_colwd - e_hextra)/(e_colwd + twd) + 1 )) | |
310 | if (( lim - e_hextra - (ecols + 1)*e_colwd - (ecols - 1)*twd >= 0 )); then | |
311 | ecols=$(( ecols + 1 )) | |
f617db13 MW |
312 | fi |
313 | ||
8e08f814 | 314 | declare -i \ |
7f903e21 MW |
315 | emacsx=$(( ecols*e_colchars + e_cextra )) \ |
316 | emacsy=$(( (XHEIGHT - e_vextra)/e_lineht )) | |
8e08f814 MW |
317 | |
318 | start-emacs () { | |
bf057abe | 319 | GDK_NATIVE_WINDOWS=1 run bgclients noip \ |
3a87e7ef MW |
320 | $emacs -bg black -geometry ${emacsx}x${emacsy}+${XSCR0_X}+${XSCR0_Y} \ |
321 | --mdw-splashy-startup | |
8e08f814 MW |
322 | } |
323 | ||
324 | ## Now place some xterms. | |
325 | ## | |
326 | ## A few smaller xterms are in general better than one great big one. 35 | |
327 | ## lines is a good height for most terminals. 25 lines is a minimum. The | |
328 | ## strategy for doling out xterms into a column is to make as many 35-liners | |
329 | ## as we can, until the remaining space would be too small for a 25-liner. | |
330 | ## If we can get two 25s out of that then we do (largest first); otherwise | |
331 | ## just make one big one. We stop at the end of a page, once we've made | |
332 | ## three xterms. | |
333 | ||
334 | start-xterms () { | |
335 | ||
336 | ## Initialize some parameters. | |
7f903e21 | 337 | declare -i x=$(( ecols*e_colwd + e_hextra + XSCR0_X )) xb=xbound |
b8d36c3c | 338 | declare -i n=0 pgx=0 l h y ht scr=0 ll=lim |
7f903e21 MW |
339 | declare -i hstd=$(( 35*t_lineht + t_vextra )) |
340 | declare -i hmin=$(( 25*t_lineht + t_vextra )) | |
b8d36c3c MW |
341 | declare -i scrx scry scrwd scrht |
342 | ||
343 | eval "scrx=\$XSCR${scr}_X scry=\$XSCR${scr}_Y | |
344 | scrwd=\$XSCR${scr}_WIDTH scrht=\$XSCR${scr}_HEIGHT" | |
8e08f814 MW |
345 | |
346 | ## Do the placement. | |
347 | while :; do | |
348 | ||
349 | ## Start a new iteration. | |
7f903e21 | 350 | if (( x + t_wd > ll )); then |
b8d36c3c MW |
351 | scr=$(( scr + 1 )) |
352 | if (( scr >= XNSCR )); then | |
353 | if (( n >= 3 )); then break; fi | |
354 | pgx=$(( pgx + XWIDTH )) xb=$(( xb + XWIDTH )) | |
355 | scr=0 | |
356 | fi | |
357 | eval "scrx=\$XSCR${scr}_X scry=\$XSCR${scr}_Y | |
358 | scrwd=\$XSCR${scr}_WIDTH scrht=\$XSCR${scr}_HEIGHT" | |
359 | x=$(( pgx + scrx )) | |
360 | ll=$(( x + scrwd )) | |
361 | if (( ll > xb )); then ll=xb; fi | |
8e08f814 MW |
362 | fi |
363 | ||
364 | ## Make large xterms. | |
b8d36c3c | 365 | y=scry ht=scrht |
7f903e21 | 366 | while (( ht - hstd >= hmin )); do |
8e08f814 | 367 | run bgclients $term $geom 80x35+$x+$y |
7f903e21 | 368 | y=$(( y + hstd )) ht=$(( ht - hstd )) n=$(( n + 1 )) |
8e08f814 MW |
369 | done |
370 | ||
371 | ## Fill the remaining space. | |
7f903e21 MW |
372 | if (( ht >= 2*hmin )); then h=$(( ht - hmin )); else h=ht; fi |
373 | l=$(( (h - t_vextra)/t_lineht )) h=$(( l*t_lineht + t_vextra )) | |
8e08f814 | 374 | run bgclients $term $geom 80x$l+$x+$y |
7f903e21 | 375 | y=$(( y + h )) ht=$(( ht - h )) n=$(( n + 1 )) |
8e08f814 MW |
376 | if ((ht >= hmin)); then |
377 | run bgclients $term $geom 80x25+$x+$y | |
7f903e21 | 378 | n=$(( n + 1 )) |
8e08f814 | 379 | fi |
7f903e21 | 380 | x=$(( x + t_wd )) |
f617db13 | 381 | done |
8e08f814 | 382 | } |
f617db13 | 383 | |
3bdada49 MW |
384 | ###-------------------------------------------------------------------------- |
385 | ### Requesters. | |
386 | ||
387 | req () { | |
388 | declare title=$1 hist=$2; shift 2 | |
3f88bd1f | 389 | cmd=$(xgetline -t "$title" -p "_Command:" -Hl "$HOME/$hist") && |
3bdada49 MW |
390 | exec "$@" "$cmd" |
391 | } | |
392 | ||
8e08f814 MW |
393 | ###-------------------------------------------------------------------------- |
394 | ### Final waiting. | |
395 | ||
396 | atom=XINIT_COMMAND$atomtag | |
397 | ||
398 | xwait () { | |
399 | while :; do | |
400 | xatom delete $atom | |
401 | info "waiting on $atom" | |
402 | line=$(xatom wait $atom) | |
403 | info "xatom: $line" | |
404 | ||
405 | case "$line" in | |
406 | :help) | |
407 | xmsg -I -t "xinitrc help" -d "xinitrc commands" - <<EOF & | |
408 | :help | |
409 | :emacs :xterms :window-manager :clients | |
3bdada49 | 410 | :ask-run :ask-command |
8e08f814 MW |
411 | :init |
412 | :terminal | |
413 | ! SHELL-COMMAND | |
414 | CLIENT | |
415 | EOF | |
416 | ;; | |
417 | :emacs | :xterms | :window-manager | :clients) | |
418 | start-${line#:} | |
419 | ;; | |
420 | :terminal) | |
421 | run bgclients $term | |
422 | ;; | |
423 | :init) | |
424 | initialize | |
425 | ;; | |
426 | :exec) | |
427 | info "restarting xinitrc" | |
428 | exec "$0" wait nostart | |
429 | ;; | |
3bdada49 | 430 | :ask-run) |
a6780078 | 431 | req "Shell command" .cmd.hist xcatch -F"Fixed 13" -- sh -c& |
3bdada49 MW |
432 | ;; |
433 | :ask-command) | |
434 | req "xinit command" .xinit.hist xatom set XINIT_COMMAND$atomtag& | |
435 | ;; | |
8e08f814 MW |
436 | :*) |
437 | xmsg -E -t "xinitrc error" "Unknown command \`$line'" & | |
438 | ;; | |
439 | !*) | |
440 | eval "${line#!}" | |
441 | ;; | |
442 | *) | |
2f616761 | 443 | set -- $line |
8e08f814 MW |
444 | run bgclients "$@" |
445 | ;; | |
446 | esac | |
447 | done | |
448 | } | |
449 | ||
8ca91005 MW |
450 | ###-------------------------------------------------------------------------- |
451 | ### Gnome session care and feeding. | |
452 | ||
453 | session-running-p () { | |
454 | dbus-send --session --print-reply --dest=org.freedesktop.DBus / \ | |
455 | org.freedesktop.DBus.GetNameOwner string:org.gnome.SessionManager \ | |
456 | >/dev/null 2>&1 | |
457 | } | |
458 | ||
d83c96c9 MW |
459 | dbus-service-running-p () { |
460 | dbus-send >/dev/null 2>&1 --session --print-reply \ | |
461 | --dest=org.freedesktop.DBus / \ | |
462 | org.freedesktop.DBus.GetNameOwner string:$1 | |
463 | } | |
464 | ||
8ca91005 | 465 | kill-gnome-session () { |
d83c96c9 MW |
466 | win=nil |
467 | while read service object logout; do | |
468 | if dbus-service-running-p $service; then win=t; break; fi | |
469 | done <<EOF | |
470 | org.xfce.SessionManager /org/xfce/SessionManager org.xfce.Session.Manager.Shutdown uint32:1 boolean:false | |
471 | org.gnome.SessionManager /org/gnome/SessionManager org.gnome.SessionManager.Logout uint32:2 | |
472 | EOF | |
473 | case $win in nil) return ;; esac | |
474 | info "killing session manager" | |
475 | dbus-send --session --dest=$service $object $logout | |
476 | for i in 1 2 3 4 5; do | |
477 | sleep 1 | |
478 | if ! dbus-service-running-p $service; then break; fi | |
479 | done | |
8ca91005 MW |
480 | } |
481 | ||
8e08f814 MW |
482 | ###-------------------------------------------------------------------------- |
483 | ### Actually start things up. | |
484 | ||
54951353 MW |
485 | if [ -f $HOME/.xinitrc-local ]; then |
486 | . $HOME/.xinitrc-local | |
487 | fi | |
488 | ||
8e08f814 MW |
489 | case "$start" in |
490 | yes) | |
491 | info "starting standard clients" | |
492 | initialize | |
493 | start-window-manager | |
494 | start-clients | |
495 | start-emacs | |
496 | start-xterms | |
497 | ;; | |
498 | no) | |
499 | info "not starting standard clients" | |
500 | ;; | |
501 | esac | |
502 | ||
503 | case "$wait" in | |
504 | yes) | |
505 | xwait | |
8ca91005 | 506 | kill-gnome-session |
8e08f814 MW |
507 | ;; |
508 | no) | |
509 | info "not waiting before exit" | |
510 | ;; | |
511 | esac | |
f617db13 | 512 | |
8e08f814 | 513 | ###----- That's all, folks -------------------------------------------------- |