[comp.emacs] walk-windows

ram-ashwin@YALE.ARPA (Ashwin Ram) (11/16/87)

Here's a nice abstraction that lets you do things like count-windows and
balance-windows pretty easily.  The function walk-windows applies its
argument, a procedure of one argument, to every visible window.

Now it's trivial to define count-windows (pass down a lambda that increments
a count), Mike's balance-windows (pass down a lambda that does an
enlarge-window on each window).  Etc. etc...

-- Ashwin Ram --

ARPA:    Ram-Ashwin@cs.yale.edu
UUCP:    {decvax,linus,seismo}!yale!Ram-Ashwin
BITNET:  Ram@yalecs

----------------------------------- cut -----------------------------------
;; walk-windows and friends.
;; Ashwin Ram, 11/12/87.

(defun walk-windows (proc &optional no-mini)
   "Applies PROC to each visible window.
Optional arg NO-MINI non-nil means don't apply PROC to the minibuffer
even if it is active."
   (let ((start (selected-window))
         (current (next-window (selected-window) no-mini)))
      (while (not (eq current start))
         (funcall proc current)
         (setq current (next-window current no-mini)))))

(defun count-windows (&optional no-mini)
   "Returns the number of visible windows.
Optional arg NO-MINI non-nil means don't count the minibuffer
even if it is active."
   (let ((count 1))
      (walk-windows (function (lambda (w) (ignore w)
                                 (setq count (+ count 1))))
                    no-mini)
      count))

(defun balance-windows ()
   "Makes all visible windows the same size."
   (interactive)
   (let ((start (selected-window))
         (size (/ (screen-height) (count-windows))))
      (walk-windows (function (lambda (w)
                                 (select-window w)
                                 (enlarge-window (- size (window-height)))))
                    'no-mini)
      (select-window start)))

----------------------------------- cut -----------------------------------

P.S. enlarge-window really should take a window as its argument, rather than
making you have to select the window first.  When called interactively, that
argument should default to the current window.

ram-ashwin@YALE.ARPA (Ashwin Ram) (11/17/87)

Oops... The starting count for count-windows should indeed be 0.  There was a
minor bug in walk-windows.  Here's the corrected code:


(defun walk-windows (proc &optional no-mini)
   "Applies PROC to each visible window.
Optional arg NO-MINI non-nil means don't apply PROC to the minibuffer
even if it is active."
   (let ((start (selected-window))
         (current (next-window (selected-window) no-mini)))
      (funcall proc start)
      (while (not (eq current start))
         (funcall proc current)
         (setq current (next-window current no-mini)))))

(defun count-windows (&optional no-mini)
   "Returns the number of visible windows.
Optional arg NO-MINI non-nil means don't count the minibuffer
even if it is active."
   (let ((count 0))
      (walk-windows (function (lambda (w) (ignore w)
                                 (setq count (+ count 1))))
                    no-mini)
      count))


Thanks for the feedback.

-- Ashwin Ram --

ARPA:    Ram-Ashwin@cs.yale.edu
UUCP:    {decvax,linus,seismo}!yale!Ram-Ashwin
BITNET:  Ram@yalecs

ram-ashwin@YALE.ARPA (Ashwin Ram) (11/18/87)

A couple of people suggested that it would be nice if walk-windows selected
each window before applying proc to it.  I'm not sure that this is "cleaner"
(since you're relying on a global somewhere to do the right thing), but it
certainly is convenient.  (It would be best if functions like enlarge-window
took a window argument (that defaulted to the current window via an
interactive spec when called interactively), so that you weren't tempted to
write procs (for walk-windows and elsewhere) that did different things
depending on which window was currently selected.)

Anyway, here is the (hopefully) final version of walk-windows.


(defun walk-windows (proc &optional no-mini)
   "Applies PROC to each visible window (after selecting it, for convenience).
Optional arg NO-MINI non-nil means don't apply PROC to the minibuffer
even if it is active."
   (let ((start (selected-window))
         (current (next-window (selected-window) no-mini)))
      (funcall proc start)
      (while (not (eq current start))
         (select-window current)
         (funcall proc current)
         (setq current (next-window current no-mini)))
      (select-window start)))


Since this function has generated quite a bit of interest, it would be nice
if it became part of GNU.  'balance-windows' is certainly a useful function.

-- Ashwin Ram --

ARPA:    Ram-Ashwin@cs.yale.edu
UUCP:    {decvax,linus,seismo}!yale!Ram-Ashwin
BITNET:  Ram@yalecs