X-Git-Url: http://git.hcoop.net/bpt/emacs.git/blobdiff_plain/fd60bf6c902b47daadda6ebf442045dbe1328941..2bfa3d3e1fb347ba76bddf77f3e288049635821d:/src/xdisp.c diff --git a/src/xdisp.c b/src/xdisp.c index 1b86ec7d9d..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; } @@ -2601,7 +2616,7 @@ safe__call (bool inhibit_quit, ptrdiff_t nargs, Lisp_Object func, va_list ap) else { ptrdiff_t i; - ptrdiff_t count = SPECPDL_INDEX (); + dynwind_begin (); struct gcpro gcpro1; Lisp_Object *args = alloca (nargs * word_size); @@ -2619,7 +2634,7 @@ safe__call (bool inhibit_quit, ptrdiff_t nargs, Lisp_Object func, va_list ap) val = internal_condition_case_n (Ffuncall, nargs, args, Qt, safe_eval_handler); UNGCPRO; - val = unbind_to (count, val); + dynwind_end (); } return val; @@ -3796,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; @@ -3844,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 @@ -4808,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 @@ -4824,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)) @@ -4882,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); @@ -8254,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; @@ -9917,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); } } @@ -10412,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 (); @@ -10486,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; } @@ -10591,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); @@ -10646,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 @@ -10668,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; } @@ -11180,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) { @@ -11476,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) { @@ -11512,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 @@ -11620,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; @@ -11676,7 +11681,7 @@ prepare_menu_bars (void) UNGCPRO; } - unbind_to (count, Qnil); + dynwind_end (); } else { @@ -11739,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); @@ -11792,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); } } @@ -11806,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 @@ -11861,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; @@ -11917,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); } } @@ -12269,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. @@ -12612,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); @@ -12624,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 { @@ -12649,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; } } @@ -12699,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; @@ -13387,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); @@ -14027,7 +14021,7 @@ redisplay_internal (void) if (interrupt_input && interrupts_deferred) request_sigio (); - unbind_to (count, Qnil); + dynwind_end (); RESUME_POLLING; } @@ -14419,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)) { @@ -14493,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)) { @@ -14523,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. @@ -15752,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) @@ -15772,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; @@ -15798,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); @@ -15862,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 @@ -16709,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 (); } @@ -20696,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) @@ -21459,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. @@ -21487,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); @@ -22139,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; @@ -22152,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; @@ -22214,7 +22260,7 @@ are the selected window and the WINDOW's buffer). */) empty_unibyte_string); } - unbind_to (count, Qnil); + dynwind_end (); return str; } @@ -22799,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 "-"; @@ -23680,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; @@ -23703,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; @@ -24020,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]; } @@ -24969,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) { @@ -25247,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 @@ -25711,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) { @@ -25727,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, @@ -29913,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); @@ -29929,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"); @@ -30599,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;