Function: split-window-internal
split-window-internal is a function defined in window.c.
Signature
(split-window-internal OLD PIXEL-SIZE SIDE NORMAL-SIZE &optional REFER)
Documentation
Split window OLD.
Second argument PIXEL-SIZE specifies the number of pixels of the new window. It must be a positive integer.
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 PIXEL-SIZE specifies the pixel
height of the new window including space reserved for the mode and/or
header/tab 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 PIXEL-SIZE specifies the
width of the new window including space reserved for fringes and the
scroll bar or a divider column.
Fourth argument NORMAL-SIZE specifies the normal size of the new window
according to the SIDE argument. Optional fifth argument REFER is as for
'split-window'.
The new pixel and normal sizes of all involved windows must have been
set correctly. See the code of split-window for how this is done.
Source Code
// Defined in /usr/src/emacs/src/window.c
// Skipping highlighting due to helpful-max-highlight.
{
/* OLD (*o) is the window to split. REFER (*r) is a reference window,
either an arbitrary live window or a former live, now deleted
window on the same frame as OLD. NEW (*n) is the new window
created anew or resurrected from REFER (*r), if specified. *p
refers either to OLD's parent window that will become NEW's parent
window too or to a new internal window that becomes OLD's and NEW's
new parent. */
struct window *o = decode_valid_window (old);
Lisp_Object frame = WINDOW_FRAME (o);
struct frame *f = XFRAME (frame);
struct window *p, *n, *r, *c;
bool horflag
/* HORFLAG is true when we split side-by-side, false otherwise. */
= EQ (side, Qt) || EQ (side, Qleft) || EQ (side, Qright);
Lisp_Object new, parent = Qnil;
bool dead = false;
CHECK_FIXNUM (pixel_size);
EMACS_INT total_size
= XFIXNUM (pixel_size) / (horflag
? FRAME_COLUMN_WIDTH (f)
: FRAME_LINE_HEIGHT (f));
/* Set combination_limit if we have to make a new parent window.
We do that if either `window-combination-limit' is t, or OLD has no
parent, or OLD is ortho-combined. */
bool combination_limit
= (EQ (Vwindow_combination_limit, Qt)
|| NILP (o->parent)
|| (horflag
? WINDOW_VERTICAL_COMBINATION_P (XWINDOW (o->parent))
: WINDOW_HORIZONTAL_COMBINATION_P (XWINDOW (o->parent))));
/* Set up reference window. */
if (NILP (refer))
{
if (WINDOW_LIVE_P (old))
/* OLD is live, use it as reference window. */
refer = old;
else
/* Use the frame's selected window as reference window. */
refer = FRAME_SELECTED_WINDOW (f);
r = XWINDOW (refer);
}
else if (CONSP (refer))
{
/* If REFER is a cons, then its car must be a deleted, former live
window and its cdr must be a deleted former parent window. Set
PARENT to the cdr of REFER and REFER to its car. WINDOW and
REFER end up as the sole children of PARENT which replaces
WINDOW in the window tree. As a special case, if REFER's cdr
is t, reuse REFER's car's old parent as new parent provided it
is a deleted former parent window. */
parent = Fcdr (refer);
refer = Fcar (refer);
r = decode_any_window (refer);
if (!NILP (r->contents) || !BUFFERP (r->old_buffer))
error ("REFER's car must specify a deleted, former live window");
else if (!BUFFER_LIVE_P (XBUFFER (r->old_buffer)))
error ("The buffer formerly shown by REFER's car has been killed");
else if (!EQ (r->frame, frame))
error ("REFER's car must specify a window on same frame as WINDOW");
if (EQ (parent, Qt))
/* If REFER's cdr is t, use the old parent of REFER's car as new
parent. */
parent = r->parent;
p = decode_any_window (parent);
if (!NILP (p->contents) || BUFFERP (p->old_buffer))
error ("REFER's cdr must specify a deleted, former parent window");
else if (!EQ (p->frame, frame))
error ("REFER's cdr must specify window on same frame as WINDOW");
dead = true;
}
else
{
r = decode_any_window (refer);
if (NILP (r->contents))
/* Presumably a deleted, former live window. Check whether its
contents can be used. */
{
if (!BUFFERP (r->old_buffer))
error ("REFER must specify a former live window (must have shown a buffer)");
else if (!BUFFER_LIVE_P (XBUFFER (r->old_buffer)))
error ("The buffer formerly shown by REFER has been killed");
else if (!EQ (r->frame, frame))
error ("REFER must specify a window on same frame as WINDOW");
dead = true;
}
else if (!NILP (parent))
error ("If REFER is a cons, its car must not specify a live window");
else if (!WINDOW_LIVE_P (refer))
error ("REFER is not a live window (does not show a buffer)");
}
/* The following bugs are caught by `split-window'. */
if (MINI_WINDOW_P (o))
error ("Attempt to split minibuffer window");
else if (total_size < (horflag ? 2 : 1))
error ("Size of new window too small (after split)");
else if (!combination_limit && !NILP (Vwindow_combination_resize))
/* `window-combination-resize' non-nil means try to resize OLD's siblings
proportionally. */
{
struct window *op = XWINDOW (o->parent);
/* Temporarily pretend we split the parent window. */
wset_new_pixel
(op, make_fixnum ((horflag ? op->pixel_width : op->pixel_height)
- XFIXNUM (pixel_size)));
if (!window_resize_check (op, horflag))
error ("Window sizes don't fit");
else
/* Undo the temporary pretension. */
wset_new_pixel
(op, make_fixnum (horflag ? op->pixel_width : op->pixel_height));
}
else
{
if (!window_resize_check (o, horflag))
error ("Resizing old window failed");
else if (XFIXNUM (pixel_size) + XFIXNUM (o->new_pixel)
!= (horflag ? o->pixel_width : o->pixel_height))
error ("Sum of sizes of old and new window don't fit");
}
/* This is our point of no return. */
if (combination_limit)
{
/* Save the old value of o->normal_cols/lines. It gets corrupted
by make_parent_window and we need it below for assigning it to
p->new_normal. */
Lisp_Object new_normal
= horflag ? o->normal_cols : o->normal_lines;
if (NILP (parent))
{
parent = make_parent_window (frame);
p = XWINDOW (parent);
}
else
/* Pacify GCC. */
p = XWINDOW (parent);
replace_window (old, parent, true);
wset_next (o, Qnil);
wset_prev (o, Qnil);
wset_parent (o, parent);
wset_combination (p, horflag, old);
if (EQ (Vwindow_combination_limit, Qt))
/* Store t in the new parent's combination_limit slot to avoid
that its children get merged into another window. */
wset_combination_limit (p, Qt);
/* These get applied below. */
wset_new_pixel
(p, make_fixnum (horflag ? o->pixel_width : o->pixel_height));
wset_new_total
(p, make_fixnum (horflag ? o->total_cols : o->total_lines));
wset_new_normal (p, new_normal);
}
else
p = XWINDOW (o->parent);
fset_redisplay (f);
if (dead)
new = refer;
else
new = make_window ();
n = XWINDOW (new);
wset_frame (n, frame);
wset_parent (n, o->parent);
if (EQ (side, Qabove) || EQ (side, Qleft))
{
wset_prev (n, o->prev);
if (NILP (n->prev))
wset_combination (p, horflag, new);
else
wset_next (XWINDOW (n->prev), new);
wset_next (n, old);
wset_prev (o, new);
}
else
{
wset_next (n, o->next);
if (!NILP (n->next))
wset_prev (XWINDOW (n->next), new);
wset_prev (n, old);
wset_next (o, new);
}
n->window_end_valid = false;
n->last_cursor_vpos = 0;
if (!dead)
{
/* Get special geometry settings from reference window. */
n->left_margin_cols = r->left_margin_cols;
n->right_margin_cols = r->right_margin_cols;
n->left_fringe_width = r->left_fringe_width;
n->right_fringe_width = r->right_fringe_width;
n->fringes_outside_margins = r->fringes_outside_margins;
n->scroll_bar_width = r->scroll_bar_width;
n->scroll_bar_height = r->scroll_bar_height;
wset_vertical_scroll_bar_type (n, r->vertical_scroll_bar_type);
wset_horizontal_scroll_bar_type (n, r->horizontal_scroll_bar_type);
}
/* Directly assign orthogonal coordinates and sizes. */
if (horflag)
{
n->pixel_top = o->pixel_top;
n->top_line = o->top_line;
n->pixel_height = o->pixel_height;
n->total_lines = o->total_lines;
}
else
{
n->pixel_left = o->pixel_left;
n->left_col = o->left_col;
n->pixel_width = o->pixel_width;
n->total_cols = o->total_cols;
}
/* Iso-coordinates and sizes are assigned by window_resize_apply,
get them ready here. */
wset_new_pixel (n, pixel_size);
EMACS_INT sum = 0;
c = XWINDOW (p->contents);
while (c)
{
if (c != n)
sum = sum + XFIXNUM (c->new_total);
c = NILP (c->next) ? 0 : XWINDOW (c->next);
}
wset_new_total (n, make_fixnum ((horflag
? p->total_cols
: p->total_lines)
- sum));
wset_new_normal (n, normal_size);
block_input ();
if (dead)
{
/* Get dead window back its old buffer and markers. */
wset_buffer (n, n->old_buffer);
set_marker_restricted
(n->start, make_fixnum (XMARKER (n->start)->charpos), n->contents);
set_marker_restricted
(n->pointm, make_fixnum (XMARKER (n->pointm)->charpos), n->contents);
set_marker_restricted
(n->old_pointm, make_fixnum (XMARKER (n->old_pointm)->charpos),
n->contents);
Vwindow_list = Qnil;
/* Remove window from the table of dead windows. */
Fremhash (make_fixnum (n->sequence_number),
window_dead_windows_table);
}
window_resize_apply (p, horflag);
adjust_frame_glyphs (f);
set_window_buffer (new, r->contents, true, true);
FRAME_WINDOW_CHANGE (f) = true;
unblock_input ();
return new;
}