X-Git-Url: https://git.hcoop.net/bpt/emacs.git/blobdiff_plain/c73bd236f75b742ad4642ec94798987ae6e3e1e8..a2bc5bdd7db3f708b7489d91919336e775c3e6ca:/src/xdisp.c diff --git a/src/xdisp.c b/src/xdisp.c index e146fde4c1..588d145e9e 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -1,7 +1,7 @@ /* Display generation from window structure and buffer text. Copyright (C) 1985, 1986, 1987, 1988, 1993, 1994, 1995, 1997, 1998, 1999, 2000, 2001, 2002, 2003, - 2004, 2005, 2006, 2007 Free Software Foundation, Inc. + 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -239,6 +239,7 @@ extern Lisp_Object Qhelp_echo; Lisp_Object Qoverriding_local_map, Qoverriding_terminal_local_map; Lisp_Object Qwindow_scroll_functions, Vwindow_scroll_functions; +Lisp_Object Qwindow_text_change_functions, Vwindow_text_change_functions; Lisp_Object Qredisplay_end_trigger_functions, Vredisplay_end_trigger_functions; Lisp_Object Qinhibit_point_motion_hooks; Lisp_Object QCeval, QCfile, QCdata, QCpropertize; @@ -696,6 +697,7 @@ int trace_move; point visible. */ int automatic_hscrolling_p; +Lisp_Object Qauto_hscroll_mode; /* How close to the margin can point get before the window is scrolled horizontally. */ @@ -915,7 +917,8 @@ static int display_mode_lines P_ ((struct window *)); static int display_mode_line P_ ((struct window *, enum face_id, Lisp_Object)); static int display_mode_element P_ ((struct it *, int, int, int, Lisp_Object, Lisp_Object, int)); static int store_mode_line_string P_ ((char *, Lisp_Object, int, int, int, Lisp_Object)); -static char *decode_mode_spec P_ ((struct window *, int, int, int, int *)); +static char *decode_mode_spec P_ ((struct window *, int, int, int, int *, + Lisp_Object *)); static void display_menu_bar P_ ((struct window *)); static int display_count_lines P_ ((int, int, int, int, int *)); static int display_string P_ ((unsigned char *, Lisp_Object, Lisp_Object, @@ -963,8 +966,8 @@ static void compute_string_pos P_ ((struct text_pos *, struct text_pos, static int face_before_or_after_it_pos P_ ((struct it *, int)); static int next_overlay_change P_ ((int)); static int handle_single_display_spec P_ ((struct it *, Lisp_Object, - Lisp_Object, struct text_pos *, - int)); + Lisp_Object, Lisp_Object, + struct text_pos *, int)); static int underlying_face_id P_ ((struct it *)); static int in_ellipses_for_invisible_text_p P_ ((struct display_pos *, struct window *)); @@ -1328,6 +1331,28 @@ pos_visible_p (w, charpos, x, y, rtop, rbot, rowh, vpos) visible_p = 1; if (visible_p) { + Lisp_Object window, prop; + + XSETWINDOW (window, w); + prop = Fget_char_property (make_number (it.position.charpos), + Qinvisible, window); + + /* If charpos coincides with invisible text covered with an + ellipsis, use the first glyph of the ellipsis to compute + the pixel positions. */ + if (TEXT_PROP_MEANS_INVISIBLE (prop) == 2) + { + struct glyph_row *row = it.glyph_row; + struct glyph *glyph = row->glyphs[TEXT_AREA]; + struct glyph *end = glyph + row->used[TEXT_AREA]; + int x = row->x; + + for (; glyph < end && glyph->charpos < charpos; glyph++) + x += glyph->pixel_width; + + top_x = x; + } + *x = top_x; *y = max (top_y + max (0, it.max_ascent - it.ascent), window_top_y); *rtop = max (0, window_top_y - top_y); @@ -2512,7 +2537,7 @@ init_iterator (it, w, charpos, bytepos, row, base_face_id) XSETWINDOW (it->window, w); it->w = w; it->f = XFRAME (w->frame); - + /* Extra space between lines (on window systems only). */ if (base_face_id == DEFAULT_FACE_ID && FRAME_WINDOW_P (it->f)) @@ -3077,16 +3102,18 @@ handle_stop (it) if (it->method == GET_FROM_DISPLAY_VECTOR) handle_overlay_change_p = 0; - /* Handle overlay changes. */ + /* Handle overlay changes. + This sets HANDLED to HANDLED_RECOMPUTE_PROPS + if it finds overlays. */ if (handle_overlay_change_p) handled = handle_overlay_change (it); - - /* Determine where to stop next. */ - if (handled == HANDLED_NORMALLY) - compute_stop_pos (it); } } while (handled == HANDLED_RECOMPUTE_PROPS); + + /* Determine where to stop next. */ + if (handled == HANDLED_NORMALLY) + compute_stop_pos (it); } @@ -3202,7 +3229,7 @@ next_overlay_change (pos) int pos; { int noverlays; - int endpos; + EMACS_INT endpos; Lisp_Object *overlays; int i; @@ -3367,18 +3394,58 @@ handle_face_prop (it) else { int base_face_id, bufpos; + int i; + Lisp_Object from_overlay + = (it->current.overlay_string_index >= 0 + ? it->string_overlays[it->current.overlay_string_index] + : Qnil); + + /* See if we got to this string directly or indirectly from + an overlay property. That includes the before-string or + after-string of an overlay, strings in display properties + provided by an overlay, their text properties, etc. + + FROM_OVERLAY is the overlay that brought us here, or nil if none. */ + if (! NILP (from_overlay)) + for (i = it->sp - 1; i >= 0; i--) + { + if (it->stack[i].current.overlay_string_index >= 0) + from_overlay + = it->string_overlays[it->stack[i].current.overlay_string_index]; + else if (! NILP (it->stack[i].from_overlay)) + from_overlay = it->stack[i].from_overlay; - if (it->current.overlay_string_index >= 0) - bufpos = IT_CHARPOS (*it); + if (!NILP (from_overlay)) + break; + } + + if (! NILP (from_overlay)) + { + bufpos = IT_CHARPOS (*it); + /* For a string from an overlay, the base face depends + only on text properties and ignores overlays. */ + base_face_id + = face_for_overlay_string (it->w, + IT_CHARPOS (*it), + it->region_beg_charpos, + it->region_end_charpos, + &next_stop, + (IT_CHARPOS (*it) + + TEXT_PROP_DISTANCE_LIMIT), + 0, + from_overlay); + } else - bufpos = 0; + { + bufpos = 0; - /* For strings from a buffer, i.e. overlay strings or strings - from a `display' property, use the face at IT's current - buffer position as the base face to merge with, so that - overlay strings appear in the same face as surrounding - text, unless they specify their own faces. */ - base_face_id = underlying_face_id (it); + /* For strings from a `display' property, use the face at + IT's current buffer position as the base face to merge + with, so that overlay strings appear in the same face as + surrounding text, unless they specify their own + faces. */ + base_face_id = underlying_face_id (it); + } new_face_id = face_at_string_position (it->w, it->string, @@ -3724,6 +3791,10 @@ handle_invisible_prop (it) it->position.bytepos = CHAR_TO_BYTE (it->position.charpos); } setup_for_ellipsis (it, 0); + /* Let the ellipsis display before + considering any properties of the following char. + Fixes jasonr@gnu.org 01 Oct 07 bug. */ + handled = HANDLED_RETURN; } } } @@ -3785,7 +3856,7 @@ static enum prop_handled handle_display_prop (it) struct it *it; { - Lisp_Object prop, object; + Lisp_Object prop, object, overlay; struct text_pos *position; /* Nonzero if some property replaces the display of the text itself. */ int display_replaced_p = 0; @@ -3813,10 +3884,12 @@ handle_display_prop (it) if (!it->string_from_display_prop_p) it->area = TEXT_AREA; - prop = Fget_char_property (make_number (position->charpos), - Qdisplay, object); + prop = get_char_property_and_overlay (make_number (position->charpos), + Qdisplay, object, &overlay); if (NILP (prop)) return HANDLED_NORMALLY; + /* Now OVERLAY is the overlay that gave us this property, or nil + if it was a text property. */ if (!STRINGP (it->string)) object = it->w->buffer; @@ -3838,22 +3911,35 @@ handle_display_prop (it) { for (; CONSP (prop); prop = XCDR (prop)) { - if (handle_single_display_spec (it, XCAR (prop), object, + if (handle_single_display_spec (it, XCAR (prop), object, overlay, position, display_replaced_p)) - display_replaced_p = 1; + { + display_replaced_p = 1; + /* If some text in a string is replaced, `position' no + longer points to the position of `object'. */ + if (STRINGP (object)) + break; + } } } else if (VECTORP (prop)) { int i; for (i = 0; i < ASIZE (prop); ++i) - if (handle_single_display_spec (it, AREF (prop, i), object, + if (handle_single_display_spec (it, AREF (prop, i), object, overlay, position, display_replaced_p)) - display_replaced_p = 1; + { + display_replaced_p = 1; + /* If some text in a string is replaced, `position' no + longer points to the position of `object'. */ + if (STRINGP (object)) + break; + } } else { - int ret = handle_single_display_spec (it, prop, object, position, 0); + int ret = handle_single_display_spec (it, prop, object, overlay, + position, 0); if (ret < 0) /* Replaced by "", i.e. nothing. */ return HANDLED_RECOMPUTE_PROPS; if (ret) @@ -3895,6 +3981,9 @@ display_prop_end (it, object, start_pos) replaced text display with something else, for example an image; we ignore such properties after the first one has been processed. + OVERLAY is the overlay this `display' property came from, + or nil if it was a text property. + If PROP is a `space' or `image' specification, and in some other cases too, set *POSITION to the position where the `display' property ends. @@ -3904,11 +3993,12 @@ display_prop_end (it, object, start_pos) "something" is "nothing". */ static int -handle_single_display_spec (it, spec, object, position, +handle_single_display_spec (it, spec, object, overlay, position, display_replaced_before_p) struct it *it; Lisp_Object spec; Lisp_Object object; + Lisp_Object overlay; struct text_pos *position; int display_replaced_before_p; { @@ -4018,7 +4108,7 @@ handle_single_display_spec (it, spec, object, position, return 0; } - /* Handle `(space_width WIDTH)'. */ + /* Handle `(space-width WIDTH)'. */ if (CONSP (spec) && EQ (XCAR (spec), Qspace_width) && CONSP (XCDR (spec))) @@ -4142,6 +4232,7 @@ handle_single_display_spec (it, spec, object, position, it->position = start_pos; it->object = NILP (object) ? it->w->buffer : object; it->method = GET_FROM_IMAGE; + it->from_overlay = Qnil; it->face_id = face_id; /* Say that we haven't consumed the characters with @@ -4212,6 +4303,7 @@ handle_single_display_spec (it, spec, object, position, it->position = *position; push_it (it); it->position = save_pos; + it->from_overlay = overlay; if (NILP (location)) it->area = TEXT_AREA; @@ -4238,13 +4330,16 @@ handle_single_display_spec (it, spec, object, position, /* Say that we haven't consumed the characters with `display' property yet. The call to pop_it in set_iterator_to_next will clean this up. */ - *position = start_pos; + if (BUFFERP (object)) + it->current.pos = start_pos; } else if (CONSP (value) && EQ (XCAR (value), Qspace)) { it->method = GET_FROM_STRETCH; it->object = value; - *position = it->position = start_pos; + it->position = start_pos; + if (BUFFERP (object)) + it->current.pos = start_pos; } #ifdef HAVE_WINDOW_SYSTEM else @@ -4258,7 +4353,8 @@ handle_single_display_spec (it, spec, object, position, /* Say that we haven't consumed the characters with `display' property yet. The call to pop_it in set_iterator_to_next will clean this up. */ - *position = start_pos; + if (BUFFERP (object)) + it->current.pos = start_pos; } #endif /* HAVE_WINDOW_SYSTEM */ @@ -4482,103 +4578,86 @@ handle_auto_composed_prop (it) if (FUNCTIONP (Vauto_composition_function)) { - Lisp_Object val; - EMACS_INT pos, this_pos; + Lisp_Object val = Qnil; + EMACS_INT pos, limit = -1; if (STRINGP (it->string)) pos = IT_STRING_CHARPOS (*it); else pos = IT_CHARPOS (*it); - this_pos = pos; - val =Fget_char_property (make_number (pos), Qauto_composed, it->string); + val = Fget_text_property (make_number (pos), Qauto_composed, it->string); if (! NILP (val)) { - Lisp_Object limit = Qnil, next; - - /* As Fnext_single_char_property_change is very slow, we - limit the search to the current line. */ - if (STRINGP (it->string)) - limit = make_number (SCHARS (it->string)); - else - limit = make_number (find_next_newline_no_quit (pos, 1)); + Lisp_Object cmp_prop; + EMACS_INT cmp_start, cmp_end; - next = (Fnext_single_property_change - (make_number (pos), Qauto_composed, it->string, limit)); - if (XINT (next) < XINT (limit)) +#ifdef USE_FONT_BACKEND + if (enable_font_backend + && get_property_and_range (pos, Qcomposition, &cmp_prop, + &cmp_start, &cmp_end, it->string) + && cmp_start == pos + && COMPOSITION_METHOD (cmp_prop) == COMPOSITION_WITH_GLYPH_STRING) + { + Lisp_Object gstring = COMPOSITION_COMPONENTS (cmp_prop); + Lisp_Object font_object = LGSTRING_FONT (gstring); + + if (! EQ (font_object, + font_at (-1, pos, FACE_FROM_ID (it->f, it->face_id), + it->w, it->string))) + /* We must re-compute the composition for the + different font. */ + val = Qnil; + } +#endif + if (! NILP (val)) { - /* The current point is auto-composed, but there exist - characters not yet composed beyond the auto-composed - region. There's a possiblity that the last - characters in the region may be newly composed. */ - int charpos = XINT (next) - 1, bytepos, c; + Lisp_Object end; + /* As Fnext_single_char_property_change is very slow, we + limit the search to the current line. */ if (STRINGP (it->string)) - { - bytepos = string_char_to_byte (it->string, charpos); - c = SDATA (it->string)[bytepos]; - } + limit = SCHARS (it->string); else - { - bytepos = CHAR_TO_BYTE (charpos); - c = FETCH_BYTE (bytepos); - } - if (c != '\n') - /* If the last character is not newline, it may be - composed with the following characters. */ - val = Qnil, pos = charpos + 1; + limit = find_next_newline_no_quit (pos, 1); + end = Fnext_single_char_property_change (make_number (pos), + Qauto_composed, + it->string, + make_number (limit)); + + if (XINT (end) < limit) + /* The current point is auto-composed, but there exist + characters not yet composed beyond the + auto-composed region. There's a possiblity that + the last characters in the region may be newly + composed. */ + val = Qnil; } } if (NILP (val)) { - int count = SPECPDL_INDEX (); - Lisp_Object args[4]; - - args[0] = Vauto_composition_function; - specbind (Qauto_composition_function, Qnil); - args[1] = make_number (pos); - args[2] = it->string; -#ifdef USE_FONT_BACKEND - if (enable_font_backend) + if (limit < 0) + limit = (STRINGP (it->string) ? SCHARS (it->string) + : find_next_newline_no_quit (pos, 1)); + if (pos < limit) { - struct face *face = FACE_FROM_ID (it->f, it->face_id); - int c; - - if (STRINGP (it->string)) - { - EMACS_INT pos_byte = IT_STRING_BYTEPOS (*it); - const unsigned char *s = SDATA (it->string) + pos_byte; + int count = SPECPDL_INDEX (); + Lisp_Object args[5]; - if (STRING_MULTIBYTE (it->string)) - it->c = STRING_CHAR (s, 0); - else - it->c = *s; - } + args[0] = Vauto_composition_function; + specbind (Qauto_composition_function, Qnil); + args[1] = make_number (pos); + args[2] = make_number (limit); +#ifdef USE_FONT_BACKEND + if (enable_font_backend) + args[3] = it->window; else - { - EMACS_INT pos_byte = IT_BYTEPOS (*it); - - it->c = FETCH_CHAR (pos_byte); - } - args[3] = font_at (it->c, this_pos, face, it->w, it->string); - } - else #endif /* USE_FONT_BACKEND */ - args[3] = Qnil; - safe_call (4, args); - unbind_to (count, Qnil); - - if (this_pos == pos) - { - val = Fget_char_property (args[1], Qauto_composed, it->string); - /* Return HANDLED_RECOMPUTE_PROPS only if function composed - something. This avoids an endless loop if they failed to - fontify the text for which reason ever. */ - if (! NILP (val)) - handled = HANDLED_RECOMPUTE_PROPS; + args[3] = Qnil; + args[4] = it->string; + safe_call (5, args); + unbind_to (count, Qnil); } - else - handled = HANDLED_RECOMPUTE_PROPS; } } @@ -4598,15 +4677,20 @@ handle_composition_prop (it) if (STRINGP (it->string)) { + unsigned char *s; + pos = IT_STRING_CHARPOS (*it); pos_byte = IT_STRING_BYTEPOS (*it); string = it->string; + s = SDATA (string) + pos_byte; + it->c = STRING_CHAR (s, 0); } else { pos = IT_CHARPOS (*it); pos_byte = IT_BYTEPOS (*it); string = Qnil; + it->c = FETCH_CHAR (pos_byte); } /* If there's a valid composition and point is not inside of the @@ -4662,8 +4746,6 @@ handle_composition_prop (it) Lisp_Object lgstring = AREF (XHASH_TABLE (composition_hash_table) ->key_and_value, cmp->hash_index * 2); - - it->c = XINT (LGLYPH_CHAR (LGSTRING_GLYPH (lgstring, 0))); } else #endif /* USE_FONT_BACKEND */ @@ -4991,7 +5073,10 @@ load_overlay_strings (it, charpos) i = 0; j = it->current.overlay_string_index; while (i < OVERLAY_STRING_CHUNK_SIZE && j < n) - it->overlay_strings[i++] = entries[j++].string; + { + it->overlay_strings[i] = entries[j].string; + it->string_overlays[i++] = entries[j++].overlay; + } CHECK_IT (it); } @@ -5037,6 +5122,7 @@ get_overlay_strings_1 (it, charpos, compute_stop_p) string. */ IT_STRING_CHARPOS (*it) = IT_STRING_BYTEPOS (*it) = 0; it->string = it->overlay_strings[0]; + it->from_overlay = Qnil; it->stop_charpos = 0; xassert (STRINGP (it->string)); it->end_charpos = SCHARS (it->string); @@ -5090,6 +5176,7 @@ push_it (it) p->face_id = it->face_id; p->string = it->string; p->method = it->method; + p->from_overlay = it->from_overlay; switch (p->method) { case GET_FROM_IMAGE: @@ -5143,6 +5230,7 @@ pop_it (it) it->current = p->current; it->position = p->position; it->string = p->string; + it->from_overlay = p->from_overlay; if (NILP (it->string)) SET_TEXT_POS (it->current.string_pos, -1, -1); it->method = p->method; @@ -5331,7 +5419,7 @@ back_to_previous_visible_line_start (it) { struct it it2; int pos; - int beg, end; + EMACS_INT beg, end; Lisp_Object val, overlay; /* If newline is part of a composition, continue from start of composition */ @@ -5910,7 +5998,7 @@ get_next_display_element (it) int pos = (it->s ? -1 : STRINGP (it->string) ? IT_STRING_CHARPOS (*it) : IT_CHARPOS (*it)); - + it->face_id = FACE_FOR_CHAR (it->f, face, it->c, pos, it->string); } @@ -8130,7 +8218,7 @@ with_echo_area_buffer_unwind_data (w) struct window *w; { int i = 0; - Lisp_Object vector; + Lisp_Object vector, tmp; /* Reduce consing by keeping one vector in Vwith_echo_area_save_vector. */ @@ -8140,22 +8228,22 @@ with_echo_area_buffer_unwind_data (w) if (NILP (vector)) vector = Fmake_vector (make_number (7), Qnil); - XSETBUFFER (AREF (vector, i), current_buffer); ++i; - AREF (vector, i) = Vdeactivate_mark, ++i; - AREF (vector, i) = make_number (windows_or_buffers_changed), ++i; + XSETBUFFER (tmp, current_buffer); ASET (vector, i, tmp); ++i; + ASET (vector, i, Vdeactivate_mark); ++i; + ASET (vector, i, make_number (windows_or_buffers_changed)); ++i; if (w) { - XSETWINDOW (AREF (vector, i), w); ++i; - AREF (vector, i) = w->buffer; ++i; - AREF (vector, i) = make_number (XMARKER (w->pointm)->charpos); ++i; - AREF (vector, i) = make_number (XMARKER (w->pointm)->bytepos); ++i; + XSETWINDOW (tmp, w); ASET (vector, i, tmp); ++i; + ASET (vector, i, w->buffer); ++i; + ASET (vector, i, make_number (XMARKER (w->pointm)->charpos)); ++i; + ASET (vector, i, make_number (XMARKER (w->pointm)->bytepos)); ++i; } else { int end = i + 4; for (; i < end; ++i) - AREF (vector, i) = Qnil; + ASET (vector, i, Qnil); } xassert (i == ASIZE (vector)); @@ -8386,7 +8474,7 @@ resize_mini_window_1 (a1, exactly, a3, a4) } -/* Resize mini-window W to fit the size of its contents. EXACT:P +/* Resize mini-window W to fit the size of its contents. EXACT_P means size the window exactly to the size needed. Otherwise, it's only enlarged until W's buffer is empty. @@ -8828,11 +8916,11 @@ clear_garbaged_frames () { Lisp_Object tail, frame; int changed_count = 0; - + FOR_EACH_FRAME (tail, frame) { struct frame *f = XFRAME (frame); - + if (FRAME_VISIBLE_P (f) && FRAME_GARBAGED_P (f)) { if (f->resized_p) @@ -8846,7 +8934,7 @@ clear_garbaged_frames () f->resized_p = 0; } } - + frame_garbaged = 0; if (changed_count) ++windows_or_buffers_changed; @@ -8876,8 +8964,6 @@ echo_area_display (update_frame_p) if (!FRAME_VISIBLE_P (f) || !f->glyphs_initialized_p) return 0; -/* The terminal frame is used as the first Emacs frame on the Mac OS. */ -#ifndef MAC_OS8 #ifdef HAVE_WINDOW_SYSTEM /* When Emacs starts, selected_frame may be the initial terminal frame. If we let this through, a message would be displayed on @@ -8885,7 +8971,6 @@ echo_area_display (update_frame_p) if (FRAME_INITIAL_P (XFRAME (selected_frame))) return 0; #endif /* HAVE_WINDOW_SYSTEM */ -#endif /* Redraw garbaged frames. */ if (frame_garbaged) @@ -9009,7 +9094,7 @@ static Lisp_Object format_mode_line_unwind_data (obuf, save_proptrans) struct buffer *obuf; { - Lisp_Object vector; + Lisp_Object vector, tmp; /* Reduce consing by keeping one vector in Vwith_echo_area_save_vector. */ @@ -9019,17 +9104,18 @@ format_mode_line_unwind_data (obuf, save_proptrans) if (NILP (vector)) vector = Fmake_vector (make_number (7), Qnil); - AREF (vector, 0) = make_number (mode_line_target); - AREF (vector, 1) = make_number (MODE_LINE_NOPROP_LEN (0)); - AREF (vector, 2) = mode_line_string_list; - AREF (vector, 3) = (save_proptrans ? mode_line_proptrans_alist : Qt); - AREF (vector, 4) = mode_line_string_face; - AREF (vector, 5) = mode_line_string_face_prop; + ASET (vector, 0, make_number (mode_line_target)); + ASET (vector, 1, make_number (MODE_LINE_NOPROP_LEN (0))); + ASET (vector, 2, mode_line_string_list); + ASET (vector, 3, save_proptrans ? mode_line_proptrans_alist : Qt); + ASET (vector, 4, mode_line_string_face); + ASET (vector, 5, mode_line_string_face_prop); if (obuf) - XSETBUFFER (AREF (vector, 6), obuf); + XSETBUFFER (tmp, obuf); else - AREF (vector, 6) = Qnil; + tmp = Qnil; + ASET (vector, 6, tmp); return vector; } @@ -9049,7 +9135,7 @@ unwind_format_mode_line (vector) if (!NILP (AREF (vector, 6))) { set_buffer_internal_1 (XBUFFER (AREF (vector, 6))); - AREF (vector, 6) = Qnil; + ASET (vector, 6, Qnil); } Vmode_line_unwind_vector = vector; @@ -10475,11 +10561,12 @@ hscroll_window_tree (window) /* Scroll when cursor is inside this scroll margin. */ h_margin = hscroll_margin * WINDOW_FRAME_COLUMN_WIDTH (w); - if ((XFASTINT (w->hscroll) - && w->cursor.x <= h_margin) - || (cursor_row->enabled_p - && cursor_row->truncated_on_right_p - && (w->cursor.x >= text_area_width - h_margin))) + if (!NILP (Fbuffer_local_value (Qauto_hscroll_mode, w->buffer)) + && ((XFASTINT (w->hscroll) + && w->cursor.x <= h_margin) + || (cursor_row->enabled_p + && cursor_row->truncated_on_right_p + && (w->cursor.x >= text_area_width - h_margin)))) { struct it it; int hscroll; @@ -10569,16 +10656,9 @@ static int hscroll_windows (window) Lisp_Object window; { - int hscrolled_p; - - if (automatic_hscrolling_p) - { - hscrolled_p = hscroll_window_tree (window); - if (hscrolled_p) - clear_desired_matrices (XFRAME (WINDOW_FRAME (XWINDOW (window)))); - } - else - hscrolled_p = 0; + int hscrolled_p = hscroll_window_tree (window); + if (hscrolled_p) + clear_desired_matrices (XFRAME (WINDOW_FRAME (XWINDOW (window)))); return hscrolled_p; } @@ -10962,29 +11042,20 @@ select_frame_for_redisplay (frame) selected_frame = frame; - for (tail = XFRAME (frame)->param_alist; CONSP (tail); tail = XCDR (tail)) - if (CONSP (XCAR (tail)) - && (sym = XCAR (XCAR (tail)), - SYMBOLP (sym)) - && (sym = indirect_variable (sym), - val = SYMBOL_VALUE (sym), - (BUFFER_LOCAL_VALUEP (val) - || SOME_BUFFER_LOCAL_VALUEP (val))) - && XBUFFER_LOCAL_VALUE (val)->check_frame) - /* Use find_symbol_value rather than Fsymbol_value - to avoid an error if it is void. */ - find_symbol_value (sym); - - for (tail = XFRAME (old)->param_alist; CONSP (tail); tail = XCDR (tail)) - if (CONSP (XCAR (tail)) - && (sym = XCAR (XCAR (tail)), - SYMBOLP (sym)) - && (sym = indirect_variable (sym), - val = SYMBOL_VALUE (sym), - (BUFFER_LOCAL_VALUEP (val) - || SOME_BUFFER_LOCAL_VALUEP (val))) - && XBUFFER_LOCAL_VALUE (val)->check_frame) - find_symbol_value (sym); + do + { + for (tail = XFRAME (frame)->param_alist; CONSP (tail); tail = XCDR (tail)) + if (CONSP (XCAR (tail)) + && (sym = XCAR (XCAR (tail)), + SYMBOLP (sym)) + && (sym = indirect_variable (sym), + val = SYMBOL_VALUE (sym), + (BUFFER_LOCAL_VALUEP (val))) + && XBUFFER_LOCAL_VALUE (val)->check_frame) + /* Use find_symbol_value rather than Fsymbol_value + to avoid an error if it is void. */ + find_symbol_value (sym); + } while (!EQ (frame, old) && (frame = old, 1)); } @@ -11137,7 +11208,7 @@ redisplay_internal (preserve_echo_area) } } - + /* Notice any pending interrupt request to change frame size. */ do_pending_window_change (1); @@ -11719,13 +11790,7 @@ redisplay_internal (preserve_echo_area) #ifdef HAVE_WINDOW_SYSTEM if (clear_image_cache_count > CLEAR_IMAGE_CACHE_COUNT) { - Lisp_Object tail, frame; - FOR_EACH_FRAME (tail, frame) - { - struct frame *f = XFRAME (frame); - if (FRAME_WINDOW_P (f)) - clear_image_cache (f, 0); - } + clear_image_caches (Qnil); clear_image_cache_count = 0; } #endif /* HAVE_WINDOW_SYSTEM */ @@ -12625,7 +12690,7 @@ compute_window_start_on_continuation_line (w) minimum distance from the old window start. */ pos = it.current.pos; min_distance = INFINITY; - while ((distance = abs (CHARPOS (start_pos) - IT_CHARPOS (it))), + while ((distance = eabs (CHARPOS (start_pos) - IT_CHARPOS (it))), distance < min_distance) { min_distance = distance; @@ -12974,8 +13039,7 @@ redisplay_window (window, just_this_one_p) *w->desired_matrix->method = 0; #endif - specbind (Qinhibit_point_motion_hooks, Qt); - + restart: reconsider_clip_changes (w, buffer); /* Has the mode line to be updated? */ @@ -13026,10 +13090,6 @@ redisplay_window (window, just_this_one_p) /* Really select the buffer, for the sake of buffer-local variables. */ set_buffer_internal_1 (XBUFFER (w->buffer)); - SET_TEXT_POS (opoint, PT, PT_BYTE); - - beg_unchanged = BEG_UNCHANGED; - end_unchanged = END_UNCHANGED; current_matrix_up_to_date_p = (!NILP (w->window_end_valid) @@ -13038,6 +13098,23 @@ redisplay_window (window, just_this_one_p) && XFASTINT (w->last_modified) >= MODIFF && XFASTINT (w->last_overlay_modified) >= OVERLAY_MODIFF); + /* Run the window-bottom-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 + && !NILP (Vwindow_text_change_functions)) + { + safe_run_hooks (Qwindow_text_change_functions); + goto restart; + } + + beg_unchanged = BEG_UNCHANGED; + end_unchanged = END_UNCHANGED; + + SET_TEXT_POS (opoint, PT, PT_BYTE); + + specbind (Qinhibit_point_motion_hooks, Qt); + buffer_unchanged_p = (!NILP (w->window_end_valid) && !current_buffer->clip_changed @@ -14342,8 +14419,7 @@ find_first_unchanged_at_end_row (w, delta, delta_bytes) /* Display must not have been paused, otherwise the current matrix is not up to date. */ - if (NILP (w->window_end_valid)) - abort (); + eassert (!NILP (w->window_end_valid)); /* A value of window_end_pos >= END_UNCHANGED means that the window end is in the range of changed text. If so, there is no @@ -14394,8 +14470,7 @@ find_first_unchanged_at_end_row (w, delta, delta_bytes) } } - if (row_found && !MATRIX_ROW_DISPLAYS_TEXT_P (row_found)) - abort (); + eassert (!row_found || MATRIX_ROW_DISPLAYS_TEXT_P (row_found)); return row_found; } @@ -16690,7 +16765,7 @@ display_menu_bar (w) break; /* Remember where item was displayed. */ - AREF (items, i + 3) = make_number (it.hpos); + ASET (items, i + 3, make_number (it.hpos)); /* Display the item, pad with one space. */ if (it.current_x < it.last_visible_x) @@ -17145,14 +17220,14 @@ display_mode_element (it, depth, field_width, precision, elt, props, risky) int multibyte; int bytepos, charpos; unsigned char *spec; + Lisp_Object string; bytepos = percent_position; charpos = (STRING_MULTIBYTE (elt) ? string_byte_to_char (elt, bytepos) : bytepos); - - spec - = decode_mode_spec (it->w, c, field, prec, &multibyte); + spec = decode_mode_spec (it->w, c, field, prec, &multibyte, + &string); switch (mode_line_target) { @@ -17162,19 +17237,24 @@ display_mode_element (it, depth, field_width, precision, elt, props, risky) break; case MODE_LINE_STRING: { - int len = strlen (spec); - Lisp_Object tem = make_string (spec, len); + if (NILP (string)) + { + int len = strlen (spec); + string = make_string (spec, len); + } props = Ftext_properties_at (make_number (charpos), elt); /* Should only keep face property in props */ - n += store_mode_line_string (NULL, tem, 0, field, prec, props); + n += store_mode_line_string (NULL, string, 0, field, prec, props); } break; case MODE_LINE_DISPLAY: { int nglyphs_before, nwritten; + if (STRINGP (string)) + spec = NULL; nglyphs_before = it->glyph_row->used[TEXT_AREA]; - nwritten = display_string (spec, Qnil, elt, + nwritten = display_string (spec, string, elt, charpos, 0, it, field, prec, 0, multibyte); @@ -17527,7 +17607,9 @@ are the selected window and the window's buffer). */) buffer = w->buffer; CHECK_BUFFER (buffer); - if (NILP (format)) + /* 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) return empty_unibyte_string; if (no_props) @@ -17836,18 +17918,19 @@ decode_mode_spec_coding (coding_system, buf, eol_flag) static char lots_of_dashes[] = "--------------------------------------------------------------------------------------------------------------------------------------------"; static char * -decode_mode_spec (w, c, field_width, precision, multibyte) +decode_mode_spec (w, c, field_width, precision, multibyte, string) struct window *w; register int c; int field_width, precision; int *multibyte; + Lisp_Object *string; { Lisp_Object obj; struct frame *f = XFRAME (WINDOW_FRAME (w)); char *decode_mode_spec_buf = f->decode_mode_spec_buffer; struct buffer *b = current_buffer; - obj = Qnil; + *string = obj = Qnil; *multibyte = 0; switch (c) @@ -18012,8 +18095,8 @@ decode_mode_spec (w, c, field_width, precision, multibyte) goto no_value; } - if (!NILP (w->base_line_number) - && !NILP (w->base_line_pos) + if (INTEGERP (w->base_line_number) + && INTEGERP (w->base_line_pos) && XFASTINT (w->base_line_pos) <= startpos) { line = XFASTINT (w->base_line_number); @@ -18210,9 +18293,11 @@ decode_mode_spec (w, c, field_width, precision, multibyte) { /* No need to mention EOL here--the terminal never needs to do EOL conversion. */ - p = decode_mode_spec_coding (CODING_ID_NAME (keyboard_coding.id), + p = decode_mode_spec_coding (CODING_ID_NAME + (FRAME_KEYBOARD_CODING (f)->id), p, 0); - p = decode_mode_spec_coding (CODING_ID_NAME (terminal_coding.id), + p = decode_mode_spec_coding (CODING_ID_NAME + (FRAME_TERMINAL_CODING (f)->id), p, 0); } p = decode_mode_spec_coding (b->buffer_file_coding_system, @@ -18238,6 +18323,7 @@ decode_mode_spec (w, c, field_width, precision, multibyte) if (STRINGP (obj)) { *multibyte = STRING_MULTIBYTE (obj); + *string = obj; return (char *) SDATA (obj); } else @@ -19219,16 +19305,16 @@ fill_composite_glyph_string (s, base_face, overlaps) s->cmp->hash_index * 2); s->face = base_face; - s->font_info = s->cmp->font; + s->font_info = base_face->font_info; s->font = s->font_info->font; for (i = 0, s->nchars = 0; i < s->cmp->glyph_len; i++, s->nchars++) { Lisp_Object g = LGSTRING_GLYPH (gstring, i); unsigned code; XChar2b * store_pos; - if (NILP (LGLYPH_FROM (g))) + if (NILP (g)) break; - code = XUINT (LGLYPH_CODE (g)); + code = LGLYPH_CODE (g); store_pos = s->char2b + i; STORE_XCHAR2B (store_pos, code >> 8, code & 0xFF); } @@ -19251,7 +19337,8 @@ fill_composite_glyph_string (s, base_face, overlaps) if (c != '\t') { - int face_id = FACE_FOR_CHAR (s->f, base_face, c, -1, Qnil); + int face_id = FACE_FOR_CHAR (s->f, base_face->ascii_face, c, + -1, Qnil); face = get_char_face_and_encoding (s->f, c, face_id, s->char2b + i, 1, 1); @@ -19615,70 +19702,6 @@ right_overwriting (s) } -/* Get face and two-byte form of character C in face FACE_ID on frame - F. The encoding of C is returned in *CHAR2B. MULTIBYTE_P non-zero - means we want to display multibyte text. DISPLAY_P non-zero means - make sure that X resources for the face returned are allocated. - Value is a pointer to a realized face that is ready for display if - DISPLAY_P is non-zero. */ - -static INLINE struct face * -get_char_face_and_encoding (f, c, face_id, char2b, multibyte_p, display_p) - struct frame *f; - int c, face_id; - XChar2b *char2b; - int multibyte_p, display_p; -{ - struct face *face = FACE_FROM_ID (f, face_id); - - if (!multibyte_p) - { - /* Unibyte case. We don't have to encode, but we have to make - sure to use a face suitable for unibyte. */ - STORE_XCHAR2B (char2b, 0, c); - face_id = FACE_FOR_CHAR (f, face, c); - face = FACE_FROM_ID (f, face_id); - } - else if (c < 128) - { - /* Case of ASCII in a face known to fit ASCII. */ - STORE_XCHAR2B (char2b, 0, c); - } - else - { - int c1, c2, charset; - - /* Split characters into bytes. If c2 is -1 afterwards, C is - really a one-byte character so that byte1 is zero. */ - SPLIT_CHAR (c, charset, c1, c2); - if (c2 > 0) - STORE_XCHAR2B (char2b, c1, c2); - else - STORE_XCHAR2B (char2b, 0, c1); - - /* Maybe encode the character in *CHAR2B. */ - if (face->font != NULL) - { - struct font_info *font_info - = FONT_INFO_FROM_ID (f, face->font_info_id); - if (font_info) - FRAME_RIF (f)->encode_char (c, char2b, font_info, 0); - } - } - - /* Make sure X resources of the face are allocated. */ -#ifdef HAVE_X_WINDOWS - if (display_p) -#endif - { - xassert (face != NULL); - PREPARE_FACE_FOR_DISPLAY (f, face); - } - - return face; -} - - /* Set background width of glyph string S. START is the index of the first glyph following S. LAST_X is the right-most x-position + 1 in the drawing area. */ @@ -19853,7 +19876,6 @@ compute_overhangs_and_x (s, x, backward_p) int n; \ \ char2b = (XChar2b *) alloca ((sizeof *char2b) * cmp->glyph_len); \ - base_face = base_face->ascii_face; \ \ /* Make glyph_strings for each glyph sequence that is drawable by \ the same face, and append them to HEAD/TAIL. */ \ @@ -20353,9 +20375,9 @@ produce_image_glyph (it) } if (it->start_of_box_run_p && slice.x == 0) - it->pixel_width += abs (face->box_line_width); + it->pixel_width += eabs (face->box_line_width); if (it->end_of_box_run_p && slice.x + slice.width == img->width) - it->pixel_width += abs (face->box_line_width); + it->pixel_width += eabs (face->box_line_width); } take_vertical_position_into_account (it); @@ -21069,6 +21091,11 @@ x_produce_glyphs (it) take_vertical_position_into_account (it); + if (it->ascent < 0) + it->ascent = 0; + if (it->descent < 0) + it->descent = 0; + if (it->glyph_row) append_glyph (it); } @@ -21093,8 +21120,8 @@ x_produce_glyphs (it) #ifdef USE_FONT_BACKEND if (cmp->method == COMPOSITION_WITH_GLYPH_STRING) { - if (! cmp->font || cmp->font != font) - font_prepare_composition (cmp); + PREPARE_FACE_FOR_DISPLAY (it->f, face); + font_prepare_composition (cmp, it->f); } else #endif /* USE_FONT_BACKEND */ @@ -21295,7 +21322,7 @@ x_produce_glyphs (it) + grefx * (rightmost - leftmost) / 2 - nrefx * width / 2 + xoff); - + btm = ((grefy == 0 ? highest : grefy == 1 ? 0 : grefy == 2 ? lowest @@ -21374,7 +21401,6 @@ x_produce_glyphs (it) it->pixel_width = cmp->pixel_width; it->ascent = it->phys_ascent = cmp->ascent; it->descent = it->phys_descent = cmp->descent; - if (face->box != FACE_NO_BOX) { int thick = face->box_line_width; @@ -21399,6 +21425,10 @@ x_produce_glyphs (it) it->ascent += overline_margin; take_vertical_position_into_account (it); + if (it->ascent < 0) + it->ascent = 0; + if (it->descent < 0) + it->descent = 0; if (it->glyph_row) append_composite_glyph (it); @@ -22672,8 +22702,8 @@ fast_find_string_pos (w, pos, object, hpos, vpos, x, y, right_p) goto found; } else if (best_glyph == NULL - || ((abs (g->charpos - pos) - < abs (best_glyph->charpos - pos)) + || ((eabs (g->charpos - pos) + < eabs (best_glyph->charpos - pos)) && (right_p ? g->charpos < pos : g->charpos > pos))) @@ -23839,6 +23869,24 @@ phys_cursor_in_rect_p (w, r) { XRectangle cr, result; struct glyph *cursor_glyph; + struct glyph_row *row; + + if (w->phys_cursor.vpos >= 0 + && w->phys_cursor.vpos < w->current_matrix->nrows + && (row = MATRIX_ROW (w->current_matrix, w->phys_cursor.vpos), + row->enabled_p) + && row->cursor_in_fringe_p) + { + /* Cursor is in the fringe. */ + cr.x = window_box_right_offset (w, + (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w) + ? RIGHT_MARGIN_AREA + : TEXT_AREA)); + cr.y = row->y; + cr.width = WINDOW_RIGHT_FRINGE_WIDTH (w); + cr.height = row->height; + return x_intersect_rectangles (&cr, r, &result); + } cursor_glyph = get_phys_cursor_glyph (w); if (cursor_glyph) @@ -23867,7 +23915,7 @@ x_draw_vertical_border (w) struct window *w; { struct frame *f = XFRAME (WINDOW_FRAME (w)); - + /* We could do better, if we knew what type of scroll-bar the adjacent windows (on either side) have... But we don't :-( However, I think this works ok. ++KFS 2003-04-25 */ @@ -24272,6 +24320,9 @@ syms_of_xdisp () staticpro (&Qwindow_scroll_functions); Qwindow_scroll_functions = intern ("window-scroll-functions"); + staticpro (&Qwindow_text_change_functions); + Qwindow_text_change_functions = intern ("window-text-change-functions"); + staticpro (&Qredisplay_end_trigger_functions); Qredisplay_end_trigger_functions = intern ("redisplay-end-trigger-functions"); @@ -24480,8 +24531,12 @@ If you want scrolling to always be a line at a time, you should set DEFVAR_INT ("scroll-conservatively", &scroll_conservatively, doc: /* *Scroll up to this many lines, to bring point back on screen. -A value of zero means to scroll the text to center point vertically -in the window. */); +If point moves off-screen, redisplay will scroll by up to +`scroll-conservatively' lines in order to bring point just barely +onto the screen again. If that cannot be done, then redisplay +recenters point as usual. + +A value of zero means always recenter point if it moves off screen. */); scroll_conservatively = 0; DEFVAR_INT ("scroll-margin", &scroll_margin, @@ -24579,6 +24634,11 @@ and its new display-start position. Note that the value of `window-end' is not valid when these functions are called. */); Vwindow_scroll_functions = Qnil; + DEFVAR_LISP ("window-text-change-functions", + &Vwindow_text_change_functions, + doc: /* Functions to call in redisplay when text in the window might change. */); + Vwindow_text_change_functions = Qnil; + DEFVAR_LISP ("redisplay-end-trigger-functions", &Vredisplay_end_trigger_functions, doc: /* Functions called when redisplay of a window reaches the end trigger. Each function is called with two arguments, the window and the end trigger value. @@ -24688,6 +24748,8 @@ the frame's other specifications determine how to blink the cursor off. */); DEFVAR_BOOL ("auto-hscroll-mode", &automatic_hscrolling_p, doc: /* *Non-nil means scroll the display automatically to make point visible. */); automatic_hscrolling_p = 1; + Qauto_hscroll_mode = intern ("auto-hscroll-mode"); + staticpro (&Qauto_hscroll_mode); DEFVAR_INT ("hscroll-margin", &hscroll_margin, doc: /* *How many columns away from the window edge point is allowed to get