From 82626e62ab27b498848e4c1822f6c4c06ad53947 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sat, 18 Jun 2022 13:07:20 +0300 Subject: [PATCH] Allow aborting redisplay stuck in 'parse-partial-sexp' * src/xdisp.c (display_working_on_window_p): New global variable. (unwind_display_working_on_window): New function. * src/keyboard.c (command_loop_1): Reset 'display_working_on_window_p' before and after executing commands. * src/window.c (Frecenter, window_scroll, displayed_window_lines): * src/indent.c (Fvertical_motion): Set 'display_working_on_window_p' before calling 'start_display'. * src/syntax.c (scan_sexps_forward): Call 'update_redisplay_ticks' after finishing the loop. --- src/dispextern.h | 2 ++ src/indent.c | 2 ++ src/keyboard.c | 2 ++ src/window.c | 16 +++++++++++++++- src/xdisp.c | 21 +++++++++++++++++++-- 5 files changed, 40 insertions(+), 3 deletions(-) diff --git a/src/dispextern.h b/src/dispextern.h index 0ea3ac8b07b..8bcd13dbb6d 100644 --- a/src/dispextern.h +++ b/src/dispextern.h @@ -3407,6 +3407,8 @@ int partial_line_height (struct it *it_origin); bool in_display_vector_p (struct it *); int frame_mode_line_height (struct frame *); extern bool redisplaying_p; +extern bool display_working_on_window_p; +extern void unwind_display_working_on_window (void); extern bool help_echo_showing_p; extern Lisp_Object help_echo_string, help_echo_window; extern Lisp_Object help_echo_object, previous_help_echo_string; diff --git a/src/indent.c b/src/indent.c index 51f6f414de3..7d9f0fe8b00 100644 --- a/src/indent.c +++ b/src/indent.c @@ -2177,6 +2177,8 @@ whether or not it is currently displayed in some window. */) line_number_display_width (w, &lnum_width, &lnum_pixel_width); SET_TEXT_POS (pt, PT, PT_BYTE); itdata = bidi_shelve_cache (); + record_unwind_protect_void (unwind_display_working_on_window); + display_working_on_window_p = true; start_display (&it, w, pt); it.lnum_width = lnum_width; first_x = it.first_visible_x; diff --git a/src/keyboard.c b/src/keyboard.c index 7d7dd2dba02..e5a991a8b21 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -1505,8 +1505,10 @@ command_loop_1 (void) executing the command, so that we don't blame the new command for the sins of the previous one. */ update_redisplay_ticks (0, NULL); + display_working_on_window_p = false; call1 (Qcommand_execute, Vthis_command); + display_working_on_window_p = false; #ifdef HAVE_WINDOW_SYSTEM /* Do not check display_hourglass_p here, because diff --git a/src/window.c b/src/window.c index ac8408a9a97..9f0df6619a3 100644 --- a/src/window.c +++ b/src/window.c @@ -5568,7 +5568,11 @@ window_scroll (Lisp_Object window, EMACS_INT n, bool whole, bool noerror) /* On GUI frames, use the pixel-based version which is much slower than the line-based one but can handle varying line heights. */ if (FRAME_WINDOW_P (XFRAME (XWINDOW (window)->frame))) - window_scroll_pixel_based (window, n, whole, noerror); + { + record_unwind_protect_void (unwind_display_working_on_window); + display_working_on_window_p = true; + window_scroll_pixel_based (window, n, whole, noerror); + } else window_scroll_line_based (window, n, whole, noerror); @@ -6496,9 +6500,14 @@ displayed_window_lines (struct window *w) CLIP_TEXT_POS_FROM_MARKER (start, w->start); itdata = bidi_shelve_cache (); + + specpdl_ref count = SPECPDL_INDEX (); + record_unwind_protect_void (unwind_display_working_on_window); + display_working_on_window_p = true; start_display (&it, w, start); move_it_vertically (&it, height); bottom_y = line_bottom_y (&it); + unbind_to (count, Qnil); bidi_unshelve_cache (itdata, false); /* Add in empty lines at the bottom of the window. */ @@ -6592,6 +6601,10 @@ and redisplay normally--don't erase and redraw the frame. */) data structures might not be set up yet then. */ if (!FRAME_INITIAL_P (XFRAME (w->frame))) { + specpdl_ref count = SPECPDL_INDEX (); + + record_unwind_protect_void (unwind_display_working_on_window); + display_working_on_window_p = true; if (center_p) { struct it it; @@ -6708,6 +6721,7 @@ and redisplay normally--don't erase and redraw the frame. */) bidi_unshelve_cache (itdata, false); } + unbind_to (count, Qnil); } else { diff --git a/src/xdisp.c b/src/xdisp.c index 1ba9132e8c0..1d52bbc6c93 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -1030,6 +1030,15 @@ static struct glyph_slice null_glyph_slice = { 0, 0, 0, 0 }; bool redisplaying_p; +/* True while some display-engine code is working on layout of some + window. + + WARNING: Use sparingly, preferably only in top level of commands + and important functions, because using it in nested calls might + reset the flag when the inner call returns, behind the back of + the callers. */ +bool display_working_on_window_p; + /* If a string, XTread_socket generates an event to display that string. (The display is done in read_char.) */ @@ -10961,6 +10970,7 @@ window_text_pixel_size (Lisp_Object window, Lisp_Object from, Lisp_Object to, max_y = XFIXNUM (y_limit); itdata = bidi_shelve_cache (); + start_display (&it, w, startp); int start_y = it.current_y; @@ -16970,6 +16980,13 @@ unwind_redisplay (void) unblock_buffer_flips (); } +/* Function registered with record_unwind_protect before calling + start_display outside of redisplay_internal. */ +void +unwind_display_working_on_window (void) +{ + display_working_on_window_p = false; +} /* Mark the display of leaf window W as accurate or inaccurate. If ACCURATE_P, mark display of W as accurate. @@ -17199,9 +17216,9 @@ update_redisplay_ticks (int ticks, struct window *w) cwindow = w; window_ticks = 0; } - /* Some callers can be run in contexts unrelated to redisplay, so + /* Some callers can be run in contexts unrelated to display code, so don't abort them and don't update the tick count in those cases. */ - if (!w && !redisplaying_p) + if (!w && !redisplaying_p && !display_working_on_window_p) return; if (ticks > 0) -- 2.39.2