X-Git-Url: https://git.hcoop.net/bpt/emacs.git/blobdiff_plain/dd72e25cb2561f180437db5e84b08dd7670809ae..2bfa3d3e1fb347ba76bddf77f3e288049635821d:/src/xdisp.c diff --git a/src/xdisp.c b/src/xdisp.c index b7821eb504..5fe278079e 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -98,7 +98,9 @@ along with GNU Emacs. If not, see . */ This function attempts to redisplay a window by reusing parts of its existing display. It finds and reuses the part that was not - changed, and redraws the rest. + changed, and redraws the rest. (The "id" part in the function's + name stands for "insert/delete", not for "identification" or + somesuch.) . try_window @@ -113,6 +115,19 @@ along with GNU Emacs. If not, see . */ optimizations were successful, redisplay calls redisplay_windows, which performs a full redisplay of all windows. + Note that there's one more important optimization up Emacs's + sleeve, but it is related to actually redrawing the potentially + changed portions of the window/frame, not to reproducing the + desired matrices of those potentially changed portions. Namely, + the function update_frame and its subroutines, which you will find + in dispnew.c, compare the desired matrices with the current + matrices, and only redraw the portions that changed. So it could + happen that the functions in this file for some reason decide that + the entire desired matrix needs to be regenerated from scratch, and + still only parts of the Emacs display, or even nothing at all, will + be actually delivered to the glass, because update_frame has found + that the new and the old screen contents are similar or identical. + Desired matrices. Desired matrices are always built per Emacs window. The function @@ -622,7 +637,7 @@ void wset_redisplay (struct window *w) { /* Beware: selected_window can be nil during early stages. */ - if (!EQ (make_lisp_ptr (w, Lisp_Vectorlike), selected_window)) + if (!EQ (w->header.self, selected_window)) redisplay_other_windows (); w->redisplay = true; } @@ -1262,12 +1277,23 @@ Value is the height in pixels of the line at point. */) struct it it; struct text_pos pt; struct window *w = XWINDOW (selected_window); + struct buffer *old_buffer = NULL; + Lisp_Object result; + if (XBUFFER (w->contents) != current_buffer) + { + old_buffer = current_buffer; + set_buffer_internal_1 (XBUFFER (w->contents)); + } SET_TEXT_POS (pt, PT, PT_BYTE); start_display (&it, w, pt); it.vpos = it.current_y = 0; last_height = 0; - return make_number (line_bottom_y (&it)); + result = make_number (line_bottom_y (&it)); + if (old_buffer) + set_buffer_internal_1 (old_buffer); + + return result; } /* Return the default pixel height of text lines in window W. The @@ -2580,8 +2606,8 @@ safe_eval_handler (Lisp_Object arg, ptrdiff_t nargs, Lisp_Object *args) following. Return the result, or nil if something went wrong. Prevent redisplay during the evaluation. */ -Lisp_Object -safe_call (ptrdiff_t nargs, Lisp_Object func, ...) +static Lisp_Object +safe__call (bool inhibit_quit, ptrdiff_t nargs, Lisp_Object func, va_list ap) { Lisp_Object val; @@ -2589,32 +2615,42 @@ safe_call (ptrdiff_t nargs, Lisp_Object func, ...) val = Qnil; else { - va_list ap; ptrdiff_t i; - ptrdiff_t count = SPECPDL_INDEX (); + dynwind_begin (); struct gcpro gcpro1; Lisp_Object *args = alloca (nargs * word_size); args[0] = func; - va_start (ap, func); for (i = 1; i < nargs; i++) args[i] = va_arg (ap, Lisp_Object); - va_end (ap); GCPRO1 (args[0]); gcpro1.nvars = nargs; specbind (Qinhibit_redisplay, Qt); + if (inhibit_quit) + specbind (Qinhibit_quit, Qt); /* Use Qt to ensure debugger does not run, so there is no possibility of wanting to redisplay. */ val = internal_condition_case_n (Ffuncall, nargs, args, Qt, safe_eval_handler); UNGCPRO; - val = unbind_to (count, val); + dynwind_end (); } return val; } +Lisp_Object +safe_call (ptrdiff_t nargs, Lisp_Object func, ...) +{ + Lisp_Object retval; + va_list ap; + + va_start (ap, func); + retval = safe__call (false, nargs, func, ap); + va_end (ap); + return retval; +} /* Call function FN with one argument ARG. Return the result, or nil if something went wrong. */ @@ -2625,12 +2661,30 @@ safe_call1 (Lisp_Object fn, Lisp_Object arg) return safe_call (2, fn, arg); } +static Lisp_Object +safe__call1 (bool inhibit_quit, Lisp_Object fn, ...) +{ + Lisp_Object retval; + va_list ap; + + va_start (ap, fn); + retval = safe__call (inhibit_quit, 2, fn, ap); + va_end (ap); + return retval; +} + static Lisp_Object Qeval; Lisp_Object safe_eval (Lisp_Object sexpr) { - return safe_call1 (Qeval, sexpr); + return safe__call1 (false, Qeval, sexpr); +} + +static Lisp_Object +safe__eval (bool inhibit_quit, Lisp_Object sexpr) +{ + return safe__call1 (inhibit_quit, Qeval, sexpr); } /* Call function FN with two arguments ARG1 and ARG2. @@ -3757,7 +3811,7 @@ handle_fontified_prop (struct it *it) no amount of fontifying will be able to change it. */ NILP (prop) && IT_CHARPOS (*it) < Z)) { - ptrdiff_t count = SPECPDL_INDEX (); + dynwind_begin (); Lisp_Object val; struct buffer *obuf = current_buffer; ptrdiff_t begv = BEGV, zv = ZV; @@ -3805,7 +3859,7 @@ handle_fontified_prop (struct it *it) UNGCPRO; } - unbind_to (count, Qnil); + dynwind_end (); /* Fontification functions routinely call `save-restriction'. Normally, this tags clip_changed, which can confuse redisplay @@ -4769,7 +4823,7 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object, if (!NILP (form) && !EQ (form, Qt)) { - ptrdiff_t count = SPECPDL_INDEX (); + dynwind_begin (); struct gcpro gcpro1; /* Bind `object' to the object having the `display' property, a @@ -4785,7 +4839,7 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object, GCPRO1 (form); form = safe_eval (form); UNGCPRO; - unbind_to (count, Qnil); + dynwind_end (); } if (NILP (form)) @@ -4843,11 +4897,11 @@ 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 (); + dynwind_begin (); specbind (Qheight, face->lface[LFACE_HEIGHT_INDEX]); value = safe_eval (it->font_height); - unbind_to (count, Qnil); + dynwind_end (); if (NUMBERP (value)) new_height = XFLOATINT (value); @@ -8215,7 +8269,7 @@ next_element_from_buffer (struct it *it) /* Get the next character, maybe multibyte. */ p = BYTE_POS_ADDR (IT_BYTEPOS (*it)); - if (it->multibyte_p && !ASCII_BYTE_P (*p)) + if (it->multibyte_p && !ASCII_CHAR_P (*p)) it->c = STRING_CHAR_AND_LENGTH (p, it->len); else it->c = *p, it->len = 1; @@ -8517,7 +8571,7 @@ move_it_in_display_line_to (struct it *it, } else { - if (it->line_wrap == WORD_WRAP) + if (it->line_wrap == WORD_WRAP && it->area == TEXT_AREA) { if (IT_DISPLAYING_WHITESPACE (it)) may_wrap = 1; @@ -8801,8 +8855,11 @@ move_it_in_display_line_to (struct it *it, if (closest_pos < ZV) { RESTORE_IT (it, &ppos_it, ppos_data); - move_it_in_display_line_to (it, closest_pos, -1, - MOVE_TO_POS); + /* Don't recurse if closest_pos is equal to + to_charpos, since we have just tried that. */ + if (closest_pos != to_charpos) + move_it_in_display_line_to (it, closest_pos, -1, + MOVE_TO_POS); result = MOVE_POS_MATCH_OR_ZV; } else @@ -8863,8 +8920,9 @@ move_it_in_display_line_to (struct it *it, && !at_eob_p && closest_pos < ZV) { RESTORE_IT (it, &ppos_it, ppos_data); - move_it_in_display_line_to (it, closest_pos, -1, - MOVE_TO_POS); + if (closest_pos != to_charpos) + move_it_in_display_line_to (it, closest_pos, -1, + MOVE_TO_POS); } result = MOVE_POS_MATCH_OR_ZV; break; @@ -8882,7 +8940,9 @@ move_it_in_display_line_to (struct it *it, if (closest_pos < ZV) { RESTORE_IT (it, &ppos_it, ppos_data); - move_it_in_display_line_to (it, closest_pos, -1, MOVE_TO_POS); + if (closest_pos != to_charpos) + move_it_in_display_line_to (it, closest_pos, -1, + MOVE_TO_POS); } result = MOVE_POS_MATCH_OR_ZV; break; @@ -9511,6 +9571,7 @@ move_it_by_lines (struct it *it, ptrdiff_t dvpos) ptrdiff_t start_charpos, i; int nchars_per_row = (it->last_visible_x - it->first_visible_x) / FRAME_COLUMN_WIDTH (it->f); + bool hit_pos_limit = false; ptrdiff_t pos_limit; /* Start at the beginning of the screen line containing IT's @@ -9527,8 +9588,11 @@ move_it_by_lines (struct it *it, ptrdiff_t dvpos) pos_limit = BEGV; else pos_limit = max (start_charpos + dvpos * nchars_per_row, BEGV); + for (i = -dvpos; i > 0 && IT_CHARPOS (*it) > pos_limit; --i) back_to_previous_visible_line_start (it); + if (i > 0 && IT_CHARPOS (*it) <= pos_limit) + hit_pos_limit = true; reseat (it, it->current.pos, 1); /* Move further back if we end up in a string or an image. */ @@ -9572,6 +9636,25 @@ move_it_by_lines (struct it *it, ptrdiff_t dvpos) else bidi_unshelve_cache (it2data, 1); } + else if (hit_pos_limit && pos_limit > BEGV + && dvpos < 0 && it2.vpos < -dvpos) + { + /* If we hit the limit, but still didn't make it far enough + back, that means there's a display string with a newline + covering a large chunk of text, and that caused + back_to_previous_visible_line_start try to go too far. + Punish those who commit such atrocities by going back + until we've reached DVPOS, after lifting the limit, which + could make it slow for very long lines. "If it hurts, + don't do that!" */ + dvpos += it2.vpos; + RESTORE_IT (it, it, it2data); + for (i = -dvpos; i > 0; --i) + { + back_to_previous_visible_line_start (it); + it->vpos--; + } + } else RESTORE_IT (it, it, it2data); } @@ -9849,9 +9932,7 @@ message_dolog (const char *m, ptrdiff_t nbytes, bool nlflag, bool multibyte) for (i = 0; i < nbytes; i += char_bytes) { c = string_char_and_length (msg + i, &char_bytes); - work[0] = (ASCII_CHAR_P (c) - ? c - : multibyte_char_to_unibyte (c)); + work[0] = CHAR_TO_BYTE8 (c); insert_1_both (work, 1, 1, 1, 0, 0); } } @@ -10133,19 +10214,17 @@ message_with_string (const char *m, Lisp_Object string, int log) { if (m) { - /* ENCODE_SYSTEM below can GC and/or relocate the Lisp - String whose data pointer might be passed to us in M. So - we use a local copy. */ - char *fmt = xstrdup (m); + /* ENCODE_SYSTEM below can GC and/or relocate the + Lisp data, so make sure we don't use it here. */ + eassert (relocatable_string_data_p (m) != 1); if (noninteractive_need_newline) putc ('\n', stderr); noninteractive_need_newline = 0; - fprintf (stderr, fmt, SDATA (ENCODE_SYSTEM (string))); + fprintf (stderr, m, SDATA (ENCODE_SYSTEM (string))); if (!cursor_in_echo_area) fprintf (stderr, "\n"); fflush (stderr); - xfree (fmt); } } else if (INTERACTIVE) @@ -10346,7 +10425,7 @@ with_echo_area_buffer (struct window *w, int which, { Lisp_Object buffer; int this_one, the_other, clear_buffer_p, rc; - ptrdiff_t count = SPECPDL_INDEX (); + dynwind_begin (); /* If buffers aren't live, make new ones. */ ensure_echo_area_buffers (); @@ -10420,7 +10499,7 @@ with_echo_area_buffer (struct window *w, int which, eassert (BEGV >= BEG); eassert (ZV <= Z && ZV >= BEGV); - unbind_to (count, Qnil); + dynwind_end (); return rc; } @@ -10525,11 +10604,11 @@ setup_echo_area_for_printing (int multibyte_p) if (Z > BEG) { - ptrdiff_t count = SPECPDL_INDEX (); + dynwind_begin (); specbind (Qinhibit_read_only, Qt); /* Note that undo recording is always disabled. */ del_range (BEG, Z); - unbind_to (count, Qnil); + dynwind_end (); } TEMP_SET_PT_BOTH (BEG, BEG_BYTE); @@ -10580,13 +10659,6 @@ display_echo_area (struct window *w) { int i, no_message_p, window_height_changed_p; - /* Temporarily disable garbage collections while displaying the echo - area. This is done because a GC can print a message itself. - That message would modify the echo area buffer's contents while a - redisplay of the buffer is going on, and seriously confuse - redisplay. */ - ptrdiff_t count = inhibit_garbage_collection (); - /* If there is no message, we must call display_echo_area_1 nevertheless because it resizes the window. But we will have to reset the echo_area_buffer in question to nil at the end because @@ -10602,7 +10674,6 @@ display_echo_area (struct window *w) if (no_message_p) echo_area_buffer[i] = Qnil; - unbind_to (count, Qnil); return window_height_changed_p; } @@ -11114,11 +11185,11 @@ echo_area_display (int update_frame_p) /* Must update other windows. Likewise as in other cases, don't let this update be interrupted by pending input. */ - ptrdiff_t count = SPECPDL_INDEX (); + dynwind_begin (); specbind (Qredisplay_dont_pause, Qt); windows_or_buffers_changed = 44; redisplay_internal (); - unbind_to (count, Qnil); + dynwind_end (); } else if (FRAME_WINDOW_P (f) && n == 0) { @@ -11410,7 +11481,7 @@ x_consider_frame_title (Lisp_Object frame) char *title; ptrdiff_t len; struct it it; - ptrdiff_t count = SPECPDL_INDEX (); + dynwind_begin (); FOR_EACH_FRAME (tail, other_frame) { @@ -11446,7 +11517,7 @@ x_consider_frame_title (Lisp_Object frame) display_mode_element (&it, 0, -1, -1, fmt, Qnil, 0); len = MODE_LINE_NOPROP_LEN (title_start); title = mode_line_noprop_buf + title_start; - unbind_to (count, Qnil); + dynwind_end (); /* Set the title only if it's changed. This avoids consing in the common case where it hasn't. (If it turns out that we've @@ -11509,7 +11580,7 @@ prepare_menu_bars (void) } } } - safe_call1 (Vpre_redisplay_function, windows); + safe__call1 (true, Vpre_redisplay_function, windows); } /* Update all frame titles based on their buffer names, etc. We do @@ -11554,7 +11625,7 @@ prepare_menu_bars (void) if (all_windows) { Lisp_Object tail, frame; - ptrdiff_t count = SPECPDL_INDEX (); + dynwind_begin (); /* 1 means that update_menu_bar has run its hooks so any further calls to update_menu_bar shouldn't do so again. */ int menu_bar_hooks_run = 0; @@ -11610,7 +11681,7 @@ prepare_menu_bars (void) UNGCPRO; } - unbind_to (count, Qnil); + dynwind_end (); } else { @@ -11673,7 +11744,7 @@ update_menu_bar (struct frame *f, int save_match_data, int hooks_run) || window_buffer_changed (w)) { struct buffer *prev = current_buffer; - ptrdiff_t count = SPECPDL_INDEX (); + dynwind_begin (); specbind (Qinhibit_menubar_update, Qt); @@ -11726,7 +11797,7 @@ update_menu_bar (struct frame *f, int save_match_data, int hooks_run) w->update_mode_line = 1; #endif /* ! (USE_X_TOOLKIT || HAVE_NTGUI || HAVE_NS || USE_GTK) */ - unbind_to (count, Qnil); + dynwind_end (); set_buffer_internal_1 (prev); } } @@ -11740,11 +11811,6 @@ update_menu_bar (struct frame *f, int save_match_data, int hooks_run) #ifdef HAVE_WINDOW_SYSTEM -/* Tool-bar item index of the item on which a mouse button was pressed - or -1. */ - -int last_tool_bar_item; - /* Select `frame' temporarily without running all the code in do_switch_frame. FIXME: Maybe do_switch_frame should be trimmed down similarly @@ -11795,7 +11861,7 @@ update_tool_bar (struct frame *f, int save_match_data) || window_buffer_changed (w)) { struct buffer *prev = current_buffer; - ptrdiff_t count = SPECPDL_INDEX (); + dynwind_begin (); Lisp_Object frame, new_tool_bar; int new_n_tool_bar; struct gcpro gcpro1; @@ -11851,7 +11917,7 @@ update_tool_bar (struct frame *f, int save_match_data) UNGCPRO; - unbind_to (count, Qnil); + dynwind_end (); set_buffer_internal_1 (prev); } } @@ -12203,11 +12269,6 @@ tool_bar_height (struct frame *f, int *n_rows, bool pixelwise) #endif /* !USE_GTK && !HAVE_NS */ -#if defined USE_GTK || defined HAVE_NS -EXFUN (Ftool_bar_height, 2) ATTRIBUTE_CONST; -EXFUN (Ftool_bar_lines_needed, 1) ATTRIBUTE_CONST; -#endif - DEFUN ("tool-bar-height", Ftool_bar_height, Stool_bar_height, 0, 2, 0, doc: /* Return the number of lines occupied by the tool bar of FRAME. @@ -12546,7 +12607,7 @@ handle_tool_bar_click (struct frame *f, int x, int y, int down_p, where the button was pressed, disregarding where it was released. */ if (NILP (Vmouse_highlight) && !down_p) - prop_idx = last_tool_bar_item; + prop_idx = f->last_tool_bar_item; /* If item is disabled, do nothing. */ enabled_p = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_ENABLED_P); @@ -12558,7 +12619,7 @@ handle_tool_bar_click (struct frame *f, int x, int y, int down_p, /* Show item in pressed state. */ if (!NILP (Vmouse_highlight)) show_mouse_face (hlinfo, DRAW_IMAGE_SUNKEN); - last_tool_bar_item = prop_idx; + f->last_tool_bar_item = prop_idx; } else { @@ -12583,7 +12644,7 @@ handle_tool_bar_click (struct frame *f, int x, int y, int down_p, event.arg = key; event.modifiers = modifiers; kbd_buffer_store_event (&event); - last_tool_bar_item = -1; + f->last_tool_bar_item = -1; } } @@ -12633,8 +12694,7 @@ note_tool_bar_highlight (struct frame *f, int x, int y) mouse_down_p = (x_mouse_grabbed (dpyinfo) && f == dpyinfo->last_mouse_frame); - if (mouse_down_p - && last_tool_bar_item != prop_idx) + if (mouse_down_p && f->last_tool_bar_item != prop_idx) return; draw = mouse_down_p ? DRAW_IMAGE_SUNKEN : DRAW_IMAGE_RAISED; @@ -13321,7 +13381,7 @@ redisplay_internal (void) /* Record a function that clears redisplaying_p when we leave this function. */ - count = SPECPDL_INDEX (); + dynwind_begin (); record_unwind_protect_void (unwind_redisplay); redisplaying_p = 1; specbind (Qinhibit_free_realized_faces, Qnil); @@ -13961,7 +14021,7 @@ redisplay_internal (void) if (interrupt_input && interrupts_deferred) request_sigio (); - unbind_to (count, Qnil); + dynwind_end (); RESUME_POLLING; } @@ -14353,7 +14413,7 @@ set_cursor_from_row (struct window *w, struct glyph_row *row, pos_after, 0); if (prop_pos >= pos_before) - bpos_max = prop_pos - 1; + bpos_max = prop_pos; } if (INTEGERP (chprop)) { @@ -14427,7 +14487,7 @@ set_cursor_from_row (struct window *w, struct glyph_row *row, pos_after, 0); if (prop_pos >= pos_before) - bpos_max = prop_pos - 1; + bpos_max = prop_pos; } if (INTEGERP (chprop)) { @@ -14457,7 +14517,7 @@ set_cursor_from_row (struct window *w, struct glyph_row *row, GLYPH_BEFORE and GLYPH_AFTER. */ if (!((row->reversed_p ? glyph > glyphs_end : glyph < glyphs_end) && BUFFERP (glyph->object) && glyph->charpos == pt_old) - && !(bpos_max < pt_old && pt_old <= bpos_covered)) + && !(bpos_max <= pt_old && pt_old <= bpos_covered)) { /* An empty line has a single glyph whose OBJECT is zero and whose CHARPOS is the position of a newline on that line. @@ -15644,9 +15704,6 @@ try_cursor_movement (Lisp_Object window, struct text_pos startp, int *scroll_ste return rc; } -#if !defined USE_TOOLKIT_SCROLL_BARS || defined USE_GTK -static -#endif void set_vertical_scroll_bar (struct window *w) { @@ -15689,7 +15746,51 @@ set_vertical_scroll_bar (struct window *w) selected_window is redisplayed. We can return without actually redisplaying the window if fonts has been - changed on window's frame. In that case, redisplay_internal will retry. */ + changed on window's frame. In that case, redisplay_internal will retry. + + As one of the important parts of redisplaying a window, we need to + decide whether the previous window-start position (stored in the + window's w->start marker position) is still valid, and if it isn't, + recompute it. Some details about that: + + . The previous window-start could be in a continuation line, in + which case we need to recompute it when the window width + changes. See compute_window_start_on_continuation_line and its + call below. + + . The text that changed since last redisplay could include the + previous window-start position. In that case, we try to salvage + what we can from the current glyph matrix by calling + try_scrolling, which see. + + . Some Emacs command could force us to use a specific window-start + position by setting the window's force_start flag, or gently + propose doing that by setting the window's optional_new_start + flag. In these cases, we try using the specified start point if + that succeeds (i.e. the window desired matrix is successfully + recomputed, and point location is within the window). In case + of optional_new_start, we first check if the specified start + position is feasible, i.e. if it will allow point to be + displayed in the window. If using the specified start point + fails, e.g., if new fonts are needed to be loaded, we abort the + redisplay cycle and leave it up to the next cycle to figure out + things. + + . Note that the window's force_start flag is sometimes set by + redisplay itself, when it decides that the previous window start + point is fine and should be kept. Search for "goto force_start" + below to see the details. Like the values of window-start + specified outside of redisplay, these internally-deduced values + are tested for feasibility, and ignored if found to be + unfeasible. + + . Note that the function try_window, used to completely redisplay + a window, accepts the window's start point as its argument. + This is used several times in the redisplay code to control + where the window start will be, according to user options such + as scroll-conservatively, and also to ensure the screen line + showing point will be fully (as opposed to partially) visible on + display. */ static void redisplay_window (Lisp_Object window, bool just_this_one_p) @@ -15709,7 +15810,7 @@ redisplay_window (Lisp_Object window, bool just_this_one_p) It indicates that the buffer contents and narrowing are unchanged. */ bool buffer_unchanged_p = false; int temp_scroll_step = 0; - ptrdiff_t count = SPECPDL_INDEX (); + dynwind_begin (); int rc; int centering_position = -1; int last_line_misfit = 0; @@ -15735,6 +15836,8 @@ redisplay_window (Lisp_Object window, bool just_this_one_p) eassert (XMARKER (w->start)->buffer == buffer); eassert (XMARKER (w->pointm)->buffer == buffer); + /* We come here again if we need to run window-text-change-functions + below. */ restart: reconsider_clip_changes (w); frame_line_height = default_line_pixel_height (w); @@ -15799,7 +15902,7 @@ redisplay_window (Lisp_Object window, bool just_this_one_p) && !current_buffer->prevent_redisplay_optimizations_p && !window_outdated (w)); - /* Run the window-bottom-change-functions + /* Run the window-text-change-functions if it is possible that the text on the screen has changed (either due to modification of the text, or any other reason). */ if (!current_matrix_up_to_date_p @@ -16400,12 +16503,50 @@ redisplay_window (Lisp_Object window, bool just_this_one_p) /* Consider the following case: Window starts at BEGV, there is invisible, intangible text at BEGV, so that display starts at some point START > BEGV. It can happen that we are called with - PT somewhere between BEGV and START. Try to handle that case. */ + PT somewhere between BEGV and START. Try to handle that case, + and similar ones. */ if (w->cursor.vpos < 0) { - struct glyph_row *row = w->current_matrix->rows; - if (row->mode_line_p) - ++row; + /* First, try locating the proper glyph row for PT. */ + struct glyph_row *row = + row_containing_pos (w, PT, w->current_matrix->rows, NULL, 0); + + /* Sometimes point is at the beginning of invisible text that is + before the 1st character displayed in the row. In that case, + row_containing_pos fails to find the row, because no glyphs + with appropriate buffer positions are present in the row. + Therefore, we next try to find the row which shows the 1st + position after the invisible text. */ + if (!row) + { + Lisp_Object val = + get_char_property_and_overlay (make_number (PT), Qinvisible, + Qnil, NULL); + + if (TEXT_PROP_MEANS_INVISIBLE (val)) + { + ptrdiff_t alt_pos; + Lisp_Object invis_end = + Fnext_single_char_property_change (make_number (PT), Qinvisible, + Qnil, Qnil); + + if (NATNUMP (invis_end)) + alt_pos = XFASTINT (invis_end); + else + alt_pos = ZV; + row = row_containing_pos (w, alt_pos, w->current_matrix->rows, + NULL, 0); + } + } + /* Finally, fall back on the first row of the window after the + header line (if any). This is slightly better than not + displaying the cursor at all. */ + if (!row) + { + row = w->current_matrix->rows; + if (row->mode_line_p) + ++row; + } set_cursor_from_row (w, row, w->current_matrix, 0, 0, 0, 0); } @@ -16608,7 +16749,7 @@ redisplay_window (Lisp_Object window, bool just_this_one_p) if (CHARPOS (lpoint) <= ZV) TEMP_SET_PT_BOTH (CHARPOS (lpoint), BYTEPOS (lpoint)); - unbind_to (count, Qnil); + dynwind_end (); } @@ -18616,6 +18757,7 @@ insert_left_trunc_glyphs (struct it *it) truncate_it.current_x = 0; truncate_it.face_id = DEFAULT_FACE_ID; truncate_it.glyph_row = &scratch_glyph_row; + truncate_it.area = TEXT_AREA; truncate_it.glyph_row->used[TEXT_AREA] = 0; CHARPOS (truncate_it.position) = BYTEPOS (truncate_it.position) = -1; truncate_it.object = make_number (0); @@ -20594,6 +20736,10 @@ Value is the new character position of point. */) && !b->clip_changed && !b->prevent_redisplay_optimizations_p && !window_outdated (w) + /* We rely below on the cursor coordinates to be up to date, but + we cannot trust them if some command moved point since the + last complete redisplay. */ + && w->last_point == BUF_PT (b) && w->cursor.vpos >= 0 && w->cursor.vpos < w->current_matrix->nrows && (row = MATRIX_ROW (w->current_matrix, w->cursor.vpos))->enabled_p) @@ -21357,7 +21503,7 @@ display_mode_line (struct window *w, enum face_id face_id, Lisp_Object format) { struct it it; struct face *face; - ptrdiff_t count = SPECPDL_INDEX (); + dynwind_begin (); init_iterator (&it, w, -1, -1, NULL, face_id); /* Don't extend on a previously drawn mode-line. @@ -21385,7 +21531,7 @@ display_mode_line (struct window *w, enum face_id face_id, Lisp_Object format) display_mode_element (&it, 0, 0, 0, format, Qnil, 0); pop_kboard (); - unbind_to (count, Qnil); + dynwind_end (); /* Fill up with spaces. */ display_string (" ", Qnil, Qnil, 0, 0, &it, 10000, -1, -1, 0); @@ -21784,7 +21930,7 @@ display_mode_element (struct it *it, int depth, int field_width, int precision, if (CONSP (XCDR (elt))) { Lisp_Object spec; - spec = safe_eval (XCAR (XCDR (elt))); + spec = safe__eval (true, XCAR (XCDR (elt))); n += display_mode_element (it, depth, field_width - n, precision - n, spec, props, risky); @@ -22037,7 +22183,7 @@ are the selected window and the WINDOW's buffer). */) struct buffer *old_buffer = NULL; int face_id; int no_props = INTEGERP (face); - ptrdiff_t count = SPECPDL_INDEX (); + dynwind_begin (); Lisp_Object str; int string_start = 0; @@ -22050,8 +22196,10 @@ are the selected window and the WINDOW's buffer). */) /* Make formatting the modeline a non-op when noninteractive, otherwise there will be problems later caused by a partially initialized frame. */ - if (NILP (format) || noninteractive) + if (NILP (format) || noninteractive) { + dynwind_end (); return empty_unibyte_string; + } if (no_props) face = Qnil; @@ -22112,7 +22260,7 @@ are the selected window and the WINDOW's buffer). */) empty_unibyte_string); } - unbind_to (count, Qnil); + dynwind_end (); return str; } @@ -22601,7 +22749,7 @@ decode_mode_spec (struct window *w, register int c, int field_width, return decode_mode_spec_buf; no_value: { - char* p = decode_mode_spec_buf; + char *p = decode_mode_spec_buf; int pad = width - 2; while (pad-- > 0) *p++ = ' '; @@ -22697,10 +22845,8 @@ decode_mode_spec (struct window *w, register int c, int field_width, case '@': { - ptrdiff_t count = inhibit_garbage_collection (); Lisp_Object val = call1 (intern ("file-remote-p"), BVAR (current_buffer, directory)); - unbind_to (count, Qnil); if (NILP (val)) return "-"; @@ -23349,7 +23495,7 @@ calc_pixel_width_or_height (double *res, struct it *it, Lisp_Object prop, return OK_PIXELS (WINDOW_SCROLL_BAR_AREA_WIDTH (it->w)); } - prop = buffer_local_value_1 (prop, it->w->contents); + prop = buffer_local_value (prop, it->w->contents); if (EQ (prop, Qunbound)) prop = Qnil; } @@ -23401,7 +23547,7 @@ calc_pixel_width_or_height (double *res, struct it *it, Lisp_Object prop, return OK_PIXELS (pixels); } - car = buffer_local_value_1 (car, it->w->contents); + car = buffer_local_value (car, it->w->contents); if (EQ (car, Qunbound)) car = Qnil; } @@ -23578,7 +23724,7 @@ get_char_face_and_encoding (struct frame *f, int c, int face_id, #endif { eassert (face != NULL); - PREPARE_FACE_FOR_DISPLAY (f, face); + prepare_face_for_display (f, face); } return face; @@ -23601,7 +23747,7 @@ get_glyph_face_and_encoding (struct frame *f, struct glyph *glyph, /* Make sure X resources of the face are allocated. */ eassert (face != NULL); - PREPARE_FACE_FOR_DISPLAY (f, face); + prepare_face_for_display (f, face); if (two_byte_p) *two_byte_p = 0; @@ -23918,7 +24064,7 @@ fill_stretch_glyph_string (struct glyph_string *s, int start, int end) s->ybase += voffset; /* The case that face->gc == 0 is handled when drawing the glyph - string by calling PREPARE_FACE_FOR_DISPLAY. */ + string by calling prepare_face_for_display. */ eassert (s->face); return glyph - s->row->glyphs[s->area]; } @@ -24516,13 +24662,16 @@ draw_glyphs (struct window *w, int x, struct glyph_row *row, else overlap_hl = DRAW_NORMAL_TEXT; + if (hl != overlap_hl) + clip_head = head; j = i; BUILD_GLYPH_STRINGS (j, start, h, t, overlap_hl, dummy_x, last_x); start = i; compute_overhangs_and_x (t, head->x, 1); prepend_glyph_string_lists (&head, &tail, h, t); - clip_head = head; + if (clip_head == NULL) + clip_head = head; } /* Prepend glyph strings for glyphs in front of the first glyph @@ -24543,7 +24692,8 @@ draw_glyphs (struct window *w, int x, struct glyph_row *row, else overlap_hl = DRAW_NORMAL_TEXT; - clip_head = head; + if (hl == overlap_hl || clip_head == NULL) + clip_head = head; BUILD_GLYPH_STRINGS (i, start, h, t, overlap_hl, dummy_x, last_x); for (s = h; s; s = s->next) @@ -24567,13 +24717,16 @@ draw_glyphs (struct window *w, int x, struct glyph_row *row, else overlap_hl = DRAW_NORMAL_TEXT; + if (hl != overlap_hl) + clip_tail = tail; BUILD_GLYPH_STRINGS (end, i, h, t, overlap_hl, x, last_x); /* Because BUILD_GLYPH_STRINGS updates the first argument, we don't have `end = i;' here. */ compute_overhangs_and_x (h, tail->x + tail->width, 0); append_glyph_string_lists (&head, &tail, h, t); - clip_tail = tail; + if (clip_tail == NULL) + clip_tail = tail; } /* Append glyph strings for glyphs following the last glyph @@ -24591,7 +24744,8 @@ draw_glyphs (struct window *w, int x, struct glyph_row *row, else overlap_hl = DRAW_NORMAL_TEXT; - clip_tail = tail; + if (hl == overlap_hl || clip_tail == NULL) + clip_tail = tail; i++; /* We must include the Ith glyph. */ BUILD_GLYPH_STRINGS (end, i, h, t, overlap_hl, x, last_x); @@ -24859,7 +25013,7 @@ produce_image_glyph (struct it *it) 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); + prepare_face_for_display (it->f, face); if (it->image_id < 0) { @@ -25137,7 +25291,7 @@ produce_stretch_glyph (struct it *it) { struct face *face = FACE_FROM_ID (it->f, it->face_id); font = face->font ? face->font : FRAME_FONT (it->f); - PREPARE_FACE_FOR_DISPLAY (it->f, face); + prepare_face_for_display (it->f, face); } #endif @@ -25601,7 +25755,7 @@ produce_glyphless_glyph (struct it *it, int for_no_font, Lisp_Object acronym) face = FACE_FROM_ID (it->f, face_id); font = face->font ? face->font : FRAME_FONT (it->f); - PREPARE_FACE_FOR_DISPLAY (it->f, face); + prepare_face_for_display (it->f, face); if (it->glyphless_method == GLYPHLESS_DISPLAY_ACRONYM) { @@ -25617,7 +25771,7 @@ produce_glyphless_glyph (struct it *it, int for_no_font, Lisp_Object acronym) sprintf (buf, "%0*X", it->c < 0x10000 ? 4 : 6, it->c); str = buf; } - for (len = 0; str[len] && ASCII_BYTE_P (str[len]) && len < 6; len++) + for (len = 0; str[len] && ASCII_CHAR_P (str[len]) && len < 6; len++) code[len] = font->driver->encode_char (font, str[len]); upper_len = (len + 1) / 2; font->driver->text_extents (font, code, upper_len, @@ -26942,9 +27096,6 @@ draw_phys_cursor_glyph (struct window *w, struct glyph_row *row, /* Erase the image of a cursor of window W from the screen. */ -#ifndef HAVE_NTGUI -static -#endif void erase_phys_cursor (struct window *w) { @@ -27253,7 +27404,7 @@ show_mouse_face (Mouse_HLInfo *hlinfo, enum draw_glyphs_face draw) if (/* If window is in the process of being destroyed, don't bother to do anything. */ w->current_matrix != NULL - /* Don't update mouse highlight if hidden */ + /* Don't update mouse highlight if hidden. */ && (draw != DRAW_MOUSE_FACE || !hlinfo->mouse_face_hidden) /* Recognize when we are called to operate on rows that don't exist anymore. This can happen when a window is split. */ @@ -28470,8 +28621,8 @@ note_mode_line_or_margin_highlight (Lisp_Object window, int x, int y, else if (area == ON_MODE_LINE) { Lisp_Object default_help - = buffer_local_value_1 (Qmode_line_default_help_echo, - w->contents); + = buffer_local_value (Qmode_line_default_help_echo, + w->contents); if (STRINGP (default_help)) { @@ -29806,6 +29957,8 @@ x_intersect_rectangles (XRectangle *r1, XRectangle *r2, XRectangle *result) void syms_of_xdisp (void) { +#include "xdisp.x" + Vwith_echo_area_save_vector = Qnil; staticpro (&Vwith_echo_area_save_vector); @@ -29822,25 +29975,6 @@ syms_of_xdisp (void) message_dolog_marker3 = Fmake_marker (); staticpro (&message_dolog_marker3); -#ifdef GLYPH_DEBUG - defsubr (&Sdump_frame_glyph_matrix); - defsubr (&Sdump_glyph_matrix); - defsubr (&Sdump_glyph_row); - defsubr (&Sdump_tool_bar_row); - defsubr (&Strace_redisplay); - defsubr (&Strace_to_stderr); -#endif -#ifdef HAVE_WINDOW_SYSTEM - defsubr (&Stool_bar_height); - defsubr (&Slookup_image_map); -#endif - defsubr (&Sline_pixel_height); - defsubr (&Sformat_mode_line); - defsubr (&Sinvisible_p); - defsubr (&Scurrent_bidi_paragraph_direction); - defsubr (&Swindow_text_pixel_size); - defsubr (&Smove_point_visually); - DEFSYM (Qmenu_bar_update_hook, "menu-bar-update-hook"); DEFSYM (Qoverriding_terminal_local_map, "overriding-terminal-local-map"); DEFSYM (Qoverriding_local_map, "overriding-local-map"); @@ -30492,7 +30626,7 @@ init_xdisp (void) /* Allocate the buffer for frame titles. Also used for `format-mode-line'. */ int size = 100; - mode_line_noprop_buf = xmalloc (size); + mode_line_noprop_buf = xmalloc_atomic (size); mode_line_noprop_buf_end = mode_line_noprop_buf + size; mode_line_noprop_ptr = mode_line_noprop_buf; mode_line_target = MODE_LINE_DISPLAY;