mirror of
git://git.sv.gnu.org/emacs.git
synced 2026-02-23 08:20:41 -08:00
Window configuration, balancing and fit-to-buffer rewrites.
* window.c (delete_deletable_window): Re-add. (Fset_window_configuration): Rewrite to handle dead buffers and consequently deletable windows. (window_tree, Fwindow_tree): Remove. Supply functionality in window.el. (compare_window_configurations): Simplify code. * window.el (window-tree-1, window-tree): New functions, moving the latter to window.el. (bw-get-tree, bw-get-tree-1, bw-find-tree-sub) (bw-find-tree-sub-1, bw-l, bw-t, bw-r, bw-b, bw-dir, bw-eqdir) (bw-refresh-edges): Remove. (balance-windows-1, balance-windows-2): New functions. (balance-windows): Rewrite in terms of window tree functions, balance-windows-1 and balance-windows-2. (bw-adjust-window): Remove. (balance-windows-area-adjust): New function with functionality of bw-adjust-window but using resize-window. (set-window-text-height): Rewrite doc-string. Use normalize-live-window and resize-window. (enlarge-window-horizontally, shrink-window-horizontally): Rename argument to DELTA. (window-buffer-height): New function. (fit-window-to-buffer, shrink-window-if-larger-than-buffer): Rewrite using new window resize routines. (kill-buffer-and-window, mouse-autoselect-window-select): Use ignore-errors instead of condition-case. (quit-window): Call delete-frame instead of delete-windows-on for the only buffer on frame.
This commit is contained in:
parent
1ab0dee5ca
commit
6198ccd0b2
4 changed files with 525 additions and 614 deletions
|
|
@ -1,3 +1,28 @@
|
|||
2011-06-11 Martin Rudalics <rudalics@gmx.at>
|
||||
|
||||
* window.el (window-tree-1, window-tree): New functions, moving
|
||||
the latter to window.el.
|
||||
(bw-get-tree, bw-get-tree-1, bw-find-tree-sub)
|
||||
(bw-find-tree-sub-1, bw-l, bw-t, bw-r, bw-b, bw-dir, bw-eqdir)
|
||||
(bw-refresh-edges): Remove.
|
||||
(balance-windows-1, balance-windows-2): New functions.
|
||||
(balance-windows): Rewrite in terms of window tree functions,
|
||||
balance-windows-1 and balance-windows-2.
|
||||
(bw-adjust-window): Remove.
|
||||
(balance-windows-area-adjust): New function with functionality of
|
||||
bw-adjust-window but using resize-window.
|
||||
(set-window-text-height): Rewrite doc-string. Use
|
||||
normalize-live-window and resize-window.
|
||||
(enlarge-window-horizontally, shrink-window-horizontally): Rename
|
||||
argument to DELTA.
|
||||
(window-buffer-height): New function.
|
||||
(fit-window-to-buffer, shrink-window-if-larger-than-buffer):
|
||||
Rewrite using new window resize routines.
|
||||
(kill-buffer-and-window, mouse-autoselect-window-select): Use
|
||||
ignore-errors instead of condition-case.
|
||||
(quit-window): Call delete-frame instead of delete-windows-on
|
||||
for the only buffer on frame.
|
||||
|
||||
2011-06-10 Martin Rudalics <rudalics@gmx.at>
|
||||
|
||||
* loadup.el (top-level): Load window before files for the sake
|
||||
|
|
|
|||
738
lisp/window.el
738
lisp/window.el
|
|
@ -2077,6 +2077,47 @@ WINDOW can be any window and defaults to the selected window."
|
|||
(defsubst frame-root-window-p (window)
|
||||
"Return non-nil if WINDOW is the root window of its frame."
|
||||
(eq window (frame-root-window window)))
|
||||
|
||||
(defun window-tree-1 (window &optional next)
|
||||
"Return window tree rooted at WINDOW.
|
||||
Optional argument NEXT non-nil means include windows right
|
||||
siblings in the return value.
|
||||
|
||||
See the documentation of `window-tree' for a description of the
|
||||
return value."
|
||||
(let (list)
|
||||
(while window
|
||||
(setq list
|
||||
(cons
|
||||
(cond
|
||||
((window-vchild window)
|
||||
(cons t (cons (window-edges window)
|
||||
(window-tree-1 (window-vchild window) t))))
|
||||
((window-hchild window)
|
||||
(cons nil (cons (window-edges window)
|
||||
(window-tree-1 (window-hchild window) t))))
|
||||
(t window))
|
||||
list))
|
||||
(setq window (when next (window-next window))))
|
||||
(nreverse list)))
|
||||
|
||||
(defun window-tree (&optional frame)
|
||||
"Return the window tree of frame FRAME.
|
||||
FRAME must be a live frame and defaults to the selected frame.
|
||||
The return value is a list of the form (ROOT MINI), where ROOT
|
||||
represents the window tree of the frame's root window, and MINI
|
||||
is the frame's minibuffer window.
|
||||
|
||||
If the root window is not split, ROOT is the root window itself.
|
||||
Otherwise, ROOT is a list (DIR EDGES W1 W2 ...) where DIR is nil
|
||||
for a horizontal split, and t for a vertical split. EDGES gives
|
||||
the combined size and position of the subwindows in the split,
|
||||
and the rest of the elements are the subwindows in the split.
|
||||
Each of the subwindows may again be a window or a list
|
||||
representing a window split, and so on. EDGES is a list \(LEFT
|
||||
TOP RIGHT BOTTOM) as returned by `window-edges'."
|
||||
(setq frame (normalize-live-frame frame))
|
||||
(window-tree-1 (frame-root-window frame) t))
|
||||
|
||||
(defun other-window (count &optional all-frames)
|
||||
"Select another window in cyclic ordering of windows.
|
||||
|
|
@ -3184,201 +3225,125 @@ The selected window remains selected. Return the new window."
|
|||
|
||||
(defalias 'split-window-horizontally 'split-window-side-by-side)
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;; `balance-windows' subroutines using `window-tree'
|
||||
;;; Balancing windows.
|
||||
|
||||
;;; Translate from internal window tree format
|
||||
;; The following routine uses the recycled code from an old version of
|
||||
;; `resize-subwindows'. It's not very pretty, but coding it the way the
|
||||
;; new `resize-subwindows' code does would hardly make it any shorter or
|
||||
;; more readable (FWIW we'd need three loops - one to calculate the
|
||||
;; minimum sizes per window, one to enlarge or shrink windows until the
|
||||
;; new parent-size matches, and one where we shrink the largest/enlarge
|
||||
;; the smallest window).
|
||||
(defun balance-windows-2 (window horizontal)
|
||||
"Subroutine of `balance-windows-1'.
|
||||
WINDOW must be an iso-combination."
|
||||
(let* ((first (window-child window))
|
||||
(sub first)
|
||||
(number-of-children 0)
|
||||
(parent-size (window-new-total window))
|
||||
(total-sum parent-size)
|
||||
found failed size sub-total sub-delta sub-amount rest)
|
||||
(while sub
|
||||
(setq number-of-children (1+ number-of-children))
|
||||
(when (window-size-fixed-p sub horizontal)
|
||||
(setq total-sum
|
||||
(- total-sum (window-total-size sub horizontal)))
|
||||
(set-window-new-normal sub 'ignore))
|
||||
(setq sub (window-right sub)))
|
||||
|
||||
(defun bw-get-tree (&optional window-or-frame)
|
||||
"Get a window split tree in our format.
|
||||
(setq failed t)
|
||||
(while (and failed (> number-of-children 0))
|
||||
(setq size (/ total-sum number-of-children))
|
||||
(setq failed nil)
|
||||
(setq sub first)
|
||||
(while (and sub (not failed))
|
||||
;; Ignore subwindows that should be ignored or are stuck.
|
||||
(unless (resize-subwindows-skip-p sub)
|
||||
(setq found t)
|
||||
(setq sub-total (window-total-size sub horizontal))
|
||||
(setq sub-delta (- size sub-total))
|
||||
(setq sub-amount
|
||||
(window-sizable sub sub-delta horizontal))
|
||||
;; Register the new total size for this subwindow.
|
||||
(set-window-new-total sub (+ sub-total sub-amount))
|
||||
(unless (= sub-amount sub-delta)
|
||||
(setq total-sum (- total-sum sub-total sub-amount))
|
||||
(setq number-of-children (1- number-of-children))
|
||||
;; We failed and need a new round.
|
||||
(setq failed t)
|
||||
(set-window-new-normal sub 'skip)))
|
||||
(setq sub (window-right sub))))
|
||||
|
||||
WINDOW-OR-FRAME must be nil, a frame, or a window. If it is nil,
|
||||
then the whole window split tree for `selected-frame' is returned.
|
||||
If it is a frame, then this is used instead. If it is a window,
|
||||
then the smallest tree containing that window is returned."
|
||||
(when window-or-frame
|
||||
(unless (or (framep window-or-frame)
|
||||
(windowp window-or-frame))
|
||||
(error "Not a frame or window: %s" window-or-frame)))
|
||||
(let ((subtree (bw-find-tree-sub window-or-frame)))
|
||||
(when subtree
|
||||
(if (integerp subtree)
|
||||
nil
|
||||
(bw-get-tree-1 subtree)))))
|
||||
(setq rest (% total-sum number-of-children))
|
||||
;; Fix rounding by trying to enlarge non-stuck windows by one line
|
||||
;; (column) until `rest' is zero.
|
||||
(setq sub first)
|
||||
(while (and sub (> rest 0))
|
||||
(unless (resize-subwindows-skip-p window)
|
||||
(set-window-new-total sub 1 t)
|
||||
(setq rest (1- rest)))
|
||||
(setq sub (window-right sub)))
|
||||
|
||||
(defun bw-get-tree-1 (split)
|
||||
(if (windowp split)
|
||||
split
|
||||
(let ((dir (car split))
|
||||
(edges (car (cdr split)))
|
||||
(childs (cdr (cdr split))))
|
||||
(list
|
||||
(cons 'dir (if dir 'ver 'hor))
|
||||
(cons 'b (nth 3 edges))
|
||||
(cons 'r (nth 2 edges))
|
||||
(cons 't (nth 1 edges))
|
||||
(cons 'l (nth 0 edges))
|
||||
(cons 'childs (mapcar #'bw-get-tree-1 childs))))))
|
||||
;; Fix rounding by trying to enlarge stuck windows by one line
|
||||
;; (column) until `rest' equals zero.
|
||||
(setq sub first)
|
||||
(while (and sub (> rest 0))
|
||||
(unless (eq (window-new-normal sub) 'ignore)
|
||||
(set-window-new-total sub 1 t)
|
||||
(setq rest (1- rest)))
|
||||
(setq sub (window-right sub)))
|
||||
|
||||
(defun bw-find-tree-sub (window-or-frame &optional get-parent)
|
||||
(let* ((window (when (windowp window-or-frame) window-or-frame))
|
||||
(frame (when (windowp window) (window-frame window)))
|
||||
(wt (car (window-tree frame))))
|
||||
(when (< 1 (length (window-list frame 0)))
|
||||
(if window
|
||||
(bw-find-tree-sub-1 wt window get-parent)
|
||||
wt))))
|
||||
(setq sub first)
|
||||
(while sub
|
||||
;; Record new normal sizes.
|
||||
(set-window-new-normal
|
||||
sub (/ (if (eq (window-new-normal sub) 'ignore)
|
||||
(window-total-size sub horizontal)
|
||||
(window-new-total sub))
|
||||
(float parent-size)))
|
||||
;; Recursively balance each subwindow's subwindows.
|
||||
(balance-windows-1 sub horizontal)
|
||||
(setq sub (window-right sub)))))
|
||||
|
||||
(defun bw-find-tree-sub-1 (tree win &optional get-parent)
|
||||
(unless (windowp win) (error "Not a window: %s" win))
|
||||
(if (memq win tree)
|
||||
(if get-parent
|
||||
get-parent
|
||||
tree)
|
||||
(let ((childs (cdr (cdr tree)))
|
||||
child
|
||||
subtree)
|
||||
(while (and childs (not subtree))
|
||||
(setq child (car childs))
|
||||
(setq childs (cdr childs))
|
||||
(when (and child (listp child))
|
||||
(setq subtree (bw-find-tree-sub-1 child win get-parent))))
|
||||
(if (integerp subtree)
|
||||
(progn
|
||||
(if (= 1 subtree)
|
||||
tree
|
||||
(1- subtree)))
|
||||
subtree
|
||||
))))
|
||||
|
||||
;;; Window or object edges
|
||||
|
||||
(defun bw-l (obj)
|
||||
"Left edge of OBJ."
|
||||
(if (windowp obj) (nth 0 (window-edges obj)) (cdr (assq 'l obj))))
|
||||
(defun bw-t (obj)
|
||||
"Top edge of OBJ."
|
||||
(if (windowp obj) (nth 1 (window-edges obj)) (cdr (assq 't obj))))
|
||||
(defun bw-r (obj)
|
||||
"Right edge of OBJ."
|
||||
(if (windowp obj) (nth 2 (window-edges obj)) (cdr (assq 'r obj))))
|
||||
(defun bw-b (obj)
|
||||
"Bottom edge of OBJ."
|
||||
(if (windowp obj) (nth 3 (window-edges obj)) (cdr (assq 'b obj))))
|
||||
|
||||
;;; Split directions
|
||||
|
||||
(defun bw-dir (obj)
|
||||
"Return window split tree direction if OBJ.
|
||||
If OBJ is a window return 'both. If it is a window split tree
|
||||
then return its direction."
|
||||
(if (symbolp obj)
|
||||
obj
|
||||
(if (windowp obj)
|
||||
'both
|
||||
(let ((dir (cdr (assq 'dir obj))))
|
||||
(unless (memq dir '(hor ver both))
|
||||
(error "Can't find dir in %s" obj))
|
||||
dir))))
|
||||
|
||||
(defun bw-eqdir (obj1 obj2)
|
||||
"Return t if window split tree directions are equal.
|
||||
OBJ1 and OBJ2 should be either windows or window split trees in
|
||||
our format. The directions returned by `bw-dir' are compared and
|
||||
t is returned if they are `eq' or one of them is 'both."
|
||||
(let ((dir1 (bw-dir obj1))
|
||||
(dir2 (bw-dir obj2)))
|
||||
(or (eq dir1 dir2)
|
||||
(eq dir1 'both)
|
||||
(eq dir2 'both))))
|
||||
|
||||
;;; Building split tree
|
||||
|
||||
(defun bw-refresh-edges (obj)
|
||||
"Refresh the edge information of OBJ and return OBJ."
|
||||
(unless (windowp obj)
|
||||
(let ((childs (cdr (assq 'childs obj)))
|
||||
(ol 1000)
|
||||
(ot 1000)
|
||||
(or -1)
|
||||
(ob -1))
|
||||
(dolist (o childs)
|
||||
(when (> ol (bw-l o)) (setq ol (bw-l o)))
|
||||
(when (> ot (bw-t o)) (setq ot (bw-t o)))
|
||||
(when (< or (bw-r o)) (setq or (bw-r o)))
|
||||
(when (< ob (bw-b o)) (setq ob (bw-b o))))
|
||||
(setq obj (delq 'l obj))
|
||||
(setq obj (delq 't obj))
|
||||
(setq obj (delq 'r obj))
|
||||
(setq obj (delq 'b obj))
|
||||
(add-to-list 'obj (cons 'l ol))
|
||||
(add-to-list 'obj (cons 't ot))
|
||||
(add-to-list 'obj (cons 'r or))
|
||||
(add-to-list 'obj (cons 'b ob))
|
||||
))
|
||||
obj)
|
||||
|
||||
;;; Balance windows
|
||||
(defun balance-windows-1 (window &optional horizontal)
|
||||
"Subroutine of `balance-windows'."
|
||||
(if (window-child window)
|
||||
(let ((sub (window-child window)))
|
||||
(if (window-iso-combined-p sub horizontal)
|
||||
(balance-windows-2 window horizontal)
|
||||
(let ((size (window-new-total window)))
|
||||
(while sub
|
||||
(set-window-new-total sub size)
|
||||
(balance-windows-1 sub horizontal)
|
||||
(setq sub (window-right sub))))))))
|
||||
|
||||
(defun balance-windows (&optional window-or-frame)
|
||||
"Make windows the same heights or widths in window split subtrees.
|
||||
|
||||
When called non-interactively WINDOW-OR-FRAME may be either a
|
||||
window or a frame. It then balances the windows on the implied
|
||||
frame. If the parameter is a window only the corresponding window
|
||||
subtree is balanced."
|
||||
"Balance the sizes of subwindows of WINDOW-OR-FRAME.
|
||||
WINDOW-OR-FRAME is optional and defaults to the selected frame.
|
||||
If WINDOW-OR-FRAME denotes a frame, balance the sizes of all
|
||||
subwindows of that frame's root window. If WINDOW-OR-FRAME
|
||||
denots a window, balance the sizes of all subwindows of that
|
||||
window."
|
||||
(interactive)
|
||||
(let (
|
||||
(wt (bw-get-tree window-or-frame))
|
||||
(w)
|
||||
(h)
|
||||
(tried-sizes)
|
||||
(last-sizes)
|
||||
(windows (window-list nil 0)))
|
||||
(when wt
|
||||
(while (not (member last-sizes tried-sizes))
|
||||
(when last-sizes (setq tried-sizes (cons last-sizes tried-sizes)))
|
||||
(setq last-sizes (mapcar (lambda (w)
|
||||
(window-edges w))
|
||||
windows))
|
||||
(when (eq 'hor (bw-dir wt))
|
||||
(setq w (- (bw-r wt) (bw-l wt))))
|
||||
(when (eq 'ver (bw-dir wt))
|
||||
(setq h (- (bw-b wt) (bw-t wt))))
|
||||
(bw-balance-sub wt w h)))))
|
||||
|
||||
(defun bw-adjust-window (window delta horizontal)
|
||||
"Wrapper around `adjust-window-trailing-edge' with error checking.
|
||||
Arguments WINDOW, DELTA and HORIZONTAL are passed on to that function."
|
||||
;; `adjust-window-trailing-edge' may fail if delta is too large.
|
||||
(while (>= (abs delta) 1)
|
||||
(condition-case nil
|
||||
(progn
|
||||
(adjust-window-trailing-edge window delta horizontal)
|
||||
(setq delta 0))
|
||||
(error
|
||||
;;(message "adjust: %s" (error-message-string err))
|
||||
(setq delta (/ delta 2))))))
|
||||
|
||||
(defun bw-balance-sub (wt w h)
|
||||
(setq wt (bw-refresh-edges wt))
|
||||
(unless w (setq w (- (bw-r wt) (bw-l wt))))
|
||||
(unless h (setq h (- (bw-b wt) (bw-t wt))))
|
||||
(if (windowp wt)
|
||||
(progn
|
||||
(when w
|
||||
(let ((dw (- w (- (bw-r wt) (bw-l wt)))))
|
||||
(when (/= 0 dw)
|
||||
(bw-adjust-window wt dw t))))
|
||||
(when h
|
||||
(let ((dh (- h (- (bw-b wt) (bw-t wt)))))
|
||||
(when (/= 0 dh)
|
||||
(bw-adjust-window wt dh nil)))))
|
||||
(let* ((childs (cdr (assq 'childs wt)))
|
||||
(cw (when w (/ w (if (bw-eqdir 'hor wt) (length childs) 1))))
|
||||
(ch (when h (/ h (if (bw-eqdir 'ver wt) (length childs) 1)))))
|
||||
(dolist (c childs)
|
||||
(bw-balance-sub c cw ch)))))
|
||||
(let* ((window
|
||||
(cond
|
||||
((or (not window-or-frame)
|
||||
(frame-live-p window-or-frame))
|
||||
(frame-root-window window-or-frame))
|
||||
((or (window-live-p window-or-frame)
|
||||
(window-child window-or-frame))
|
||||
window-or-frame)
|
||||
(t
|
||||
(error "Not a window or frame %s" window-or-frame))))
|
||||
(frame (window-frame window)))
|
||||
;; Balance vertically.
|
||||
(resize-window-reset (window-frame window))
|
||||
(balance-windows-1 window)
|
||||
(resize-window-apply frame)
|
||||
;; Balance horizontally.
|
||||
(resize-window-reset (window-frame window) t)
|
||||
(balance-windows-1 window t)
|
||||
(resize-window-apply frame t)))
|
||||
|
||||
(defun window-fixed-size-p (&optional window direction)
|
||||
"Return t if WINDOW cannot be resized in DIRECTION.
|
||||
|
|
@ -3391,13 +3356,25 @@ nil (i.e. any), `height' or `width'."
|
|||
'((height . width) (width . height))))))))
|
||||
|
||||
;;; A different solution to balance-windows.
|
||||
|
||||
(defvar window-area-factor 1
|
||||
"Factor by which the window area should be over-estimated.
|
||||
This is used by `balance-windows-area'.
|
||||
Changing this globally has no effect.")
|
||||
(make-variable-buffer-local 'window-area-factor)
|
||||
|
||||
(defun balance-windows-area-adjust (window delta horizontal)
|
||||
"Wrapper around `resize-window' with error checking.
|
||||
Arguments WINDOW, DELTA and HORIZONTAL are passed on to that function."
|
||||
;; `resize-window' may fail if delta is too large.
|
||||
(while (>= (abs delta) 1)
|
||||
(condition-case nil
|
||||
(progn
|
||||
(resize-window window delta horizontal)
|
||||
(setq delta 0))
|
||||
(error
|
||||
;;(message "adjust: %s" (error-message-string err))
|
||||
(setq delta (/ delta 2))))))
|
||||
|
||||
(defun balance-windows-area ()
|
||||
"Make all visible windows the same area (approximately).
|
||||
See also `window-area-factor' to change the relative size of
|
||||
|
|
@ -3459,7 +3436,9 @@ specific buffers."
|
|||
;; Make sure negligible differences don't accumulate to
|
||||
;; become significant.
|
||||
(setq carry (+ carry areadiff))
|
||||
(bw-adjust-window win diff horiz)
|
||||
;; This used `adjust-window-trailing-edge' before and uses
|
||||
;; `resize-window' now. Error wrapping is still needed.
|
||||
(balance-windows-area-adjust win diff horiz)
|
||||
;; (sit-for 0.5)
|
||||
(let ((change (cons win (window-edges win))))
|
||||
;; If the same change has been seen already for this window,
|
||||
|
|
@ -4314,13 +4293,15 @@ documentation for additional customization information."
|
|||
|
||||
(defun set-window-text-height (window height)
|
||||
"Set the height in lines of the text display area of WINDOW to HEIGHT.
|
||||
HEIGHT doesn't include the mode line or header line, if any, or
|
||||
any partial-height lines in the text display area.
|
||||
WINDOW must be a live window. HEIGHT 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 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."
|
||||
(setq window (normalize-live-window window))
|
||||
(let ((delta (- height (window-text-height window))))
|
||||
(unless (zerop delta)
|
||||
;; Setting window-min-height to a value like 1 can lead to very
|
||||
|
|
@ -4328,36 +4309,21 @@ where some error may be present."
|
|||
;; windows 1-line tall, which means that there's no more space for
|
||||
;; the modeline.
|
||||
(let ((window-min-height (min 2 height))) ; One text line plus a modeline.
|
||||
(if (and window (not (eq window (selected-window))))
|
||||
(save-selected-window
|
||||
(select-window window 'norecord)
|
||||
(enlarge-window delta))
|
||||
(enlarge-window delta))))))
|
||||
(resize-window window delta)))))
|
||||
|
||||
|
||||
(defun enlarge-window-horizontally (columns)
|
||||
"Make selected window COLUMNS wider.
|
||||
(defun enlarge-window-horizontally (delta)
|
||||
"Make selected window DELTA columns wider.
|
||||
Interactively, if no argument is given, make selected window one
|
||||
column wider."
|
||||
(interactive "p")
|
||||
(enlarge-window columns t))
|
||||
(enlarge-window delta t))
|
||||
|
||||
(defun shrink-window-horizontally (columns)
|
||||
"Make selected window COLUMNS narrower.
|
||||
(defun shrink-window-horizontally (delta)
|
||||
"Make selected window DELTA columns narrower.
|
||||
Interactively, if no argument is given, make selected window one
|
||||
column narrower."
|
||||
(interactive "p")
|
||||
(shrink-window columns t))
|
||||
|
||||
(defun window-buffer-height (window)
|
||||
"Return the height (in screen lines) of the buffer that WINDOW is displaying."
|
||||
(with-current-buffer (window-buffer window)
|
||||
(max 1
|
||||
(count-screen-lines (point-min) (point-max)
|
||||
;; If buffer ends with a newline, ignore it when
|
||||
;; counting height unless point is after it.
|
||||
(eobp)
|
||||
window))))
|
||||
(shrink-window delta t))
|
||||
|
||||
(defun count-screen-lines (&optional beg end count-final-newline window)
|
||||
"Return the number of screen lines in the region.
|
||||
|
|
@ -4395,80 +4361,99 @@ in some window."
|
|||
(goto-char (point-min))
|
||||
(1+ (vertical-motion (buffer-size) window))))))
|
||||
|
||||
(defun fit-window-to-buffer (&optional window max-height min-height)
|
||||
(defun window-buffer-height (window)
|
||||
"Return the height (in screen lines) of the buffer that WINDOW is displaying."
|
||||
(with-current-buffer (window-buffer window)
|
||||
(max 1
|
||||
(count-screen-lines (point-min) (point-max)
|
||||
;; If buffer ends with a newline, ignore it when
|
||||
;; counting height unless point is after it.
|
||||
(eobp)
|
||||
window))))
|
||||
|
||||
;;; Resizing buffers to fit their contents exactly.
|
||||
(defun fit-window-to-buffer (&optional window max-height min-height override)
|
||||
"Adjust height of WINDOW to display its buffer's contents exactly.
|
||||
WINDOW defaults to the selected window.
|
||||
Optional argument MAX-HEIGHT specifies the maximum height of the
|
||||
window and defaults to the maximum permissible height of a window
|
||||
on WINDOW's frame.
|
||||
Optional argument MIN-HEIGHT specifies the minimum height of the
|
||||
window and defaults to `window-min-height'.
|
||||
Both, MAX-HEIGHT and MIN-HEIGHT are specified in lines and
|
||||
include the mode line and header line, if any.
|
||||
WINDOW can be any live window and defaults to the selected one.
|
||||
|
||||
Return non-nil if height was orderly adjusted, nil otherwise.
|
||||
Optional argument MAX-HEIGHT specifies the maximum height of
|
||||
WINDOW and defaults to the height of WINDOW's frame. Optional
|
||||
argument MIN-HEIGHT specifies the minimum height of WINDOW and
|
||||
defaults to `window-min-height'. Both, MAX-HEIGHT and MIN-HEIGHT
|
||||
are specified in lines and include the mode line and header line,
|
||||
if any.
|
||||
|
||||
Caution: This function can delete WINDOW and/or other windows
|
||||
when their height shrinks to less than MIN-HEIGHT."
|
||||
Optional argument OVERRIDE non-nil means override restrictions
|
||||
imposed by `window-min-height' and `window-min-width' on the size
|
||||
of WINDOW.
|
||||
|
||||
Return the number of lines by which WINDOW was enlarged or
|
||||
shrunk. If an error occurs during resizing, return nil but don't
|
||||
signal an error.
|
||||
|
||||
Note that even if this function makes WINDOW large enough to show
|
||||
_all_ lines of its buffer you might not see the first lines when
|
||||
WINDOW was scrolled."
|
||||
(interactive)
|
||||
;; Do all the work in WINDOW and its buffer and restore the selected
|
||||
;; window and the current buffer when we're done.
|
||||
(let ((old-buffer (current-buffer))
|
||||
value)
|
||||
(with-selected-window (or window (setq window (selected-window)))
|
||||
(set-buffer (window-buffer))
|
||||
;; Use `condition-case' to handle any fixed-size windows and other
|
||||
;; pitfalls nearby.
|
||||
(condition-case nil
|
||||
(let* (;; MIN-HEIGHT must not be less than 1 and defaults to
|
||||
;; `window-min-height'.
|
||||
(min-height (max (or min-height window-min-height) 1))
|
||||
(max-window-height
|
||||
;; Maximum height of any window on this frame.
|
||||
(min (window-height (frame-root-window)) (frame-height)))
|
||||
;; MAX-HEIGHT must not be larger than max-window-height and
|
||||
;; defaults to max-window-height.
|
||||
(max-height
|
||||
(min (or max-height max-window-height) max-window-height))
|
||||
(desired-height
|
||||
;; The height necessary to show all of WINDOW's buffer,
|
||||
;; constrained by MIN-HEIGHT and MAX-HEIGHT.
|
||||
(max
|
||||
(min
|
||||
;; For an empty buffer `count-screen-lines' returns zero.
|
||||
;; Even in that case we need one line for the cursor.
|
||||
(+ (max (count-screen-lines) 1)
|
||||
;; For non-minibuffers count the mode line, if any.
|
||||
(if (and (not (window-minibuffer-p)) mode-line-format)
|
||||
1 0)
|
||||
;; Count the header line, if any.
|
||||
(if header-line-format 1 0))
|
||||
max-height)
|
||||
min-height))
|
||||
(delta
|
||||
;; How much the window height has to change.
|
||||
(if (= (window-height) (window-height (frame-root-window)))
|
||||
;; Don't try to resize a full-height window.
|
||||
0
|
||||
(- desired-height (window-height))))
|
||||
;; Do something reasonable so `enlarge-window' can make
|
||||
;; windows as small as MIN-HEIGHT.
|
||||
(window-min-height (min min-height window-min-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)))
|
||||
(set-window-point window (1- (window-point))))
|
||||
;; Adjust WINDOW's height to the nominally correct one
|
||||
;; (which may actually be slightly off because of variable
|
||||
;; height text, etc).
|
||||
(unless (zerop delta)
|
||||
(enlarge-window delta))
|
||||
;; `enlarge-window' might have deleted WINDOW, so make sure
|
||||
;; WINDOW's still alive for the remainder of this.
|
||||
;; Note: Deleting WINDOW is clearly counter-intuitive in
|
||||
;; this context, but we can't do much about it given the
|
||||
;; current semantics of `enlarge-window'.
|
||||
(when (window-live-p window)
|
||||
(setq window (normalize-live-window window))
|
||||
;; Can't resize a full height or fixed-size window.
|
||||
(unless (or (window-size-fixed-p window)
|
||||
(window-full-height-p window))
|
||||
;; `with-selected-window' should orderly restore the current buffer.
|
||||
(with-selected-window window
|
||||
;; We are in WINDOW's buffer now.
|
||||
(let* ( ;; Adjust MIN-HEIGHT.
|
||||
(min-height
|
||||
(if override
|
||||
(window-min-size window nil window)
|
||||
(max (or min-height window-min-height)
|
||||
window-safe-min-height)))
|
||||
(max-window-height
|
||||
(window-total-size (frame-root-window window)))
|
||||
;; Adjust MAX-HEIGHT.
|
||||
(max-height
|
||||
(if (or override (not max-height))
|
||||
max-window-height
|
||||
(min max-height max-window-height)))
|
||||
;; Make `desired-height' the height necessary to show
|
||||
;; all of WINDOW's buffer, constrained by MIN-HEIGHT
|
||||
;; and MAX-HEIGHT.
|
||||
(desired-height
|
||||
(max
|
||||
(min
|
||||
(+ (count-screen-lines)
|
||||
;; For non-minibuffers count the mode line, if any.
|
||||
(if (and (not (window-minibuffer-p window))
|
||||
mode-line-format)
|
||||
1
|
||||
0)
|
||||
;; Count the header line, if any.
|
||||
(if header-line-format 1 0))
|
||||
max-height)
|
||||
min-height))
|
||||
(desired-delta
|
||||
(- desired-height (window-total-size window)))
|
||||
(delta
|
||||
(if (> desired-delta 0)
|
||||
(min desired-delta
|
||||
(window-max-delta window nil window))
|
||||
(max desired-delta
|
||||
(- (window-min-delta window nil window))))))
|
||||
;; This `condition-case' shouldn't be necessary, but who knows?
|
||||
(condition-case nil
|
||||
(if (zerop delta)
|
||||
;; Return zero if DELTA became zero in the proces.
|
||||
0
|
||||
;; 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)))
|
||||
;; It's silly to put `point' at the end of the previous
|
||||
;; line and so maybe force horizontal scrolling.
|
||||
(set-window-point window (line-beginning-position 0)))
|
||||
;; Call `resize-window' with OVERRIDE argument equal WINDOW.
|
||||
(resize-window window delta nil window)
|
||||
;; Check if the last line is surely fully visible. If
|
||||
;; not, enlarge the window.
|
||||
(let ((end (save-excursion
|
||||
|
|
@ -4486,25 +4471,15 @@ when their height shrinks to less than MIN-HEIGHT."
|
|||
(forward-line 0))
|
||||
(point))))
|
||||
(set-window-vscroll window 0)
|
||||
;; This loop might in some rare pathological cases raise
|
||||
;; an error - another reason for the `condition-case'.
|
||||
(while (and (< desired-height max-height)
|
||||
(= desired-height (window-height))
|
||||
(= desired-height (window-total-size))
|
||||
(not (pos-visible-in-window-p end)))
|
||||
(enlarge-window 1)
|
||||
(setq desired-height (1+ desired-height))))
|
||||
;; Return non-nil only if nothing "bad" happened.
|
||||
(setq value t)))
|
||||
(error nil)))
|
||||
(when (buffer-live-p old-buffer)
|
||||
(set-buffer old-buffer))
|
||||
value))
|
||||
|
||||
(defun window-safely-shrinkable-p (&optional window)
|
||||
"Return t if WINDOW can be shrunk without shrinking other windows.
|
||||
WINDOW defaults to the selected window."
|
||||
(with-selected-window (or window (selected-window))
|
||||
(let ((edges (window-edges)))
|
||||
(or (= (nth 2 edges) (nth 2 (window-edges (previous-window))))
|
||||
(= (nth 0 edges) (nth 0 (window-edges (next-window))))))))
|
||||
(resize-window window 1 nil window)
|
||||
(setq desired-height (1+ desired-height)))))
|
||||
(error (setq delta nil)))
|
||||
delta))))
|
||||
|
||||
(defun shrink-window-if-larger-than-buffer (&optional window)
|
||||
"Shrink height of WINDOW if its buffer doesn't need so many lines.
|
||||
|
|
@ -4512,42 +4487,28 @@ More precisely, shrink WINDOW vertically to be as small as
|
|||
possible, while still showing the full contents of its buffer.
|
||||
WINDOW defaults to the selected window.
|
||||
|
||||
Do not shrink to less than `window-min-height' lines. Do nothing
|
||||
if the buffer contains more lines than the present window height,
|
||||
or if some of the window's contents are scrolled out of view, or
|
||||
if shrinking this window would also shrink another window, or if
|
||||
the window is the only window of its frame.
|
||||
Do not shrink WINDOW to less than `window-min-height' lines. Do
|
||||
nothing if the buffer contains more lines than the present window
|
||||
height, or if some of the window's contents are scrolled out of
|
||||
view, or if shrinking this window would also shrink another
|
||||
window, or if the window is the only window of its frame.
|
||||
|
||||
Return non-nil if the window was shrunk, nil otherwise."
|
||||
(interactive)
|
||||
(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-safely-shrinkable-p window)
|
||||
(pos-visible-in-window-p (point-min) window)
|
||||
(not (eq mini 'only))
|
||||
(or (not mini)
|
||||
(let ((mini-window (minibuffer-window frame)))
|
||||
(or (null mini-window)
|
||||
(not (eq frame (window-frame mini-window)))
|
||||
(< (nth 3 edges)
|
||||
(nth 1 (window-edges mini-window)))
|
||||
(> (nth 1 edges)
|
||||
(frame-parameter frame 'menu-bar-lines))))))
|
||||
(fit-window-to-buffer window (window-height window)))))
|
||||
|
||||
(setq window (normalize-live-window window))
|
||||
;; Make sure that WINDOW is vertically combined and `point-min' is
|
||||
;; visible (for whatever reason that's needed). The remaining issues
|
||||
;; should be taken care of by `fit-window-to-buffer'.
|
||||
(when (and (window-iso-combined-p window)
|
||||
(pos-visible-in-window-p (point-min) window))
|
||||
(fit-window-to-buffer window (window-total-size window))))
|
||||
|
||||
(defun kill-buffer-and-window ()
|
||||
"Kill the current buffer and delete the selected window."
|
||||
(interactive)
|
||||
(let ((window-to-delete (selected-window))
|
||||
(buffer-to-kill (current-buffer))
|
||||
(delete-window-hook (lambda ()
|
||||
(condition-case nil
|
||||
(delete-window)
|
||||
(error nil)))))
|
||||
(delete-window-hook (lambda () (ignore-errors (delete-window)))))
|
||||
(unwind-protect
|
||||
(progn
|
||||
(add-hook 'kill-buffer-hook delete-window-hook t t)
|
||||
|
|
@ -4558,10 +4519,9 @@ Return non-nil if the window was shrunk, nil otherwise."
|
|||
(delete-window))))
|
||||
;; If the buffer is not dead for some reason (probably because
|
||||
;; of a `quit' signal), remove the hook again.
|
||||
(condition-case nil
|
||||
(with-current-buffer buffer-to-kill
|
||||
(remove-hook 'kill-buffer-hook delete-window-hook t))
|
||||
(error nil)))))
|
||||
(ignore-errors
|
||||
(with-current-buffer buffer-to-kill
|
||||
(remove-hook 'kill-buffer-hook delete-window-hook t))))))
|
||||
|
||||
(defun quit-window (&optional kill window)
|
||||
"Quit WINDOW and bury its buffer.
|
||||
|
|
@ -4584,10 +4544,9 @@ Otherwise, bury WINDOW's buffer, see `bury-buffer'."
|
|||
;; try to delete it.
|
||||
(let* ((window (or window (selected-window)))
|
||||
(frame (window-frame window)))
|
||||
(if (eq window (frame-root-window frame))
|
||||
;; WINDOW is alone on its frame. `delete-windows-on'
|
||||
;; knows how to handle that case.
|
||||
(delete-windows-on buffer frame)
|
||||
(if (frame-root-window-p window)
|
||||
;; WINDOW is alone on its frame.
|
||||
(delete-frame frame)
|
||||
;; There are other windows on its frame, delete WINDOW.
|
||||
(delete-window window)))
|
||||
;; Otherwise, switch to another buffer in the selected window.
|
||||
|
|
@ -4597,7 +4556,6 @@ Otherwise, bury WINDOW's buffer, see `bury-buffer'."
|
|||
(if kill
|
||||
(kill-buffer buffer)
|
||||
(bury-buffer buffer))))
|
||||
|
||||
|
||||
(defvar recenter-last-op nil
|
||||
"Indicates the last recenter operation performed.
|
||||
|
|
@ -4689,7 +4647,6 @@ by `recenter-positions'."
|
|||
(move-to-window-line (round (* recenter-last-op (window-height))))))))))
|
||||
|
||||
(define-key global-map [?\M-r] 'move-to-window-line-top-bottom)
|
||||
|
||||
|
||||
;;; Scrolling commands.
|
||||
|
||||
|
|
@ -4837,7 +4794,6 @@ With arg N, put point N/10 of the way from the true end."
|
|||
(end-of-buffer arg))
|
||||
(recenter '(t)))
|
||||
(select-window orig-window))))
|
||||
|
||||
|
||||
(defvar mouse-autoselect-window-timer nil
|
||||
"Timer used by delayed window autoselection.")
|
||||
|
|
@ -4891,62 +4847,60 @@ means suspend autoselection."
|
|||
If the mouse position has stabilized in a non-selected window, select
|
||||
that window. The minibuffer window is selected only if the minibuffer is
|
||||
active. This function is run by `mouse-autoselect-window-timer'."
|
||||
(condition-case nil
|
||||
(let* ((mouse-position (mouse-position))
|
||||
(window
|
||||
(condition-case nil
|
||||
(window-at (cadr mouse-position) (cddr mouse-position)
|
||||
(car mouse-position))
|
||||
(error nil))))
|
||||
(cond
|
||||
((or (menu-or-popup-active-p)
|
||||
(and window
|
||||
(not (coordinates-in-window-p (cdr mouse-position) window))))
|
||||
;; A menu / popup dialog is active or the mouse is on the scroll-bar
|
||||
;; of WINDOW, temporarily suspend delayed autoselection.
|
||||
(mouse-autoselect-window-start mouse-position nil t))
|
||||
((eq mouse-autoselect-window-state 'suspend)
|
||||
;; Delayed autoselection was temporarily suspended, reenable it.
|
||||
(mouse-autoselect-window-start mouse-position))
|
||||
((and window (not (eq window (selected-window)))
|
||||
(or (not (numberp mouse-autoselect-window))
|
||||
(and (> mouse-autoselect-window 0)
|
||||
;; If `mouse-autoselect-window' is positive, select
|
||||
;; window if the window is the same as before.
|
||||
(eq window mouse-autoselect-window-window))
|
||||
;; Otherwise select window if the mouse is at the same
|
||||
;; position as before. Observe that the first test after
|
||||
;; starting autoselection usually fails since the value of
|
||||
;; `mouse-autoselect-window-position' recorded there is the
|
||||
;; position where the mouse has entered the new window and
|
||||
;; not necessarily where the mouse has stopped moving.
|
||||
(equal mouse-position mouse-autoselect-window-position))
|
||||
;; The minibuffer is a candidate window if it's active.
|
||||
(or (not (window-minibuffer-p window))
|
||||
(eq window (active-minibuffer-window))))
|
||||
;; Mouse position has stabilized in non-selected window: Cancel
|
||||
;; delayed autoselection and try to select that window.
|
||||
(mouse-autoselect-window-cancel t)
|
||||
;; Select window where mouse appears unless the selected window is the
|
||||
;; minibuffer. Use `unread-command-events' in order to execute pre-
|
||||
;; and post-command hooks and trigger idle timers. To avoid delaying
|
||||
;; autoselection again, set `mouse-autoselect-window-state'."
|
||||
(unless (window-minibuffer-p (selected-window))
|
||||
(setq mouse-autoselect-window-state 'select)
|
||||
(setq unread-command-events
|
||||
(cons (list 'select-window (list window))
|
||||
unread-command-events))))
|
||||
((or (and window (eq window (selected-window)))
|
||||
(not (numberp mouse-autoselect-window))
|
||||
(equal mouse-position mouse-autoselect-window-position))
|
||||
;; Mouse position has either stabilized in the selected window or at
|
||||
;; `mouse-autoselect-window-position': Cancel delayed autoselection.
|
||||
(mouse-autoselect-window-cancel t))
|
||||
(t
|
||||
;; Mouse position has not stabilized yet, resume delayed
|
||||
;; autoselection.
|
||||
(mouse-autoselect-window-start mouse-position window))))
|
||||
(error nil)))
|
||||
(ignore-errors
|
||||
(let* ((mouse-position (mouse-position))
|
||||
(window
|
||||
(ignore-errors
|
||||
(window-at (cadr mouse-position) (cddr mouse-position)
|
||||
(car mouse-position)))))
|
||||
(cond
|
||||
((or (menu-or-popup-active-p)
|
||||
(and window
|
||||
(not (coordinates-in-window-p (cdr mouse-position) window))))
|
||||
;; A menu / popup dialog is active or the mouse is on the scroll-bar
|
||||
;; of WINDOW, temporarily suspend delayed autoselection.
|
||||
(mouse-autoselect-window-start mouse-position nil t))
|
||||
((eq mouse-autoselect-window-state 'suspend)
|
||||
;; Delayed autoselection was temporarily suspended, reenable it.
|
||||
(mouse-autoselect-window-start mouse-position))
|
||||
((and window (not (eq window (selected-window)))
|
||||
(or (not (numberp mouse-autoselect-window))
|
||||
(and (> mouse-autoselect-window 0)
|
||||
;; If `mouse-autoselect-window' is positive, select
|
||||
;; window if the window is the same as before.
|
||||
(eq window mouse-autoselect-window-window))
|
||||
;; Otherwise select window if the mouse is at the same
|
||||
;; position as before. Observe that the first test after
|
||||
;; starting autoselection usually fails since the value of
|
||||
;; `mouse-autoselect-window-position' recorded there is the
|
||||
;; position where the mouse has entered the new window and
|
||||
;; not necessarily where the mouse has stopped moving.
|
||||
(equal mouse-position mouse-autoselect-window-position))
|
||||
;; The minibuffer is a candidate window if it's active.
|
||||
(or (not (window-minibuffer-p window))
|
||||
(eq window (active-minibuffer-window))))
|
||||
;; Mouse position has stabilized in non-selected window: Cancel
|
||||
;; delayed autoselection and try to select that window.
|
||||
(mouse-autoselect-window-cancel t)
|
||||
;; Select window where mouse appears unless the selected window is the
|
||||
;; minibuffer. Use `unread-command-events' in order to execute pre-
|
||||
;; and post-command hooks and trigger idle timers. To avoid delaying
|
||||
;; autoselection again, set `mouse-autoselect-window-state'."
|
||||
(unless (window-minibuffer-p (selected-window))
|
||||
(setq mouse-autoselect-window-state 'select)
|
||||
(setq unread-command-events
|
||||
(cons (list 'select-window (list window))
|
||||
unread-command-events))))
|
||||
((or (and window (eq window (selected-window)))
|
||||
(not (numberp mouse-autoselect-window))
|
||||
(equal mouse-position mouse-autoselect-window-position))
|
||||
;; Mouse position has either stabilized in the selected window or at
|
||||
;; `mouse-autoselect-window-position': Cancel delayed autoselection.
|
||||
(mouse-autoselect-window-cancel t))
|
||||
(t
|
||||
;; Mouse position has not stabilized yet, resume delayed
|
||||
;; autoselection.
|
||||
(mouse-autoselect-window-start mouse-position window))))))
|
||||
|
||||
(defun handle-select-window (event)
|
||||
"Handle select-window events."
|
||||
|
|
|
|||
|
|
@ -1,3 +1,12 @@
|
|||
2011-06-11 Martin Rudalics <rudalics@gmx.at>
|
||||
|
||||
* window.c (delete_deletable_window): Re-add.
|
||||
(Fset_window_configuration): Rewrite to handle dead buffers and
|
||||
consequently deletable windows.
|
||||
(window_tree, Fwindow_tree): Remove. Supply functionality in
|
||||
window.el.
|
||||
(compare_window_configurations): Simplify code.
|
||||
|
||||
2011-06-11 Andreas Schwab <schwab@linux-m68k.org>
|
||||
|
||||
* image.c (imagemagick_load_image): Fix type mismatch.
|
||||
|
|
|
|||
367
src/window.c
367
src/window.c
|
|
@ -1974,6 +1974,14 @@ recombine_windows (Lisp_Object window)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If WINDOW can be deleted, delete it. */
|
||||
static Lisp_Object
|
||||
delete_deletable_window (Lisp_Object window)
|
||||
{
|
||||
if (!NILP (call1 (Qwindow_deletable_p, window)))
|
||||
call1 (Qdelete_window, window);
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
Window List
|
||||
|
|
@ -5388,6 +5396,7 @@ the return value is nil. Otherwise the value is t. */)
|
|||
struct Lisp_Vector *saved_windows;
|
||||
Lisp_Object new_current_buffer;
|
||||
Lisp_Object frame;
|
||||
Lisp_Object auto_buffer_name;
|
||||
FRAME_PTR f;
|
||||
EMACS_INT old_point = -1;
|
||||
|
||||
|
|
@ -5443,6 +5452,8 @@ the return value is nil. Otherwise the value is t. */)
|
|||
However, there is other stuff we should still try to do below. */
|
||||
if (FRAME_LIVE_P (f))
|
||||
{
|
||||
Lisp_Object window;
|
||||
Lisp_Object dead_windows = Qnil;
|
||||
register struct window *w;
|
||||
register struct saved_window *p;
|
||||
struct window *root_window;
|
||||
|
|
@ -5519,7 +5530,8 @@ the return value is nil. Otherwise the value is t. */)
|
|||
for (k = 0; k < saved_windows->header.size; k++)
|
||||
{
|
||||
p = SAVED_WINDOW_N (saved_windows, k);
|
||||
w = XWINDOW (p->window);
|
||||
window = p->window;
|
||||
w = XWINDOW (window);
|
||||
w->next = Qnil;
|
||||
|
||||
if (!NILP (p->parent))
|
||||
|
|
@ -5582,55 +5594,70 @@ the return value is nil. Otherwise the value is t. */)
|
|||
|
||||
/* Reinstall the saved buffer and pointers into it. */
|
||||
if (NILP (p->buffer))
|
||||
/* An internal window. */
|
||||
w->buffer = p->buffer;
|
||||
else
|
||||
else if (!NILP (BVAR (XBUFFER (p->buffer), name)))
|
||||
/* If saved buffer is alive, install it. */
|
||||
{
|
||||
if (!NILP (BVAR (XBUFFER (p->buffer), name)))
|
||||
/* If saved buffer is alive, install it. */
|
||||
{
|
||||
w->buffer = p->buffer;
|
||||
w->start_at_line_beg = p->start_at_line_beg;
|
||||
set_marker_restricted (w->start, p->start, w->buffer);
|
||||
set_marker_restricted (w->pointm, p->pointm, w->buffer);
|
||||
Fset_marker (BVAR (XBUFFER (w->buffer), mark),
|
||||
p->mark, w->buffer);
|
||||
w->buffer = p->buffer;
|
||||
w->start_at_line_beg = p->start_at_line_beg;
|
||||
set_marker_restricted (w->start, p->start, w->buffer);
|
||||
set_marker_restricted (w->pointm, p->pointm, w->buffer);
|
||||
Fset_marker (BVAR (XBUFFER (w->buffer), mark),
|
||||
p->mark, w->buffer);
|
||||
|
||||
/* As documented in Fcurrent_window_configuration, don't
|
||||
restore the location of point in the buffer which was
|
||||
current when the window configuration was recorded. */
|
||||
if (!EQ (p->buffer, new_current_buffer)
|
||||
&& XBUFFER (p->buffer) == current_buffer)
|
||||
Fgoto_char (w->pointm);
|
||||
}
|
||||
else if (NILP (w->buffer) || NILP (BVAR (XBUFFER (w->buffer), name)))
|
||||
/* Else unless window has a live buffer, get one. */
|
||||
{
|
||||
w->buffer = Fcdr (Fcar (Vbuffer_alist));
|
||||
/* This will set the markers to beginning of visible
|
||||
range. */
|
||||
set_marker_restricted (w->start, make_number (0), w->buffer);
|
||||
set_marker_restricted (w->pointm, make_number (0),w->buffer);
|
||||
w->start_at_line_beg = Qt;
|
||||
}
|
||||
else
|
||||
/* Keeping window's old buffer; make sure the markers
|
||||
are real. */
|
||||
{
|
||||
/* Set window markers at start of visible range. */
|
||||
if (XMARKER (w->start)->buffer == 0)
|
||||
set_marker_restricted (w->start, make_number (0),
|
||||
w->buffer);
|
||||
if (XMARKER (w->pointm)->buffer == 0)
|
||||
set_marker_restricted_both (w->pointm, w->buffer,
|
||||
BUF_PT (XBUFFER (w->buffer)),
|
||||
BUF_PT_BYTE (XBUFFER (w->buffer)));
|
||||
w->start_at_line_beg = Qt;
|
||||
}
|
||||
/* As documented in Fcurrent_window_configuration, don't
|
||||
restore the location of point in the buffer which was
|
||||
current when the window configuration was recorded. */
|
||||
if (!EQ (p->buffer, new_current_buffer)
|
||||
&& XBUFFER (p->buffer) == current_buffer)
|
||||
Fgoto_char (w->pointm);
|
||||
}
|
||||
else if (!NILP (w->buffer) && !NILP (BVAR (XBUFFER (w->buffer), name)))
|
||||
/* Keep window's old buffer; make sure the markers are
|
||||
real. */
|
||||
{
|
||||
/* Set window markers at start of visible range. */
|
||||
if (XMARKER (w->start)->buffer == 0)
|
||||
set_marker_restricted (w->start, make_number (0),
|
||||
w->buffer);
|
||||
if (XMARKER (w->pointm)->buffer == 0)
|
||||
set_marker_restricted_both (w->pointm, w->buffer,
|
||||
BUF_PT (XBUFFER (w->buffer)),
|
||||
BUF_PT_BYTE (XBUFFER (w->buffer)));
|
||||
w->start_at_line_beg = Qt;
|
||||
}
|
||||
else if (STRINGP (auto_buffer_name =
|
||||
Fwindow_parameter (window, Qauto_buffer_name))
|
||||
&& SCHARS (auto_buffer_name) != 0
|
||||
&& !NILP (w->buffer = Fget_buffer_create (auto_buffer_name)))
|
||||
{
|
||||
set_marker_restricted (w->start, make_number (0), w->buffer);
|
||||
set_marker_restricted (w->pointm, make_number (0), w->buffer);
|
||||
w->start_at_line_beg = Qt;
|
||||
}
|
||||
else
|
||||
/* Window has no live buffer, get one. */
|
||||
{
|
||||
/* Get the buffer via other_buffer_safely in order to
|
||||
avoid showing an unimportant buffer and, if necessary, to
|
||||
recreate *scratch* in the course (part of Juanma's bs-show
|
||||
scenario from March 2011). */
|
||||
w->buffer = other_buffer_safely (Fcurrent_buffer ());
|
||||
/* This will set the markers to beginning of visible
|
||||
range. */
|
||||
set_marker_restricted (w->start, make_number (0), w->buffer);
|
||||
set_marker_restricted (w->pointm, make_number (0), w->buffer);
|
||||
w->start_at_line_beg = Qt;
|
||||
if (!NILP (w->dedicated))
|
||||
/* Record this window as dead. */
|
||||
dead_windows = Fcons (window, dead_windows);
|
||||
/* Make sure window is no more dedicated. */
|
||||
w->dedicated = Qnil;
|
||||
}
|
||||
}
|
||||
|
||||
FRAME_ROOT_WINDOW (f) = data->root_window;
|
||||
|
||||
/* Arrange *not* to restore point in the buffer that was
|
||||
current when the window configuration was saved. */
|
||||
if (EQ (XWINDOW (data->current_window)->buffer, new_current_buffer))
|
||||
|
|
@ -5638,10 +5665,10 @@ the return value is nil. Otherwise the value is t. */)
|
|||
make_number (old_point),
|
||||
XWINDOW (data->current_window)->buffer);
|
||||
|
||||
/* In the following call to `select-window, prevent "swapping
|
||||
out point" in the old selected window using the buffer that
|
||||
has been restored into it. We already swapped out that point
|
||||
from that window's old buffer. */
|
||||
/* In the following call to `select-window', prevent "swapping out
|
||||
point" in the old selected window using the buffer that has
|
||||
been restored into it. We already swapped out that point from
|
||||
that window's old buffer. */
|
||||
select_window (data->current_window, Qnil, 1);
|
||||
BVAR (XBUFFER (XWINDOW (selected_window)->buffer), last_selected_window)
|
||||
= selected_window;
|
||||
|
|
@ -5682,9 +5709,16 @@ the return value is nil. Otherwise the value is t. */)
|
|||
}
|
||||
|
||||
adjust_glyphs (f);
|
||||
|
||||
UNBLOCK_INPUT;
|
||||
|
||||
/* Scan dead buffer windows. */
|
||||
for (; CONSP (dead_windows); dead_windows = XCDR (dead_windows))
|
||||
{
|
||||
window = XCAR (dead_windows);
|
||||
if (WINDOW_LIVE_P (window) && !EQ (window, FRAME_ROOT_WINDOW (f)))
|
||||
delete_deletable_window (window);
|
||||
}
|
||||
|
||||
/* Fselect_window will have made f the selected frame, so we
|
||||
reselect the proper frame here. Fhandle_switch_frame will change the
|
||||
selected window too, but that doesn't make the call to
|
||||
|
|
@ -5930,82 +5964,6 @@ redirection (see `redirect-frame-focus'). */)
|
|||
XSETWINDOW_CONFIGURATION (tem, data);
|
||||
return (tem);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
Window Split Tree
|
||||
***********************************************************************/
|
||||
|
||||
static Lisp_Object
|
||||
window_tree (struct window *w)
|
||||
{
|
||||
Lisp_Object tail = Qnil;
|
||||
Lisp_Object result = Qnil;
|
||||
|
||||
while (w)
|
||||
{
|
||||
Lisp_Object wn;
|
||||
|
||||
XSETWINDOW (wn, w);
|
||||
if (!NILP (w->hchild))
|
||||
wn = Fcons (Qnil, Fcons (Fwindow_edges (wn),
|
||||
window_tree (XWINDOW (w->hchild))));
|
||||
else if (!NILP (w->vchild))
|
||||
wn = Fcons (Qt, Fcons (Fwindow_edges (wn),
|
||||
window_tree (XWINDOW (w->vchild))));
|
||||
|
||||
if (NILP (result))
|
||||
{
|
||||
result = tail = Fcons (wn, Qnil);
|
||||
}
|
||||
else
|
||||
{
|
||||
XSETCDR (tail, Fcons (wn, Qnil));
|
||||
tail = XCDR (tail);
|
||||
}
|
||||
|
||||
w = NILP (w->next) ? 0 : XWINDOW (w->next);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
DEFUN ("window-tree", Fwindow_tree, Swindow_tree,
|
||||
0, 1, 0,
|
||||
doc: /* Return the window tree for frame FRAME.
|
||||
|
||||
The return value is a list of the form (ROOT MINI), where ROOT
|
||||
represents the window tree of the frame's root window, and MINI
|
||||
is the frame's minibuffer window.
|
||||
|
||||
If the root window is not split, ROOT is the root window itself.
|
||||
Otherwise, ROOT is a list (DIR EDGES W1 W2 ...) where DIR is nil for a
|
||||
horizontal split, and t for a vertical split, EDGES gives the combined
|
||||
size and position of the subwindows in the split, and the rest of the
|
||||
elements are the subwindows in the split. Each of the subwindows may
|
||||
again be a window or a list representing a window split, and so on.
|
||||
EDGES is a list \(LEFT TOP RIGHT BOTTOM) as returned by `window-edges'.
|
||||
|
||||
If FRAME is nil or omitted, return information on the currently
|
||||
selected frame. */)
|
||||
(Lisp_Object frame)
|
||||
{
|
||||
FRAME_PTR f;
|
||||
|
||||
if (NILP (frame))
|
||||
frame = selected_frame;
|
||||
|
||||
CHECK_FRAME (frame);
|
||||
f = XFRAME (frame);
|
||||
|
||||
if (!FRAME_LIVE_P (f))
|
||||
return Qnil;
|
||||
|
||||
return window_tree (XWINDOW (FRAME_ROOT_WINDOW (f)));
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
Marginal Areas
|
||||
|
|
@ -6365,116 +6323,82 @@ freeze_window_starts (struct frame *f, int freeze_p)
|
|||
Initialization
|
||||
***********************************************************************/
|
||||
|
||||
/* Return 1 if window configurations C1 and C2
|
||||
describe the same state of affairs. This is used by Fequal. */
|
||||
/* Return 1 if window configurations CONFIGURATION1 and CONFIGURATION2
|
||||
describe the same state of affairs. This is used by Fequal.
|
||||
|
||||
ignore_positions non-zero means ignore non-matching scroll positions
|
||||
and the like.
|
||||
|
||||
This ignores a couple of things like the dedicatedness status of
|
||||
window, splits, nest and the like. This might have to be fixed. */
|
||||
|
||||
int
|
||||
compare_window_configurations (Lisp_Object c1, Lisp_Object c2, int ignore_positions)
|
||||
compare_window_configurations (Lisp_Object configuration1, Lisp_Object configuration2, int ignore_positions)
|
||||
{
|
||||
register struct save_window_data *d1, *d2;
|
||||
struct Lisp_Vector *sw1, *sw2;
|
||||
struct Lisp_Vector *sws1, *sws2;
|
||||
int i;
|
||||
|
||||
CHECK_WINDOW_CONFIGURATION (c1);
|
||||
CHECK_WINDOW_CONFIGURATION (c2);
|
||||
CHECK_WINDOW_CONFIGURATION (configuration1);
|
||||
CHECK_WINDOW_CONFIGURATION (configuration2);
|
||||
|
||||
d1 = (struct save_window_data *) XVECTOR (c1);
|
||||
d2 = (struct save_window_data *) XVECTOR (c2);
|
||||
sw1 = XVECTOR (d1->saved_windows);
|
||||
sw2 = XVECTOR (d2->saved_windows);
|
||||
d1 = (struct save_window_data *) XVECTOR (configuration1);
|
||||
d2 = (struct save_window_data *) XVECTOR (configuration2);
|
||||
sws1 = XVECTOR (d1->saved_windows);
|
||||
sws2 = XVECTOR (d2->saved_windows);
|
||||
|
||||
if (d1->frame_cols != d2->frame_cols)
|
||||
/* Frame settings must match. */
|
||||
if (d1->frame_cols != d2->frame_cols
|
||||
|| d1->frame_lines != d2->frame_lines
|
||||
|| d1->frame_menu_bar_lines != d2->frame_menu_bar_lines
|
||||
|| !EQ (d1->selected_frame, d2->selected_frame)
|
||||
|| !EQ (d1->current_buffer, d2->current_buffer)
|
||||
|| (!ignore_positions
|
||||
&& (!EQ (d1->minibuf_scroll_window, d2->minibuf_scroll_window)
|
||||
|| !EQ (d1->minibuf_selected_window, d2->minibuf_selected_window)))
|
||||
|| !EQ (d1->focus_frame, d2->focus_frame)
|
||||
/* Verify that the two configurations have the same number of windows. */
|
||||
|| sws1->header.size != sws2->header.size)
|
||||
return 0;
|
||||
if (d1->frame_lines != d2->frame_lines)
|
||||
return 0;
|
||||
if (d1->frame_menu_bar_lines != d2->frame_menu_bar_lines)
|
||||
return 0;
|
||||
if (! EQ (d1->selected_frame, d2->selected_frame))
|
||||
return 0;
|
||||
/* Don't compare the current_window field directly.
|
||||
Instead see w1_is_current and w2_is_current, below. */
|
||||
if (! EQ (d1->current_buffer, d2->current_buffer))
|
||||
return 0;
|
||||
if (! ignore_positions)
|
||||
|
||||
for (i = 0; i < sws1->header.size; i++)
|
||||
{
|
||||
if (! EQ (d1->minibuf_scroll_window, d2->minibuf_scroll_window))
|
||||
return 0;
|
||||
if (! EQ (d1->minibuf_selected_window, d2->minibuf_selected_window))
|
||||
return 0;
|
||||
}
|
||||
/* Don't compare the root_window field.
|
||||
We don't require the two configurations
|
||||
to use the same window object,
|
||||
and the two root windows must be equivalent
|
||||
if everything else compares equal. */
|
||||
if (! EQ (d1->focus_frame, d2->focus_frame))
|
||||
return 0;
|
||||
|
||||
/* Verify that the two confis have the same number of windows. */
|
||||
if (sw1->header.size != sw2->header.size)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < sw1->header.size; i++)
|
||||
{
|
||||
struct saved_window *p1, *p2;
|
||||
struct saved_window *sw1, *sw2;
|
||||
int w1_is_current, w2_is_current;
|
||||
|
||||
p1 = SAVED_WINDOW_N (sw1, i);
|
||||
p2 = SAVED_WINDOW_N (sw2, i);
|
||||
sw1 = SAVED_WINDOW_N (sws1, i);
|
||||
sw2 = SAVED_WINDOW_N (sws2, i);
|
||||
|
||||
/* Verify that the current windows in the two
|
||||
configurations correspond to each other. */
|
||||
w1_is_current = EQ (d1->current_window, p1->window);
|
||||
w2_is_current = EQ (d2->current_window, p2->window);
|
||||
|
||||
if (w1_is_current != w2_is_current)
|
||||
return 0;
|
||||
|
||||
/* Verify that the corresponding windows do match. */
|
||||
if (! EQ (p1->buffer, p2->buffer))
|
||||
return 0;
|
||||
if (! EQ (p1->left_col, p2->left_col))
|
||||
return 0;
|
||||
if (! EQ (p1->top_line, p2->top_line))
|
||||
return 0;
|
||||
if (! EQ (p1->total_cols, p2->total_cols))
|
||||
return 0;
|
||||
if (! EQ (p1->total_lines, p2->total_lines))
|
||||
return 0;
|
||||
if (! EQ (p1->display_table, p2->display_table))
|
||||
return 0;
|
||||
if (! EQ (p1->parent, p2->parent))
|
||||
return 0;
|
||||
if (! EQ (p1->prev, p2->prev))
|
||||
return 0;
|
||||
if (! ignore_positions)
|
||||
{
|
||||
if (! EQ (p1->hscroll, p2->hscroll))
|
||||
return 0;
|
||||
if (!EQ (p1->min_hscroll, p2->min_hscroll))
|
||||
return 0;
|
||||
if (! EQ (p1->start_at_line_beg, p2->start_at_line_beg))
|
||||
return 0;
|
||||
if (NILP (Fequal (p1->start, p2->start)))
|
||||
return 0;
|
||||
if (NILP (Fequal (p1->pointm, p2->pointm)))
|
||||
return 0;
|
||||
if (NILP (Fequal (p1->mark, p2->mark)))
|
||||
return 0;
|
||||
}
|
||||
if (! EQ (p1->left_margin_cols, p2->left_margin_cols))
|
||||
return 0;
|
||||
if (! EQ (p1->right_margin_cols, p2->right_margin_cols))
|
||||
return 0;
|
||||
if (! EQ (p1->left_fringe_width, p2->left_fringe_width))
|
||||
return 0;
|
||||
if (! EQ (p1->right_fringe_width, p2->right_fringe_width))
|
||||
return 0;
|
||||
if (! EQ (p1->fringes_outside_margins, p2->fringes_outside_margins))
|
||||
return 0;
|
||||
if (! EQ (p1->scroll_bar_width, p2->scroll_bar_width))
|
||||
return 0;
|
||||
if (! EQ (p1->vertical_scroll_bar_type, p2->vertical_scroll_bar_type))
|
||||
if (
|
||||
/* The "current" windows in the two configurations must
|
||||
correspond to each other. */
|
||||
EQ (d1->current_window, sw1->window)
|
||||
!= EQ (d2->current_window, sw2->window)
|
||||
/* Windows' buffers must match. */
|
||||
|| !EQ (sw1->buffer, sw2->buffer)
|
||||
|| !EQ (sw1->left_col, sw2->left_col)
|
||||
|| !EQ (sw1->top_line, sw2->top_line)
|
||||
|| !EQ (sw1->total_cols, sw2->total_cols)
|
||||
|| !EQ (sw1->total_lines, sw2->total_lines)
|
||||
|| !EQ (sw1->display_table, sw2->display_table)
|
||||
/* The next two disjuncts check the window structure for
|
||||
equality. */
|
||||
|| !EQ (sw1->parent, sw2->parent)
|
||||
|| !EQ (sw1->prev, sw2->prev)
|
||||
|| (!ignore_positions
|
||||
&& (!EQ (sw1->hscroll, sw2->hscroll)
|
||||
|| !EQ (sw1->min_hscroll, sw2->min_hscroll)
|
||||
|| !EQ (sw1->start_at_line_beg, sw2->start_at_line_beg)
|
||||
|| NILP (Fequal (sw1->start, sw2->start))
|
||||
|| NILP (Fequal (sw1->pointm, sw2->pointm))
|
||||
|| NILP (Fequal (sw1->mark, sw2->mark))))
|
||||
|| !EQ (sw1->left_margin_cols, sw2->left_margin_cols)
|
||||
|| !EQ (sw1->right_margin_cols, sw2->right_margin_cols)
|
||||
|| !EQ (sw1->left_fringe_width, sw2->left_fringe_width)
|
||||
|| !EQ (sw1->right_fringe_width, sw2->right_fringe_width)
|
||||
|| !EQ (sw1->fringes_outside_margins, sw2->fringes_outside_margins)
|
||||
|| !EQ (sw1->scroll_bar_width, sw2->scroll_bar_width)
|
||||
|| !EQ (sw1->vertical_scroll_bar_type, sw2->vertical_scroll_bar_type))
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -6768,7 +6692,6 @@ function `window-nest' and altered by the function `set-window-nest'. */);
|
|||
defsubr (&Swindow_configuration_frame);
|
||||
defsubr (&Sset_window_configuration);
|
||||
defsubr (&Scurrent_window_configuration);
|
||||
defsubr (&Swindow_tree);
|
||||
defsubr (&Sset_window_margins);
|
||||
defsubr (&Swindow_margins);
|
||||
defsubr (&Sset_window_fringes);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue