X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/8865587c55f251ac624e6730505de66d15b28562..1fa9f860564d1b7f223c73395b77efeab3b48555:/src/xdisp.c diff --git a/src/xdisp.c b/src/xdisp.c index a3224e2510..051d307852 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -434,22 +434,54 @@ static Lisp_Object Vmessage_stack; 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. Not 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). + + 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. */ @@ -2661,10 +2693,18 @@ init_iterator (struct it *it, struct window *w, 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. */ @@ -4014,21 +4054,26 @@ face_before_or_after_it_pos (struct it *it, bool before_p) /* With bidi iteration, the character before the current in the visual order cannot be found by simple iteration, because "reverse" reordering is not - supported. Instead, we need to use the move_it_* - family of functions. */ + supported. Instead, we need to start from the string + beginning and go all the way to the current string + position, remembering the previous position. */ /* Ignore face changes before the first visible character on this display line. */ if (it->current_x <= it->first_visible_x) return it->face_id; SAVE_IT (it_copy, *it, it_copy_data); - /* Implementation note: Since move_it_in_display_line - works in the iterator geometry, and thinks the first - character is always the leftmost, even in R2L lines, - we don't need to distinguish between the R2L and L2R - cases here. */ - move_it_in_display_line (&it_copy, SCHARS (it_copy.string), - it_copy.current_x - 1, MOVE_TO_X); - charpos = IT_STRING_CHARPOS (it_copy); + IT_STRING_CHARPOS (it_copy) = 0; + bidi_init_it (0, 0, FRAME_WINDOW_P (it_copy.f), &it_copy.bidi_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 @@ -4108,11 +4153,15 @@ face_before_or_after_it_pos (struct it *it, bool before_p) { if (before_p) { + int current_x; + /* With bidi iteration, the character before the current in the visual order cannot be found by simple iteration, because "reverse" reordering is not supported. Instead, we need to use the move_it_* - family of functions. */ + family of functions, and move to the previous + character starting from the beginning of the visual + line. */ /* Ignore face changes before the first visible character on this display line. */ if (it->current_x <= it->first_visible_x) @@ -4123,8 +4172,9 @@ face_before_or_after_it_pos (struct it *it, bool before_p) character is always the leftmost, even in R2L lines, we don't need to distinguish between the R2L and L2R cases here. */ - move_it_in_display_line (&it_copy, ZV, - it_copy.current_x - 1, MOVE_TO_X); + current_x = it_copy.current_x; + move_it_vertically_backward (&it_copy, 0); + move_it_in_display_line (&it_copy, ZV, current_x - 1, MOVE_TO_X); pos = it_copy.current.pos; RESTORE_IT (it, it, it_copy_data); } @@ -13318,6 +13368,9 @@ redisplay_internal (void) /* True means redisplay has to redisplay the miniwindow. */ bool update_miniwindow_p = false; + /* True means we need to redraw frames whose 'redisplay' bit is set. */ + bool consider_some_frames_p = false; + TRACE ((stderr, "redisplay_internal %d\n", redisplaying_p)); /* No redisplay if running in batch mode or frame is not yet fully @@ -13365,6 +13418,10 @@ redisplay_internal (void) pending = false; forget_escape_and_glyphless_faces (); + inhibit_free_realized_faces = false; + + consider_some_frames_p = 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. */ @@ -13412,7 +13469,7 @@ redisplay_internal (void) /* 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); } @@ -13510,9 +13567,12 @@ redisplay_internal (void) 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); @@ -13531,6 +13591,8 @@ redisplay_internal (void) && FRAME_VISIBLE_P (XFRAME (w->frame)) && !FRAME_OBSCURED_P (XFRAME (w->frame)) && !XFRAME (w->frame)->cursor_type_changed + && !XFRAME (w->frame)->face_change + && !XFRAME (w->frame)->redisplay /* Make sure recorded data applies to current buffer, etc. */ && this_line_buffer == current_buffer && match_p @@ -13726,13 +13788,31 @@ redisplay_internal (void) #endif /* Build desired matrices, and update the display. If - consider_all_windows_p, do it for all windows on all frames. - Otherwise do it for selected_window, only. */ + consider_all_windows_p, do it for all windows on all frames. If + a frame's 'redisplay' flag is set, do it for all windows on each + such frame. Otherwise do it for selected_window, only. */ + + if (!consider_all_windows_p) + { + FOR_EACH_FRAME (tail, frame) + { + if (XFRAME (frame)->redisplay + && XFRAME (frame) != sf + && !FRAME_INITIAL_P (XFRAME (frame))) + { + consider_some_frames_p = true; + break; + } + } + } - if (consider_all_windows_p) + if (consider_all_windows_p || consider_some_frames_p) { FOR_EACH_FRAME (tail, frame) - XFRAME (frame)->updated_p = false; + { + if (XFRAME (frame)->redisplay || consider_all_windows_p) + XFRAME (frame)->updated_p = false; + } propagate_buffer_redisplay (); @@ -13746,6 +13826,9 @@ redisplay_internal (void) && !EQ (FRAME_TTY (f)->top_frame, frame)) continue; + if (!consider_all_windows_p && !f->redisplay) + continue; + retry_frame: if (FRAME_WINDOW_P (f) || FRAME_TERMCAP_P (f) || f == sf) { @@ -13852,6 +13935,10 @@ redisplay_internal (void) if (sf->fonts_changed) 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, which can cause an apparent I/O error. */ @@ -15387,6 +15474,7 @@ try_cursor_movement (Lisp_Object window, struct text_pos startp, && !update_mode_lines && !windows_or_buffers_changed && !f->cursor_type_changed + && !f->redisplay && NILP (Vshow_trailing_whitespace) /* This code is not used for mini-buffer for the sake of the case of redisplaying to replace an echo area message; since in @@ -15877,6 +15965,7 @@ redisplay_window (Lisp_Object window, bool just_this_one_p) && REDISPLAY_SOME_P () && !w->redisplay && !w->update_mode_line + && !f->face_change && !f->redisplay && !buffer->text->redisplay && BUF_PT (buffer) == w->last_point) @@ -16996,6 +17085,7 @@ try_window_reusing_current_matrix (struct window *w) /* Don't try to reuse the display if windows have been split or such. */ || windows_or_buffers_changed + || f->redisplay || f->cursor_type_changed) return false; @@ -17773,7 +17863,7 @@ try_window_id (struct window *w) GIVE_UP (1); /* This flag is used to prevent redisplay optimizations. */ - if (windows_or_buffers_changed || f->cursor_type_changed) + if (windows_or_buffers_changed || f->cursor_type_changed || f->redisplay) GIVE_UP (2); /* This function's optimizations cannot be used if overlays have @@ -19782,7 +19872,8 @@ push_prefix_prop (struct it *it, Lisp_Object prop) 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 @@ -21038,7 +21129,7 @@ window-specific overlays, which can affect the results. Strong directional characters `L', `R', and `AL' can have their intrinsic directionality overridden by directional override -control characters RLO \(u+202e) and LRO \(u+202d). See the +control characters RLO (u+202e) and LRO (u+202d). See the function `get-char-code-property' for a way to inquire about the `bidi-class' property of a character. */) (Lisp_Object from, Lisp_Object to, Lisp_Object object) @@ -25946,9 +26037,7 @@ produce_stretch_glyph (struct it *it) 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' @@ -25968,10 +26057,9 @@ produce_stretch_glyph (struct it *it) 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)) @@ -30994,18 +31082,18 @@ This variable is not guaranteed to be accurate except while processing DEFVAR_LISP ("frame-title-format", Vframe_title_format, doc: /* Template for displaying the title bar of visible frames. -\(Assuming the window manager supports this feature.) +(Assuming the window manager supports this feature.) This variable has the same structure as `mode-line-format', except that the %c and %l constructs are ignored. It is used only on frames for -which no explicit name has been set \(see `modify-frame-parameters'). */); +which no explicit name has been set (see `modify-frame-parameters'). */); DEFVAR_LISP ("icon-title-format", Vicon_title_format, doc: /* Template for displaying the title bar of an iconified frame. -\(Assuming the window manager supports this feature.) +(Assuming the window manager supports this feature.) This variable has the same structure as `mode-line-format' (which see), and is used only on frames for which no explicit name has been set -\(see `modify-frame-parameters'). */); +(see `modify-frame-parameters'). */); Vicon_title_format = Vframe_title_format = listn (CONSTYPE_PURE, 3, @@ -31064,9 +31152,9 @@ A positive number means delay autoselection by that many seconds: a window is autoselected only after the mouse has remained in that window for the duration of the delay. A negative number has a similar effect, but causes windows to be -autoselected only after the mouse has stopped moving. \(Because of +autoselected only after the mouse has stopped moving. (Because of the way Emacs compares mouse events, you will occasionally wait twice -that time before the window gets selected.\) +that time before the window gets selected.) Any other value means to autoselect window instantaneously when the mouse pointer enters it. @@ -31364,13 +31452,11 @@ display table takes effect; in this case, Emacs does not consult 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); }