diff options
Diffstat (limited to 'src/xdisp.c')
-rw-r--r-- | src/xdisp.c | 696 |
1 files changed, 390 insertions, 306 deletions
diff --git a/src/xdisp.c b/src/xdisp.c index f575b27fec5..aced59e1b8e 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -288,6 +288,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ #include <config.h> #include <stdio.h> +#include <stdlib.h> #include <limits.h> #include "lisp.h" @@ -621,15 +622,15 @@ bset_update_mode_line (struct buffer *b) b->text->redisplay = true; } -void -maybe_set_redisplay (Lisp_Object symbol) +DEFUN ("set-buffer-redisplay", Fset_buffer_redisplay, + Sset_buffer_redisplay, 4, 4, 0, + doc: /* Mark the current buffer for redisplay. +This function may be passed to `add-variable-watcher'. */) + (Lisp_Object symbol, Lisp_Object newval, Lisp_Object op, Lisp_Object where) { - 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; - } + bset_update_mode_line (current_buffer); + current_buffer->prevent_redisplay_optimizations_p = true; + return Qnil; } #ifdef GLYPH_DEBUG @@ -817,6 +818,8 @@ static void iterate_out_of_display_property (struct it *); static void pop_it (struct it *); static void redisplay_internal (void); static void echo_area_display (bool); +static void block_buffer_flips (void); +static void unblock_buffer_flips (void); static void redisplay_windows (Lisp_Object); static void redisplay_window (Lisp_Object, bool); static Lisp_Object redisplay_window_error (Lisp_Object); @@ -1247,27 +1250,18 @@ default_line_pixel_height (struct window *w) static Lisp_Object string_from_display_spec (Lisp_Object spec) { - if (CONSP (spec)) + if (VECTORP (spec)) { - while (CONSP (spec)) - { - if (STRINGP (XCAR (spec))) - return XCAR (spec); - spec = XCDR (spec); - } + for (ptrdiff_t i = 0; i < ASIZE (spec); i++) + if (STRINGP (AREF (spec, i))) + return AREF (spec, i); } - else if (VECTORP (spec)) + else { - ptrdiff_t i; - - for (i = 0; i < ASIZE (spec); i++) - { - if (STRINGP (AREF (spec, i))) - return AREF (spec, i); - } - return Qnil; + for (; CONSP (spec); spec = XCDR (spec)) + if (STRINGP (XCAR (spec))) + return XCAR (spec); } - return spec; } @@ -1317,10 +1311,16 @@ pos_visible_p (struct window *w, ptrdiff_t charpos, int *x, int *y, SET_TEXT_POS_FROM_MARKER (top, w->start); /* Scrolling a minibuffer window via scroll bar when the echo area shows long text sometimes resets the minibuffer contents behind - our backs. */ - if (CHARPOS (top) > ZV) + our backs. Also, someone might narrow-to-region and immediately + call a scroll function. */ + if (CHARPOS (top) > ZV || CHARPOS (top) < BEGV) SET_TEXT_POS (top, BEGV, BEGV_BYTE); + /* If the top of the window is after CHARPOS, the latter is surely + not visible. */ + if (charpos >= 0 && CHARPOS (top) > charpos) + return visible_p; + /* Compute exact mode line heights. */ if (WINDOW_WANTS_MODELINE_P (w)) w->mode_line_height @@ -1813,7 +1813,7 @@ estimate_mode_line_height (struct frame *f, enum face_id face_id) cache and mode line face are not yet initialized. */ if (FRAME_FACE_CACHE (f)) { - struct face *face = FACE_FROM_ID (f, face_id); + struct face *face = FACE_FROM_ID_OR_NULL (f, face_id); if (face) { if (face->font) @@ -2232,7 +2232,7 @@ get_phys_cursor_geometry (struct window *w, struct glyph_row *row, ascent = row->ascent; if (row->ascent < glyph->ascent) { - y =- glyph->ascent - row->ascent; + y -= glyph->ascent - row->ascent; ascent = glyph->ascent; } @@ -2494,7 +2494,7 @@ remember_mouse_glyph (struct frame *f, int gx, int gy, NativeRectangle *rect) /* Visible feedback for debugging. */ #if false && defined HAVE_X_WINDOWS - XDrawRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), + XDrawRectangle (FRAME_X_DISPLAY (f), FRAME_X_DRAWABLE (f), f->output_data.x->normal_gc, gx, gy, width, height); #endif @@ -2918,7 +2918,7 @@ init_iterator (struct it *it, struct window *w, /* If we have a boxed mode line, make the first character appear with a left box line. */ - face = FACE_FROM_ID (it->f, remapped_base_face_id); + face = FACE_FROM_ID_OR_NULL (it->f, remapped_base_face_id); if (face && face->box != FACE_NO_BOX) it->start_of_box_run_p = true; } @@ -3877,9 +3877,9 @@ handle_face_prop (struct it *it) { struct face *new_face = FACE_FROM_ID (it->f, new_face_id); /* If it->face_id is -1, old_face below will be NULL, see - the definition of FACE_FROM_ID. This will happen if this - is the initial call that gets the face. */ - struct face *old_face = FACE_FROM_ID (it->f, it->face_id); + the definition of FACE_FROM_ID_OR_NULL. This will happen + if this is the initial call that gets the face. */ + struct face *old_face = FACE_FROM_ID_OR_NULL (it->f, it->face_id); /* If the value of face_id of the iterator is -1, we have to look in front of IT's position and see whether there is a @@ -3888,7 +3888,7 @@ handle_face_prop (struct it *it) { int prev_face_id = face_before_it_pos (it); - old_face = FACE_FROM_ID (it->f, prev_face_id); + old_face = FACE_FROM_ID_OR_NULL (it->f, prev_face_id); } /* If the new face has a box, but the old face does not, @@ -3988,7 +3988,7 @@ handle_face_prop (struct it *it) if (new_face_id != it->face_id) { struct face *new_face = FACE_FROM_ID (it->f, new_face_id); - struct face *old_face = FACE_FROM_ID (it->f, it->face_id); + struct face *old_face = FACE_FROM_ID_OR_NULL (it->f, it->face_id); /* If new face has a box but old face hasn't, this is the start of a run of characters with box, i.e. it has a @@ -4847,7 +4847,6 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object, it->font_height = XCAR (XCDR (spec)); if (!NILP (it->font_height)) { - struct face *face = FACE_FROM_ID (it->f, it->face_id); int new_height = -1; if (CONSP (it->font_height) @@ -4866,6 +4865,7 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object, { /* Call function with current height as argument. Value is the new height. */ + struct face *face = FACE_FROM_ID (it->f, it->face_id); Lisp_Object height; height = safe_call1 (it->font_height, face->lface[LFACE_HEIGHT_INDEX]); @@ -4887,6 +4887,7 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object, /* Evaluate IT->font_height with `height' bound to the current specified height to get the new height. */ ptrdiff_t count = SPECPDL_INDEX (); + struct face *face = FACE_FROM_ID (it->f, it->face_id); specbind (Qheight, face->lface[LFACE_HEIGHT_INDEX]); value = safe_eval (it->font_height); @@ -5016,8 +5017,6 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object, || EQ (XCAR (spec), Qright_fringe)) && CONSP (XCDR (spec))) { - int fringe_bitmap; - if (it) { if (!FRAME_WINDOW_P (it->f)) @@ -5042,8 +5041,8 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object, #ifdef HAVE_WINDOW_SYSTEM value = XCAR (XCDR (spec)); - if (!SYMBOLP (value) - || !(fringe_bitmap = lookup_fringe_bitmap (value))) + int fringe_bitmap = SYMBOLP (value) ? lookup_fringe_bitmap (value) : 0; + if (! fringe_bitmap) /* If we return here, POSITION has been advanced across the text with this property. */ { @@ -6096,7 +6095,7 @@ pop_it (struct it *it) break; case GET_FROM_STRING: { - struct face *face = FACE_FROM_ID (it->f, it->face_id); + struct face *face = FACE_FROM_ID_OR_NULL (it->f, it->face_id); /* Restore the face_box_p flag, since it could have been overwritten by the face of the object that we just finished @@ -6778,7 +6777,8 @@ static next_element_function const get_next_element[NUM_IT_METHODS] = || ((IT)->cmp_it.stop_pos == (CHARPOS) \ && composition_reseat_it (&(IT)->cmp_it, CHARPOS, BYTEPOS, \ END_CHARPOS, (IT)->w, \ - FACE_FROM_ID ((IT)->f, (IT)->face_id), \ + FACE_FROM_ID_OR_NULL ((IT)->f, \ + (IT)->face_id), \ (IT)->string))) @@ -7081,6 +7081,19 @@ get_next_display_element (struct it *it) goto display_control; } + /* Handle non-ascii hyphens in the mode where it only + gets highlighting. */ + + if (nonascii_hyphen_p && EQ (Vnobreak_char_display, Qt)) + { + /* Merge `nobreak-space' into the current face. */ + face_id = merge_faces (it->f, Qnobreak_hyphen, 0, + it->face_id); + XSETINT (it->ctl_chars[0], '-'); + ctl_len = 1; + goto display_control; + } + /* Handle sequences that start with the "escape glyph". */ /* the default escape glyph is \. */ @@ -7097,15 +7110,6 @@ get_next_display_element (struct it *it) ? merge_faces (it->f, Qt, lface_id, it->face_id) : merge_escape_glyph_face (it)); - /* Draw non-ASCII hyphen with just highlighting: */ - - if (nonascii_hyphen_p && EQ (Vnobreak_char_display, Qt)) - { - XSETINT (it->ctl_chars[0], '-'); - ctl_len = 1; - goto display_control; - } - /* Draw non-ASCII space/hyphen with escape glyph: */ if (nonascii_space_p || nonascii_hyphen_p) @@ -7203,7 +7207,7 @@ get_next_display_element (struct it *it) if (it->method == GET_FROM_STRING && it->sp) { int face_id = underlying_face_id (it); - struct face *face = FACE_FROM_ID (it->f, face_id); + struct face *face = FACE_FROM_ID_OR_NULL (it->f, face_id); if (face) { @@ -7736,8 +7740,8 @@ next_element_from_display_vector (struct it *it) /* Glyphs in the display vector could have the box face, so we need to set the related flags in the iterator, as appropriate. */ - this_face = FACE_FROM_ID (it->f, it->face_id); - prev_face = FACE_FROM_ID (it->f, prev_face_id); + this_face = FACE_FROM_ID_OR_NULL (it->f, it->face_id); + prev_face = FACE_FROM_ID_OR_NULL (it->f, prev_face_id); /* Is this character the first character of a box-face run? */ it->start_of_box_run_p = (this_face && this_face->box != FACE_NO_BOX @@ -7762,7 +7766,7 @@ next_element_from_display_vector (struct it *it) it->saved_face_id); } } - next_face = FACE_FROM_ID (it->f, next_face_id); + next_face = FACE_FROM_ID_OR_NULL (it->f, next_face_id); it->end_of_box_run_p = (this_face && this_face->box != FACE_NO_BOX && (!next_face || next_face->box == FACE_NO_BOX)); @@ -8554,7 +8558,8 @@ move_it_in_display_line_to (struct it *it, void *ppos_data = NULL; bool may_wrap = false; enum it_method prev_method = it->method; - ptrdiff_t closest_pos IF_LINT (= 0), prev_pos = IT_CHARPOS (*it); + ptrdiff_t closest_pos UNINIT; + ptrdiff_t prev_pos = IT_CHARPOS (*it); bool saw_smaller_pos = prev_pos < to_charpos; /* Don't produce glyphs in produce_glyphs. */ @@ -8605,8 +8610,7 @@ move_it_in_display_line_to (struct it *it, && it->dpvec + it->current.dpvec_index + 1 >= it->dpend))) /* If there's a line-/wrap-prefix, handle it. */ - if (it->hpos == 0 && it->method == GET_FROM_BUFFER - && it->current_y < it->last_visible_y) + if (it->hpos == 0 && it->method == GET_FROM_BUFFER) handle_line_prefix (it); if (IT_CHARPOS (*it) < CHARPOS (this_line_min_pos)) @@ -9033,6 +9037,11 @@ move_it_in_display_line_to (struct it *it, } else result = MOVE_NEWLINE_OR_CR; + /* If we've processed the newline, make sure this flag is + reset, as it must only be set when the newline itself is + processed. */ + if (result == MOVE_NEWLINE_OR_CR) + it->constrain_row_ascent_descent_p = false; break; } @@ -9868,26 +9877,28 @@ the maximum pixel-height of all text lines. The optional argument FROM, if non-nil, specifies the first text position and defaults to the minimum accessible position of the buffer. -If FROM is t, use the minimum accessible position that is not a newline -character. TO, if non-nil, specifies the last text position and +If FROM is t, use the minimum accessible position that starts a +non-empty line. TO, if non-nil, specifies the last text position and defaults to the maximum accessible position of the buffer. If TO is t, -use the maximum accessible position that is not a newline character. +use the maximum accessible position that ends a non-empty line. The optional argument X-LIMIT, if non-nil, specifies the maximum text width that can be returned. X-LIMIT nil or omitted, means to use the -pixel-width of WINDOW's body; use this if you do not intend to change -the width of WINDOW. Use the maximum width WINDOW may assume if you -intend to change WINDOW's width. In any case, text whose x-coordinate -is beyond X-LIMIT is ignored. Since calculating the width of long lines -can take some time, it's always a good idea to make this argument as -small as possible; in particular, if the buffer contains long lines that -shall be truncated anyway. +pixel-width of WINDOW's body; use this if you want to know how high +WINDOW should be become in order to fit all of its buffer's text with +the width of WINDOW unaltered. Use the maximum width WINDOW may assume +if you intend to change WINDOW's width. In any case, text whose +x-coordinate is beyond X-LIMIT is ignored. Since calculating the width +of long lines can take some time, it's always a good idea to make this +argument as small as possible; in particular, if the buffer contains +long lines that shall be truncated anyway. The optional argument Y-LIMIT, if non-nil, specifies the maximum text -height that can be returned. Text lines whose y-coordinate is beyond -Y-LIMIT are ignored. Since calculating the text height of a large -buffer can take some time, it makes sense to specify this argument if -the size of the buffer is unknown. +height (excluding the height of the mode- or header-line, if any) that +can be returned. Text lines whose y-coordinate is beyond Y-LIMIT are +ignored. Since calculating the text height of a large buffer can take +some time, it makes sense to specify this argument if the size of the +buffer is large or unknown. Optional argument MODE-AND-HEADER-LINE nil or omitted means do not include the height of the mode- or header-line of WINDOW in the return @@ -9905,7 +9916,7 @@ include the height of both, if present, in the return value. */) ptrdiff_t start, end, pos; struct text_pos startp; void *itdata = NULL; - int c, max_y = -1, x = 0, y = 0; + int c, max_x = 0, max_y = 0, x = 0, y = 0; CHECK_BUFFER (buffer); b = XBUFFER (buffer); @@ -9950,11 +9961,13 @@ include the height of both, if present, in the return value. */) end = max (start, min (XINT (to), ZV)); } - if (!NILP (y_limit)) - { - CHECK_NUMBER (y_limit); - max_y = min (XINT (y_limit), INT_MAX); - } + if (!NILP (x_limit) && RANGED_INTEGERP (0, x_limit, INT_MAX)) + max_x = XINT (x_limit); + + if (NILP (y_limit)) + max_y = INT_MAX; + else if (RANGED_INTEGERP (0, y_limit, INT_MAX)) + max_y = XINT (y_limit); itdata = bidi_shelve_cache (); SET_TEXT_POS (startp, start, CHAR_TO_BYTE (start)); @@ -9964,27 +9977,33 @@ include the height of both, if present, in the return value. */) x = move_it_to (&it, end, -1, max_y, -1, MOVE_TO_POS | MOVE_TO_Y); else { - CHECK_NUMBER (x_limit); - it.last_visible_x = min (XINT (x_limit), INFINITY); + it.last_visible_x = max_x; /* Actually, we never want move_it_to stop at to_x. But to make sure that move_it_in_display_line_to always moves far enough, we set it to INT_MAX and specify MOVE_TO_X. */ x = move_it_to (&it, end, INT_MAX, max_y, -1, MOVE_TO_POS | MOVE_TO_X | MOVE_TO_Y); + /* Don't return more than X-LIMIT. */ + if (x > max_x) + x = max_x; } - y = it.current_y + it.max_ascent + it.max_descent; + /* Subtract height of header-line which was counted automatically by + start_display. */ + y = it.current_y + it.max_ascent + it.max_descent + - WINDOW_HEADER_LINE_HEIGHT (w); + /* Don't return more than Y-LIMIT. */ + if (y > max_y) + y = max_y; - if (!EQ (mode_and_header_line, Qheader_line) - && !EQ (mode_and_header_line, Qt)) - /* Do not count the header-line which was counted automatically by - start_display. */ - y = y - WINDOW_HEADER_LINE_HEIGHT (w); + if (EQ (mode_and_header_line, Qheader_line) + || EQ (mode_and_header_line, Qt)) + /* Re-add height of header-line as requested. */ + y = y + WINDOW_HEADER_LINE_HEIGHT (w); if (EQ (mode_and_header_line, Qmode_line) || EQ (mode_and_header_line, Qt)) - /* Do count the mode-line which is not included automatically by - start_display. */ + /* Add height of mode-line as requested. */ y = y + WINDOW_MODE_LINE_HEIGHT (w); bidi_unshelve_cache (itdata, false); @@ -10562,25 +10581,21 @@ update_echo_area (void) static void ensure_echo_area_buffers (void) { - int i; - - for (i = 0; i < 2; ++i) + for (int i = 0; i < 2; i++) if (!BUFFERP (echo_buffer[i]) || !BUFFER_LIVE_P (XBUFFER (echo_buffer[i]))) { - char name[30]; - Lisp_Object old_buffer; - int j; - - old_buffer = echo_buffer[i]; - echo_buffer[i] = Fget_buffer_create - (make_formatted_string (name, " *Echo Area %d*", i)); + Lisp_Object old_buffer = echo_buffer[i]; + static char const name_fmt[] = " *Echo Area %d*"; + char name[sizeof name_fmt + INT_STRLEN_BOUND (int)]; + AUTO_STRING_WITH_LEN (lname, name, sprintf (name, name_fmt, i)); + echo_buffer[i] = Fget_buffer_create (lname); bset_truncate_lines (XBUFFER (echo_buffer[i]), Qnil); /* to force word wrap in echo area - it was decided to postpone this*/ /* XBUFFER (echo_buffer[i])->word_wrap = Qt; */ - for (j = 0; j < 2; ++j) + for (int j = 0; j < 2; j++) if (EQ (old_buffer, echo_area_buffer[j])) echo_area_buffer[j] = echo_buffer[i]; } @@ -11327,7 +11342,7 @@ clear_garbaged_frames (void) fset_redisplay (f); f->garbaged = false; f->resized_p = false; - } + } } frame_garbaged = false; @@ -11725,6 +11740,12 @@ x_consider_frame_title (Lisp_Object frame) record_unwind_protect (unwind_format_mode_line, format_mode_line_unwind_data (f, current_buffer, selected_window, false)); + /* select-frame calls resize_mini_window, which could resize the + mini-window and by that undo the effect of this redisplay + cycle wrt minibuffer and echo-area display. Binding + inhibit-redisplay to t makes the call to resize_mini_window a + no-op, thus avoiding the adverse side effects. */ + specbind (Qinhibit_redisplay, Qt); Fselect_window (f->selected_window, Qt); set_buffer_internal_1 @@ -11867,24 +11888,7 @@ prepare_menu_bars (void) && !XBUFFER (w->contents)->text->redisplay) continue; - /* If a window on this frame changed size, report that to - the user and clear the size-change flag. */ - if (FRAME_WINDOW_SIZES_CHANGED (f)) - { - Lisp_Object functions; - - /* Clear flag first in case we get an error below. */ - FRAME_WINDOW_SIZES_CHANGED (f) = false; - functions = Vwindow_size_change_functions; - - while (CONSP (functions)) - { - if (!EQ (XCAR (functions), Qt)) - call1 (XCAR (functions), frame); - functions = XCDR (functions); - } - } - + run_window_size_change_functions (frame); menu_bar_hooks_run = update_menu_bar (f, false, menu_bar_hooks_run); #ifdef HAVE_WINDOW_SYSTEM update_tool_bar (f, false); @@ -13036,6 +13040,17 @@ hscroll_window_tree (Lisp_Object window) init_to_row_start (&it, w, cursor_row); it.last_visible_x = INFINITY; move_it_in_display_line_to (&it, pt, -1, MOVE_TO_POS); + /* If the line ends in an overlay string with a newline, + we might infloop, because displaying the window will + want to put the cursor after the overlay, i.e. at X + coordinate of zero on the next screen line. So we + use the buffer position prior to the overlay string + instead. */ + if (it.method == GET_FROM_STRING && pt > 1) + { + init_to_row_start (&it, w, cursor_row); + move_it_in_display_line_to (&it, pt - 1, -1, MOVE_TO_POS); + } current_buffer = saved_current_buffer; /* Position cursor in window. */ @@ -13517,6 +13532,12 @@ redisplay_internal (void) bool polling_stopped_here = false; Lisp_Object tail, frame; + /* 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). */ + enum { MAX_HSCROLL_RETRIES = 16 }; + int hscroll_retries = 0; + /* True means redisplay has to consider all windows on all frames. False, only selected_window is considered. */ bool consider_all_windows_p; @@ -13556,10 +13577,11 @@ redisplay_internal (void) count = SPECPDL_INDEX (); record_unwind_protect_void (unwind_redisplay); redisplaying_p = true; + block_buffer_flips (); specbind (Qinhibit_free_realized_faces, Qnil); /* Record this function, so it appears on the profiler's backtraces. */ - record_in_backtrace (Qredisplay_internal, 0, 0); + record_in_backtrace (Qredisplay_internal_xC_functionx, 0, 0); FOR_EACH_FRAME (tail, frame) XFRAME (frame)->already_hscrolled_p = false; @@ -13680,24 +13702,12 @@ redisplay_internal (void) it's too late for the hooks in window-size-change-functions, which have been examined already in prepare_menu_bars. So in that case we call the hooks here only for the selected frame. */ - if (sf->redisplay && FRAME_WINDOW_SIZES_CHANGED (sf)) + if (sf->redisplay) { - Lisp_Object functions; ptrdiff_t count1 = SPECPDL_INDEX (); record_unwind_save_match_data (); - - /* Clear flag first in case we get an error below. */ - FRAME_WINDOW_SIZES_CHANGED (sf) = false; - functions = Vwindow_size_change_functions; - - while (CONSP (functions)) - { - if (!EQ (XCAR (functions), Qt)) - call1 (XCAR (functions), selected_frame); - functions = XCDR (functions); - } - + run_window_size_change_functions (selected_frame); unbind_to (count1, Qnil); } @@ -13719,22 +13729,10 @@ redisplay_internal (void) { if (sf->redisplay) { - Lisp_Object functions; ptrdiff_t count1 = SPECPDL_INDEX (); record_unwind_save_match_data (); - - /* Clear flag first in case we get an error below. */ - FRAME_WINDOW_SIZES_CHANGED (sf) = false; - functions = Vwindow_size_change_functions; - - while (CONSP (functions)) - { - if (!EQ (XCAR (functions), Qt)) - call1 (XCAR (functions), selected_frame); - functions = XCDR (functions); - } - + run_window_size_change_functions (selected_frame); unbind_to (count1, Qnil); } @@ -14057,8 +14055,12 @@ redisplay_internal (void) if (!f->already_hscrolled_p) { f->already_hscrolled_p = true; - if (hscroll_windows (f->root_window)) - goto retry_frame; + if (hscroll_retries <= MAX_HSCROLL_RETRIES + && hscroll_windows (f->root_window)) + { + hscroll_retries++; + goto retry_frame; + } } /* If the frame's redisplay flag was not set before @@ -14073,7 +14075,23 @@ redisplay_internal (void) use them in update_frame will segfault. Therefore, we must redisplay this frame. */ if (!f_redisplay_flag && f->redisplay) - goto retry_frame; + goto retry_frame; + + /* In some case (e.g., window resize), we notice + only during window updating that the window + content changed unpredictably (e.g., a GTK + scrollbar moved) and that our previous estimation + of the frame content was garbage. We have to + start over. These cases should be rare, so going + all the way back to the top of redisplay should + be good enough. + + Why FRAME_WINDOW_P? See + https://lists.gnu.org/archive/html/emacs-devel/2016-10/msg00957.html + + */ + if (FRAME_GARBAGED_P (f) && FRAME_WINDOW_P (f)) + goto retry; /* Prevent various kinds of signals during display update. stdio is not robust about handling @@ -14102,6 +14120,7 @@ redisplay_internal (void) 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); @@ -14111,9 +14130,6 @@ redisplay_internal (void) } else if (FRAME_VISIBLE_P (sf) && !FRAME_OBSCURED_P (sf)) { - Lisp_Object mini_window = FRAME_MINIBUF_WINDOW (sf); - struct frame *mini_frame; - displayed_buffer = XBUFFER (XWINDOW (selected_window)->contents); /* Use list_of_error, not Qerror, so that we catch only errors and don't run the debugger. */ @@ -14121,8 +14137,8 @@ redisplay_internal (void) list_of_error, redisplay_window_error); if (update_miniwindow_p) - internal_condition_case_1 (redisplay_window_1, mini_window, - list_of_error, + internal_condition_case_1 (redisplay_window_1, + FRAME_MINIBUF_WINDOW (sf), list_of_error, redisplay_window_error); /* Compare desired and current matrices, perform output. */ @@ -14159,8 +14175,12 @@ redisplay_internal (void) if (FRAME_VISIBLE_P (sf) && !FRAME_OBSCURED_P (sf)) { - if (hscroll_windows (selected_window)) - goto retry; + if (hscroll_retries <= MAX_HSCROLL_RETRIES + && hscroll_windows (selected_window)) + { + hscroll_retries++; + goto retry; + } XWINDOW (selected_window)->must_be_updated_p = true; pending = update_frame (sf, false, false); @@ -14172,16 +14192,20 @@ redisplay_internal (void) have put text on a frame other than the selected one, so the above call to update_frame would not have caught it. Catch it here. */ - mini_window = FRAME_MINIBUF_WINDOW (sf); - mini_frame = XFRAME (WINDOW_FRAME (XWINDOW (mini_window))); + Lisp_Object mini_window = FRAME_MINIBUF_WINDOW (sf); + struct frame *mini_frame = XFRAME (WINDOW_FRAME (XWINDOW (mini_window))); if (mini_frame != sf && FRAME_WINDOW_P (mini_frame)) { XWINDOW (mini_window)->must_be_updated_p = true; pending |= update_frame (mini_frame, false, false); mini_frame->cursor_type_changed = false; - if (!pending && hscroll_windows (mini_window)) - goto retry; + if (!pending && hscroll_retries <= MAX_HSCROLL_RETRIES + && hscroll_windows (mini_window)) + { + hscroll_retries++; + goto retry; + } } } @@ -14295,6 +14319,11 @@ redisplay_internal (void) RESUME_POLLING; } +static void +unwind_redisplay_preserve_echo_area (void) +{ + unblock_buffer_flips (); +} /* Redisplay, but leave alone any recent echo area message unless another message has been requested in its place. @@ -14312,6 +14341,12 @@ redisplay_preserve_echo_area (int from_where) { TRACE ((stderr, "redisplay_preserve_echo_area (%d)\n", from_where)); + block_input (); + ptrdiff_t count = SPECPDL_INDEX (); + record_unwind_protect_void (unwind_redisplay_preserve_echo_area); + block_buffer_flips (); + unblock_input (); + if (!NILP (echo_area_buffer[1])) { /* We have a previously displayed message, but no current @@ -14324,6 +14359,7 @@ redisplay_preserve_echo_area (int from_where) redisplay_internal (); flush_frame (SELECTED_FRAME ()); + unbind_to (count, Qnil); } @@ -14333,6 +14369,7 @@ static void unwind_redisplay (void) { redisplaying_p = false; + unblock_buffer_flips (); } @@ -14442,6 +14479,38 @@ disp_char_vector (struct Lisp_Char_Table *dp, int c) return val; } +static int buffer_flip_blocked_depth; + +static void +block_buffer_flips (void) +{ + eassert (buffer_flip_blocked_depth >= 0); + buffer_flip_blocked_depth++; +} + +static void +unblock_buffer_flips (void) +{ + eassert (buffer_flip_blocked_depth > 0); + if (--buffer_flip_blocked_depth == 0) + { + Lisp_Object tail, frame; + block_input (); + FOR_EACH_FRAME (tail, frame) + { + struct frame *f = XFRAME (frame); + if (FRAME_TERMINAL (f)->buffer_flipping_unblocked_hook) + (*FRAME_TERMINAL (f)->buffer_flipping_unblocked_hook) (f); + } + unblock_input (); + } +} + +bool +buffer_flipping_blocked_p (void) +{ + return buffer_flip_blocked_depth > 0; +} /*********************************************************************** @@ -15338,6 +15407,40 @@ try_scrolling (Lisp_Object window, bool just_this_one_p, if (dy > 0) scroll_down_p = true; } + else if (PT == IT_CHARPOS (it) + && IT_CHARPOS (it) < ZV + && it.method == GET_FROM_STRING + && arg_scroll_conservatively > scroll_limit + && it.current_x == 0) + { + enum move_it_result skip; + int y1 = it.current_y; + int vpos; + + /* A before-string that includes newlines and is displayed + on the last visible screen line could fail us under + scroll-conservatively > 100, because we will be unable to + position the cursor on that last visible line. Try to + recover by finding the first screen line that has some + glyphs coming from the buffer text. */ + do { + skip = move_it_in_display_line_to (&it, ZV, -1, MOVE_TO_POS); + if (skip != MOVE_NEWLINE_OR_CR + || IT_CHARPOS (it) != PT + || it.method == GET_FROM_BUFFER) + break; + vpos = it.vpos; + move_it_to (&it, -1, -1, -1, vpos + 1, MOVE_TO_VPOS); + } while (it.vpos > vpos); + + dy = it.current_y - y1; + + if (dy > scroll_max) + return SCROLLING_FAILED; + + if (dy > 0) + scroll_down_p = true; + } } if (scroll_down_p) @@ -15542,12 +15645,14 @@ try_scrolling (Lisp_Object window, bool just_this_one_p, The new window start will be computed, based on W's width, starting from the start of the continued line. It is the start of the - screen line with the minimum distance from the old start W->start. */ + screen line with the minimum distance from the old start W->start, + which is still before point (otherwise point will definitely not + be visible in the window). */ static bool compute_window_start_on_continuation_line (struct window *w) { - struct text_pos pos, start_pos; + struct text_pos pos, start_pos, pos_before_pt; bool window_start_changed_p = false; SET_TEXT_POS_FROM_MARKER (start_pos, w->start); @@ -15575,10 +15680,14 @@ compute_window_start_on_continuation_line (struct window *w) reseat_at_previous_visible_line_start (&it); /* If the line start is "too far" away from the window start, - say it takes too much time to compute a new window start. */ - if (CHARPOS (start_pos) - IT_CHARPOS (it) - /* PXW: Do we need upper bounds here? */ - < WINDOW_TOTAL_LINES (w) * WINDOW_TOTAL_COLS (w)) + say it takes too much time to compute a new window start. + Also, give up if the line start is after point, as in that + case point will not be visible with any window start we + compute. */ + if (IT_CHARPOS (it) <= PT + || (CHARPOS (start_pos) - IT_CHARPOS (it) + /* PXW: Do we need upper bounds here? */ + < WINDOW_TOTAL_LINES (w) * WINDOW_TOTAL_COLS (w))) { int min_distance, distance; @@ -15588,12 +15697,14 @@ compute_window_start_on_continuation_line (struct window *w) decreased, the new window start will be < the old start. So, we're looking for the display line start with the minimum distance from the old window start. */ - pos = it.current.pos; + pos_before_pt = pos = it.current.pos; min_distance = INFINITY; while ((distance = eabs (CHARPOS (start_pos) - IT_CHARPOS (it))), distance < min_distance) { min_distance = distance; + if (CHARPOS (pos) <= PT) + pos_before_pt = pos; pos = it.current.pos; if (it.line_wrap == WORD_WRAP) { @@ -15616,6 +15727,13 @@ compute_window_start_on_continuation_line (struct window *w) move_it_by_lines (&it, 1); } + /* It makes very little sense to make the new window start + after point, as point won't be visible. If that's what + the loop above finds, fall back on the candidate before + or at point that is closest to the old window start. */ + if (CHARPOS (pos) > PT) + pos = pos_before_pt; + /* Set the window start there. */ SET_MARKER_FROM_TEXT_POS (w->start, pos); window_start_changed_p = true; @@ -16163,6 +16281,7 @@ redisplay_window (Lisp_Object window, bool just_this_one_p) bool last_line_misfit = false; ptrdiff_t beg_unchanged, end_unchanged; int frame_line_height; + bool use_desired_matrix; void *itdata = NULL; SET_TEXT_POS (lpoint, PT, PT_BYTE); @@ -16891,7 +17010,7 @@ redisplay_window (Lisp_Object window, bool just_this_one_p) itdata = bidi_shelve_cache (); /* Redisplay the window. */ - bool use_desired_matrix = false; + use_desired_matrix = false; if (!current_matrix_up_to_date_p || windows_or_buffers_changed || f->cursor_type_changed @@ -16931,6 +17050,27 @@ redisplay_window (Lisp_Object window, bool just_this_one_p) move_it_by_lines (&it, -1); try_window (window, it.current.pos, 0); } + else if (scroll_conservatively > SCROLL_LIMIT + && (it.method == GET_FROM_STRING + || overlay_touches_p (IT_CHARPOS (it))) + && IT_CHARPOS (it) < ZV) + { + /* If the window starts with a before-string that spans more + than one screen line, using that position to display the + window might fail to bring point into the view, because + start_display will always start by displaying the string, + whereas the code above determines where to set w->start + by the buffer position of the place where it takes screen + coordinates. Try to recover by finding the next screen + line that displays buffer text. */ + ptrdiff_t pos0 = IT_CHARPOS (it); + + clear_glyph_matrix (w->desired_matrix); + do { + move_it_by_lines (&it, 1); + } while (IT_CHARPOS (it) == pos0); + try_window (window, it.current.pos, 0); + } else { /* Not much we can do about it. */ @@ -17131,16 +17271,7 @@ redisplay_window (Lisp_Object window, bool just_this_one_p) ignore_mouse_drag_p = true; #endif } - ptrdiff_t count1 = SPECPDL_INDEX (); - /* x_consider_frame_title calls select-frame, which calls - resize_mini_window, which could resize the mini-window and by - that undo the effect of this redisplay cycle wrt minibuffer - and echo-area display. Binding inhibit-redisplay to t makes - the call to resize_mini_window a no-op, thus avoiding the - adverse side effects. */ - specbind (Qinhibit_redisplay, Qt); x_consider_frame_title (w->frame); - unbind_to (count1, Qnil); #endif } @@ -18747,7 +18878,7 @@ try_window_id (struct window *w) eassert (MATRIX_ROW_DISPLAYS_TEXT_P (first_unchanged_at_end_row)); row = find_last_row_displaying_text (w->current_matrix, &it, first_unchanged_at_end_row); - eassert (row && MATRIX_ROW_DISPLAYS_TEXT_P (row)); + eassume (row && MATRIX_ROW_DISPLAYS_TEXT_P (row)); adjust_window_ends (w, row, true); eassert (w->window_end_bytepos >= 0); IF_DEBUG (debug_method_add (w, "A")); @@ -18777,10 +18908,9 @@ try_window_id (struct window *w) struct glyph_row *current_row = current_matrix->rows + vpos; struct glyph_row *desired_row = desired_matrix->rows + vpos; - for (row = NULL; - row == NULL && vpos >= first_vpos; - --vpos, --current_row, --desired_row) + for (row = NULL; !row; --vpos, --current_row, --desired_row) { + eassert (first_vpos <= vpos); if (desired_row->enabled_p) { if (MATRIX_ROW_DISPLAYS_TEXT_P (desired_row)) @@ -18790,7 +18920,6 @@ try_window_id (struct window *w) row = current_row; } - eassert (row != NULL); w->window_end_vpos = vpos + 1; w->window_end_pos = Z - MATRIX_ROW_END_CHARPOS (row); w->window_end_bytepos = Z_BYTE - MATRIX_ROW_END_BYTEPOS (row); @@ -19554,7 +19683,6 @@ append_space_for_newline (struct it *it, bool default_face_p) struct text_pos saved_pos; Lisp_Object saved_object; struct face *face; - struct glyph *g; saved_object = it->object; saved_pos = it->position; @@ -19590,7 +19718,7 @@ append_space_for_newline (struct it *it, bool default_face_p) /* Make sure this space glyph has the right ascent and descent values, or else cursor at end of line will look funny, and height of empty lines will be incorrect. */ - g = it->glyph_row->glyphs[TEXT_AREA] + n; + struct glyph *g = it->glyph_row->glyphs[TEXT_AREA] + n; struct font *font = face->font ? face->font : FRAME_FONT (it->f); if (n == 0) { @@ -19715,15 +19843,15 @@ extend_face_to_end_of_line (struct it *it) return; /* The default face, possibly remapped. */ - default_face = FACE_FROM_ID (f, lookup_basic_face (f, DEFAULT_FACE_ID)); + default_face = FACE_FROM_ID_OR_NULL (f, + lookup_basic_face (f, DEFAULT_FACE_ID)); /* Face extension extends the background and box of IT->face_id to the end of the line. If the background equals the background of the frame, we don't have to do anything. */ - if (it->face_before_selective_p) - face = FACE_FROM_ID (f, it->saved_face_id); - else - face = FACE_FROM_ID (f, it->face_id); + face = FACE_FROM_ID (f, (it->face_before_selective_p + ? it->saved_face_id + : it->face_id)); if (FRAME_WINDOW_P (f) && MATRIX_ROW_DISPLAYS_TEXT_P (it->glyph_row) @@ -20463,16 +20591,16 @@ display_line (struct it *it) struct it wrap_it; void *wrap_data = NULL; bool may_wrap = false; - int wrap_x IF_LINT (= 0); + int wrap_x UNINIT; int wrap_row_used = -1; - int wrap_row_ascent IF_LINT (= 0), wrap_row_height IF_LINT (= 0); - int wrap_row_phys_ascent IF_LINT (= 0), wrap_row_phys_height IF_LINT (= 0); - int wrap_row_extra_line_spacing IF_LINT (= 0); - ptrdiff_t wrap_row_min_pos IF_LINT (= 0), wrap_row_min_bpos IF_LINT (= 0); - ptrdiff_t wrap_row_max_pos IF_LINT (= 0), wrap_row_max_bpos IF_LINT (= 0); + int wrap_row_ascent UNINIT, wrap_row_height UNINIT; + int wrap_row_phys_ascent UNINIT, wrap_row_phys_height UNINIT; + int wrap_row_extra_line_spacing UNINIT; + ptrdiff_t wrap_row_min_pos UNINIT, wrap_row_min_bpos UNINIT; + ptrdiff_t wrap_row_max_pos UNINIT, wrap_row_max_bpos UNINIT; int cvpos; ptrdiff_t min_pos = ZV + 1, max_pos = 0; - ptrdiff_t min_bpos IF_LINT (= 0), max_bpos IF_LINT (= 0); + ptrdiff_t min_bpos UNINIT, max_bpos UNINIT; bool pending_handle_line_prefix = false; /* We always start displaying at hpos zero even if hscrolled. */ @@ -21889,7 +22017,6 @@ Value is the new character position of point. */) } /* Move to the target X coordinate. */ -#ifdef HAVE_WINDOW_SYSTEM /* On GUI frames, as we don't know the X coordinate of the character to the left of point, moving point to the left requires walking, one grapheme cluster at a time, until we @@ -21946,9 +22073,7 @@ Value is the new character position of point. */) new_pos.bytepos = CHAR_TO_BYTE (new_pos.charpos); it.current.pos = new_pos; } - else -#endif - if (it.current_x != target_x) + else if (it.current_x != target_x) move_it_in_display_line_to (&it, ZV, target_x, MOVE_TO_POS | MOVE_TO_X); /* If we ended up in a display string that covers point, move to @@ -23410,6 +23535,16 @@ decode_mode_spec_coding (Lisp_Object coding_system, char *buf, bool eol_flag) return buf; } +/* Return the approximate percentage N is of D (rounding upward), or 99, + whichever is less. Assume 0 < D and 0 <= N <= D * INT_MAX / 100. */ + +static int +percent99 (ptrdiff_t n, ptrdiff_t d) +{ + int percent = (d - 1 + 100.0 * n) / d; + return min (percent, 99); +} + /* Return a string for the output of a mode line %-spec for window W, generated by character C. FIELD_WIDTH > 0 means pad the string returned with spaces to that value. Return a Lisp string in @@ -23697,29 +23832,17 @@ decode_mode_spec (struct window *w, register int c, int field_width, case 'p': { ptrdiff_t pos = marker_position (w->start); - ptrdiff_t total = BUF_ZV (b) - BUF_BEGV (b); + ptrdiff_t begv = BUF_BEGV (b); + ptrdiff_t zv = BUF_ZV (b); - if (w->window_end_pos <= BUF_Z (b) - BUF_ZV (b)) - { - if (pos <= BUF_BEGV (b)) - return "All"; - else - return "Bottom"; - } - else if (pos <= BUF_BEGV (b)) + if (w->window_end_pos <= BUF_Z (b) - zv) + return pos <= begv ? "All" : "Bottom"; + else if (pos <= begv) return "Top"; else { - if (total > 1000000) - /* Do it differently for a large value, to avoid overflow. */ - total = ((pos - BUF_BEGV (b)) + (total / 100) - 1) / (total / 100); - else - total = ((pos - BUF_BEGV (b)) * 100 + total - 1) / total; - /* We can't normally display a 3-digit number, - so get us a 2-digit number that is close. */ - if (total == 100) - total = 99; - sprintf (decode_mode_spec_buf, "%2"pD"d%%", total); + sprintf (decode_mode_spec_buf, "%2d%%", + percent99 (pos - begv, zv - begv)); return decode_mode_spec_buf; } } @@ -23729,30 +23852,16 @@ decode_mode_spec (struct window *w, register int c, int field_width, { ptrdiff_t toppos = marker_position (w->start); ptrdiff_t botpos = BUF_Z (b) - w->window_end_pos; - ptrdiff_t total = BUF_ZV (b) - BUF_BEGV (b); + ptrdiff_t begv = BUF_BEGV (b); + ptrdiff_t zv = BUF_ZV (b); - if (botpos >= BUF_ZV (b)) - { - if (toppos <= BUF_BEGV (b)) - return "All"; - else - return "Bottom"; - } + if (zv <= botpos) + return toppos <= begv ? "All" : "Bottom"; else { - if (total > 1000000) - /* Do it differently for a large value, to avoid overflow. */ - total = ((botpos - BUF_BEGV (b)) + (total / 100) - 1) / (total / 100); - else - total = ((botpos - BUF_BEGV (b)) * 100 + total - 1) / total; - /* We can't normally display a 3-digit number, - so get us a 2-digit number that is close. */ - if (total == 100) - total = 99; - if (toppos <= BUF_BEGV (b)) - sprintf (decode_mode_spec_buf, "Top%2"pD"d%%", total); - else - sprintf (decode_mode_spec_buf, "%2"pD"d%%", total); + sprintf (decode_mode_spec_buf, + &"Top%2d%%"[begv < toppos ? sizeof "Top" - 1 : 0], + percent99 (botpos - begv, zv - begv)); return decode_mode_spec_buf; } } @@ -24584,7 +24693,6 @@ init_glyph_string (struct glyph_string *s, s->hdc = hdc; #endif s->display = FRAME_X_DISPLAY (s->f); - s->window = FRAME_X_WINDOW (s->f); s->char2b = char2b; s->hl = hl; s->row = row; @@ -24697,7 +24805,6 @@ get_glyph_face_and_encoding (struct frame *f, struct glyph *glyph, face = FACE_FROM_ID (f, glyph->face_id); /* Make sure X resources of the face are allocated. */ - eassert (face != NULL); prepare_face_for_display (f, face); if (face->font) @@ -25422,7 +25529,7 @@ compute_overhangs_and_x (struct glyph_string *s, int x, bool backward_p) #define BUILD_COMPOSITE_GLYPH_STRING(START, END, HEAD, TAIL, HL, X, LAST_X) \ do { \ int face_id = (row)->glyphs[area][START].face_id; \ - struct face *base_face = FACE_FROM_ID (f, face_id); \ + struct face *base_face = FACE_FROM_ID (f, face_id); \ ptrdiff_t cmp_id = (row)->glyphs[area][START].u.cmp.id; \ struct composition *cmp = composition_table[cmp_id]; \ XChar2b *char2b; \ @@ -25643,7 +25750,7 @@ draw_glyphs (struct window *w, int x, struct glyph_row *row, { struct glyph_string *h, *t; Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f); - int mouse_beg_col IF_LINT (= 0), mouse_end_col IF_LINT (= 0); + int mouse_beg_col UNINIT, mouse_end_col UNINIT; bool check_mouse_face = false; int dummy_x = 0; @@ -26045,7 +26152,6 @@ produce_image_glyph (struct it *it) eassert (it->what == IT_IMAGE); face = FACE_FROM_ID (it->f, it->face_id); - eassert (face); /* Make sure X resources of the face is loaded. */ prepare_face_for_display (it->f, face); @@ -26060,7 +26166,6 @@ produce_image_glyph (struct it *it) } img = IMAGE_FROM_ID (it->f, it->image_id); - eassert (img); /* Make sure X resources of the image is loaded. */ prepare_image_for_display (it->f, img); @@ -26216,7 +26321,6 @@ produce_xwidget_glyph (struct it *it) eassert (it->what == IT_XWIDGET); struct face *face = FACE_FROM_ID (it->f, it->face_id); - eassert (face); /* Make sure X resources of the face is loaded. */ prepare_face_for_display (it->f, face); @@ -26742,12 +26846,8 @@ calc_line_height_property (struct it *it, Lisp_Object val, struct font *font, struct face *face; face_id = lookup_named_face (it->f, face_name, false); - if (face_id < 0) - return make_number (-1); - - face = FACE_FROM_ID (it->f, face_id); - font = face->font; - if (font == NULL) + face = FACE_FROM_ID_OR_NULL (it->f, face_id); + if (face == NULL || ((font = face->font) == NULL)) return make_number (-1); boff = font->baseline_offset; if (font->vertical_centering) @@ -26897,7 +26997,7 @@ produce_glyphless_glyph (struct it *it, bool for_no_font, Lisp_Object acronym) } else if (it->glyphless_method == GLYPHLESS_DISPLAY_EMPTY_BOX) { - width = CHAR_WIDTH (it->c); + width = CHARACTER_WIDTH (it->c); if (width == 0) width = 1; else if (width > 4) @@ -27393,18 +27493,21 @@ x_produce_glyphs (struct it *it) int leftmost, rightmost, lowest, highest; int lbearing, rbearing; int i, width, ascent, descent; - int c IF_LINT (= 0); /* cmp->glyph_len can't be zero; see Bug#8512 */ + int c; XChar2b char2b; struct font_metrics *pcm; ptrdiff_t pos; - for (glyph_len = cmp->glyph_len; glyph_len > 0; glyph_len--) - if ((c = COMPOSITION_GLYPH (cmp, glyph_len - 1)) != '\t') - break; + eassume (0 < glyph_len); /* See Bug#8512. */ + do + c = COMPOSITION_GLYPH (cmp, glyph_len - 1); + while (c == '\t' && 0 < --glyph_len); + bool right_padded = glyph_len < cmp->glyph_len; for (i = 0; i < glyph_len; i++) { - if ((c = COMPOSITION_GLYPH (cmp, i)) != '\t') + c = COMPOSITION_GLYPH (cmp, i); + if (c != '\t') break; cmp->offsets[i * 2] = cmp->offsets[i * 2 + 1] = 0; } @@ -28103,7 +28206,7 @@ get_window_cursor_type (struct window *w, struct glyph *glyph, int *width, /* Using a block cursor on large images can be very annoying. So use a hollow cursor for "large" images. If image is not transparent (no mask), also use hollow cursor. */ - struct image *img = IMAGE_FROM_ID (f, glyph->u.img_id); + struct image *img = IMAGE_OPT_FROM_ID (f, glyph->u.img_id); if (img != NULL && IMAGEP (img->spec)) { /* Arbitrarily, interpret "Large" as >32x32 and >NxN @@ -28727,12 +28830,12 @@ show_mouse_face (Mouse_HLInfo *hlinfo, enum draw_glyphs_face draw) } } -#ifdef HAVE_WINDOW_SYSTEM /* When we've written over the cursor, arrange for it to be displayed again. */ if (FRAME_WINDOW_P (f) && phys_cursor_on_p && !w->phys_cursor_on_p) { +#ifdef HAVE_WINDOW_SYSTEM int hpos = w->phys_cursor.hpos; /* When the window is hscrolled, cursor hpos can legitimately be @@ -28747,8 +28850,8 @@ show_mouse_face (Mouse_HLInfo *hlinfo, enum draw_glyphs_face draw) display_and_set_cursor (w, true, hpos, w->phys_cursor.vpos, w->phys_cursor.x, w->phys_cursor.y); unblock_input (); - } #endif /* HAVE_WINDOW_SYSTEM */ + } } #ifdef HAVE_WINDOW_SYSTEM @@ -29688,12 +29791,17 @@ Returns the alist element for the first matching AREA in MAP. */) clip_to_bounds (INT_MIN, XINT (x), INT_MAX), clip_to_bounds (INT_MIN, XINT (y), INT_MAX)); } +#endif /* HAVE_WINDOW_SYSTEM */ /* Display frame CURSOR, optionally using shape defined by POINTER. */ static void define_frame_cursor1 (struct frame *f, Cursor cursor, Lisp_Object pointer) { +#ifdef HAVE_WINDOW_SYSTEM + if (!FRAME_WINDOW_P (f)) + return; + /* Do not change cursor shape while dragging mouse. */ if (EQ (do_mouse_tracking, Qdragging)) return; @@ -29710,10 +29818,10 @@ define_frame_cursor1 (struct frame *f, Cursor cursor, Lisp_Object pointer) cursor = FRAME_X_OUTPUT (f)->horizontal_drag_cursor; else if (EQ (pointer, intern ("nhdrag"))) cursor = FRAME_X_OUTPUT (f)->vertical_drag_cursor; -#ifdef HAVE_X_WINDOWS +# ifdef HAVE_X_WINDOWS else if (EQ (pointer, intern ("vdrag"))) cursor = FRAME_DISPLAY_INFO (f)->vertical_scroll_bar_cursor; -#endif +# endif else if (EQ (pointer, intern ("hourglass"))) cursor = FRAME_X_OUTPUT (f)->hourglass_cursor; else if (EQ (pointer, Qmodeline)) @@ -29724,10 +29832,9 @@ define_frame_cursor1 (struct frame *f, Cursor cursor, Lisp_Object pointer) if (cursor != No_Cursor) FRAME_RIF (f)->define_frame_cursor (f, cursor); +#endif } -#endif /* HAVE_WINDOW_SYSTEM */ - /* Take proper action when mouse has moved to the mode or header line or marginal area AREA of window W, x-position X and y-position Y. X is relative to the start of the text display area of W, so the @@ -29749,12 +29856,11 @@ note_mode_line_or_margin_highlight (Lisp_Object window, int x, int y, int dx, dy, width, height; ptrdiff_t charpos; Lisp_Object string, object = Qnil; - Lisp_Object pos IF_LINT (= Qnil), help; - + Lisp_Object pos UNINIT; Lisp_Object mouse_face; int original_x_pixel = x; struct glyph * glyph = NULL, * row_start_glyph = NULL; - struct glyph_row *row IF_LINT (= 0); + struct glyph_row *row UNINIT; if (area == ON_MODE_LINE || area == ON_HEADER_LINE) { @@ -29794,7 +29900,7 @@ note_mode_line_or_margin_highlight (Lisp_Object window, int x, int y, &object, &dx, &dy, &width, &height); } - help = Qnil; + Lisp_Object help = Qnil; #ifdef HAVE_WINDOW_SYSTEM if (IMAGEP (object)) @@ -30042,10 +30148,7 @@ note_mode_line_or_margin_highlight (Lisp_Object window, int x, int y, if ((area == ON_MODE_LINE || area == ON_HEADER_LINE) && !mouse_face_shown) clear_mouse_face (hlinfo); -#ifdef HAVE_WINDOW_SYSTEM - if (FRAME_WINDOW_P (f)) - define_frame_cursor1 (f, cursor, pointer); -#endif + define_frame_cursor1 (f, cursor, pointer); } @@ -30189,7 +30292,7 @@ note_mouse_highlight (struct frame *f, int x, int y) /* Look for :pointer property on image. */ if (glyph != NULL && glyph->type == IMAGE_GLYPH) { - struct image *img = IMAGE_FROM_ID (f, glyph->u.img_id); + struct image *img = IMAGE_OPT_FROM_ID (f, glyph->u.img_id); if (img != NULL && IMAGEP (img->spec)) { Lisp_Object image_map, hotspot; @@ -30250,15 +30353,15 @@ note_mouse_highlight (struct frame *f, int x, int y) { if (clear_mouse_face (hlinfo)) cursor = No_Cursor; -#ifdef HAVE_WINDOW_SYSTEM if (FRAME_WINDOW_P (f) && NILP (pointer)) { +#ifdef HAVE_WINDOW_SYSTEM if (area != TEXT_AREA) cursor = FRAME_X_OUTPUT (f)->nontext_cursor; else pointer = Vvoid_text_area_pointer; - } #endif + } goto set_cursor; } @@ -30369,8 +30472,8 @@ note_mouse_highlight (struct frame *f, int x, int y) { /* The mouse-highlighting, if any, comes from an overlay or text property in the buffer. */ - Lisp_Object buffer IF_LINT (= Qnil); - Lisp_Object disp_string IF_LINT (= Qnil); + Lisp_Object buffer UNINIT; + Lisp_Object disp_string UNINIT; if (STRINGP (object)) { @@ -30570,15 +30673,7 @@ note_mouse_highlight (struct frame *f, int x, int y) } set_cursor: - -#ifdef HAVE_WINDOW_SYSTEM - if (FRAME_WINDOW_P (f)) - define_frame_cursor1 (f, cursor, pointer); -#else - /* This is here to prevent a compiler error, about "label at end of - compound statement". */ - return; -#endif + define_frame_cursor1 (f, cursor, pointer); } @@ -31215,7 +31310,7 @@ syms_of_xdisp (void) /* Non-nil means don't actually do any redisplay. */ DEFSYM (Qinhibit_redisplay, "inhibit-redisplay"); - DEFSYM (Qredisplay_internal, "redisplay_internal (C function)"); + DEFSYM (Qredisplay_internal_xC_functionx, "redisplay_internal (C function)"); DEFVAR_BOOL("inhibit-message", inhibit_message, doc: /* Non-nil means calls to `message' are not displayed. @@ -31229,6 +31324,7 @@ They are still logged to the *Messages* buffer. */); message_dolog_marker3 = Fmake_marker (); staticpro (&message_dolog_marker3); + defsubr (&Sset_buffer_redisplay); #ifdef GLYPH_DEBUG defsubr (&Sdump_frame_glyph_matrix); defsubr (&Sdump_glyph_matrix); @@ -31286,8 +31382,10 @@ They are still logged to the *Messages* buffer. */); /* Name and number of the face used to highlight escape glyphs. */ DEFSYM (Qescape_glyph, "escape-glyph"); - /* Name and number of the face used to highlight non-breaking spaces. */ + /* Name and number of the face used to highlight non-breaking + spaces/hyphens. */ DEFSYM (Qnobreak_space, "nobreak-space"); + DEFSYM (Qnobreak_hyphen, "nobreak-hyphen"); /* The symbol 'image' which is the car of the lists used to represent images in Lisp. Also a tool bar style. */ @@ -31399,7 +31497,7 @@ The face used for trailing whitespace is `trailing-whitespace'. */); doc: /* Control highlighting of non-ASCII space and hyphen chars. If the value is t, Emacs highlights non-ASCII chars which have the same appearance as an ASCII space or hyphen, using the `nobreak-space' -or `escape-glyph' face respectively. +or `nobreak-hyphen' face respectively. U+00A0 (no-break space), U+00AD (soft hyphen), U+2010 (hyphen), and U+2011 (non-breaking hyphen) are affected. @@ -31552,16 +31650,6 @@ If nil, disable message logging. If t, log messages but don't truncate the buffer when it becomes large. */); Vmessage_log_max = make_number (1000); - DEFVAR_LISP ("window-size-change-functions", Vwindow_size_change_functions, - doc: /* Functions called during redisplay, if window sizes have changed. -The value should be a list of functions that take one argument. -During the first part of redisplay, for each frame, if any of its windows -have changed size since the last redisplay, or have been split or deleted, -all the functions in the list are called, with the frame as argument. -If redisplay decides to resize the minibuffer window, it calls these -functions on behalf of that as well. */); - Vwindow_size_change_functions = Qnil; - DEFVAR_LISP ("window-scroll-functions", Vwindow_scroll_functions, doc: /* List of functions to call before redisplaying a window with scrolling. Each function is called with two arguments, the window and its new @@ -31906,10 +31994,6 @@ display table takes effect; in this case, Emacs does not consult doc: /* */); 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; - DEFVAR_BOOL ("redisplay--inhibit-bidi", redisplay__inhibit_bidi, doc: /* Non-nil means it is not safe to attempt bidi reordering for display. */); /* Initialize to t, since we need to disable reordering until |