bool in_display_vector_p (struct it *);
int frame_mode_line_height (struct frame *);
extern bool redisplaying_p;
+extern unsigned int redisplay_counter;
extern bool display_working_on_window_p;
extern void unwind_display_working_on_window (void);
extern bool help_echo_showing_p;
/* Resetting redisplaying_p to 0 makes sure that debug output is
displayed if the debugger is invoked during redisplay. */
debug_while_redisplaying = redisplaying_p;
+ int redisplay_counter_before = redisplay_counter;
redisplaying_p = 0;
specbind (Qdebugger_may_continue,
debug_while_redisplaying ? Qnil : Qt);
/* Interrupting redisplay and resuming it later is not safe under
all circumstances. So, when the debugger returns, abort the
interrupted redisplay by going back to the top-level. */
- /* FIXME: Move this to the redisplay code? */
if (debug_while_redisplaying
- && !EQ (Vdebugger, Qdebug_early))
+ && redisplay_counter_before != redisplay_counter)
+ /* FIXME: Rather than jump all the way to `top-level`
+ we should exit only the current redisplay. */
Ftop_level ();
return unbind_to (count, val);
Lisp form evaluation
***********************************************************************/
+/* The redisplay is not re-entrant. But we can run ELisp code during
+ redisplay, which in turn can trigger redisplay.
+ We try to make this inner redisplay work correctly, but it messes up
+ the state of the outer redisplay, so when we return to this outer
+ redisplay, we need to abort it.
+ To dect this case, we keep a counter that identifies every call to the
+ redisplay, so we can detect when a nested redisplay happened by the
+ fact that the counter has changed. */
+
+unsigned int redisplay_counter = 0;
+
/* Error handler for dsafe_eval and dsafe_call. */
static Lisp_Object
specbind (Qinhibit_redisplay, Qt);
if (inhibit_quit)
specbind (Qinhibit_quit, Qt);
+ int redisplay_counter_before = redisplay_counter;
/* Use Qt to ensure debugger does not run,
- so there is no possibility of wanting to redisplay. */
+ to reduce the risk of wanting to redisplay. */
val = internal_condition_case_n (f, nargs, args, Qt,
dsafe_eval_handler);
+ if (redisplay_counter_before != redisplay_counter)
+ /* A nested redisplay happened, abort this one! */
+ /* FIXME: Rather than jump all the way to `top-level`
+ we should exit only the current redisplay. */
+ Ftop_level ();
+
val = unbind_to (count, val);
}
bool polling_stopped_here = false;
Lisp_Object tail, frame;
+ redisplay_counter++;
+
/* Set a limit to the number of retries we perform due to horizontal
scrolling, this avoids getting stuck in an uninterruptible
infinite loop (Bug #24633). */