Subject: Re: bug#51007: 27.2; emacs hangs when using window-toggle-side-windows

From: martin rudalics <[email-masked]>
Date: Sun, 10 Oct 2021 19:16:38 +0200

Indrajeet

I think I have fixed this here.  Basically, the bug totally breaks the
behavior with -nw but only partially breaks the gui behavior.  In the
latter case, parts of the window structure are corrupted but apparently
these do not substantially inhibit working with Emacs here.  It's not
excluded though, that the NS port fails in the gui case as well.

I attach two fixes for this:

- window.c.diff is the one I intend to install on Emacs 28 soon.

- window-27.diff is one you can install for Emacs 27 provided you are
   able to build Emacs on your system.  It includes the window.el patch
   which is already on Emacs 28.  If you can't build Emacs yourself, I'm
   afraid you have to wait for the new release.

Good luck and many thanks for the forensics, martin
diff --git a/src/window.c b/src/window.c
index a6e8ee0d53..150c717ce8 100644
--- a/src/window.c
+++ b/src/window.c
@@ -3194,8 +3194,10 @@ DEFUN ("delete-other-windows-internal", Fdelete_other_windows_internal,
 window-start value is reasonable when this function is called.  */)
      (Lisp_Object window, Lisp_Object root)
 {
-  struct window *w, *r, *s;
-  struct frame *f;
+  struct window *w = decode_valid_window (window);
+  struct window *r, *s;
+  Lisp_Object frame = w->frame;
+  struct frame *f = XFRAME (frame);
   Lisp_Object sibling, pwindow, delta;
   Lisp_Object swindow UNINIT;
   ptrdiff_t startpos UNINIT, startbyte UNINIT;
@@ -3203,9 +3205,7 @@ DEFUN ("delete-other-windows-internal", Fdelete_other_windows_internal,
   int new_top;
   bool resize_failed = false;

-  w = decode_valid_window (window);
   XSETWINDOW (window, w);
-  f = XFRAME (w->frame);

   if (NILP (root))
     /* ROOT is the frame's root window.  */
@@ -3245,7 +3245,7 @@ DEFUN ("delete-other-windows-internal", Fdelete_other_windows_internal,
       /* Make sure WINDOW is the frame's selected window.  */
       if (!EQ (window, FRAME_SELECTED_WINDOW (f)))
 	{
-	  if (EQ (selected_frame, w->frame))
+	  if (EQ (selected_frame, frame))
 	    Fselect_window (window, Qnil);
 	  else
 	    /* Do not clear f->select_mini_window_flag here.  If the
@@ -3278,7 +3278,7 @@ DEFUN ("delete-other-windows-internal", Fdelete_other_windows_internal,

       if (!EQ (swindow, FRAME_SELECTED_WINDOW (f)))
 	{
-	  if (EQ (selected_frame, w->frame))
+	  if (EQ (selected_frame, frame))
 	    Fselect_window (swindow, Qnil);
 	  else
 	    fset_selected_window (f, swindow);
@@ -3313,18 +3313,12 @@ DEFUN ("delete-other-windows-internal", Fdelete_other_windows_internal,
       w->top_line = r->top_line;
       resize_root_window (window, delta, Qnil, Qnil, Qt);
       if (window_resize_check (w, false))
-	{
-	  window_resize_apply (w, false);
-	  window_pixel_to_total (w->frame, Qnil);
-	}
+	window_resize_apply (w, false);
       else
 	{
 	  resize_root_window (window, delta, Qnil, Qt, Qt);
 	  if (window_resize_check (w, false))
-	    {
-	      window_resize_apply (w, false);
-	      window_pixel_to_total (w->frame, Qnil);
-	    }
+	    window_resize_apply (w, false);
 	  else
 	    resize_failed = true;
 	}
@@ -3337,18 +3331,12 @@ DEFUN ("delete-other-windows-internal", Fdelete_other_windows_internal,
 	  XSETINT (delta, r->pixel_width - w->pixel_width);
 	  resize_root_window (window, delta, Qt, Qnil, Qt);
 	  if (window_resize_check (w, true))
-	    {
-	      window_resize_apply (w, true);
-	      window_pixel_to_total (w->frame, Qt);
-	    }
+	    window_resize_apply (w, true);
 	  else
 	    {
 	      resize_root_window (window, delta, Qt, Qt, Qt);
 	      if (window_resize_check (w, true))
-		{
-		  window_resize_apply (w, true);
-		  window_pixel_to_total (w->frame, Qt);
-		}
+		window_resize_apply (w, true);
 	      else
 		resize_failed = true;
 	    }
@@ -3390,6 +3378,12 @@ DEFUN ("delete-other-windows-internal", Fdelete_other_windows_internal,
     }

   replace_window (root, window, true);
+  /* Assign new total sizes to all windows on FRAME.  We can't do that
+     _before_ WINDOW replaces ROOT since 'window--pixel-to-total' works
+     on the whole frame and thus would work on the frame's old window
+     configuration (Bug#51007).  */
+  window_pixel_to_total (frame, Qnil);
+  window_pixel_to_total (frame, Qt);

   /* This must become SWINDOW anyway .......  */
   if (BUFFERP (w->contents) && !resize_failed)
diff --git a/lisp/window.el b/lisp/window.el
index 95db01bca4..b844e8d17a 100644
--- a/lisp/window.el
+++ b/lisp/window.el
@@ -1192,7 +1192,8 @@ window-toggle-side-windows
      ((setq state (frame-parameter frame 'window-state))
       ;; A window state was saved for FRAME.  Restore it and put the
       ;; current root window into its main window.
-      (let ((main-state (window-state-get (frame-root-window frame))))
+      (let ((window-combination-resize t)
+            (main-state (window-state-get (frame-root-window frame))))
         (window-state-put state (frame-root-window frame) t)
         (window-state-put main-state (window-main-window frame)))
       (window--sides-reverse-frame frame))
diff --git a/src/window.c b/src/window.c
index f231187f7b..71c0d91ab2 100644
--- a/src/window.c
+++ b/src/window.c
@@ -3296,7 +3296,7 @@ DEFUN ("delete-other-windows-internal", Fdelete_other_windows_internal,
       if (window_resize_check (w, false))
 	{
 	  window_resize_apply (w, false);
-	  window_pixel_to_total (w->frame, Qnil);
+/** 	  window_pixel_to_total (w->frame, Qnil); **/
 	}
       else
 	{
@@ -3304,7 +3304,7 @@ DEFUN ("delete-other-windows-internal", Fdelete_other_windows_internal,
 	  if (window_resize_check (w, false))
 	    {
 	      window_resize_apply (w, false);
-	      window_pixel_to_total (w->frame, Qnil);
+/** 	      window_pixel_to_total (w->frame, Qnil); **/
 	    }
 	  else
 	    resize_failed = true;
@@ -3320,7 +3320,7 @@ DEFUN ("delete-other-windows-internal", Fdelete_other_windows_internal,
 	  if (window_resize_check (w, true))
 	    {
 	      window_resize_apply (w, true);
-	      window_pixel_to_total (w->frame, Qt);
+/** 	      window_pixel_to_total (w->frame, Qt); **/
 	    }
 	  else
 	    {
@@ -3328,7 +3328,7 @@ DEFUN ("delete-other-windows-internal", Fdelete_other_windows_internal,
 	      if (window_resize_check (w, true))
 		{
 		  window_resize_apply (w, true);
-		  window_pixel_to_total (w->frame, Qt);
+/** 		  window_pixel_to_total (w->frame, Qt); **/
 		}
 	      else
 		resize_failed = true;
@@ -3371,6 +3371,8 @@ DEFUN ("delete-other-windows-internal", Fdelete_other_windows_internal,
     }

   replace_window (root, window, true);
+  window_pixel_to_total (w->frame, Qnil);
+  window_pixel_to_total (w->frame, Qt);

   /* This must become SWINDOW anyway .......  */
   if (BUFFERP (w->contents) && !resize_failed)