1 ;;; zone.el --- idle display hacks
3 ;; Copyright (C) 2000 Free Software Foundation, Inc.
5 ;;; Author: Victor Zandy <zandy@cs.wisc.edu>
6 ;;; Maintainer: Thien-Thi Nguyen <ttn@gnu.org>
8 ;;; Created: June 6, 1998
10 ;; This file is part of GNU Emacs.
12 ;; GNU Emacs is free software; you can redistribute it and/or modify
13 ;; it under the terms of the GNU General Public License as published by
14 ;; the Free Software Foundation; either version 2, or (at your option)
17 ;; GNU Emacs is distributed in the hope that it will be useful,
18 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 ;; GNU General Public License for more details.
22 ;; You should have received a copy of the GNU General Public License
23 ;; along with GNU Emacs; see the file COPYING. If not, write to the
24 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
25 ;; Boston, MA 02111-1307, USA.
29 ;; Don't zone out in front of Emacs! Try M-x zone.
30 ;; If it eventually irritates you, try M-x zone-leave-me-alone.
32 ;; Bored by the zone pyrotechnics? Write your own! Add it to
35 ;; WARNING: Not appropriate for Emacs sessions over modems or
36 ;; computers as slow as mine.
38 ;; THANKS: Christopher Mayer, Scott Flinchbaugh, Rachel Kalmar,
45 (eval-when-compile (require 'cl
))
47 (defvar zone-timer nil
)
50 "*Seconds to idle before zoning out.")
52 ;; Vector of functions that zone out. `zone' will execute one of
53 ;; these functions, randomly chosen. The chosen function is invoked
54 ;; in the *zone* buffer, which contains the text of the selected
55 ;; window. If the function loops, it *must* periodically check and
56 ;; halt if `input-pending-p' is t (because quitting is disabled when
57 ;; Emacs idle timers are run).
58 (defvar zone-programs
[
60 zone-pgm-putz-with-case
65 zone-pgm-rotate-LR-lockstep
66 zone-pgm-rotate-RL-lockstep
67 zone-pgm-rotate-LR-variable
68 zone-pgm-rotate-RL-variable
70 zone-pgm-drip-fretfully
71 zone-pgm-five-oclock-swan-dive
72 zone-pgm-martini-swan-dive
73 zone-pgm-paragraph-spaz
77 (defmacro zone-orig
(&rest body
)
78 `(with-current-buffer (get 'zone
'orig-buffer
)
83 "Zone out, completely."
85 (and (timerp zone-timer
) (cancel-timer zone-timer
))
87 (let ((f (selected-frame))
88 (outbuf (get-buffer-create "*zone*"))
89 (text (buffer-substring (window-start) (window-end)))
90 (wp (1+ (- (window-point (selected-window))
92 (put 'zone
'orig-buffer
(current-buffer))
94 (setq mode-name
"Zone")
97 (switch-to-buffer outbuf
)
98 (setq buffer-undo-list t
)
99 (untabify (point-min) (point-max))
100 (set-window-start (selected-window) (point-min))
101 (set-window-point (selected-window) wp
)
103 (let ((pgm (elt zone-programs
(random (length zone-programs
))))
104 (ct (and f
(frame-parameter f
'cursor-type
))))
105 (when ct
(modify-frame-parameters f
'((cursor-type .
(bar .
0)))))
108 (message "Zoning... (%s)" pgm
)
110 ;; If some input is pending, zone says "sorry", which
111 ;; isn't nice; this might happen e.g. when they invoke the
112 ;; game by clicking the menu bar. So discard any pending
113 ;; input before zoning out.
114 (if (input-pending-p)
117 (message "Zoning...sorry"))
119 (while (not (input-pending-p))
120 (message (format "We were zoning when we wrote %s..." pgm
))
122 (message "...here's hoping we didn't hose your buffer!")
124 (quit (ding) (message "Zoning...sorry")))
125 (when ct
(modify-frame-parameters f
(list (cons 'cursor-type ct
)))))
127 (zone-when-idle zone-idle
)))
129 ;;;; Zone when idle, or not.
131 (defvar zone-timer nil
132 "Timer that zone sets to triggle idle zoning out.
133 If t, zone won't zone out.")
135 (defun zone-when-idle (secs)
136 "Zone out when Emacs has been idle for SECS seconds."
137 (interactive "nHow long before I start zoning (seconds): ")
141 (setq zone-timer
(run-with-idle-timer secs t
'zone
))))
143 (defun zone-leave-me-alone ()
144 "Don't zone out when Emacs is idle."
146 (and (timerp zone-timer
) (cancel-timer zone-timer
))
148 (message "I won't zone out any more"))
153 (defun zone-shift-up ()
157 (if (looking-at "\n") (1+ (point)) (point))))
158 (s (buffer-substring b e
)))
160 (goto-char (point-max))
163 (defun zone-shift-down ()
164 (goto-char (point-max))
170 (if (looking-at "\n") (1+ (point)) (point))))
171 (s (buffer-substring b e
)))
173 (goto-char (point-min))
176 (defun zone-shift-left ()
179 (let ((c (following-char)))
185 (defun zone-shift-right ()
189 (let ((c (preceding-char)))
190 (delete-backward-char 1)
195 (defun zone-pgm-jitter ()
209 (goto-char (point-min))
210 (while (not (input-pending-p))
211 (funcall (elt ops
(random (length ops
))))
212 (goto-char (point-min))
216 ;;;; zone-pgm-whack-chars
219 (let ((tbl (make-string 128 ?x
))
226 (defun zone-pgm-whack-chars ()
227 (let ((tbl (copy-sequence zone-wc-tbl
)))
228 (while (not (input-pending-p))
231 (aset tbl i
(+ 48 (random (- 123 48))))
233 (translate-region (point-min) (point-max) tbl
)
237 ;;;; zone-pgm-dissolve
239 (defun zone-remove-text ()
244 (goto-char (point-min))
246 (if (looking-at "[^(){}\n\t ]")
247 (let ((n (random 5)))
257 (defun zone-pgm-dissolve ()
262 ;;;; zone-pgm-explode
264 (defun zone-exploding-remove ()
268 (goto-char (point-min))
270 (if (looking-at "[^*\n\t ]")
271 (let ((n (random 5)))
280 (defun zone-pgm-explode ()
281 (zone-exploding-remove)
285 ;;;; zone-pgm-putz-with-case
287 ;; Faster than `zone-pgm-putz-with-case', but not as good: all
288 ;; instances of the same letter have the same case, which produces a
289 ;; less interesting effect than you might imagine.
290 (defun zone-pgm-2nd-putz-with-case ()
291 (let ((tbl (make-string 128 ?x
))
296 (while (not (input-pending-p))
300 (if (zerop (random 5))
303 (setq i
(+ i
(1+ (random 5)))))
307 (if (zerop (random 5))
310 (setq i
(+ i
(1+ (random 5)))))
311 (translate-region (point-min) (point-max) tbl
)
314 (defun zone-pgm-putz-with-case ()
315 (goto-char (point-min))
316 (while (not (input-pending-p))
317 (let ((np (+ 2 (random 5)))
321 (let ((prec (preceding-char))
322 (props (text-properties-at (1- (point)))))
323 (insert (if (zerop (random 2))
326 (set-text-properties (1- (point)) (point) props
))
329 (setq np
(+ np
(1+ (random 5))))))
330 (goto-char (point-min))
336 (defun zone-line-specs ()
339 (goto-char (window-start))
340 (while (< (point) (window-end))
341 (when (looking-at "[\t ]*\\([^\n]+\\)")
342 (setq ret
(cons (cons (match-beginning 1) (match-end 1)) ret
)))
346 (defun zone-pgm-rotate (&optional random-style
)
350 (mapcar (lambda (ent)
351 (let* ((beg (car ent
))
353 (amt (if random-style
354 (funcall random-style
)
356 (when (< (- end
(abs amt
)) beg
)
357 (setq amt
(random (- end beg
))))
361 (vector amt beg
(- end
(abs amt
)))
366 amt aamt cut paste txt i ent
)
367 (while (not (input-pending-p))
370 (setq ent
(aref specs i
))
371 (setq amt
(aref ent
0) aamt
(abs amt
))
374 (setq cut
2 paste
1))
375 (goto-char (aref ent cut
))
376 (setq txt
(buffer-substring (point) (+ (point) aamt
)))
378 (goto-char (aref ent paste
))
383 (defun zone-pgm-rotate-LR-lockstep ()
384 (zone-pgm-rotate (lambda () 1)))
386 (defun zone-pgm-rotate-RL-lockstep ()
387 (zone-pgm-rotate (lambda () -
1)))
389 (defun zone-pgm-rotate-LR-variable ()
390 (zone-pgm-rotate (lambda () (1+ (random 3)))))
392 (defun zone-pgm-rotate-RL-variable ()
393 (zone-pgm-rotate (lambda () (1- (- (random 3))))))
398 (defun zone-cpos (pos)
399 (buffer-substring pos
(1+ pos
)))
401 (defun zone-fret (pos)
402 (let* ((case-fold-search nil
)
403 (c-string (zone-cpos pos
))
405 ((string-match "[a-z]" c-string
) (upcase c-string
))
406 ((string-match "[A-Z]" c-string
) (downcase c-string
))
409 (wait 0.5 (* wait
0.8)))
413 (insert (if (= 0 (% i
2)) hmm c-string
))
415 (delete-char -
1) (insert c-string
)))
417 (defun zone-fall-through-ws (c col wend
)
418 (let ((fall-p nil
) ; todo: move outward
420 (o (point)) ; for terminals w/o cursor hiding
428 (insert (if (< (point) wend
) c
" "))
434 (sit-for (setq wait
(* wait
0.8))))
435 (setq p
(1- (point))))
438 (defun zone-pgm-drip (&optional fret-p pancake-p
)
439 (let* ((ww (1- (window-width)))
444 (goto-char (point-min))
445 ;; fill out rectangular ws block
448 (let ((cc (current-column)))
450 (insert (make-string (- ww cc
) ?
))
451 (delete-char (- ww cc
))))
454 ;; what the hell is going on here?
455 (let ((nl (- wh
(count-lines (point-min) (point)))))
457 (let ((line (concat (make-string (1- ww
) ?
) "\n")))
463 (while (not (input-pending-p))
464 (goto-char (point-min))
466 (let ((wbeg (window-start))
469 ;; select non-ws character, but don't miss too much
470 (goto-char (+ wbeg
(random (- wend wbeg
))))
471 (while (looking-at "[ \n\f]")
472 (if (= total
(setq mc
(1+ mc
)))
474 (goto-char (+ wbeg
(random (- wend wbeg
))))))
475 ;; character animation sequence
477 (when fret-p
(zone-fret p
))
479 (setq fall-p
(zone-fall-through-ws
480 (zone-cpos p
) (current-column) wend
))))
481 ;; assuming current-column has not changed...
484 (< (count-lines (point-min) (point))
498 (defun zone-pgm-drip-fretfully ()
501 (defun zone-pgm-five-oclock-swan-dive ()
502 (zone-pgm-drip nil t
))
504 (defun zone-pgm-martini-swan-dive ()
508 ;;;; zone-pgm-paragraph-spaz
510 (defun zone-pgm-paragraph-spaz ()
511 (if (memq (zone-orig major-mode
) '(text-mode fundamental-mode
))
512 (let ((fill-column fill-column
)
515 (max-fc (1- (frame-width))))
518 (setq fill-column
(+ fill-column
(- (random 5) 2)))
519 (when (< fill-column fc-min
)
520 (setq fc-min fill-column
))
521 (when (> fill-column max-fc
)
522 (setq fill-column max-fc
))
523 (when (> fill-column fc-max
)
524 (setq fc-max fill-column
))))
525 (message "Zoning... (zone-pgm-rotate)")
531 (defun zone-pgm-stress ()
532 (goto-char (point-min))
533 (let (lines bg m-fg m-bg
)
534 (while (< (point) (point-max))
537 (setq lines
(cons (buffer-substring p
(point)) lines
))))
539 (when (display-color-p)
540 (setq bg
(frame-parameter (selected-frame) 'background-color
)
541 m-fg
(face-foreground 'modeline
)
542 m-bg
(face-background 'modeline
))
543 (set-face-foreground 'modeline bg
)
544 (set-face-background 'modeline bg
))
545 (let ((msg "Zoning... (zone-pgm-stress)"))
546 (while (not (string= msg
""))
547 (message (setq msg
(substring msg
1)))
549 (while (not (input-pending-p))
550 (when (< 50 (random 100))
551 (goto-char (point-max))
553 (let ((kill-whole-line t
))
555 (goto-char (point-min))
556 (insert (nth (random (length lines
)) lines
)))
557 (message (concat (make-string (random (- (frame-width) 5)) ?
) "grrr"))
559 (when (display-color-p)
560 (set-face-foreground 'modeline m-fg
)
561 (set-face-background 'modeline m-bg
))))
565 ;;; zone.el ends here