Package: emacs;
Reported by: Alan Mackenzie <acm <at> muc.de>
Date: Mon, 9 Nov 2015 09:35:01 UTC
Severity: normal
Found in versions 24.0.90, 25.0.50
Done: Eli Zaretskii <eliz <at> gnu.org>
Bug is archived. No further changes may be made.
Message #34 received at 21869 <at> debbugs.gnu.org (full text, mbox):
From: Alan Mackenzie <acm <at> muc.de> To: 21869 <at> debbugs.gnu.org Cc: rudalics <at> gmx.at, Eli Zaretskii <eliz <at> gnu.org>, pipcet <at> gmail.com, 21333 <at> debbugs.gnu.org Subject: Re: bug#21869: [Patch] Redisplay: after echo area diminishes in size, Follow Mode windows aren't resynchronised. Date: Tue, 17 Nov 2015 17:56:23 +0000
On Mon, Nov 16, 2015 at 03:03:57PM +0000, Alan Mackenzie wrote: > On Mon, Nov 09, 2015 at 10:50:57PM +0200, Eli Zaretskii wrote: > > > Date: Mon, 9 Nov 2015 19:42:00 +0000 > > > From: Alan Mackenzie <acm <at> muc.de> > > > Cc: 21869 <at> debbugs.gnu.org, Pip Cet <pipcet <at> gmail.com> > > > > Probably bug#830 and bug#21333. > Quick summary of the bug: with Follow Mode active, with a multi-line > display in the echo area, do C-f. The echo area resizes to one line, > but the Follow Mode windows don't get resynchronised. > Quick summary of the cause: redisplay_internal calls prepare_menu_bars > (which invokes the window-size-change-functions hook) before it calls > echo_area_display (which resizes the echo area). Thus changes to the > echo area size aren't yet in place when window-size-change-functions is > invoked. > 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. > An advantage of this change is that a recursive invocation of > redisplay_internal inside echo_area_display could be removed, improving > performance. No it couldn't. That invocation is not a recursive one, it's the main call of redisplay_internal for the message functions. Here is a patch implementing the above scheme. It should also fix bug#21333 (or, at least, go a long way towards fixing it): Invoke window-size-change-functions after changing echo area height. Fixes bug #21869 and probably bug #21333. Separate the resizing of the echo area from the displaying of text in it. This allows window-size-change-functions to be invoked after the former, but before the latter, according to its specification. src/xdisp.c (message3_nolog): Invoke resize_mini_window_1 before calling echo_area_display. (display_echo_area): Change type to (static) void. Change contract such that the echo area must have been resized, if nec., before calling, and that this function doesn't resize. (display_echo_area_1): Now always return false, since the function never resizes. (echo_area_display): Add extra parameter `window_height_changed_p', replacing a local of the same name. The function no longer resizes the echo area. (redisplay_internal): Invoke resize_mini_window_1 before calling prepare_menu_bars (which invokes window-size-change-functions). diff --git a/src/xdisp.c b/src/xdisp.c index 30dfac5..68e56b7 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -800,6 +800,9 @@ static int redisplay_mode_lines (Lisp_Object, bool); static void handle_line_prefix (struct it *); static void handle_stop_backwards (struct it *, ptrdiff_t); +static bool with_echo_area_buffer (struct window *, int, + bool (*)(ptrdiff_t, Lisp_Object), + ptrdiff_t, Lisp_Object); static void unwind_with_echo_area_buffer (Lisp_Object); static Lisp_Object with_echo_area_buffer_unwind_data (struct window *); static bool current_message_1 (ptrdiff_t, Lisp_Object); @@ -815,7 +818,7 @@ static void push_it (struct it *, struct text_pos *); static void iterate_out_of_display_property (struct it *); static void pop_it (struct it *); static void redisplay_internal (void); -static void echo_area_display (bool); +static void echo_area_display (bool, bool); static void redisplay_windows (Lisp_Object); static void redisplay_window (Lisp_Object, bool); static Lisp_Object redisplay_window_error (Lisp_Object); @@ -10234,8 +10237,10 @@ message3_nolog (Lisp_Object m) /* Get the frame containing the mini-buffer that the selected frame is using. */ Lisp_Object mini_window = FRAME_MINIBUF_WINDOW (sf); + struct window *mw = XWINDOW (mini_window); Lisp_Object frame = XWINDOW (mini_window)->frame; struct frame *f = XFRAME (frame); + bool window_height_changed_p; if (FRAME_VISIBLE_P (sf) && !FRAME_VISIBLE_P (f)) Fmake_frame_visible (frame); @@ -10253,7 +10258,12 @@ message3_nolog (Lisp_Object m) clear_message (true, true); do_pending_window_change (false); - echo_area_display (true); + if (window_height_changed_p = + with_echo_area_buffer (mw, display_last_displayed_message_p, + resize_mini_window_1, + (intptr_t) mw, Qt)) + FRAME_WINDOW_SIZES_CHANGED (sf) = true; + echo_area_display (true, window_height_changed_p); do_pending_window_change (false); if (FRAME_TERMINAL (f)->frame_up_to_date_hook) (*FRAME_TERMINAL (f)->frame_up_to_date_hook) (f); @@ -10711,15 +10721,15 @@ setup_echo_area_for_printing (bool multibyte_p) } -/* Display an echo area message in window W. Value is true if W's - height is changed. If display_last_displayed_message_p, - display the message that was last displayed, otherwise - display the current message. */ +/* Display an echo area message in window W. If + display_last_displayed_message_p, display the message that was last + displayed, otherwise display the current message. The window + height of W must already have been set for the message. */ -static bool +static void display_echo_area (struct window *w) { - bool no_message_p, window_height_changed_p; + bool no_message_p; /* Temporarily disable garbage collections while displaying the echo area. This is done because a GC can print a message itself. @@ -10735,24 +10745,22 @@ display_echo_area (struct window *w) bool i = display_last_displayed_message_p; no_message_p = NILP (echo_area_buffer[i]); - window_height_changed_p - = with_echo_area_buffer (w, display_last_displayed_message_p, - display_echo_area_1, - (intptr_t) w, Qnil); + with_echo_area_buffer (w, display_last_displayed_message_p, + display_echo_area_1, + (intptr_t) w, Qnil); if (no_message_p) echo_area_buffer[i] = Qnil; unbind_to (count, Qnil); - return window_height_changed_p; } /* Helper for display_echo_area. Display the current buffer which contains the current echo area message in window W, a mini-window, - a pointer to which is passed in A1. A2..A4 are currently not used. - Change the height of W so that all of the message is displayed. - Value is true if height of W was changed. */ + a pointer to which is passed in A1. The height of W must already + have been set to the correct height for the message. Always + returns false. */ static bool display_echo_area_1 (ptrdiff_t a1, Lisp_Object a2) @@ -10767,11 +10775,6 @@ display_echo_area_1 (ptrdiff_t a1, Lisp_Object a2) here. */ forget_escape_and_glyphless_faces (); - /* Do this before displaying, so that we have a large enough glyph - matrix for the display. If we can't get enough space for the - whole text, display the last N lines. That works by setting w->start. */ - bool window_height_changed_p = resize_mini_window (w, false); - /* Use the starting position chosen by resize_mini_window. */ SET_TEXT_POS_FROM_MARKER (start, w->start); @@ -10780,7 +10783,7 @@ display_echo_area_1 (ptrdiff_t a1, Lisp_Object a2) XSETWINDOW (window, w); try_window (window, start, 0); - return window_height_changed_p; + return false; } @@ -11196,16 +11199,17 @@ clear_garbaged_frames (void) } -/* Redisplay the echo area of the selected frame. If UPDATE_FRAME_P, update - selected_frame. */ +/* Redisplay the echo area of the selected frame. If UPDATE_FRAME_P, + update selected_frame. WINDOW_HEIGHT_CHANGED_P states whether the + echo area's height has just been changed. It is ignored unless + UPDATE_FRAME_P is true. */ static void -echo_area_display (bool update_frame_p) +echo_area_display (bool update_frame_p, bool window_height_changed_p) { Lisp_Object mini_window; struct window *w; struct frame *f; - bool window_height_changed_p = false; struct frame *sf = SELECTED_FRAME (); mini_window = FRAME_MINIBUF_WINDOW (sf); @@ -11230,7 +11234,7 @@ echo_area_display (bool update_frame_p) if (!NILP (echo_area_buffer[0]) || minibuf_level == 0) { echo_area_window = mini_window; - window_height_changed_p = display_echo_area (w); + display_echo_area (w); w->must_be_updated_p = true; /* Update the display, unless called from redisplay_internal. @@ -13497,6 +13501,19 @@ redisplay_internal (void) /* Clear frames marked as garbaged. */ clear_garbaged_frames (); + /* Resize the echo area, if needed, before the invocation of + window-size-change-functions. */ + { + Lisp_Object mini_window = FRAME_MINIBUF_WINDOW (sf); + struct window *mw = XWINDOW (mini_window); + + if (!MINI_WINDOW_P (XWINDOW (selected_window)) + && with_echo_area_buffer (mw, display_last_displayed_message_p, + resize_mini_window_1, + (intptr_t) mw, Qnil)) + FRAME_WINDOW_SIZES_CHANGED (sf) = true; + } + /* Build menubar and tool-bar items. */ if (NILP (Vmemory_full)) prepare_menu_bars (); @@ -13534,7 +13551,7 @@ redisplay_internal (void) echo-area doesn't show through. */ && !MINI_WINDOW_P (XWINDOW (selected_window)))) { - echo_area_display (false); + echo_area_display (false, false); if (message_cleared_p) update_miniwindow_p = true; -- Alan Mackenzie (Nuremberg, Germany).
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.