unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
From: martin rudalics <rudalics@gmx.at>
To: Eli Zaretskii <eliz@gnu.org>
Cc: pranshusharma366@gmail.com, emacs-devel@gnu.org
Subject: Re: Add function to rotate/transpose all windows
Date: Fri, 27 Sep 2024 19:29:21 +0200	[thread overview]
Message-ID: <3d4546ac-70d9-4865-b42d-0dc50cb0f3a7@gmx.at> (raw)
In-Reply-To: <86o74aa41b.fsf@gnu.org>

[-- Attachment #1: Type: text/plain, Size: 831 bytes --]

 > This doc string needs to be more detailed in what it means to "put the
 > window object of DEAD in the place of LIVE".  For example, it
 > currently keeps silent about what happens to LIVE after the call.

The fact that LIVE existed at all was a misfeature.  I now put the dead
window right into the new window created by 'split-window' with the help
of a new argument.  Patch attached.  Tested with

(let ((dead (split-window nil nil t)))
   (set-window-buffer dead "*Messages*")
   (message "%s" (next-window))
   (sit-for 2)
   (delete-window dead)
   (let ((live (split-window nil nil nil nil dead)))
     (message "%s" (next-window))))

 > Finally, this needs to be documented in the ELisp manual and called
 > out in NEWS.

Sure.  I'll wait until the OP approves the concept and was able to make
use of it.

Thanks, martin

[-- Attachment #2: resurrect.diff --]
[-- Type: text/x-patch, Size: 12834 bytes --]

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;
 

  reply	other threads:[~2024-09-27 17:29 UTC|newest]

Thread overview: 36+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-09-24 13:45 Add function to rotate/transpose all windows pranshu sharma
2024-09-24 13:53 ` Eli Zaretskii
2024-09-25  8:05   ` martin rudalics
2024-09-25  8:34     ` pranshu sharma
2024-09-25  9:31       ` martin rudalics
2024-09-25 10:50         ` pranshu sharma
2024-09-25 13:53           ` martin rudalics
2024-09-25 15:31             ` pranshu sharma
2024-09-26 14:10       ` martin rudalics
2024-09-26 14:22         ` Eli Zaretskii
2024-09-27 17:29           ` martin rudalics [this message]
2024-09-28  7:52             ` pranshu sharma
2024-09-28  9:26               ` martin rudalics
2024-09-28 10:53                 ` pranshu sharma
2024-09-28 14:48                   ` martin rudalics
2024-09-29  7:36                     ` pranshu sharma
2024-09-29  8:40                       ` martin rudalics
2024-09-29  9:23                         ` pranshu sharma
2024-09-29 14:48                           ` martin rudalics
2024-09-30  6:29                             ` pranshu sharma
2024-09-30  8:57                               ` martin rudalics
2024-09-28  7:58             ` pranshu sharma
2024-09-28  8:18             ` Eli Zaretskii
2024-09-28  9:40               ` martin rudalics
2024-09-28 11:35                 ` Eli Zaretskii
2024-09-28 14:58                   ` martin rudalics
2024-09-28 15:28                     ` Eli Zaretskii
2024-09-28 13:22                 ` pranshu sharma
2024-09-28 14:21                   ` Eli Zaretskii
2024-09-28 14:49                   ` martin rudalics
2024-09-27 10:06         ` pranshu sharma
2024-09-27 17:29           ` martin rudalics
2024-09-24 17:40 ` Petteri Hintsanen
2024-09-24 19:34 ` Charles Choi
2024-09-25  2:00   ` Emanuel Berg
2024-09-25  7:00   ` pranshu sharma

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=3d4546ac-70d9-4865-b42d-0dc50cb0f3a7@gmx.at \
    --to=rudalics@gmx.at \
    --cc=eliz@gnu.org \
    --cc=emacs-devel@gnu.org \
    --cc=pranshusharma366@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).