struct glyph_matrix *);
#endif
static void mirror_line_dance (struct window *, int, int, int *, char *);
-static void update_window_tree (struct window *);
-static void update_window (struct window *);
-static void write_matrix (struct frame *, bool, bool, bool);
-static void scrolling (struct frame *);
+static bool update_window_tree (struct window *, bool);
+static bool update_window (struct window *, bool);
+static bool write_matrix (struct frame *, bool, bool, bool, bool);
+static bool scrolling (struct frame *);
static void set_window_cursor_after_update (struct window *);
static void adjust_frame_glyphs_for_window_redisplay (struct frame *);
static void adjust_frame_glyphs_for_frame_redisplay (struct frame *);
}
#endif
+/* True means last display completed. False means it was preempted. */
+
+bool display_completed;
+
/* True means SIGWINCH happened when not safe. */
static bool delayed_size_change;
\f
/* Add to the redisplay history how window W has been displayed.
MSG is a trace containing the information how W's glyph matrix
- has been constructed. */
+ has been constructed. PAUSED_P means that the update
+ has been interrupted for pending input. */
static void
-add_window_display_history (struct window *w, const char *msg)
+add_window_display_history (struct window *w, const char *msg, bool paused_p)
{
char *buf;
void *ptr = w;
++history_idx;
snprintf (buf, sizeof redisplay_history[0].trace,
- "%"PRIuMAX": window %p %s\n%s",
+ "%"PRIuMAX": window %p (%s)%s\n%s",
history_tick++,
ptr,
((BUFFERP (w->contents)
&& STRINGP (BVAR (XBUFFER (w->contents), name)))
? SSDATA (BVAR (XBUFFER (w->contents), name))
: "???"),
+ paused_p ? " ***paused***" : "",
msg);
}
current matrix over a call to adjust_glyph_matrix, we must
make a copy of the current glyphs, and restore the current
matrix' contents from that copy. */
- if (!FRAME_GARBAGED_P (f)
+ if (display_completed
+ && !FRAME_GARBAGED_P (f)
&& matrix_dim.width == f->current_matrix->matrix_w
&& matrix_dim.height == f->current_matrix->matrix_h
/* For some reason, the frame glyph matrix gets corrupted if
frame and window share glyphs. */
strcpy (w->current_matrix->method, w->desired_matrix->method);
- add_window_display_history (w, w->current_matrix->method);
+ add_window_display_history (w, w->current_matrix->method, 0);
#endif
}
struct window *w = XWINDOW (window);
if (w->must_be_updated_p)
{
- update_window (w);
+ update_window (w, true);
w->must_be_updated_p = false;
Lisp_Object tem = *current;
*current = *desired;
#endif
}
-static void
-update_window_frame (struct frame *f)
+static bool
+update_window_frame (struct frame *f, bool force_p)
{
eassert (FRAME_WINDOW_P (f));
update_begin (f);
update_tab_bar (f);
update_tool_bar (f);
struct window *root_window = XWINDOW (f->root_window);
- update_window_tree (root_window);
+ bool paused_p = update_window_tree (root_window, force_p);
update_end (f);
set_window_update_flags (root_window, false);
+ return paused_p;
}
-static void
-update_initial_frame (struct frame *f)
+static bool
+update_initial_frame (struct frame *f, bool force_p)
{
build_frame_matrix (f);
struct window *root_window = XWINDOW (f->root_window);
set_window_update_flags (root_window, false);
+ return false;
}
static void
fflush (FRAME_TTY (f)->output);
}
-static void
-update_tty_frame (struct frame *f)
+static bool
+update_tty_frame (struct frame *f, bool force_p)
{
build_frame_matrix (f);
+ return false;
}
/* Return the cursor position of the selected window of frame F, in
}
}
-void
-combine_updates_for_frame (struct frame *f, bool inhibit_scrolling)
+bool
+combine_updates_for_frame (struct frame *f, bool force_p, bool inhibit_scrolling)
{
struct frame *root = root_frame (f);
eassert (FRAME_VISIBLE_P (root));
}
update_begin (root);
- write_matrix (root, inhibit_scrolling, 1, false);
- make_matrix_current (root);
+ bool paused = write_matrix (root, force_p, inhibit_scrolling, 1, false);
+ if (!paused)
+ make_matrix_current (root);
update_end (root);
/* If a child is displayed, and the cursor is displayed in another
- frame, the child might lay above the cursor, so that it appears to
+ frame, the child might lay above the cursor, so that it appers to
"shine through" the child. Avoid that because it's confusing. */
if (topmost_child)
terminal_cursor_magic (root, topmost_child);
add_frame_display_history (f, false);
#endif
}
+
+ return paused;
}
/* Update on the screen all root frames ROOTS. Called from
redisplay_internal as the last step of redisplaying. */
-void
-combine_updates (Lisp_Object roots, bool inhibit_scrolling)
+bool
+combine_updates (Lisp_Object roots, bool force_p, bool inhibit_scrolling)
{
+ if (redisplay_dont_pause)
+ force_p = true;
+
for (; CONSP (roots); roots = XCDR (roots))
{
struct frame *root = XFRAME (XCAR (roots));
- combine_updates_for_frame (root, inhibit_scrolling);
+ if (combine_updates_for_frame (root, force_p, inhibit_scrolling))
+ {
+ display_completed = false;
+ return true;
+ }
}
+
+ display_completed = true;
+ return false;
}
/* Update frame F based on the data in desired matrices.
- If INHIBIT_SCROLLING, don't try scrolling. */
-void
-update_frame (struct frame *f, bool inhibit_scrolling)
+ If FORCE_P, don't let redisplay be stopped by detecting pending input.
+ If INHIBIT_SCROLLING, don't try scrolling.
+
+ Value is true if redisplay was stopped due to pending input. */
+
+bool
+update_frame (struct frame *f, bool force_p, bool inhibit_scrolling)
{
+ struct window *root_window = XWINDOW (f->root_window);
+
+ if (redisplay_dont_pause)
+ force_p = true;
+ else if (!force_p && detect_input_pending_ignore_squeezables ())
+ {
+ /* Reset flags indicating that a window should be updated. */
+ set_window_update_flags (root_window, false);
+ display_completed = false;
+ return true;
+ }
+
+ bool paused;
if (FRAME_WINDOW_P (f))
- update_window_frame (f);
+ paused = update_window_frame (f, force_p);
else if (FRAME_INITIAL_P (f))
- update_initial_frame (f);
+ paused = update_initial_frame (f, force_p);
else
- update_tty_frame (f);
+ paused = update_tty_frame (f, force_p);
+
+ if (paused)
+ display_completed = false;
+ return paused;
}
/* Update a TTY frame F that has a menu dropped down over some of its
cursor_at_point_p = !(row >= 0 && col >= 0);
/* Do not stop due to pending input, and do not try scrolling. This
means that write_glyphs will always return false. */
- write_matrix (f, 1, cursor_at_point_p, true);
+ write_matrix (f, 1, 1, cursor_at_point_p, true);
make_matrix_current (f);
clear_desired_matrices (f);
/* ROW and COL tell us where in the menu to position the cursor, so
/* Reset flags indicating that a window should be updated. */
set_window_update_flags (root_window, false);
+ display_completed = true;
}
/* Update the mouse position for a frame F. This handles both
Window-based updates
************************************************************************/
-/* Perform updates in window tree rooted at W. */
+/* Perform updates in window tree rooted at W.
+ If FORCE_P, don't stop updating if input is pending. */
-static void
-update_window_tree (struct window *w)
+static bool
+update_window_tree (struct window *w, bool force_p)
{
- while (w)
+ bool paused_p = 0;
+
+ while (w && !paused_p)
{
if (WINDOWP (w->contents))
- update_window_tree (XWINDOW (w->contents));
+ paused_p |= update_window_tree (XWINDOW (w->contents), force_p);
else if (w->must_be_updated_p)
- update_window (w);
+ paused_p |= update_window (w, force_p);
w = NILP (w->next) ? 0 : XWINDOW (w->next);
}
+
+ return paused_p;
}
-/* Update window W if its flag must_be_updated_p is set. */
+/* Update window W if its flag must_be_updated_p is set.
+ If FORCE_P, don't stop updating if input is pending. */
void
update_single_window (struct window *w)
/* Update W. */
update_begin (f);
- update_window (w);
+ update_window (w, true);
update_end (f);
/* Reset flag in W. */
#endif /* GLYPH_DEBUG */
-/* Update display of window W. */
+/* Update display of window W.
+ If FORCE_P, don't stop updating when input is pending. */
-static void
-update_window (struct window *w)
+static bool
+update_window (struct window *w, bool force_p)
{
struct glyph_matrix *desired_matrix = w->desired_matrix;
+ bool paused_p;
+ int preempt_count = clip_to_bounds (1, baud_rate / 2400 + 1, INT_MAX);
#ifdef HAVE_WINDOW_SYSTEM
struct redisplay_interface *rif = FRAME_RIF (XFRAME (WINDOW_FRAME (w)));
#endif
eassert (FRAME_WINDOW_P (XFRAME (WINDOW_FRAME (w))));
#endif
+ /* Check pending input the first time so that we can quickly return. */
+ if (!force_p)
+ detect_input_pending_ignore_squeezables ();
+
/* If forced to complete the update, no input is pending, or we are
tracking the mouse, do the update. */
- struct glyph_row *row, *end;
- struct glyph_row *mode_line_row;
- struct glyph_row *tab_line_row;
- struct glyph_row *header_line_row;
- int yb;
- bool changed_p = 0, mouse_face_overwritten_p = 0;
- bool invisible_rows_marked = false;
+ if (force_p || !input_pending || !NILP (track_mouse))
+ {
+ struct glyph_row *row, *end;
+ struct glyph_row *mode_line_row;
+ struct glyph_row *tab_line_row;
+ struct glyph_row *header_line_row;
+ int yb;
+ bool changed_p = 0, mouse_face_overwritten_p = 0;
+ int n_updated = 0;
+ bool invisible_rows_marked = false;
#ifdef HAVE_WINDOW_SYSTEM
- gui_update_window_begin (w);
+ gui_update_window_begin (w);
#else
- (void) changed_p;
+ (void) changed_p;
#endif
- yb = window_text_bottom_y (w);
- row = MATRIX_ROW (desired_matrix, 0);
- end = MATRIX_MODE_LINE_ROW (desired_matrix);
-
- /* Take note of the tab line, if there is one. We will
- update it below, after updating all of the window's lines. */
- if (row->mode_line_p && row->tab_line_p)
- {
- tab_line_row = row;
- ++row;
- }
- else
- tab_line_row = NULL;
+ yb = window_text_bottom_y (w);
+ row = MATRIX_ROW (desired_matrix, 0);
+ end = MATRIX_MODE_LINE_ROW (desired_matrix);
- /* Take note of the header line, if there is one. We will
- update it below, after updating all of the window's lines. */
- if (row->mode_line_p)
- {
- header_line_row = row;
- ++row;
- }
- else
- header_line_row = NULL;
-
- /* Update the mode line, if necessary. */
- mode_line_row = MATRIX_MODE_LINE_ROW (desired_matrix);
- if (mode_line_row->mode_line_p && mode_line_row->enabled_p)
- {
- mode_line_row->y = yb + WINDOW_SCROLL_BAR_AREA_HEIGHT (w);
- update_window_line (w, MATRIX_ROW_VPOS (mode_line_row,
- desired_matrix),
- &mouse_face_overwritten_p);
- }
+ /* Take note of the tab line, if there is one. We will
+ update it below, after updating all of the window's lines. */
+ if (row->mode_line_p && row->tab_line_p)
+ {
+ tab_line_row = row;
+ ++row;
+ }
+ else
+ tab_line_row = NULL;
- /* Find first enabled row. Optimizations in redisplay_internal
- may lead to an update with only one row enabled. There may
- be also completely empty matrices. */
- while (row < end && !row->enabled_p)
- ++row;
+ /* Take note of the header line, if there is one. We will
+ update it below, after updating all of the window's lines. */
+ if (row->mode_line_p)
+ {
+ header_line_row = row;
+ ++row;
+ }
+ else
+ header_line_row = NULL;
- /* Try reusing part of the display by copying. */
- if (row < end && !desired_matrix->no_scrolling_p)
- {
- int rc = scrolling_window (w, (tab_line_row != NULL ? 1 : 0)
- + (header_line_row != NULL ? 1 : 0));
- if (rc < 0)
+ /* Update the mode line, if necessary. */
+ mode_line_row = MATRIX_MODE_LINE_ROW (desired_matrix);
+ if (mode_line_row->mode_line_p && mode_line_row->enabled_p)
{
- /* All rows were found to be equal. */
- goto set_cursor;
+ mode_line_row->y = yb + WINDOW_SCROLL_BAR_AREA_HEIGHT (w);
+ update_window_line (w, MATRIX_ROW_VPOS (mode_line_row,
+ desired_matrix),
+ &mouse_face_overwritten_p);
}
- else if (rc > 0)
+
+ /* Find first enabled row. Optimizations in redisplay_internal
+ may lead to an update with only one row enabled. There may
+ be also completely empty matrices. */
+ while (row < end && !row->enabled_p)
+ ++row;
+
+ /* Try reusing part of the display by copying. */
+ if (row < end && !desired_matrix->no_scrolling_p)
{
- /* We've scrolled the display. */
- changed_p = 1;
+ int rc = scrolling_window (w, (tab_line_row != NULL ? 1 : 0)
+ + (header_line_row != NULL ? 1 : 0));
+ if (rc < 0)
+ {
+ /* All rows were found to be equal. */
+ paused_p = 0;
+ goto set_cursor;
+ }
+ else if (rc > 0)
+ {
+ /* We've scrolled the display. */
+ force_p = 1;
+ changed_p = 1;
+ }
}
- }
- /* Update the rest of the lines. */
- for (; row < end; ++row)
- /* scrolling_window resets the enabled_p flag of the rows it
- reuses from current_matrix. */
- if (row->enabled_p)
- {
- int vpos = MATRIX_ROW_VPOS (row, desired_matrix);
- int i;
-
- changed_p |= update_window_line (w, vpos,
- &mouse_face_overwritten_p);
-
- /* Mark all rows below the last visible one in the current
- matrix as invalid. This is necessary because of
- variable line heights. Consider the case of three
- successive redisplays, where the first displays 5
- lines, the second 3 lines, and the third 5 lines again.
- If the second redisplay wouldn't mark rows in the
- current matrix invalid, the third redisplay might be
- tempted to optimize redisplay based on lines displayed
- in the first redisplay. */
- if (MATRIX_ROW_BOTTOM_Y (row) >= yb)
+ /* Update the rest of the lines. */
+ for (; row < end && (force_p || !input_pending); ++row)
+ /* scrolling_window resets the enabled_p flag of the rows it
+ reuses from current_matrix. */
+ if (row->enabled_p)
{
- for (i = vpos + 1; i < w->current_matrix->nrows - 1; ++i)
- SET_MATRIX_ROW_ENABLED_P (w->current_matrix, i, false);
- invisible_rows_marked = true;
+ int vpos = MATRIX_ROW_VPOS (row, desired_matrix);
+ int i;
+
+ /* We'll have to play a little bit with when to
+ detect_input_pending. If it's done too often,
+ scrolling large windows with repeated scroll-up
+ commands will too quickly pause redisplay. */
+ if (!force_p && ++n_updated % preempt_count == 0)
+ detect_input_pending_ignore_squeezables ();
+ changed_p |= update_window_line (w, vpos,
+ &mouse_face_overwritten_p);
+
+ /* Mark all rows below the last visible one in the current
+ matrix as invalid. This is necessary because of
+ variable line heights. Consider the case of three
+ successive redisplays, where the first displays 5
+ lines, the second 3 lines, and the third 5 lines again.
+ If the second redisplay wouldn't mark rows in the
+ current matrix invalid, the third redisplay might be
+ tempted to optimize redisplay based on lines displayed
+ in the first redisplay. */
+ if (MATRIX_ROW_BOTTOM_Y (row) >= yb)
+ {
+ for (i = vpos + 1; i < w->current_matrix->nrows - 1; ++i)
+ SET_MATRIX_ROW_ENABLED_P (w->current_matrix, i, false);
+ invisible_rows_marked = true;
+ }
}
- }
- /* If the window doesn't display its mode line, make sure the
- corresponding row of the current glyph matrix is disabled, so
- that if and when the mode line is displayed again, it will be
- cleared and completely redrawn. */
- if (!window_wants_mode_line (w))
- SET_MATRIX_ROW_ENABLED_P (w->current_matrix,
- w->current_matrix->nrows - 1, false);
-
- if (!invisible_rows_marked)
- {
- /* If we didn't mark the invisible rows in the current
- matrix as invalid above, do that now. This can happen if
- scrolling_window updates the last visible rows of the
- current matrix, in which case the above loop doesn't get
- to examine the last visible row. */
- int i;
- for (i = 0; i < w->current_matrix->nrows - 1; ++i)
+ /* If the window doesn't display its mode line, make sure the
+ corresponding row of the current glyph matrix is disabled, so
+ that if and when the mode line is displayed again, it will be
+ cleared and completely redrawn. */
+ if (!window_wants_mode_line (w))
+ SET_MATRIX_ROW_ENABLED_P (w->current_matrix,
+ w->current_matrix->nrows - 1, false);
+
+ /* Was display preempted? */
+ paused_p = row < end;
+
+ if (!paused_p && !invisible_rows_marked)
{
- struct glyph_row *current_row = MATRIX_ROW (w->current_matrix, i);
- if (current_row->enabled_p
- && MATRIX_ROW_BOTTOM_Y (current_row) >= yb)
+ /* If we didn't mark the invisible rows in the current
+ matrix as invalid above, do that now. This can happen if
+ scrolling_window updates the last visible rows of the
+ current matrix, in which case the above loop doesn't get
+ to examine the last visible row. */
+ int i;
+ for (i = 0; i < w->current_matrix->nrows - 1; ++i)
{
- for (++i ; i < w->current_matrix->nrows - 1; ++i)
- SET_MATRIX_ROW_ENABLED_P (w->current_matrix, i, false);
+ struct glyph_row *current_row = MATRIX_ROW (w->current_matrix, i);
+ if (current_row->enabled_p
+ && MATRIX_ROW_BOTTOM_Y (current_row) >= yb)
+ {
+ for (++i ; i < w->current_matrix->nrows - 1; ++i)
+ SET_MATRIX_ROW_ENABLED_P (w->current_matrix, i, false);
+ }
}
}
- }
- set_cursor:
+ set_cursor:
- /* Update the tab line after scrolling because a new tab
- line would otherwise overwrite lines at the top of the window
- that can be scrolled. */
- if (tab_line_row && tab_line_row->enabled_p)
- {
- tab_line_row->y = 0;
- update_window_line (w, 0, &mouse_face_overwritten_p);
- }
-
- /* Update the header line after scrolling because a new header
- line would otherwise overwrite lines at the top of the window
- that can be scrolled. */
- if (header_line_row && header_line_row->enabled_p)
- {
- header_line_row->y = tab_line_row ? CURRENT_TAB_LINE_HEIGHT (w) : 0;
- update_window_line (w, tab_line_row ? 1 : 0, &mouse_face_overwritten_p);
- }
+ /* Update the tab line after scrolling because a new tab
+ line would otherwise overwrite lines at the top of the window
+ that can be scrolled. */
+ if (tab_line_row && tab_line_row->enabled_p)
+ {
+ tab_line_row->y = 0;
+ update_window_line (w, 0, &mouse_face_overwritten_p);
+ }
- /* Fix the appearance of overlapping/overlapped rows. */
- if (!w->pseudo_window_p)
- {
-#ifdef HAVE_WINDOW_SYSTEM
- if (changed_p && rif->fix_overlapping_area)
+ /* Update the header line after scrolling because a new header
+ line would otherwise overwrite lines at the top of the window
+ that can be scrolled. */
+ if (header_line_row && header_line_row->enabled_p)
{
- redraw_overlapped_rows (w, yb);
- redraw_overlapping_rows (w, yb);
+ header_line_row->y = tab_line_row ? CURRENT_TAB_LINE_HEIGHT (w) : 0;
+ update_window_line (w, tab_line_row ? 1 : 0, &mouse_face_overwritten_p);
}
+
+ /* Fix the appearance of overlapping/overlapped rows. */
+ if (!paused_p && !w->pseudo_window_p)
+ {
+#ifdef HAVE_WINDOW_SYSTEM
+ if (changed_p && rif->fix_overlapping_area)
+ {
+ redraw_overlapped_rows (w, yb);
+ redraw_overlapping_rows (w, yb);
+ }
#endif
- /* Make cursor visible at cursor position of W. */
- set_window_cursor_after_update (w);
+ /* Make cursor visible at cursor position of W. */
+ set_window_cursor_after_update (w);
#if 0 /* Check that current matrix invariants are satisfied. This is
- for debugging only. See the comment of check_matrix_invariants. */
- IF_DEBUG (check_matrix_invariants (w));
+ for debugging only. See the comment of check_matrix_invariants. */
+ IF_DEBUG (check_matrix_invariants (w));
#endif
- }
+ }
#ifdef GLYPH_DEBUG
- /* Remember the redisplay method used to display the matrix. */
- strcpy (w->current_matrix->method, w->desired_matrix->method);
+ /* Remember the redisplay method used to display the matrix. */
+ strcpy (w->current_matrix->method, w->desired_matrix->method);
#endif
#ifdef HAVE_WINDOW_SYSTEM
- update_window_fringes (w, 0);
+ update_window_fringes (w, 0);
- /* End the update of window W. Don't set the cursor if we
- paused updating the display because in this case,
- set_window_cursor_after_update hasn't been called, and
- W->output_cursor doesn't contain the cursor location. */
- gui_update_window_end (w, true, mouse_face_overwritten_p);
+ /* End the update of window W. Don't set the cursor if we
+ paused updating the display because in this case,
+ set_window_cursor_after_update hasn't been called, and
+ W->output_cursor doesn't contain the cursor location. */
+ gui_update_window_end (w, !paused_p, mouse_face_overwritten_p);
#endif
- /* If the update wasn't interrupted, this window has been
- completely updated. */
- w->must_be_updated_p = false;
+ /* If the update wasn't interrupted, this window has been
+ completely updated. */
+ if (!paused_p)
+ w->must_be_updated_p = false;
+ }
+ else
+ paused_p = 1;
#ifdef GLYPH_DEBUG
/* check_current_matrix_flags (w); */
- add_window_display_history (w, w->current_matrix->method);
+ add_window_display_history (w, w->current_matrix->method, paused_p);
#endif
xwidget_end_redisplay (w, w->current_matrix);
clear_glyph_matrix (desired_matrix);
+
+ return paused_p;
}
#ifdef HAVE_WINDOW_SYSTEM
}
/* Write desired matix of tty frame F and make it current.
+
+ FORCE_P means that the update should not be stopped by pending input.
INHIBIT_ID_P means that scrolling by insert/delete should not be tried.
- SET_CURSOR_P false means do not set cursor at point in selected window. */
+ SET_CURSOR_P false means do not set cursor at point in selected window.
-static void
-write_matrix (struct frame *f, bool inhibit_id_p,
+ Value is true if update was stopped due to pending input. */
+
+static bool
+write_matrix (struct frame *f, bool force_p, bool inhibit_id_p,
bool set_cursor_p, bool updating_menu_p)
{
+ if (!force_p && detect_input_pending_ignore_squeezables ())
+ return true;
+
/* If we cannot insert/delete lines, it's no use trying it. */
if (!FRAME_LINE_INS_DEL_OK (f))
inhibit_id_p = true;
i/d line if just want cursor motion. */
int first_row = first_enabled_row (f->desired_matrix);
if (!inhibit_id_p && first_row >= 0)
- scrolling (f);
+ force_p |= scrolling (f);
/* Update the individual lines as needed. Do bottom line first. This
is done so that messages are made visible when pausing. */
if (MATRIX_ROW_ENABLED_P (f->desired_matrix, last_row))
write_row (f, last_row, updating_menu_p);
+ bool pause_p = false;
if (first_row >= 0)
- for (int i = first_row; i < last_row; ++i)
- if (MATRIX_ROW_ENABLED_P (f->desired_matrix, i))
- write_row (f, i, updating_menu_p);
+ {
+ const int preempt_count = clip_to_bounds (1, baud_rate / 2400 + 1, INT_MAX);
+
+ for (int i = first_row, n = 0; i < last_row; ++i)
+ if (MATRIX_ROW_ENABLED_P (f->desired_matrix, i))
+ {
+ if (!force_p && n % preempt_count == 0
+ && detect_input_pending_ignore_squeezables ())
+ {
+ pause_p = true;
+ break;
+ }
+
+ write_row (f, i, updating_menu_p);
+ ++n;
+ }
+ }
/* Now just clean up termcap drivers and set cursor, etc. */
- if (set_cursor_p)
+ if (!pause_p && set_cursor_p)
tty_set_cursor ();
+
+ return pause_p;
}
/* Do line insertions/deletions on frame F for frame-based redisplay. */
-static void
+static bool
scrolling (struct frame *frame)
{
/* In fact this code should never be reached at all under
if (!MATRIX_ROW_ENABLED_P (current_matrix, i))
{
SAFE_FREE ();
- return;
+ return false;
}
old_hash[i] = line_hash_code (frame, MATRIX_ROW (current_matrix, i));
if (! MATRIX_ROW_ENABLED_P (desired_matrix, i))
|| unchanged_at_bottom == height)
{
SAFE_FREE ();
- return;
+ return true;
}
window_size = (height - unchanged_at_top
SAFE_FREE ();
#endif
+ return false;
}
DEFUN ("redisplay", Fredisplay, Sredisplay, 0, 1, 0,
- doc : /* Perform redisplay.
-Optional arg FORCE exists for historical reasons and is ignored.
-Value is t if redisplay has been performed, nil if executing a
-keyboard macro. */)
+ doc: /* Perform redisplay.
+Optional arg FORCE, if non-nil, prevents redisplay from being
+preempted by arriving input, even if `redisplay-dont-pause' is nil.
+If `redisplay-dont-pause' is non-nil (the default), redisplay is never
+preempted by arriving input, so FORCE does nothing.
+
+Return t if redisplay was performed, nil if redisplay was preempted
+immediately by pending input. */)
(Lisp_Object force)
{
swallow_events (true);
- if (!NILP (Vexecuting_kbd_macro))
+ if ((detect_input_pending_run_timers (1)
+ && NILP (force) && !redisplay_dont_pause)
+ || !NILP (Vexecuting_kbd_macro))
return Qnil;
+ specpdl_ref count = SPECPDL_INDEX ();
+ if (!NILP (force) && !redisplay_dont_pause)
+ specbind (Qredisplay_dont_pause, Qt);
redisplay_preserve_echo_area (2);
- return Qt;
+ return unbind_to (count, Qt);
}
/* This is the "purpose" slot of a display table. */
DEFSYM (Qdisplay_table, "display-table");
DEFSYM (Qframe__z_order_lessp, "frame--z-order-lessp");
+
+ DEFSYM (Qredisplay_dont_pause, "redisplay-dont-pause");
DEFSYM (Qtty_non_selected_cursor, "tty-non-selected-cursor");
DEFVAR_INT ("baud-rate", baud_rate,
See `buffer-display-table' for more information. */);
Vstandard_display_table = Qnil;
+ DEFVAR_BOOL ("redisplay-dont-pause", redisplay_dont_pause,
+ doc: /* Nil means display update is paused when input is detected. */);
+ /* Contrary to expectations, a value of "false" can be detrimental to
+ responsiveness since aborting a redisplay throws away some of the
+ work already performed. It's usually more efficient (and gives
+ more prompt feedback to the user) to let the redisplay terminate,
+ and just completely skip the next command's redisplay (which is
+ done regardless of this setting if there's pending input at the
+ beginning of the next redisplay). */
+ redisplay_dont_pause = true;
+
DEFVAR_LISP ("x-show-tooltip-timeout", Vx_show_tooltip_timeout,
doc: /* The default timeout (in seconds) for `x-show-tip'. */);
Vx_show_tooltip_timeout = make_fixnum (5);
static void mark_window_display_accurate_1 (struct window *, bool);
static bool row_for_charpos_p (struct glyph_row *, ptrdiff_t);
static bool cursor_row_p (struct glyph_row *);
+static int redisplay_mode_lines (Lisp_Object, bool);
static void handle_line_prefix (struct it *);
here could cause confusion. */
if (update_frame_p && !redisplaying_p)
{
+ int n = 0;
+
+ /* If the display update has been interrupted by pending
+ input, update mode lines in the frame. Due to the
+ pending input, it might have been that redisplay hasn't
+ been called, so that mode lines above the echo area are
+ garbaged. This looks odd, so we prevent it here. */
+ if (!display_completed)
+ {
+ n = redisplay_mode_lines (FRAME_ROOT_WINDOW (f), false);
+
+#ifdef HAVE_WINDOW_SYSTEM
+ if (FRAME_WINDOW_P (f)
+ && FRAME_RIF (f)->clear_under_internal_border)
+ FRAME_RIF (f)->clear_under_internal_border (f);
+#endif
+ }
+
if (window_height_changed_p
/* Don't do this if Emacs is shutting down. Redisplay
needs to run hooks. */
/* Must update other windows. Likewise as in other
cases, don't let this update be interrupted by
pending input. */
+ specpdl_ref count = SPECPDL_INDEX ();
+ specbind (Qredisplay_dont_pause, Qt);
fset_redisplay (f);
redisplay_internal ();
+ unbind_to (count, Qnil);
}
- else if (FRAME_WINDOW_P (f))
+ else if (FRAME_WINDOW_P (f) && n == 0)
{
/* Window configuration is the same as before.
Can do with a display update of the echo area,
}
else
{
- update_frame (f, true);
+ update_frame (f, true, true);
if (is_tty_frame (f))
- combine_updates_for_frame (f, true);
+ combine_updates_for_frame (f, true, true);
}
/* If cursor is in the echo area, make sure that the next
struct window *w = XWINDOW (selected_window);
struct window *sw;
struct frame *fr;
+ bool pending;
bool must_finish = false, match_p;
struct text_pos tlbufpos, tlendpos;
int number_of_visible_frames;
/* Remember the currently selected window. */
sw = w;
+ pending = false;
forget_escape_and_glyphless_faces ();
inhibit_free_realized_faces = false;
unrequest_sigio ();
STOP_POLLING;
- update_frame (f, false);
+ pending |= update_frame (f, false, false);
/* On some platforms (at least MS-Windows), the
scroll_run_hook called from scrolling_window
called from update_frame could set the frame's
}
if (CONSP (tty_root_frames))
- combine_updates (tty_root_frames, false);
+ pending |= combine_updates (tty_root_frames, false, false);
eassert (EQ (XFRAME (selected_frame)->selected_window, selected_window));
- /* Do the mark_window_display_accurate after all windows have
- been redisplayed because this call resets flags in buffers
- which are needed for proper redisplay. */
- FOR_EACH_FRAME (tail, frame)
+ if (!pending)
{
- struct frame *f = XFRAME (frame);
- if (f->updated_p)
- {
- f->redisplay = false;
- f->garbaged = false;
- mark_window_display_accurate (f->root_window, true);
- if (FRAME_TERMINAL (f)->frame_up_to_date_hook)
- FRAME_TERMINAL (f)->frame_up_to_date_hook (f);
- }
+ /* Do the mark_window_display_accurate after all windows have
+ been redisplayed because this call resets flags in buffers
+ which are needed for proper redisplay. */
+ FOR_EACH_FRAME (tail, frame)
+ {
+ struct frame *f = XFRAME (frame);
+ if (f->updated_p)
+ {
+ f->redisplay = false;
+ f->garbaged = false;
+ mark_window_display_accurate (f->root_window, true);
+ if (FRAME_TERMINAL (f)->frame_up_to_date_hook)
+ FRAME_TERMINAL (f)->frame_up_to_date_hook (f);
+ }
+ }
}
}
else if (FRAME_REDISPLAY_P (sf))
}
XWINDOW (selected_window)->must_be_updated_p = true;
- update_frame (sf, false);
+ pending = update_frame (sf, false, false);
if (is_tty_frame (sf))
- combine_updates_for_frame (sf, false);
+ pending |= combine_updates_for_frame (sf, false, false);
sf->cursor_type_changed = false;
sf->inhibit_clear_image_cache = false;
if (mini_frame != sf)
{
XWINDOW (mini_window)->must_be_updated_p = true;
- update_frame (mini_frame, false);
+ pending |= update_frame (mini_frame, false, false);
if (is_tty_frame (mini_frame))
- combine_updates_for_frame (mini_frame, false);
+ pending |= combine_updates_for_frame (mini_frame, false, false);
mini_frame->cursor_type_changed = false;
- if (hscroll_retries <= MAX_HSCROLL_RETRIES
+ if (!pending && hscroll_retries <= MAX_HSCROLL_RETRIES
&& hscroll_windows (mini_window))
{
hscroll_retries++;
}
}
- if (!consider_all_windows_p)
+ /* If display was paused because of pending input, make sure we do a
+ thorough update the next time. */
+ if (pending)
{
- /* This has already been done above if
- consider_all_windows_p is set. */
- if (XBUFFER (w->contents)->text->redisplay
- && buffer_window_count (XBUFFER (w->contents)) > 1)
- /* This can happen if b->text->redisplay was set during
- jit-lock. */
- propagate_buffer_redisplay ();
- mark_window_display_accurate_1 (w, true);
+ /* Prevent the optimization at the beginning of
+ redisplay_internal that tries a single-line update of the
+ line containing the cursor in the selected window. */
+ CHARPOS (this_line_start_pos) = 0;
- /* Say overlay arrows are up to date. */
- update_overlay_arrows (1);
+ /* Let the overlay arrow be updated the next time. */
+ update_overlay_arrows (0);
- if (FRAME_TERMINAL (sf)->frame_up_to_date_hook != 0)
- FRAME_TERMINAL (sf)->frame_up_to_date_hook (sf);
+ /* If we pause after scrolling, some rows in the current
+ matrices of some windows are not valid. */
+ if (!WINDOW_FULL_WIDTH_P (w)
+ && !FRAME_WINDOW_P (XFRAME (w->frame)))
+ update_mode_lines = 36;
}
+ else
+ {
+ if (!consider_all_windows_p)
+ {
+ /* This has already been done above if
+ consider_all_windows_p is set. */
+ if (XBUFFER (w->contents)->text->redisplay
+ && buffer_window_count (XBUFFER (w->contents)) > 1)
+ /* This can happen if b->text->redisplay was set during
+ jit-lock. */
+ propagate_buffer_redisplay ();
+ mark_window_display_accurate_1 (w, true);
- update_mode_lines = 0;
- windows_or_buffers_changed = 0;
+ /* Say overlay arrows are up to date. */
+ update_overlay_arrows (1);
+
+ if (FRAME_TERMINAL (sf)->frame_up_to_date_hook != 0)
+ FRAME_TERMINAL (sf)->frame_up_to_date_hook (sf);
+ }
+
+ update_mode_lines = 0;
+ windows_or_buffers_changed = 0;
+ }
/* Start SIGIO interrupts coming again. Having them off during the
code above makes it less likely one will discard output, but not
redisplay constructing glyphs, so simply exposing a frame won't
display anything in this case. So, we have to display these
frames here explicitly. */
- int new_count = 0;
-
- FOR_EACH_FRAME (tail, frame)
+ if (!pending)
{
- if (FRAME_REDISPLAY_P (XFRAME (frame)))
- new_count++;
- }
+ int new_count = 0;
+
+ FOR_EACH_FRAME (tail, frame)
+ {
+ if (FRAME_REDISPLAY_P (XFRAME (frame)))
+ new_count++;
+ }
- if (new_count != number_of_visible_frames)
- windows_or_buffers_changed = 52;
+ if (new_count != number_of_visible_frames)
+ windows_or_buffers_changed = 52;
+ }
/* Change frame size now if a change is pending. */
do_pending_window_change (true);
/* If we just did a pending size change, or have additional
visible frames, or selected_window changed, redisplay again. */
- if (windows_or_buffers_changed
+ if ((windows_or_buffers_changed && !pending)
|| (WINDOWP (selected_window)
&& (w = XWINDOW (selected_window)) != sw))
goto retry;
Mode Line
***********************************************************************/
+/* Redisplay mode lines in the window tree whose root is WINDOW.
+ If FORCE, redisplay mode lines unconditionally.
+ Otherwise, redisplay only mode lines that are garbaged. Value is
+ the number of windows whose mode lines were redisplayed. */
+
+static int
+redisplay_mode_lines (Lisp_Object window, bool force)
+{
+ int nwindows = 0;
+
+ while (!NILP (window))
+ {
+ struct window *w = XWINDOW (window);
+
+ if (WINDOWP (w->contents))
+ nwindows += redisplay_mode_lines (w->contents, force);
+ else if (force
+ || FRAME_GARBAGED_P (XFRAME (w->frame))
+ || !MATRIX_MODE_LINE_ROW (w->current_matrix)->enabled_p)
+ {
+ struct text_pos lpoint;
+ struct buffer *old = current_buffer;
+
+ /* Set the window's buffer for the mode line display. */
+ SET_TEXT_POS (lpoint, PT, PT_BYTE);
+ set_buffer_internal_1 (XBUFFER (w->contents));
+
+ /* Point refers normally to the selected window. For any
+ other window, set up appropriate value. */
+ if (!EQ (window, selected_window))
+ {
+ struct text_pos pt;
+
+ CLIP_TEXT_POS_FROM_MARKER (pt, w->pointm);
+ TEMP_SET_PT_BOTH (CHARPOS (pt), BYTEPOS (pt));
+ }
+
+ /* Display mode lines. */
+ clear_glyph_matrix (w->desired_matrix);
+ if (display_mode_lines (w))
+ ++nwindows;
+
+ /* Restore old settings. */
+ set_buffer_internal_1 (old);
+ TEMP_SET_PT_BOTH (CHARPOS (lpoint), BYTEPOS (lpoint));
+ }
+
+ window = w->next;
+ }
+
+ return nwindows;
+}
+
+
/* Display the mode line, the header line, and the tab-line of window
W. Value is the sum number of mode lines, header lines, and tab
lines actually displayed. */