;;; window.el --- GNU Emacs window commands aside from those written in C.
-;; Copyright (C) 1985, 1989, 1992, 1993, 1994 Free Software Foundation, Inc.
+;; Copyright (C) 1985, 1989, 1992, 1993, 1994, 2000
+;; Free Software Foundation, Inc.
;; Maintainer: FSF
ALL-FRAMES = `visible' means include windows on all visible frames.
ALL-FRAMES = 0 means include windows on all visible and iconified frames.
ALL-FRAMES = t means include windows on all frames including invisible frames.
+If ALL-FRAMES is a frame, it means include windows on that frame.
Anything else means restrict to the selected frame."
;; If we start from the minibuffer window, don't fail to come back to it.
(if (window-minibuffer-p (selected-window))
(setq minibuf t))
- (let* ((walk-windows-start (selected-window))
- (walk-windows-current walk-windows-start))
- (while (progn
- (setq walk-windows-current
- (next-window walk-windows-current minibuf all-frames))
- (funcall proc walk-windows-current)
- (not (eq walk-windows-current walk-windows-start))))))
+ (save-selected-window
+ (if (framep all-frames)
+ (select-window (frame-first-window all-frames)))
+ (let* (walk-windows-already-seen
+ (walk-windows-current (selected-window)))
+ (while (progn
+ (setq walk-windows-current
+ (next-window walk-windows-current minibuf all-frames))
+ (not (memq walk-windows-current walk-windows-already-seen)))
+ (setq walk-windows-already-seen
+ (cons walk-windows-current walk-windows-already-seen))
+ (funcall proc walk-windows-current)))))
+
+(defun some-window (predicate &optional minibuf all-frames default)
+ "Return a window satisfying PREDICATE.
+
+This function cycles through all visible windows using `walk-windows',
+calling PREDICATE on each one. PREDICATE is called with a window as
+argument. The first window for which PREDICATE returns a non-nil
+value is returned. If no window satisfies PREDICATE, DEFAULT is
+returned.
+
+Optional second arg MINIBUF t means count the minibuffer window even
+if not active. MINIBUF nil or omitted means count the minibuffer iff
+it is active. MINIBUF neither t nor nil means not to count the
+minibuffer even if it is active.
+
+Several frames may share a single minibuffer; if the minibuffer
+counts, all windows on all frames that share that minibuffer count
+too. Therefore, if you are using a separate minibuffer frame
+and the minibuffer is active and MINIBUF says it counts,
+`walk-windows' includes the windows in the frame from which you
+entered the minibuffer, as well as the minibuffer window.
+
+ALL-FRAMES is the optional third argument.
+ALL-FRAMES nil or omitted means cycle within the frames as specified above.
+ALL-FRAMES = `visible' means include windows on all visible frames.
+ALL-FRAMES = 0 means include windows on all visible and iconified frames.
+ALL-FRAMES = t means include windows on all frames including invisible frames.
+If ALL-FRAMES is a frame, it means include windows on that frame.
+Anything else means restrict to the selected frame."
+ (catch 'found
+ (walk-windows #'(lambda (window)
+ (when (funcall predicate window)
+ (throw 'found window)))
+ minibuf all-frames)
+ default))
(defun minibuffer-window-active-p (window)
"Return t if WINDOW (a minibuffer window) is now active."
(setq size (+ (window-width) size)))
(split-window-save-restore-data (split-window nil size t) old-w)))
\f
+(defcustom mode-line-window-height-fudge nil
+ "*Fudge factor returned by `mode-line-window-height-fudge' on graphic displays.
+If non-nil, it should be the number of lines to add to the sizes of
+windows to compensate for the extra height of the mode-line, so it
+doesn't't obscure the last line of text.
+
+If nil, an attempt is made to calculate reasonable value.
+
+This is a kluge."
+ :type '(choice (const :tag "Guess" nil)
+ (integer :tag "Extra lines" :value 1))
+ :group 'windows)
+
+;; List of face attributes that might change a face's height
+(defconst height-affecting-face-attributes
+ '(:family :height :box :font :inherit))
+
+(defsubst mode-line-window-height-fudge (&optional face)
+ "Return a fudge factor to compensate for the extra height of graphic mode-lines.
+On a non-graphic display, return 0.
+
+FACE is the face used to display the mode-line; it defaults to `mode-line'.
+
+If the variable `mode-line-window-height-fudge' has a non-nil value, it
+is returned. Otherwise, the `mode-line' face is checked to see if it
+contains any attributes that might affect its height; if it does, 1 is
+returned, otherwise 0.
+
+\[Because mode-lines on a graphics capable display may have a height
+larger than a normal text line, a window who's size is calculated to
+exactly show some text, including 1 line for the mode-line, may be
+displayed with the last text line obscured by the mode-line.
+
+To work-around this problem, call `mode-line-window-height-fudge', and
+add the return value to the requested window size.]
+
+This is a kluge."
+ (if (display-graphic-p)
+ (or
+ ;; Return user-specified value
+ mode-line-window-height-fudge
+ ;; Try and detect whether mode-line face has any attributes that
+ ;; could make it bigger than a default text line, and return a
+ ;; fudge factor of 1 if so.
+ (let ((attrs height-affecting-face-attributes)
+ (fudge 0))
+ (while attrs
+ (let ((val (face-attribute (or face 'mode-line) (pop attrs))))
+ (unless (or (null val) (eq val 'unspecified))
+ (setq fudge 1 attrs nil))))
+ fudge))
+ 0))
+
+\f
+;;; These functions should eventually be replaced with versions that
+;;; really do the job (instead of using the kludgey mode-line face
+;;; hacking junk).
+
+(defun window-text-height (&optional window)
+ "Return the height in lines of the text display area of WINDOW.
+This doesn't include the mode-line (or header-line if any) or any
+partial-height lines in the text display area.
+
+Note that the current implementation of this function may sometimes
+return an inaccurate value, but attempts to be conservative, by
+returning fewer lines than actually exist in the case where the real
+value cannot be determined."
+ (with-current-buffer (window-buffer window)
+ (- (window-height window)
+ (if (and (not (window-minibuffer-p window))
+ mode-line-format)
+ (1+ (mode-line-window-height-fudge))
+ 0)
+ (if header-line-format
+ (1+ (mode-line-window-height-fudge 'header-line))
+ 0))))
+
+(defun set-window-text-height (window height)
+ "Sets the height in lines of the text display area of WINDOW to HEIGHT.
+This doesn't include the mode-line (or header-line if any) or any
+partial-height lines in the text display area.
+
+If WINDOW is nil, the selected window is used.
+
+Note that the current implementation of this function cannot always set
+the height exactly, but attempts to be conservative, by allocating more
+lines than are actually needed in the case where some error may be present."
+ (let ((delta (- height (window-text-height window))))
+ (unless (zerop delta)
+ (let ((window-min-height 1))
+ (if (and window (not (eq window (selected-window))))
+ (save-selected-window
+ (select-window window)
+ (enlarge-window delta))
+ (enlarge-window delta))))))
+
+\f
(defun enlarge-window-horizontally (arg)
"Make current window ARG columns wider."
(interactive "p")
nil
window))))))
+(defun count-screen-lines (&optional beg end count-final-newline window)
+ "Return the number of screen lines in the region.
+The number of screen lines may be different from the number of actual lines,
+due to line breaking, display table, etc.
+
+Optional arguments BEG and END default to `point-min' and `point-max'
+respectively.
+
+If region ends with a newline, ignore it unless optinal third argument
+COUNT-FINAL-NEWLINE is non-nil.
+
+The optional fourth argument WINDOW specifies the window used for obtaining
+parameters such as width, horizontal scrolling, and so on. The default is
+to use the selected window's parameters.
+
+Like `vertical-motion', `count-screen-lines' always uses the current buffer,
+regardless of which buffer is displayed in WINDOW. This makes possible to use
+`count-screen-lines' in any buffer, whether or not it is currently displayed
+in some window."
+ (unless beg
+ (setq beg (point-min)))
+ (unless end
+ (setq end (point-max)))
+ (if (= beg end)
+ 0
+ (save-excursion
+ (save-restriction
+ (widen)
+ (narrow-to-region (min beg end)
+ (if (and (not count-final-newline)
+ (= ?\n (char-before (max beg end))))
+ (1- (max beg end))
+ (max beg end)))
+ (goto-char (point-min))
+ (1+ (vertical-motion (buffer-size) window))))))
+
+(defun fit-window-to-buffer (&optional window max-height min-height)
+ "Make WINDOW the right size to display its contents exactly.
+If the optional argument MAX-HEIGHT is supplied, it is the maximum height
+ the window is allowed to be, defaulting to the frame height.
+If the optional argument MIN-HEIGHT is supplied, it is the minimum
+ height the window is allowed to be, defaulting to `window-min-height'.
+
+The heights in MAX-HEIGHT and MIN-HEIGHT include the mode-line and/or
+header-line."
+ (interactive)
+
+ (when (null window)
+ (setq window (selected-window)))
+ (when (null max-height)
+ (setq max-height (frame-height (window-frame window))))
+
+ (let* ((window-height
+ ;; The current height of WINDOW
+ (window-height window))
+ (extra
+ ;; The amount by which the text height differs from the window
+ ;; height.
+ (- window-height (window-text-height window)))
+ (text-height
+ ;; The height necessary to show the buffer displayed by WINDOW
+ ;; (`count-screen-lines' always works on the current buffer).
+ (with-current-buffer (window-buffer window)
+ (count-screen-lines)))
+ (delta
+ ;; Calculate how much the window height has to change to show
+ ;; text-height lines, constrained by MIN-HEIGHT and MAX-HEIGHT.
+ (- (max (min (+ text-height extra) max-height)
+ (or min-height window-min-height))
+ window-height))
+ ;; We do our own height checking, so avoid any restrictions due to
+ ;; window-min-height.
+ (window-min-height 1))
+
+ ;; Don't try to redisplay with the cursor at the end
+ ;; on its own line--that would force a scroll and spoil things.
+ (if (with-current-buffer (window-buffer window)
+ (and (eobp) (bolp) (not (bobp))))
+ (set-window-point window (1- (window-point window))))
+
+ (unless (zerop delta)
+ (if (eq window (selected-window))
+ (enlarge-window delta)
+ (save-selected-window
+ (select-window window)
+ (enlarge-window delta))))))
+
(defun shrink-window-if-larger-than-buffer (&optional window)
"Shrink the WINDOW to be as small as possible to display its contents.
Do not shrink to less than `window-min-height' lines.
or if the window is not the full width of the frame,
or if the window is the only window of its frame."
(interactive)
- (save-selected-window
- (if window
- (select-window window)
- (setq window (selected-window)))
- (let* ((params (frame-parameters))
- (mini (cdr (assq 'minibuffer params)))
- (edges (window-edges)))
- (if (and (< 1 (count-windows))
- (= (window-width) (frame-width))
- (pos-visible-in-window-p (point-min) window)
- (not (eq mini 'only))
- (or (not mini)
- (< (nth 3 edges) (nth 1 (window-edges mini)))
- (> (nth 1 edges) (cdr (assq 'menu-bar-lines params)))))
- (let ((text-height (window-buffer-height window))
- (window-height (window-height)))
- ;; Don't try to redisplay with the cursor at the end
- ;; on its own line--that would force a scroll and spoil things.
- (when (and (eobp) (bolp) (not (bobp)))
- (forward-char -1))
- (when (> window-height (1+ text-height))
- (shrink-window
- (- window-height (max (1+ text-height) window-min-height)))))))))
+ (when (null window)
+ (setq window (selected-window)))
+ (let* ((frame (window-frame window))
+ (mini (frame-parameter frame 'minibuffer))
+ (edges (window-edges window)))
+ (if (and (not (eq window (frame-root-window frame)))
+ (= (window-width) (frame-width))
+ (pos-visible-in-window-p (point-min) window)
+ (not (eq mini 'only))
+ (or (not mini)
+ (< (nth 3 edges) (nth 1 (window-edges mini)))
+ (> (nth 1 edges) (frame-parameter frame 'menu-bar-lines))))
+ (fit-window-to-buffer window (window-height window)))))
(defun kill-buffer-and-window ()
"Kill the current buffer and delete the selected window."