#include "lisp.h"
#include "atimer.h"
+#include "composite.h"
#include "keyboard.h"
+#include "systime.h"
#include "frame.h"
#include "window.h"
#include "termchar.h"
#include "indent.h"
#include "commands.h"
#include "keymap.h"
-#include "macros.h"
#include "disptab.h"
#include "termhooks.h"
#include "termopts.h"
#include "intervals.h"
#include "coding.h"
-#include "process.h"
#include "region-cache.h"
#include "font.h"
#include "fontset.h"
static bool message_enable_multibyte;
-/* Nonzero if we should redraw the mode lines on the next redisplay.
- If it has value REDISPLAY_SOME, then only redisplay the mode lines where
- the `redisplay' bit has been set. Otherwise, redisplay all mode lines
- (the number used is then only used to track down the cause for this
- full-redisplay). */
+/* At each redisplay cycle, we should refresh everything there is to refresh.
+ To do that efficiently, we use many optimizations that try to make sure we
+ don't waste too much time updating things that haven't changed.
+ The coarsest such optimization is that, in the most common cases, we only
+ look at the selected-window.
+
+ To know whether other windows should be considered for redisplay, we use the
+ variable windows_or_buffers_changed: as long as it is 0, it means that we
+ have not noticed anything that should require updating anything else than
+ the selected-window. If it is set to REDISPLAY_SOME, it means that since
+ last redisplay, some changes have been made which could impact other
+ windows. To know which ones need redisplay, every buffer, window, and frame
+ has a `redisplay' bit, which (if true) means that this object needs to be
+ redisplayed. If windows_or_buffers_changed is 0, we know there's no point
+ looking for those `redisplay' bits (actually, there might be some such bits
+ set, but then only on objects which aren't displayed anyway).
+
+ OTOH if it's non-zero we wil have to loop through all windows and then check
+ the `redisplay' bit of the corresponding window, frame, and buffer, in order
+ to decide whether that window needs attention or not. Note that we can't
+ just look at the frame's redisplay bit to decide that the whole frame can be
+ skipped, since even if the frame's redisplay bit is unset, some of its
+ windows's redisplay bits may be set.
+
+ Mostly for historical reasons, windows_or_buffers_changed can also take
+ other non-zero values. In that case, the precise value doesn't matter (it
+ encodes the cause of the setting but is only used for debugging purposes),
+ and what it means is that we shouldn't pay attention to any `redisplay' bits
+ and we should simply try and redisplay every window out there. */
-int update_mode_lines;
+int windows_or_buffers_changed;
-/* Nonzero if window sizes or contents other than selected-window have changed
- since last redisplay that finished.
- If it has value REDISPLAY_SOME, then only redisplay the windows where
- the `redisplay' bit has been set. Otherwise, redisplay all windows
- (the number used is then only used to track down the cause for this
- full-redisplay). */
+/* Nonzero if we should redraw the mode lines on the next redisplay.
+ Similarly to `windows_or_buffers_changed', If it has value REDISPLAY_SOME,
+ then only redisplay the mode lines in those buffers/windows/frames where the
+ `redisplay' bit has been set.
+ For any other value, redisplay all mode lines (the number used is then only
+ used to track down the cause for this full-redisplay).
+
+ Since the frame title uses the same %-constructs as the mode line
+ (except %c and %l), if this variable is non-zero, we also consider
+ redisplaying the title of each frame, see x_consider_frame_title.
+
+ The `redisplay' bits are the same as those used for
+ windows_or_buffers_changed, and setting windows_or_buffers_changed also
+ causes recomputation of the mode lines of all those windows. IOW this
+ variable only has an effect if windows_or_buffers_changed is zero, in which
+ case we should only need to redisplay the mode-line of those objects with
+ a `redisplay' bit set but not the window's text content (tho we may still
+ need to refresh the text content of the selected-window). */
-int windows_or_buffers_changed;
+int update_mode_lines;
/* True after display_mode_line if %l was used and it displayed a
line number. */
b->text->redisplay = true;
}
+void
+maybe_set_redisplay (Lisp_Object symbol)
+{
+ if (HASH_TABLE_P (Vredisplay__variables)
+ && hash_lookup (XHASH_TABLE (Vredisplay__variables), symbol, NULL) >= 0)
+ {
+ bset_update_mode_line (current_buffer);
+ current_buffer->prevent_redisplay_optimizations_p = true;
+ }
+}
+
#ifdef GLYPH_DEBUG
/* True means print traces of redisplay if compiled with
free realized faces now because they depend on face definitions
that might have changed. Don't free faces while there might be
desired matrices pending which reference these faces. */
- if (face_change && !inhibit_free_realized_faces)
+ if (!inhibit_free_realized_faces)
{
- face_change = false;
- free_all_realized_faces (Qnil);
+ if (face_change)
+ {
+ face_change = false;
+ free_all_realized_faces (Qnil);
+ }
+ else if (XFRAME (w->frame)->face_change)
+ {
+ XFRAME (w->frame)->face_change = 0;
+ free_all_realized_faces (w->frame);
+ }
}
/* Perhaps remap BASE_FACE_ID to a user-specified alternative. */
SAVE_IT (it_copy, *it, it_copy_data);
IT_STRING_CHARPOS (it_copy) = 0;
bidi_init_it (0, 0, FRAME_WINDOW_P (it_copy.f), &it_copy.bidi_it);
- while (IT_STRING_CHARPOS (it_copy) != IT_STRING_CHARPOS (*it))
+
+ do
{
charpos = IT_STRING_CHARPOS (it_copy);
if (charpos >= SCHARS (it->string))
break;
bidi_move_to_visually_next (&it_copy.bidi_it);
}
+ while (IT_STRING_CHARPOS (it_copy) != IT_STRING_CHARPOS (*it));
+
RESTORE_IT (it, it, it_copy_data);
}
else
{
struct frame *f = XFRAME (frame);
- if (FRAME_WINDOW_P (f)
- || FRAME_MINIBUF_ONLY_P (f)
- || f->explicit_name)
+ if ((FRAME_WINDOW_P (f)
+ || FRAME_MINIBUF_ONLY_P (f)
+ || f->explicit_name)
+ && NILP (Fframe_parameter (frame, Qtooltip)))
{
/* Do we have more than one visible frame on this X display? */
Lisp_Object tail, other_frame, fmt;
static bool
redisplay_tool_bar (struct frame *f)
{
+ f->tool_bar_redisplayed = true;
#if defined (USE_GTK) || defined (HAVE_NS)
if (FRAME_EXTERNAL_TOOL_BAR (f))
pending = false;
forget_escape_and_glyphless_faces ();
+ inhibit_free_realized_faces = false;
+
/* If face_change, init_iterator will free all realized faces, which
includes the faces referenced from current matrices. So, we
can't reuse current matrices in this case. */
/* If cursor type has been changed on the frame
other than selected, consider all frames. */
if (f != sf && f->cursor_type_changed)
- update_mode_lines = 31;
+ fset_redisplay (f);
}
clear_desired_matrices (f);
}
consider_all_windows_p = (update_mode_lines
|| windows_or_buffers_changed);
-#define AINC(a,i) \
- if (VECTORP (a) && i >= 0 && i < ASIZE (a) && INTEGERP (AREF (a, i))) \
- ASET (a, i, make_number (1 + XINT (AREF (a, i))))
+#define AINC(a,i) \
+ { \
+ Lisp_Object entry = Fgethash (make_number (i), a, make_number (0)); \
+ if (INTEGERP (entry)) \
+ Fputhash (make_number (i), make_number (1 + XINT (entry)), a); \
+ }
AINC (Vredisplay__all_windows_cause, windows_or_buffers_changed);
AINC (Vredisplay__mode_lines_cause, update_mode_lines);
&& FRAME_VISIBLE_P (XFRAME (w->frame))
&& !FRAME_OBSCURED_P (XFRAME (w->frame))
&& !XFRAME (w->frame)->cursor_type_changed
+ && !XFRAME (w->frame)->face_change
/* Make sure recorded data applies to current buffer, etc. */
&& this_line_buffer == current_buffer
&& match_p
#endif
/* Build desired matrices, and update the display. If
- consider_all_windows_p, do it for all windows on all frames.
+ consider_all_windows_p, do it for all windows on all frames that
+ require redisplay, as specified by their 'redisplay' flag.
Otherwise do it for selected_window, only. */
if (consider_all_windows_p)
bool gcscrollbars
/* Only GC scrollbars when we redisplay the whole frame. */
= f->redisplay || !REDISPLAY_SOME_P ();
+ bool f_redisplay_flag = f->redisplay;
/* Mark all the scroll bars to be removed; we'll redeem
the ones we want when we redisplay their windows. */
if (gcscrollbars && FRAME_TERMINAL (f)->condemn_scroll_bars_hook)
goto retry_frame;
}
+ /* If the frame's redisplay flag was not set before
+ we went about redisplaying its windows, but it is
+ set now, that means we employed some redisplay
+ optimizations inside redisplay_windows, and
+ bypassed producing some screen lines. But if
+ f->redisplay is now set, it might mean the old
+ faces are no longer valid (e.g., if redisplaying
+ some window called some Lisp which defined a new
+ face or redefined an existing face), so trying to
+ use them in update_frame will segfault.
+ Therefore, we must redisplay this frame. */
+ if (!f_redisplay_flag && f->redisplay)
+ goto retry_frame;
+
/* Prevent various kinds of signals during display
update. stdio is not robust about handling
signals, which can cause an apparent I/O error. */
/* Compare desired and current matrices, perform output. */
update:
- /* If fonts changed, display again. */
- if (sf->fonts_changed)
- goto retry;
+ /* If fonts changed, display again. Likewise if redisplay_window_1
+ above caused some change (e.g., a change in faces) that requires
+ considering the entire frame again. */
+ if (sf->fonts_changed || sf->redisplay)
+ {
+ if (sf->redisplay)
+ {
+ /* Set this to force a more thorough redisplay.
+ Otherwise, we might immediately loop back to the
+ above "else-if" clause (since all the conditions that
+ led here might still be true), and we will then
+ infloop, because the selected-frame's redisplay flag
+ is not (and cannot be) reset. */
+ windows_or_buffers_changed = 50;
+ }
+ goto retry;
+ }
+
+ /* Prevent freeing of realized faces, since desired matrices are
+ pending that reference the faces we computed and cached. */
+ inhibit_free_realized_faces = true;
/* Prevent various kinds of signals during display update.
stdio is not robust about handling signals,
&& REDISPLAY_SOME_P ()
&& !w->redisplay
&& !w->update_mode_line
+ && !f->face_change
&& !f->redisplay
&& !buffer->text->redisplay
&& BUF_PT (buffer) == w->last_point)
finish_menu_bars:
- /* When we reach a frame's selected window, redo the frame's menu bar. */
+ /* When we reach a frame's selected window, redo the frame's menu
+ bar and the frame's title. */
if (update_mode_line
&& EQ (FRAME_SELECTED_WINDOW (f), window))
{
ignore_mouse_drag_p = true;
#endif
}
+ x_consider_frame_title (w->frame);
#endif
}
eassert (it->method == GET_FROM_BUFFER
|| it->method == GET_FROM_DISPLAY_VECTOR
- || it->method == GET_FROM_STRING);
+ || it->method == GET_FROM_STRING
+ || it->method == GET_FROM_IMAGE);
/* We need to save the current buffer/string position, so it will be
restored by pop_it, because iterate_out_of_display_property
zero_width_ok_p = true;
width = (int)tem;
}
-#ifdef HAVE_WINDOW_SYSTEM
- else if (FRAME_WINDOW_P (it->f)
- && (prop = Fplist_get (plist, QCrelative_width), NUMVAL (prop) > 0))
+ else if (prop = Fplist_get (plist, QCrelative_width), NUMVAL (prop) > 0)
{
/* Relative width `:relative-width FACTOR' specified and valid.
Compute the width of the characters having the `glyph'
it2.glyph_row = NULL;
it2.what = IT_CHARACTER;
- x_produce_glyphs (&it2);
+ PRODUCE_GLYPHS (&it2);
width = NUMVAL (prop) * it2.pixel_width;
}
-#endif /* HAVE_WINDOW_SYSTEM */
else if ((prop = Fplist_get (plist, QCalign_to), !NILP (prop))
&& calc_pixel_width_or_height (&tem, it, prop, font, true,
&align_to))
DEFVAR_LISP ("redisplay--all-windows-cause", Vredisplay__all_windows_cause,
doc: /* */);
- Vredisplay__all_windows_cause
- = Fmake_vector (make_number (100), make_number (0));
+ Vredisplay__all_windows_cause = Fmake_hash_table (0, NULL);
DEFVAR_LISP ("redisplay--mode-lines-cause", Vredisplay__mode_lines_cause,
doc: /* */);
- Vredisplay__mode_lines_cause
- = Fmake_vector (make_number (100), make_number (0));
+ Vredisplay__mode_lines_cause = Fmake_hash_table (0, NULL);
+
+ DEFVAR_LISP ("redisplay--variables", Vredisplay__variables,
+ doc: /* A hash-table of variables changing which triggers a thorough redisplay. */);
+ Vredisplay__variables = Qnil;
}