diff --git a/lisp/window.el b/lisp/window.el index 07ea9584908..b96a7863a72 100644 --- a/lisp/window.el +++ b/lisp/window.el @@ -5509,7 +5509,7 @@ window--combination-resizable (setq sibling (window-next-sibling sibling))) (/ size (1+ number)))) -(defun split-window (&optional window size side pixelwise) +(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. @@ -5552,11 +5552,21 @@ split-window root of that atomic window. The new window does not become a member of that atomic window. -If WINDOW is live, properties of the new window like margins and -scrollbars are inherited from WINDOW. If WINDOW is an internal -window, these properties as well as the buffer displayed in the -new window are inherited from the window selected on WINDOW's -frame. The selected window is not changed by this function." +If the optional fifth argument REFER is non-nil, it has to denote a +dead, former live window on the same frame as OLD or an arbitrary live +window. In the first case, REFER will become the new window with +properties like buffer, start and point, decorations and parameters as +to the last time when it was live. In the latter case the new window +will inherit properties like buffer, start and point, decorations and +parameters 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. + +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) @@ -5596,7 +5606,7 @@ split-window ((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))) + (throw 'done (split-window atom-root 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. @@ -5635,8 +5645,8 @@ split-window (window-combined-p window horizontal))) ;; 'old-pixel-size' is the current pixel size of WINDOW. (old-pixel-size (window-size window horizontal t)) - ;; 'new-size' is the specified or calculated size of the - ;; new window. + ;; 'new-pixel-size' is the specified or calculated size + ;; of the new window. new-pixel-size new-parent new-normal) (cond ((not pixel-size) @@ -5757,8 +5767,9 @@ split-window window (- (if new-parent 1.0 (window-normal-size window horizontal)) new-normal))) - (let* ((new (split-window-internal window new-pixel-size side new-normal))) - (window--pixel-to-total frame horizontal) + (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) diff --git a/src/window.c b/src/window.c index 34968ac824f..402bb0459e3 100644 --- a/src/window.c +++ b/src/window.c @@ -5073,7 +5073,7 @@ resize_frame_windows (struct frame *f, int size, bool horflag) } -DEFUN ("split-window-internal", Fsplit_window_internal, Ssplit_window_internal, 4, 4, 0, +DEFUN ("split-window-internal", Fsplit_window_internal, Ssplit_window_internal, 4, 5, 0, doc: /* Split window OLD. Second argument PIXEL-SIZE specifies the number of pixels of the new window. It must be a positive integer. @@ -5088,32 +5088,30 @@ DEFUN ("split-window-internal", Fsplit_window_internal, Ssplit_window_internal, 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 -scrollbar or a divider column. +scroll bar or a divider column. Fourth argument NORMAL-SIZE specifies the normal size of the new window -according to the SIDE argument. +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. */) - (Lisp_Object old, Lisp_Object pixel_size, Lisp_Object side, Lisp_Object normal_size) + (Lisp_Object old, Lisp_Object pixel_size, Lisp_Object side, Lisp_Object normal_size, + Lisp_Object refer) { /* OLD (*o) is the window we have to split. (*p) is either OLD's parent window or an internal window we have to install as OLD's new - parent. REFERENCE (*r) must denote a live window, or is set to OLD - provided OLD is a leaf window, or to the frame's selected window. - NEW (*n) is the new window created with some parameters taken from - REFERENCE (*r). */ - Lisp_Object new, frame, reference; - struct window *o, *p, *n, *r, *c; - struct frame *f; + parent. NEW (*n) is the new window created or adopted with + properties from REFER (*r), if specified. */ + 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); - - CHECK_WINDOW (old); - o = XWINDOW (old); - frame = WINDOW_FRAME (o); - f = XFRAME (frame); + Lisp_Object new; + bool dead = false; CHECK_FIXNUM (pixel_size); EMACS_INT total_size @@ -5131,14 +5129,38 @@ DEFUN ("split-window-internal", Fsplit_window_internal, Ssplit_window_internal, ? WINDOW_VERTICAL_COMBINATION_P (XWINDOW (o->parent)) : WINDOW_HORIZONTAL_COMBINATION_P (XWINDOW (o->parent)))); - /* We need a live reference window to initialize some parameters. */ - if (WINDOW_LIVE_P (old)) - /* OLD is live, use it as reference window. */ - reference = old; + /* 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 - /* Use the frame's selected window as reference window. */ - reference = FRAME_SELECTED_WINDOW (f); - r = XWINDOW (reference); + { + r = decode_any_window (refer); + + if (NILP (r->contents)) + /* Presumably a dead, former live window. Check whether its + content can be used. */ + { + if (!BUFFERP (r->old_buffer)) + error ("Dead reference window was not a live window"); + else if (!BUFFER_LIVE_P (XBUFFER (r->old_buffer))) + error ("Dead reference window's old buffer is dead"); + else if (!EQ (r->frame, frame)) + error ("Dead referenec window was on other frame"); + + dead = true; + } + else if (!WINDOW_LIVE_P (refer)) + error ("Reference window must not be internal"); + } /* The following bugs are caught by `split-window'. */ if (MINI_WINDOW_P (o)) @@ -5195,7 +5217,12 @@ DEFUN ("split-window-internal", Fsplit_window_internal, Ssplit_window_internal, p = XWINDOW (o->parent); fset_redisplay (f); - new = make_window (); + + if (dead) + new = refer; + else + new = make_window (); + n = XWINDOW (new); wset_frame (n, frame); wset_parent (n, o->parent); @@ -5219,19 +5246,22 @@ DEFUN ("split-window-internal", Fsplit_window_internal, Ssplit_window_internal, wset_next (o, new); } - n->window_end_valid = false; - n->last_cursor_vpos = 0; + if (!dead) + { + n->window_end_valid = false; + n->last_cursor_vpos = 0; - /* 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); + /* 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) @@ -5267,10 +5297,44 @@ DEFUN ("split-window-internal", Fsplit_window_internal, Ssplit_window_internal, 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); + Fset_marker (n->start, make_fixnum (n->del_start), n->contents); + Fset_marker (n->pointm, make_fixnum (n->del_pointm), n->contents); + Vwindow_list = Qnil; + } + else + { + /* Note: n->contents is Qnil throughout this call, so n will be + neither considered a leaf nor an internal window. */ + Lisp_Object buffer = r->contents; + struct buffer *b = XBUFFER (buffer); + + /* Provisorially set new's buffer to that of the reference window, + resize the parent, reset new's buffer to nil and do the real + set_window_buffer. */ + wset_buffer (n, buffer); + set_marker_both (n->pointm, buffer, BUF_PT (b), BUF_PT_BYTE (b)); + set_marker_restricted + (n->start, make_fixnum (b->last_window_start), buffer); + } + window_resize_apply (p, horflag); + + if (!dead) + { + /* Set buffer of NEW to buffer of reference window. We have to do it + here so the sizes of NEW are in place. But be sure to do it before + adjusting the frame glyphs - otherwise Emacs may inexplicably loop + forever. */ + wset_buffer (n, Qnil); + set_window_buffer (new, r->contents, true, true); + } + adjust_frame_glyphs (f); - /* Set buffer of NEW to buffer of reference window. */ - set_window_buffer (new, r->contents, true, true); FRAME_WINDOW_CHANGE (f) = true; unblock_input (); @@ -5368,10 +5432,16 @@ DEFUN ("delete-window-internal", Fdelete_window_internal, Sdelete_window_interna } else { + if (MARKERP (w->pointm)) + w->del_pointm = marker_position (w->pointm); + if (MARKERP (w->start)) + w->del_start = marker_position (w->start); + unshow_buffer (w); unchain_marker (XMARKER (w->pointm)); unchain_marker (XMARKER (w->old_pointm)); unchain_marker (XMARKER (w->start)); + wset_old_buffer (w, w->contents); wset_buffer (w, Qnil); /* Add WINDOW to table of dead windows so when killing a buffer WINDOW mentions, all references to that buffer can be removed @@ -7712,6 +7782,11 @@ delete_all_child_windows (Lisp_Object window) } else if (BUFFERP (w->contents)) { + if (MARKERP (w->pointm)) + w->del_pointm = marker_position (w->pointm); + if (MARKERP (w->start)) + w->del_start = marker_position (w->start); + unshow_buffer (w); unchain_marker (XMARKER (w->pointm)); unchain_marker (XMARKER (w->old_pointm)); @@ -7720,6 +7795,7 @@ delete_all_child_windows (Lisp_Object window) only, we use this slot to save the buffer for the sake of possible resurrection in Fset_window_configuration. */ wset_combination_limit (w, w->contents); + wset_old_buffer (w, w->contents); wset_buffer (w, Qnil); /* Add WINDOW to table of dead windows so when killing a buffer WINDOW mentions, all references to that buffer can be removed diff --git a/src/window.h b/src/window.h index 335e0a3453e..41ee7f6dc18 100644 --- a/src/window.h +++ b/src/window.h @@ -264,6 +264,10 @@ #define WINDOW_H_INCLUDED int total_cols; int total_lines; + /* Positions of pointm and start when window was deleted. */ + ptrdiff_t del_pointm; + ptrdiff_t del_start; + /* Number of columns display within the window is scrolled to the left. */ ptrdiff_t hscroll;