X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/dd72e25cb2561f180437db5e84b08dd7670809ae..f9fcf84a9c6e7a4510a60b41c29cadbef817af14:/lisp/window.el diff --git a/lisp/window.el b/lisp/window.el index 60f13e65c4..78257b6121 100644 --- a/lisp/window.el +++ b/lisp/window.el @@ -108,7 +108,7 @@ Return the buffer." ;; Return the buffer. buffer))) -(defun temp-buffer-window-show (&optional buffer action) +(defun temp-buffer-window-show (buffer &optional action) "Show temporary buffer BUFFER in a window. Return the window showing BUFFER. Pass ACTION as action argument to `display-buffer'." @@ -185,16 +185,19 @@ argument replaces this)." (let ((buffer (make-symbol "buffer")) (window (make-symbol "window")) (value (make-symbol "value"))) - `(let* ((,buffer (temp-buffer-window-setup ,buffer-or-name)) - (standard-output ,buffer) - ,window ,value) - (setq ,value (progn ,@body)) - (with-current-buffer ,buffer - (setq ,window (temp-buffer-window-show ,buffer ,action))) + (macroexp-let2* nil ((vbuffer-or-name buffer-or-name) + (vaction action) + (vquit-function quit-function)) + `(let* ((,buffer (temp-buffer-window-setup ,vbuffer-or-name)) + (standard-output ,buffer) + ,window ,value) + (setq ,value (progn ,@body)) + (with-current-buffer ,buffer + (setq ,window (temp-buffer-window-show ,buffer ,vaction))) - (if (functionp ,quit-function) - (funcall ,quit-function ,window ,value) - ,value)))) + (if (functionp ,vquit-function) + (funcall ,vquit-function ,window ,value) + ,value))))) (defmacro with-current-buffer-window (buffer-or-name action quit-function &rest body) "Evaluate BODY with a buffer BUFFER-OR-NAME current and show that buffer. @@ -205,16 +208,50 @@ BODY." (let ((buffer (make-symbol "buffer")) (window (make-symbol "window")) (value (make-symbol "value"))) - `(let* ((,buffer (temp-buffer-window-setup ,buffer-or-name)) - (standard-output ,buffer) - ,window ,value) - (with-current-buffer ,buffer - (setq ,value (progn ,@body)) - (setq ,window (temp-buffer-window-show ,buffer ,action))) + (macroexp-let2* nil ((vbuffer-or-name buffer-or-name) + (vaction action) + (vquit-function quit-function)) + `(let* ((,buffer (temp-buffer-window-setup ,vbuffer-or-name)) + (standard-output ,buffer) + ,window ,value) + (with-current-buffer ,buffer + (setq ,value (progn ,@body)) + (setq ,window (temp-buffer-window-show ,buffer ,vaction))) + + (if (functionp ,vquit-function) + (funcall ,vquit-function ,window ,value) + ,value))))) + +(defmacro with-displayed-buffer-window (buffer-or-name action quit-function &rest body) + "Show a buffer BUFFER-OR-NAME and evaluate BODY in that buffer. +This construct is like `with-current-buffer-window' but unlike that +displays the buffer specified by BUFFER-OR-NAME before running BODY." + (declare (debug t)) + (let ((buffer (make-symbol "buffer")) + (window (make-symbol "window")) + (value (make-symbol "value"))) + (macroexp-let2* nil ((vbuffer-or-name buffer-or-name) + (vaction action) + (vquit-function quit-function)) + `(let* ((,buffer (temp-buffer-window-setup ,vbuffer-or-name)) + (standard-output ,buffer) + ,window ,value) + (with-current-buffer ,buffer + (setq ,window (temp-buffer-window-show ,buffer ,vaction))) + + (let ((inhibit-read-only t) + (inhibit-modification-hooks t)) + (setq ,value (progn ,@body))) + + (set-window-point ,window (point-min)) + + (when (functionp (cdr (assq 'window-height (cdr ,vaction)))) + (ignore-errors + (funcall (cdr (assq 'window-height (cdr ,vaction))) ,window))) - (if (functionp ,quit-function) - (funcall ,quit-function ,window ,value) - ,value)))) + (if (functionp ,vquit-function) + (funcall ,vquit-function ,window ,value) + ,value))))) ;; The following two functions are like `window-next-sibling' and ;; `window-prev-sibling' but the WINDOW argument is _not_ optional (so @@ -341,9 +378,9 @@ Anything less might crash Emacs.") (defcustom window-min-height 4 "The minimum total height, in lines, of any window. The value has to accommodate one text line, a mode and header -line, and a bottom divider, if present. A value less than -`window-safe-min-height' is ignored. The value of this variable -is honored when windows are resized or split. +line, a horizontal scroll bar and a bottom divider, if present. +A value less than `window-safe-min-height' is ignored. The value +of this variable is honored when windows are resized or split. Applications should never rebind this variable. To resize a window to a height less than the one specified here, an @@ -706,6 +743,15 @@ number of slots on that side." (integer :tag "Number" :value 3 :size 5))) :group 'windows) +(defun window--side-window-p (window) + "Return non-nil if WINDOW is a side window or the parent of one." + (or (window-parameter window 'window-side) + (and (window-child window) + (or (window-parameter + (window-child window) 'window-side) + (window-parameter + (window-last-child window) 'window-side))))) + (defun window--major-non-side-window (&optional frame) "Return the major non-side window of frame FRAME. The optional argument FRAME must be a live frame and defaults to @@ -1079,7 +1125,6 @@ WINDOW-OR-FRAME can be a frame or a window and defaults to the selected frame. When WINDOW-OR-FRAME is a window, dump that window's frame. The buffer *window-frame-dump* is erased before dumping to it." - (interactive) (let* ((window (cond ((or (not window-or-frame) @@ -1101,9 +1146,12 @@ dumping to it." (format "frame text pixel: %s x %s cols/lines: %s x %s\n" (frame-text-width frame) (frame-text-height frame) (frame-text-cols frame) (frame-text-lines frame)) - (format "tool: %s scroll: %s fringe: %s border: %s right: %s bottom: %s\n\n" - (tool-bar-height frame t) + (format "tool: %s scroll: %s/%s fringe: %s border: %s right: %s bottom: %s\n\n" + (if (fboundp 'tool-bar-height) + (tool-bar-height frame t) + "0") (frame-scroll-bar-width frame) + (frame-scroll-bar-height frame) (frame-fringe-width frame) (frame-border-width frame) (frame-right-divider-width frame) @@ -1116,8 +1164,17 @@ dumping to it." WINDOW must be a valid window and defaults to the selected one. If HORIZONTAL is omitted or nil, return the total height of -WINDOW, in lines, like `window-total-height'. Otherwise return -the total width, in columns, like `window-total-width'. +WINDOW, in lines. If WINDOW is live, its total height includes, +in addition to the height of WINDOW's text, the heights of +WINDOW's mode and header line and a bottom divider, if any. + +If HORIZONTAL is non-nil, return the total width of WINDOW, in +columns. If WINDOW is live, its total width includes, in +addition to the width of WINDOW's text, the widths of WINDOW's +fringes, margins, scroll bars and its right divider, if any. + +If WINDOW is internal, return the respective size of the screen +areas spanned by its children. Optional argument ROUND is handled as for `window-total-height' and `window-total-width'." @@ -1224,12 +1281,14 @@ of WINDOW." value) (with-current-buffer (window-buffer window) (cond + ((window-minibuffer-p window) + (if pixelwise (frame-char-height (window-frame window)) 1)) ((and (not (window--size-ignore-p window ignore)) (window-size-fixed-p window horizontal)) ;; The minimum size of a fixed size window is its size. (window-size window horizontal pixelwise)) - ((or (eq ignore 'safe) (eq ignore window)) - ;; If IGNORE equals `safe' or WINDOW return the safe values. + ((eq ignore 'safe) + ;; If IGNORE equals `safe' return the safe value. (window-safe-min-size window horizontal pixelwise)) (horizontal ;; For the minimum width of a window take fringes and @@ -1240,8 +1299,11 @@ of WINDOW." ;; `window-min-width'. (let* ((char-size (frame-char-size window t)) (fringes (window-fringes window)) + (margins (window-margins window)) (pixel-width (+ (window-safe-min-size window t t) + (* (or (car margins) 0) char-size) + (* (or (cdr margins) 0) char-size) (car fringes) (cadr fringes) (window-scroll-bar-width window) (window-right-divider-width window)))) @@ -1253,7 +1315,7 @@ of WINDOW." (* (ceiling pixel-width char-size) char-size)) (if (window--size-ignore-p window ignore) 0 - (window-min-pixel-width))) + (window-min-pixel-width window))) (max (ceiling pixel-width char-size) (if (window--size-ignore-p window ignore) @@ -1263,6 +1325,7 @@ of WINDOW." (pixel-height (+ (window-safe-min-size window nil t) (window-header-line-height window) + (window-scroll-bar-height window) (window-mode-line-height window) (window-bottom-divider-width window)))) (if pixelwise @@ -1273,7 +1336,7 @@ of WINDOW." (* (ceiling pixel-height char-size) char-size)) (if (window--size-ignore-p window ignore) 0 - (window-min-pixel-height))) + (window-min-pixel-height window))) (max (ceiling pixel-height char-size) (if (window--size-ignore-p window ignore) 0 @@ -1470,6 +1533,18 @@ by which WINDOW can be shrunk." (window--min-delta-1 window (- size minimum) horizontal ignore trail noup pixelwise))))) +(defun frame-windows-min-size (&optional frame horizontal pixelwise) + "Return minimum number of lines of FRAME's windows. +HORIZONTAL non-nil means return number of columns of FRAME's +windows. PIXELWISE non-nil means return sizes in pixels." + (setq frame (window-normalize-frame frame)) + (let* ((root (frame-root-window frame)) + (mini (window-next-sibling root))) + (+ (window-min-size root horizontal nil pixelwise) + (if (and mini (not horizontal)) + (window-min-size mini horizontal nil pixelwise) + 0)))) + (defun window--max-delta-1 (window delta &optional horizontal ignore trail noup pixelwise) "Internal function of `window-max-delta'." (if (not (window-parent window)) @@ -1670,9 +1745,6 @@ doc-string of `window-resizable'." (defalias 'window-height 'window-total-height) (defalias 'window-width 'window-body-width) -;; Eventually the following two should work pixelwise. - -;; See discussion in bug#4543. (defun window-full-height-p (&optional window) "Return t if WINDOW is as high as its containing frame. More precisely, return t if and only if the total height of @@ -1680,8 +1752,10 @@ WINDOW equals the total height of the root window of WINDOW's frame. WINDOW must be a valid window and defaults to the selected one." (setq window (window-normalize-window window)) - (= (window-pixel-height window) - (window-pixel-height (frame-root-window window)))) + (if (window-minibuffer-p window) + (eq window (frame-root-window (window-frame window))) + (= (window-pixel-height window) + (window-pixel-height (frame-root-window window))))) (defun window-full-width-p (&optional window) "Return t if WINDOW is as wide as its containing frame. @@ -1705,28 +1779,26 @@ optional argument PIXELWISE is passed to the functions." (window-body-height window pixelwise))) (defun window-current-scroll-bars (&optional window) - "Return the current scroll bar settings for WINDOW. + "Return the current scroll bar types for WINDOW. WINDOW must be a live window and defaults to the selected one. The return value is a cons cell (VERTICAL . HORIZONTAL) where VERTICAL specifies the current location of the vertical scroll -bars (`left', `right', or nil), and HORIZONTAL specifies the -current location of the horizontal scroll bars (`top', `bottom', -or nil). +bar (`left', `right' or nil), and HORIZONTAL specifies the +current location of the horizontal scroll bar (`bottom' or nil). Unlike `window-scroll-bars', this function reports the scroll bar type actually used, once frame defaults and `scroll-bar-mode' are taken into account." (setq window (window-normalize-window window t)) - (let ((vert (nth 2 (window-scroll-bars window))) - (hor nil)) - (when (or (eq vert t) (eq hor t)) - (let ((fcsb (frame-current-scroll-bars (window-frame window)))) - (if (eq vert t) - (setq vert (car fcsb))) - (if (eq hor t) - (setq hor (cdr fcsb))))) - (cons vert hor))) + (let ((vertical (nth 2 (window-scroll-bars window))) + (horizontal (nth 5 (window-scroll-bars window))) + (inherited (frame-current-scroll-bars (window-frame window)))) + (when (eq vertical t) + (setq vertical (car inherited))) + (when (eq horizontal t) + (setq horizontal (cdr inherited))) + (cons vertical (and horizontal 'bottom)))) (defun walk-windows (fun &optional minibuf all-frames) "Cycle through all live windows, calling FUN for each one. @@ -2229,7 +2301,7 @@ Optional argument HORIZONTAL non-nil means assign new total window widths from pixel widths." (setq frame (window-normalize-frame frame)) (let* ((char-size (frame-char-size frame horizontal)) - (root (frame-root-window)) + (root (frame-root-window frame)) (root-size (window-size root horizontal t)) ;; We have to care about the minibuffer window only if it ;; appears together with the root window on this frame. @@ -2946,6 +3018,28 @@ routines." pixel-delta (/ pixel-delta (frame-char-height frame))))) +(defun window--sanitize-window-sizes (frame horizontal) + "Assert that all windows on FRAME are large enough. +If necessary and possible, make sure that every window on frame +FRAME has its minimum height. Optional argument HORIZONTAL +non-nil means to make sure that every window on frame FRAME has +its minimum width. The minimum height/width of a window is the +respective value returned by `window-min-size' for that window. + +Return t if all windows were resized appropriately. Return nil +if at least one window could not be resized as requested, which +may happen when the FRAME is not large enough to accommodate it." + (let ((value t)) + (walk-window-tree + (lambda (window) + (let ((delta (- (window-min-size window horizontal nil t) + (window-size window horizontal t)))) + (when (> delta 0) + (if (window-resizable-p window delta horizontal nil t) + (window-resize window delta horizontal nil t) + (setq value nil)))))) + value)) + (defun adjust-window-trailing-edge (window delta &optional horizontal pixelwise) "Move WINDOW's bottom edge by DELTA lines. Optional argument HORIZONTAL non-nil means move WINDOW's right @@ -4203,20 +4297,6 @@ showing BUFFER-OR-NAME." ;; If a window doesn't show BUFFER, unrecord BUFFER in it. (unrecord-window-buffer window buffer))))) -;;; Splitting windows. -(defun window-split-min-size (&optional horizontal pixelwise) - "Return minimum height of any window when splitting windows. -Optional argument HORIZONTAL non-nil means return minimum width." - (cond - (pixelwise - (if horizontal - (window-min-pixel-width) - (window-min-pixel-height))) - (horizontal - (max window-min-width window-safe-min-width)) - (t - (max window-min-height window-safe-min-height)))) - (defun split-window (&optional window size side pixelwise) "Make a new window adjacent to WINDOW. WINDOW must be a valid window and defaults to the selected one. @@ -4280,6 +4360,9 @@ frame. The selected window is not changed by this function." (pixel-size (when (numberp size) (window--size-to-pixel window size horizontal pixelwise t))) + (divider-width (if horizontal + (frame-right-divider-width frame) + (frame-bottom-divider-width frame))) atom-root) (window--check frame) (catch 'done @@ -4301,12 +4384,7 @@ frame. The selected window is not changed by this function." ;; side window, throw an error unless `window-combination-resize' ;; equals 'side. ((and (not (eq window-combination-resize 'side)) - (or (window-parameter window 'window-side) - (and (window-child window) - (or (window-parameter - (window-child window) 'window-side) - (window-parameter - (window-last-child window) 'window-side))))) + (window--side-window-p window)) (error "Cannot split side window or parent of side window")) ;; If `window-combination-resize' is 'side and window has a side ;; window sibling, bind `window-combination-limit' to t. @@ -4381,19 +4459,14 @@ frame. The selected window is not changed by this function." (cond (resize ;; SIZE unspecified, resizing. - (when (and (not (window-sizable-p - parent (- new-pixel-size) horizontal nil t)) - ;; Try again with minimum split size. - (setq new-pixel-size - (max new-pixel-size - (window-split-min-size horizontal t))) - (not (window-sizable-p - parent (- new-pixel-size) horizontal nil t))) - (error "Window %s too small for splitting 1" parent))) - ((> (+ new-pixel-size (window-min-size window horizontal nil t)) + (unless (window-sizable-p + parent (- new-pixel-size divider-width) horizontal nil t) + (error "Window %s too small for splitting (1)" parent))) + ((> (+ new-pixel-size divider-width + (window-min-size window horizontal nil t)) old-pixel-size) ;; SIZE unspecified, no resizing. - (error "Window %s too small for splitting 2" window)))) + (error "Window %s too small for splitting (2)" window)))) ((and (>= pixel-size 0) (or (>= pixel-size old-pixel-size) (< new-pixel-size @@ -4401,19 +4474,19 @@ frame. The selected window is not changed by this function." ;; SIZE specified as new size of old window. If the new size ;; is larger than the old size or the size of the new window ;; would be less than the safe minimum, signal an error. - (error "Window %s too small for splitting 3" window)) + (error "Window %s too small for splitting (3)" window)) (resize ;; SIZE specified, resizing. (unless (window-sizable-p - parent (- new-pixel-size) horizontal nil t) + parent (- new-pixel-size divider-width) horizontal nil t) ;; If we cannot resize the parent give up. - (error "Window %s too small for splitting 4" parent))) + (error "Window %s too small for splitting (4)" parent))) ((or (< new-pixel-size (window-safe-min-pixel-size window horizontal)) (< (- old-pixel-size new-pixel-size) (window-safe-min-pixel-size window horizontal))) ;; SIZE specification violates minimum size restrictions. - (error "Window %s too small for splitting 5" window))) + (error "Window %s too small for splitting (5)" window))) (window--resize-reset frame horizontal) @@ -4484,6 +4557,9 @@ frame. The selected window is not changed by this function." (set-window-parameter (window-parent new) 'window-atom t)) (set-window-parameter new 'window-atom t))) + ;; Sanitize sizes. + (window--sanitize-window-sizes frame horizontal) + (run-window-configuration-change-hook frame) (run-window-scroll-functions new) (window--check frame) @@ -5055,7 +5131,7 @@ value can be also stored on disk and read back in a new session." (let ((scroll-bars (cdr (assq 'scroll-bars state)))) (set-window-scroll-bars window (car scroll-bars) (nth 2 scroll-bars) - (nth 3 scroll-bars))) + (or (nth 3 scroll-bars) 0) (nth 5 scroll-bars))) (set-window-vscroll window (cdr (assq 'vscroll state))) ;; Adjust vertically. (if (memq window-size-fixed '(t height)) @@ -5723,7 +5799,7 @@ hold: wide as `split-width-threshold'. - When WINDOW is split evenly, the emanating windows are at least `window-min-width' or two (whichever is larger) columns wide." - (when (window-live-p window) + (when (and (window-live-p window) (not (window--side-window-p window))) (with-current-buffer (window-buffer window) (if horizontal ;; A window can be split horizontally when its width is not @@ -5965,7 +6041,7 @@ live." ;; FIXME: By the way, there could be more levels of dedication: ;; - `barely' dedicated doesn't prevent reuse of the window, only records that ;; the window hasn't been used for something else yet. -;; - `softly' dedicated only allows reuse when asked explicitly. +;; - `soft' (`softly') dedicated only allows reuse when asked explicitly. ;; - `strongly' never allows reuse. (defvar display-buffer-mark-dedicated nil "If non-nil, `display-buffer' marks the windows it creates as dedicated. @@ -5979,6 +6055,8 @@ The actual non-nil value of this variable will be copied to the (const display-buffer-pop-up-window) (const display-buffer-same-window) (const display-buffer-pop-up-frame) + (const display-buffer-below-selected) + (const display-buffer-at-bottom) (const display-buffer-in-previous-window) (const display-buffer-use-some-window) (function :tag "Other function")) @@ -6372,7 +6450,10 @@ again with `display-buffer-pop-up-window'." This either splits the selected window or reuses the window below the selected one." (let (window) - (or (and (not (frame-parameter nil 'unsplittable)) + (or (and (setq window (window-in-direction 'below)) + (eq buffer (window-buffer window)) + (window--display-buffer buffer window 'reuse alist)) + (and (not (frame-parameter nil 'unsplittable)) (let ((split-height-threshold 0) split-width-threshold) (setq window (window--try-to-split-window (selected-window) alist))) @@ -6385,13 +6466,26 @@ the selected one." (defun display-buffer-at-bottom (buffer alist) "Try displaying BUFFER in a window at the bottom of the selected frame. -This either splits the window at the bottom of the frame or the -frame's root window, or reuses an existing window at the bottom -of the selected frame." - (let (bottom-window window) +This either reuses such a window provided it shows BUFFER +already, splits a window at the bottom of the frame or the +frame's root window, or reuses some window at the bottom of the +selected frame." + (let (bottom-window bottom-window-shows-buffer window) (walk-window-tree - (lambda (window) (setq bottom-window window)) nil nil 'nomini) - (or (and (not (frame-parameter nil 'unsplittable)) + (lambda (window) + (cond + ((window-in-direction 'below window)) + ((and (not bottom-window-shows-buffer) + (eq buffer (window-buffer window))) + (setq bottom-window-shows-buffer t) + (setq bottom-window window)) + ((not bottom-window) + (setq bottom-window window))) + nil nil 'nomini)) + (or (and bottom-window-shows-buffer + (window--display-buffer + buffer bottom-window 'reuse alist display-buffer-mark-dedicated)) + (and (not (frame-parameter nil 'unsplittable)) (let (split-width-threshold) (setq window (window--try-to-split-window bottom-window alist))) (window--display-buffer @@ -6496,7 +6590,7 @@ that frame." ;; resize it to its old height but don't signal an error. (when (and (listp quad) (integerp (nth 3 quad)) - (/= (nth 3 quad) (window-total-height window))) + (> (nth 3 quad) (window-total-height window))) (condition-case nil (window-resize window (- (nth 3 quad) (window-total-height window))) (error nil))) @@ -7076,7 +7170,10 @@ FRAME." (value (window-text-pixel-size nil t t workarea-width workarea-height t)) (width (+ (car value) (window-right-divider-width))) - (height (+ (cdr value) (window-bottom-divider-width)))) + (height + (+ (cdr value) + (window-bottom-divider-width) + (window-scroll-bar-height)))) ;; Don't change height or width when the window's size is fixed ;; in either direction or ONLY forbids it. (cond @@ -7160,7 +7257,7 @@ and header line and a bottom divider, if any. If WINDOW is part of a horizontal combination and the value of the option `fit-window-to-buffer-horizontally' is non-nil, adjust -WINDOW's height. The new width of WINDOW is calculated from the +WINDOW's width. The new width of WINDOW is calculated from the maximum length of its buffer's lines that follow the current start position of WINDOW. The optional argument MAX-WIDTH specifies a maximum width and defaults to the width of WINDOW's @@ -7235,6 +7332,7 @@ accessible position." ;; height. Its width remains fixed. (setq height (+ (cdr (window-text-pixel-size nil nil t nil (frame-pixel-height) t)) + (window-scroll-bar-height window) (window-bottom-divider-width))) ;; Round height. (unless pixelwise @@ -7276,10 +7374,10 @@ accessible position." max-width)) (+ total-width (window-max-delta nil t nil nil nil nil pixelwise)))) - ;; When fitting vertically, assume that WINDOW's start - ;; position remains unaltered. WINDOW can't get wider - ;; than its frame's pixel width, its height remains - ;; unaltered. + ;; When fitting horizontally, assume that WINDOW's + ;; start position remains unaltered. WINDOW can't get + ;; wider than its frame's pixel width, its height + ;; remains unaltered. (width (+ (car (window-text-pixel-size nil (window-start) (point-max) (frame-pixel-width) @@ -7288,7 +7386,7 @@ accessible position." ;; overshoots when the first line below ;; the bottom is wider than the window. (* body-height - (if pixelwise char-height 1)))) + (if pixelwise 1 char-height)))) (window-right-divider-width)))) (unless pixelwise (setq width (/ (+ width char-width -1) char-width)))