Function: split-window
split-window is a byte-compiled function defined in window.el.gz.
Signature
(split-window &optional WINDOW SIZE SIDE PIXELWISE REFER)
Documentation
Make a new window adjacent to WINDOW.
WINDOW must be a valid window and defaults to the selected one. Return the new window which is always a live window.
Optional argument SIZE a positive number means make WINDOW SIZE
lines or columns tall. If SIZE is negative, make the new window
-SIZE lines or columns tall. If and only if SIZE is non-nil, its
absolute value can be less than window-min-height or
window-min-width; so this command can make a new window as
small as one line or two columns. SIZE defaults to half of
WINDOW's size.
Optional third argument SIDE nil (or below) specifies that the
new window shall be located below WINDOW. SIDE above means the
new window shall be located above WINDOW. In both cases SIZE
specifies the new number of lines for WINDOW (or the new window
if SIZE is negative) including space reserved for the mode and/or
header line.
SIDE t (or right) specifies that the new window shall be
located on the right side of WINDOW. SIDE left means the new
window shall be located on the left of WINDOW. In both cases
SIZE specifies the new number of columns for WINDOW (or the new
window provided SIZE is negative) including space reserved for
fringes and the scrollbar or a divider column.
For compatibility reasons, SIDE up and down are interpreted
as above and below. Any other non-nil value for SIDE is
currently handled like t (or right).
As a rule, if WINDOW already forms a combination that matches the SIDE
parameter and window-combination-limit(var)/window-combination-limit(fun) is nil, reuse WINDOW's parent
in the window tree as parent of the new window. If WINDOW is in a
combination that is orthogonal to the SIDE parameter or if
window-combination-limit(var)/window-combination-limit(fun) is non-nil, make a new parent window that
replaces WINDOW in the window tree and make WINDOW and the new window
its sole child windows. This standard behavior can be overridden via
the REFER argument.
PIXELWISE, if non-nil, means to interpret SIZE pixelwise.
If the optional fifth argument REFER is non-nil, it specifies a reference window used for setting up properties of the new window. REFER can be either a window or a cons cell of two windows.
If REFER is a cons cell, its car has to specify a deleted, former live window - a window that has shown a buffer before - on the same frame as WINDOW. That buffer must be still live. The cdr has to specify a deleted window that was a parent window on the same frame as WINDOW before it was deleted. In this case, rather then making new windows, replace WINDOW with the cdr of REFER in the window tree and make WINDOW and REFER's car its new child windows. Buffer, start and point positions of REFER's car are set to the values they had immediately before REFER's car was deleted the last time. Decorations and parameters remain unaltered from their values before REFER's car and cdr were deleted.
Alternatively REFER may specify a deleted, former live window - a window that has shown a buffer before - on the same frame as WINDOW. In this case do not make a new window but rather make REFER live again and insert it into the window tree at the position and with the sizes the new window would have been given. Buffer, start and point positions of REFER are set to the values they had immediately before REFER was deleted the last time. Decorations and parameters remain unaltered from their values before REFER was deleted. Throw an error if REFER's buffer has been deleted after REFER itself was deleted.
Otherwise REFER must specify a live window. In this case, the new window will inherit properties like buffer, start and point position and some decorations from REFER. If REFER is nil or omitted, then if WINDOW is live, any such properties are inherited from WINDOW. If, however, WINDOW is an internal window, the new window will inherit these properties from the window selected on WINDOW's frame.
If the variable ignore-window-parameters is non-nil or the
split-window parameter of WINDOW equals t, do not process any
parameters of WINDOW. Otherwise, if the split-window parameter of
WINDOW specifies a function, call that function with the three first
arguments WINDOW, SIZE and SIDE and return the value returned by that
function.
Otherwise, if WINDOW is part of an atomic window, "split" the root of that atomic window. The new window does not become a member of that atomic window.
The selected window and the selected window on WINDOW's frame are not changed by this function.
Probably introduced at or before Emacs version 24.1.
Source Code
;; Defined in /usr/src/emacs/lisp/window.el.gz
(defun split-window (&optional window size side pixelwise refer)
"Make a new window adjacent to WINDOW.
WINDOW must be a valid window and defaults to the selected one.
Return the new window which is always a live window.
Optional argument SIZE a positive number means make WINDOW SIZE
lines or columns tall. If SIZE is negative, make the new window
-SIZE lines or columns tall. If and only if SIZE is non-nil, its
absolute value can be less than `window-min-height' or
`window-min-width'; so this command can make a new window as
small as one line or two columns. SIZE defaults to half of
WINDOW's size.
Optional third argument SIDE nil (or `below') specifies that the
new window shall be located below WINDOW. SIDE `above' means the
new window shall be located above WINDOW. In both cases SIZE
specifies the new number of lines for WINDOW (or the new window
if SIZE is negative) including space reserved for the mode and/or
header line.
SIDE t (or `right') specifies that the new window shall be
located on the right side of WINDOW. SIDE `left' means the new
window shall be located on the left of WINDOW. In both cases
SIZE specifies the new number of columns for WINDOW (or the new
window provided SIZE is negative) including space reserved for
fringes and the scrollbar or a divider column.
For compatibility reasons, SIDE `up' and `down' are interpreted
as `above' and `below'. Any other non-nil value for SIDE is
currently handled like t (or `right').
As a rule, if WINDOW already forms a combination that matches the SIDE
parameter and `window-combination-limit' is nil, reuse WINDOW's parent
in the window tree as parent of the new window. If WINDOW is in a
combination that is orthogonal to the SIDE parameter or if
`window-combination-limit' is non-nil, make a new parent window that
replaces WINDOW in the window tree and make WINDOW and the new window
its sole child windows. This standard behavior can be overridden via
the REFER argument.
PIXELWISE, if non-nil, means to interpret SIZE pixelwise.
If the optional fifth argument REFER is non-nil, it specifies a
reference window used for setting up properties of the new window.
REFER can be either a window or a cons cell of two windows.
If REFER is a cons cell, its car has to specify a deleted, former live
window - a window that has shown a buffer before - on the same frame as
WINDOW. That buffer must be still live. The cdr has to specify a
deleted window that was a parent window on the same frame as WINDOW
before it was deleted. In this case, rather then making new windows,
replace WINDOW with the cdr of REFER in the window tree and make WINDOW
and REFER's car its new child windows. Buffer, start and point
positions of REFER's car are set to the values they had immediately
before REFER's car was deleted the last time. Decorations and
parameters remain unaltered from their values before REFER's car and cdr
were deleted.
Alternatively REFER may specify a deleted, former live window - a window
that has shown a buffer before - on the same frame as WINDOW. In this
case do not make a new window but rather make REFER live again and
insert it into the window tree at the position and with the sizes the
new window would have been given. Buffer, start and point positions of
REFER are set to the values they had immediately before REFER was
deleted the last time. Decorations and parameters remain unaltered from
their values before REFER was deleted. Throw an error if REFER's buffer
has been deleted after REFER itself was deleted.
Otherwise REFER must specify a live window. In this case, the new
window will inherit properties like buffer, start and point position and
some decorations from REFER. If REFER is nil or omitted, then if WINDOW
is live, any such properties are inherited from WINDOW. If, however,
WINDOW is an internal window, the new window will inherit these
properties from the window selected on WINDOW's frame.
If the variable `ignore-window-parameters' is non-nil or the
`split-window' parameter of WINDOW equals t, do not process any
parameters of WINDOW. Otherwise, if the `split-window' parameter of
WINDOW specifies a function, call that function with the three first
arguments WINDOW, SIZE and SIDE and return the value returned by that
function.
Otherwise, if WINDOW is part of an atomic window, \"split\" the root of
that atomic window. The new window does not become a member of that
atomic window.
The selected window and the selected window on WINDOW's frame are not
changed by this function."
(setq window (window-normalize-window window))
(let* ((side (cond
((not side) 'below)
((eq side 'up) 'above)
((eq side 'down) 'below)
((memq side '(below above right left)) side)
(t 'right)))
(horizontal (not (memq side '(below above))))
(frame (window-frame window))
(parent (window-parent window))
(function (window-parameter window 'split-window))
(window-side (window-parameter window 'window-side))
;; Rebind the following two variables since in some cases we
;; have to override their value.
(window-combination-limit window-combination-limit)
(window-combination-resize window-combination-resize)
(char-size (frame-char-size window horizontal))
(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 ignore)
(window--check frame)
(catch 'done
(cond
;; Ignore window parameters if either `ignore-window-parameters'
;; is t or the 'split-window' parameter equals t.
((or ignore-window-parameters (eq function t)))
((functionp function)
;; The 'split-window' parameter specifies the function to call.
;; If that function is `ignore', do nothing.
(throw 'done (funcall function window size side)))
;; If WINDOW is part of an atomic window, split the root window
;; of that atomic window instead.
((and (window-parameter window 'window-atom)
(setq atom-root (window-atom-root window))
(not (eq atom-root window)))
(throw 'done (split-window atom-root size side pixelwise refer)))
;; If WINDOW's frame has a side window and WINDOW specifies the
;; frame's root window, split the frame's main window instead
;; (Bug#73627).
((and (eq window (frame-root-window frame))
(not ignore-window-parameters)
(window-with-parameter 'window-side nil frame))
(throw 'done (split-window (window-main-window frame)
size side pixelwise refer)))
;; If WINDOW is a side window or its first or last child is a
;; side window, throw an error unless `window-combination-resize'
;; equals 'side.
((and (not (eq window-combination-resize 'side))
(window-parameter window 'window-side))
(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.
((and (not (eq window-combination-resize 'side))
(or (and (window-prev-sibling window)
(window-parameter
(window-prev-sibling window) 'window-side))
(and (window-next-sibling window)
(window-parameter
(window-next-sibling window) 'window-side))))
(setq window-combination-limit t)))
;; If `window-combination-resize' is t and SIZE is non-negative,
;; bind `window-combination-limit' to t.
(when (and (eq window-combination-resize t)
pixel-size (> pixel-size 0))
(setq window-combination-limit t))
(let* ((parent-pixel-size
;; 'parent-pixel-size' is the pixel size of WINDOW's
;; parent, provided it has one.
(when parent (window-size parent horizontal t)))
;; 'resize' non-nil means we are supposed to resize other
;; windows in WINDOW's combination.
(resize
(and window-combination-resize
(or (window-parameter window 'window-side)
(not (eq window-combination-resize 'side)))
(not (eq window-combination-limit t))
;; Resize makes sense in iso-combinations only.
(window-combined-p window horizontal)))
;; 'old-pixel-size' is the current pixel size of WINDOW.
(old-pixel-size (window-size window horizontal t))
;; 'new-pixel-size' is the specified or calculated size
;; of the new window.
new-pixel-size new-parent new-normal)
(cond
((not pixel-size)
(setq new-pixel-size
(if resize
;; When resizing try to give the new window the
;; average size of a window in its combination.
(max (min (- parent-pixel-size
(window-min-size parent horizontal nil t))
(window--combination-resizable parent horizontal))
(window-min-pixel-size))
;; Else try to give the new window half the size
;; of WINDOW (plus an eventual odd pixel).
(/ old-pixel-size 2)))
(unless window-resize-pixelwise
;; Round to nearest char-size multiple.
(setq new-pixel-size
(* char-size (round new-pixel-size char-size)))))
((>= pixel-size 0)
;; SIZE non-negative specifies the new size of WINDOW.
;; Note: Specifying a non-negative SIZE is practically
;; always done as workaround for making the new window
;; appear above or on the left of the new window (the
;; ispell window is a typical example of that). In all
;; these cases the SIDE argument should be set to 'above
;; or 'left in order to support the 'resize option.
;; Here we have to nest the windows instead, see above.
(setq new-pixel-size (- old-pixel-size pixel-size)))
(t
;; SIZE negative specifies the size of the new window.
(setq new-pixel-size (- pixel-size))))
;; Check SIZE.
(cond
((not pixel-size)
(cond
(resize
;; SIZE unspecified, resizing.
(unless (or (window-sizable-p
parent (- (+ new-pixel-size divider-width)) horizontal
nil t)
(window-sizable-p
parent (- (+ new-pixel-size divider-width)) horizontal
(setq ignore 'preserved) t))
(error "Window %s too small for splitting" parent)))
((and (> (+ new-pixel-size divider-width
(window-min-size window horizontal nil t))
old-pixel-size)
(> (+ new-pixel-size divider-width
(window-min-size
window horizontal (setq ignore 'preserved) t))
old-pixel-size))
;; SIZE unspecified, no resizing.
(error "Window %s too small for splitting" window))))
((and (>= pixel-size 0)
(or (>= pixel-size old-pixel-size)
(< new-pixel-size
(window-safe-min-pixel-size window horizontal))))
;; 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" window))
(resize
;; SIZE specified, resizing.
(unless (or (window-sizable-p
parent (- (+ new-pixel-size divider-width)) horizontal
nil t)
(window-sizable-p
parent (- (+ new-pixel-size divider-width)) horizontal
(setq ignore 'preserved) t))
;; If we cannot resize the parent give up.
(error "Window %s too small for splitting" 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" window)))
(window--resize-reset frame horizontal)
(setq new-parent
;; Make new-parent non-nil if we need a new parent window;
;; either because we want to nest or because WINDOW is not
;; iso-combined.
(or (eq window-combination-limit t)
(not (window-combined-p window horizontal))))
(setq new-normal
;; Make new-normal the normal size of the new window.
(cond
(pixel-size (/ (float new-pixel-size)
(if new-parent old-pixel-size parent-pixel-size)))
(new-parent 0.5)
(resize (/ 1.0 (1+ (window-combinations parent horizontal t))))
(t (/ (window-normal-size window horizontal) 2.0))))
(if resize
;; Try to get space from OLD's siblings. We could go "up" and
;; try getting additional space from surrounding windows but
;; we won't be able to return space to those windows when we
;; delete the one we create here. Hence we do not go up.
(progn
(window--resize-child-windows
parent (- new-pixel-size) horizontal nil ignore)
(let* ((normal (- 1.0 new-normal))
(sub (window-child parent)))
(while sub
(set-window-new-normal
sub (* (window-normal-size sub horizontal) normal))
(setq sub (window-right sub)))))
;; Get entire space from WINDOW.
(set-window-new-pixel
window (- old-pixel-size new-pixel-size))
(window--resize-this-window
window (- new-pixel-size) horizontal ignore)
(set-window-new-normal
window (- (if new-parent 1.0 (window-normal-size window horizontal))
new-normal)))
(unless horizontal
(let ((quit-restore (window-parameter window 'quit-restore)))
(when quit-restore
(let ((quad (nth 1 quit-restore)))
(when (and (listp quad) (integerp (nth 3 quad)))
;; When WINDOW has a 'quit-restore' parameter that
;; specifies a previous height to restore, remove that
;; - it does more harm than good now (Bug#78835).
(setf (nth 3 quad) nil))))))
(let ((new (split-window-internal
window new-pixel-size side new-normal refer)))
(window--pixel-to-total frame horizontal)
;; Assign window-side parameters, if any.
(cond
((eq window-combination-resize 'side)
(let ((window-side
(cond
(window-side window-side)
((eq side 'above) 'top)
((eq side 'below) 'bottom)
(t side))))
;; We made a new side window.
(set-window-parameter new 'window-side window-side)
(when (and new-parent (window-parameter window 'window-side))
;; We've been splitting a side root window. Give the
;; new parent the same window-side parameter.
(set-window-parameter
(window-parent new) 'window-side window-side))))
((eq window-combination-resize 'atom)
;; Make sure `window--check' won't destroy an existing
;; atomic window in case the new window gets nested inside.
(unless (window-parameter window 'window-atom)
(set-window-parameter window 'window-atom t))
(when new-parent
(set-window-parameter (window-parent new) 'window-atom t))
(set-window-parameter new 'window-atom t)))
;; Make the new window inherit the `min-margins' parameter of
;; WINDOW (Bug#44483).
(let ((min-margins (window-parameter window 'min-margins)))
(when min-margins
(set-window-parameter new 'min-margins min-margins)))
;; Sanitize sizes unless SIZE was specified.
(unless size
(window--sanitize-window-sizes horizontal))
(run-window-scroll-functions new)
(window--check frame)
;; Always return the new window.
new)))))