Subject: Re: bug#19576: write-file writes the wrong buffer

From: Eli Zaretskii <[email-masked]>
Date: Wed, 18 Nov 2015 19:45:03 +0200

> Date: Tue, 17 Nov 2015 20:02:04 +0000
> From: Alan Mackenzie <[email-masked]>
> Cc: [email-masked]
> 
> On Tue, Nov 17, 2015 at 02:55:39AM +0200, Juri Linkov wrote:
> > >> Conceptually it should be easy to do that.  Save/restore current buffer,
> > >> selected window and frame.  But Alan (concerned about ‘follow-mode’),
> > >> Pip (who unfortunately disappeared) and Eli are currently discussing how
> > >> to fix ‘window-size-change-functions’ in various other ways as well.
> 
> I have a fix for the `window-size-change-functions' problem, which I
> posted just over an hour ago (see bug #21869 or #21333).  The fix
> consists of only invoking w-s-c-f after any change to the echo area size
> has been done.  This might have some relevance for the current bug.  (I
> haven't followed the current bug, I'm afraid.)  I really need the
> go-ahead from Eli before I can commit the fix to the emacs-25 or master
> branch.

Thanks for working on this, and sorry for the delay in reviewing your
suggested changes.

> I propose the following strategy to fix the bug:
> 
> 1. Call resize_mini_window from redisplay_internal before the call to
>   prepare_menu_bars.
> 2. Remove the call to resize_mini_window from display_echo_area_1, and
>   make that function of type void.
> 3. Change the contract of echo_area_display, such that the echo area
>   must have been set to the correct height before calling it.
> 4. Adapt message3_nolog (the only other function which calls
>   echo_area_display) to call resize_mini_window.
> 
> As a result of these changes, any change in the size of the echo area
> would be taken into account when invoking window-size-change-functions.

I must say I prefer to avoid changes in the processing order of the
display engine, unless they are absolutely necessary and we understand
very well the effect of the order change.  Which IMO is not the case
here.

Could you try a simpler patch below?  It seems to fix both your test
case and the one originally reported in bug#21333.

Martin, is there any reason why window_resize_apply doesn't set the
frame's window_sizes_changed flag, but instead relies on its callers
to do that?

--- src/window.c~0	2015-11-11 07:57:56.000000000 +0200
+++ src/window.c	2015-11-18 18:47:51.875303700 +0200
@@ -4555,6 +4555,7 @@ grow_mini_window (struct window *w, int 
 	  /* Enforce full redisplay of the frame.  */
 	  /* FIXME: Shouldn't window--resize-root-window-vertically do it?  */
 	  fset_redisplay (f);
+	  FRAME_WINDOW_SIZES_CHANGED (f) = true;
 	  adjust_frame_glyphs (f);
 	  unblock_input ();
 	}
@@ -4594,6 +4595,7 @@ shrink_mini_window (struct window *w, bo
 	  /* Enforce full redisplay of the frame.  */
 	  /* FIXME: Shouldn't window--resize-root-window-vertically do it?  */
 	  fset_redisplay (f);
+	  FRAME_WINDOW_SIZES_CHANGED (f) = true;
 	  adjust_frame_glyphs (f);
 	  unblock_input ();
 	}
--- src/xdisp.c~0	2015-11-11 07:57:43.000000000 +0200
+++ src/xdisp.c	2015-11-18 18:53:32.333087700 +0200
@@ -13536,6 +13536,32 @@ redisplay_internal (void)
     {
       echo_area_display (false);
 
+      /* If echo_area_display resizes the mini-window, the redisplay and
+	 window_sizes_changed flags of the selected frame are set, but
+	 it's too late for the hooks in window-size-change-functions,
+	 which have been examined already in prepare_menu_bars.  So in
+	 that case we call the hooks here only for the selected frame.  */
+      if (sf->redisplay && FRAME_WINDOW_SIZES_CHANGED (sf))
+	{
+	  Lisp_Object functions;
+	  ptrdiff_t count1 = SPECPDL_INDEX ();
+
+	  record_unwind_save_match_data ();
+
+	  /* Clear flag first in case we get an error below.  */
+	  FRAME_WINDOW_SIZES_CHANGED (sf) = false;
+	  functions = Vwindow_size_change_functions;
+
+	  while (CONSP (functions))
+	    {
+	      if (!EQ (XCAR (functions), Qt))
+		call1 (XCAR (functions), selected_frame);
+	      functions = XCDR (functions);
+	    }
+
+	  unbind_to (count1, Qnil);
+	}
+
       if (message_cleared_p)
 	update_miniwindow_p = true;