diff --git a/src/window.c b/src/window.c index 34968ac824f..312619737f3 100644 --- a/src/window.c +++ b/src/window.c @@ -5368,10 +5368,14 @@ DEFUN ("delete-window-internal", Fdelete_window_internal, Sdelete_window_interna } else { + w->del_pointm = marker_position (w->pointm); + 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 @@ -5437,6 +5441,97 @@ DEFUN ("delete-window-internal", Fdelete_window_internal, Sdelete_window_interna return Qnil; } + + +DEFUN ("resurrect-window", Fresurrect_window, Sresurrect_window, 2, 2, 0, + doc: /* Resurrect dead window DEAD in lieu of live window LIVE. +DEAD must denote a dead window that was a live window before it was +deleted. LIVE must denote a live window. Put the window object of DEAD +in the place of LIVE such that the resulting window inherits LIVE's +geometric properties and its position within the window tree while all +other properties including the buffer and its positions, decorations and +parameters are inherited from DEAD. + +DEAD must have been on the same frame as LIVE and its old buffer must be +still live. If LIVE was selected or its frame's selected window, select +DEAD or make it its frame's selected window instead. */) + (Lisp_Object dead, Lisp_Object live) +{ + struct window *l = decode_live_window (live); + struct window *d = decode_any_window (dead); + Lisp_Object frame = WINDOW_FRAME (l); + struct frame *f = XFRAME (frame); + Lisp_Object tem; + bool selected = EQ (live, selected_window); + bool frame_selected = EQ (live, f->selected_window); + + if (!NILP (d->contents)) + error ("Attempt to resurrect undead window"); + else if (!BUFFERP (d->old_buffer)) + error ("Dead window has no old buffer"); + else if (!BUFFER_LIVE_P (XBUFFER (d->old_buffer))) + error ("Dead window's old buffer is dead"); + else if (!EQ (l->frame, d->frame)) + error ("Live and dead widows must be on same frame"); + + block_input (); + + /* Copy links and geometry of LIVE into DEAD. */ + memcpy (&d->next, &l->next, + offsetof (struct window, contents) + - offsetof (struct window, next)); + memcpy (&d->pixel_left, &l->pixel_left, + offsetof (struct window, hscroll) + - offsetof (struct window, pixel_left)); + + /* Replace LIVE in window tree with DEAD. */ + if (!NILP (d->next)) + wset_prev (XWINDOW (d->next), dead); + + if (!NILP (d->prev)) + wset_next (XWINDOW (d->prev), dead); + + tem = d->parent; + if (!NILP (tem) && EQ (XWINDOW (tem)->contents, live)) + wset_combination (XWINDOW (tem), XWINDOW (tem)->horizontal, dead); + + /* Get DEAD back its old buffer and markers. */ + wset_buffer (d, d->old_buffer); + Fset_marker (d->start, make_fixnum (d->del_start), d->contents); + Fset_marker (d->pointm, make_fixnum (d->del_pointm), d->contents); + + /* Deal with LIVE. */ + wset_next (l, Qnil); /* Don't delete l->next too. */ + free_window_matrices (l); + l->del_pointm = marker_position (l->pointm); + l->del_start = marker_position (l->start); + unshow_buffer (l); + unchain_marker (XMARKER (l->pointm)); + unchain_marker (XMARKER (l->old_pointm)); + unchain_marker (XMARKER (l->start)); + wset_old_buffer (l, l->contents); + wset_buffer (l, Qnil); + /* Add WINDOW to table of dead windows so when killing a buffer WINDOW + mentions, all references to that buffer can be removed and the + buffer be collected. */ + Fputhash (make_fixnum (l->sequence_number), + live, window_dead_windows_table); + + /* Selection status. */ + if (selected) + Fselect_window (dead, Qt); + else if (frame_selected) + fset_selected_window (f, dead); + + /* Tell redisplay. */ + fset_redisplay (f); + Vwindow_list = Qnil; + adjust_frame_glyphs (f); + unblock_input (); + FRAME_WINDOW_CHANGE (f) = true; + + return Qnil; +} /*********************************************************************** Resizing Mini-Windows @@ -7712,6 +7807,9 @@ delete_all_child_windows (Lisp_Object window) } else if (BUFFERP (w->contents)) { + w->del_pointm = marker_position (w->pointm); + w->del_start = marker_position (w->start); + unshow_buffer (w); unchain_marker (XMARKER (w->pointm)); unchain_marker (XMARKER (w->old_pointm)); @@ -7720,6 +7818,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 @@ -9146,6 +9245,7 @@ syms_of_window (void) defsubr (&Sget_buffer_window); defsubr (&Sdelete_other_windows_internal); defsubr (&Sdelete_window_internal); + defsubr (&Sresurrect_window); defsubr (&Sresize_mini_window_internal); defsubr (&Sset_window_buffer); defsubr (&Srun_window_configuration_change_hook); 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;