X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/6d9257263ebfa2dc2d39809584a4e67f5f8b4662..75e6b97059b6e5b012b1084677070add5c5b0c19:/src/xdisp.c diff --git a/src/xdisp.c b/src/xdisp.c index de62a64698..8ed0adfc89 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -198,8 +198,6 @@ Boston, MA 02111-1307, USA. */ #endif #ifdef MAC_OS #include "macterm.h" - -Cursor No_Cursor; #endif #ifndef FRAME_X_OUTPUT @@ -217,6 +215,8 @@ extern int pending_menu_activation; extern int interrupt_input; extern int command_loop_level; +extern Lisp_Object do_mouse_tracking; + extern int minibuffer_auto_raise; extern Lisp_Object Vminibuffer_list; @@ -264,6 +264,10 @@ int mouse_autoselect_window; int auto_raise_tool_bar_buttons_p; +/* Non-zero means to reposition window if cursor line is only partially visible. */ + +int make_cursor_line_fully_visible_p; + /* Margin around tool bar buttons in pixels. */ Lisp_Object Vtool_bar_button_margin; @@ -301,10 +305,14 @@ extern Lisp_Object Qface, Qinvisible, Qwidth; Lisp_Object Vdisplay_pixels_per_inch; Lisp_Object Qspace, QCalign_to, QCrelative_width, QCrelative_height; Lisp_Object Qleft_margin, Qright_margin, Qspace_width, Qraise; +Lisp_Object Qslice; +Lisp_Object Qcenter; Lisp_Object Qmargin, Qpointer; +Lisp_Object Qline_height, Qtotal; extern Lisp_Object Qheight; extern Lisp_Object QCwidth, QCheight, QCascent; extern Lisp_Object Qscroll_bar; +extern Lisp_Object Qcursor; /* Non-nil means highlight trailing whitespace. */ @@ -314,7 +322,7 @@ Lisp_Object Vshow_trailing_whitespace; extern Lisp_Object Voverflow_newline_into_fringe; /* Test if overflow newline into fringe. Called with iterator IT - at or past right window margin, and with IT->current_x set. */ + at or past right window margin, and with IT->current_x set. */ #define IT_OVERFLOW_NEWLINE_INTO_FRINGE(it) \ (!NILP (Voverflow_newline_into_fringe) \ @@ -334,6 +342,11 @@ Lisp_Object Vvoid_text_area_pointer; Lisp_Object Qtrailing_whitespace; +/* Name and number of the face used to highlight escape glyphs. */ + +Lisp_Object Qescape_glyph; +int escape_glyph_face; + /* The symbol `image' which is the car of the lists used to represent images in Lisp. */ @@ -403,6 +416,13 @@ int multiple_frames; Lisp_Object Vglobal_mode_string; + +/* List of variables (symbols) which hold markers for overlay arrows. + The symbols on this list are examined during redisplay to determine + where to display overlay arrows. */ + +Lisp_Object Voverlay_arrow_variable_list; + /* Marker for where to display an arrow on top of the buffer text. */ Lisp_Object Voverlay_arrow_position; @@ -411,11 +431,17 @@ Lisp_Object Voverlay_arrow_position; Lisp_Object Voverlay_arrow_string; -/* Values of those variables at last redisplay. However, if - Voverlay_arrow_position is a marker, last_arrow_position is its +/* Values of those variables at last redisplay are stored as + properties on `overlay-arrow-position' symbol. However, if + Voverlay_arrow_position is a marker, last-arrow-position is its numerical position. */ -static Lisp_Object last_arrow_position, last_arrow_string; +Lisp_Object Qlast_arrow_position, Qlast_arrow_string; + +/* Alternative overlay-arrow-string and overlay-arrow-bitmap + properties on a symbol in overlay-arrow-variable-list. */ + +Lisp_Object Qoverlay_arrow_string, Qoverlay_arrow_bitmap; /* Like mode-line-format, but for the title bar on a visible frame. */ @@ -656,10 +682,6 @@ EMACS_INT hscroll_margin; /* How much to scroll horizontally when point is inside the above margin. */ Lisp_Object Vhscroll_step; -/* A list of symbols, one for each supported image type. */ - -Lisp_Object Vimage_types; - /* The variable `resize-mini-windows'. If nil, don't resize mini-windows. If t, always resize them to fit the text they display. If `grow-only', let mini-windows grow only until they @@ -783,13 +805,16 @@ int help_echo_pos; Lisp_Object previous_help_echo_string; +/* Null glyph slice */ + +static struct glyph_slice null_glyph_slice = { 0, 0, 0, 0 }; /* Function prototypes. */ -static void setup_for_ellipsis P_ ((struct it *)); +static void setup_for_ellipsis P_ ((struct it *, int)); static void mark_window_display_accurate_1 P_ ((struct window *, int)); -static int single_display_prop_string_p P_ ((Lisp_Object, Lisp_Object)); +static int single_display_spec_string_p P_ ((Lisp_Object, Lisp_Object)); static int display_prop_string_p P_ ((Lisp_Object, Lisp_Object)); static int cursor_row_p P_ ((struct window *, struct glyph_row *)); static int redisplay_mode_lines P_ ((Lisp_Object, int)); @@ -811,7 +836,7 @@ static int store_frame_title P_ ((const unsigned char *, int, int)); static void x_consider_frame_title P_ ((Lisp_Object)); static void handle_stop P_ ((struct it *)); static int tool_bar_lines_needed P_ ((struct frame *)); -static int single_display_prop_intangible_p P_ ((Lisp_Object)); +static int single_display_spec_intangible_p P_ ((Lisp_Object)); static void ensure_echo_area_buffers P_ ((void)); static Lisp_Object unwind_with_echo_area_buffer P_ ((Lisp_Object)); static Lisp_Object with_echo_area_buffer_unwind_data P_ ((struct window *)); @@ -832,10 +857,11 @@ static struct text_pos display_prop_end P_ ((struct it *, Lisp_Object, static int compute_window_start_on_continuation_line P_ ((struct window *)); static Lisp_Object safe_eval_handler P_ ((Lisp_Object)); static void insert_left_trunc_glyphs P_ ((struct it *)); -static struct glyph_row *get_overlay_arrow_glyph_row P_ ((struct window *)); +static struct glyph_row *get_overlay_arrow_glyph_row P_ ((struct window *, + Lisp_Object)); static void extend_face_to_end_of_line P_ ((struct it *)); -static int append_space P_ ((struct it *, int)); -static int make_cursor_line_fully_visible P_ ((struct window *)); +static int append_space_for_newline P_ ((struct it *, int)); +static int make_cursor_line_fully_visible P_ ((struct window *, int)); static int try_scrolling P_ ((Lisp_Object, int, EMACS_INT, EMACS_INT, int, int)); static int try_cursor_movement P_ ((Lisp_Object, struct text_pos, int *)); static int trailing_whitespace_p P_ ((int)); @@ -871,7 +897,7 @@ static void next_overlay_string P_ ((struct it *)); static void reseat P_ ((struct it *, struct text_pos, int)); static void reseat_1 P_ ((struct it *, struct text_pos, int)); static void back_to_previous_visible_line_start P_ ((struct it *)); -static void reseat_at_previous_visible_line_start P_ ((struct it *)); +void reseat_at_previous_visible_line_start P_ ((struct it *)); static void reseat_at_next_visible_line_start P_ ((struct it *, int)); static int next_element_from_display_vector P_ ((struct it *)); static int next_element_from_string P_ ((struct it *)); @@ -904,7 +930,7 @@ static void compute_string_pos P_ ((struct text_pos *, struct text_pos, Lisp_Object)); static int face_before_or_after_it_pos P_ ((struct it *, int)); static int next_overlay_change P_ ((int)); -static int handle_single_display_prop P_ ((struct it *, Lisp_Object, +static int handle_single_display_spec P_ ((struct it *, Lisp_Object, Lisp_Object, struct text_pos *, int)); static int underlying_face_id P_ ((struct it *)); @@ -1220,9 +1246,9 @@ line_bottom_y (it) and header-lines heights. */ int -pos_visible_p (w, charpos, fully, exact_mode_line_heights_p) +pos_visible_p (w, charpos, fully, x, y, exact_mode_line_heights_p) struct window *w; - int charpos, *fully, exact_mode_line_heights_p; + int charpos, *fully, *x, *y, exact_mode_line_heights_p; { struct it it; struct text_pos top; @@ -1270,14 +1296,27 @@ pos_visible_p (w, charpos, fully, exact_mode_line_heights_p) visible_p = 1; *fully = bottom_y <= it.last_visible_y; } + if (visible_p && x) + { + *x = it.current_x; + *y = max (top_y + it.max_ascent - it.ascent, window_top_y); + } } else if (it.current_y + it.max_ascent + it.max_descent > it.last_visible_y) { + struct it it2; + + it2 = it; move_it_by_lines (&it, 1, 0); if (charpos < IT_CHARPOS (it)) { visible_p = 1; - *fully = 0; + if (x) + { + move_it_to (&it2, charpos, -1, -1, -1, MOVE_TO_POS); + *x = it2.current_x; + *y = it2.current_y + it2.max_ascent - it2.ascent; + } } } @@ -1285,6 +1324,7 @@ pos_visible_p (w, charpos, fully, exact_mode_line_heights_p) set_buffer_internal_1 (old_buffer); current_header_line_height = current_mode_line_height = -1; + return visible_p; } @@ -1754,7 +1794,8 @@ get_glyph_string_clip_rect (s, nr) /* If drawing a tool-bar window, draw it over the internal border at the top of the window. */ - if (s->w == XWINDOW (s->f->tool_bar_window)) + if (WINDOWP (s->f->tool_bar_window) + && s->w == XWINDOW (s->f->tool_bar_window)) r.y -= FRAME_INTERNAL_BORDER_WIDTH (s->f); } @@ -1778,8 +1819,9 @@ get_glyph_string_clip_rect (s, nr) height = max (FRAME_LINE_HEIGHT (s->f), glyph->ascent + glyph->descent); if (height < r.height) { - r.y = s->ybase + glyph->descent - height; - r.height = height; + int max_y = r.y + r.height; + r.y = min (max_y, s->ybase + glyph->descent - height); + r.height = min (max_y - r.y, height); } } @@ -1904,10 +1946,14 @@ check_it (it) xassert (STRINGP (it->string)); xassert (IT_STRING_CHARPOS (*it) >= 0); } - else if (it->method == next_element_from_buffer) + else { - /* Check that character and byte positions agree. */ - xassert (IT_CHARPOS (*it) == BYTE_TO_CHAR (IT_BYTEPOS (*it))); + xassert (IT_STRING_CHARPOS (*it) < 0); + if (it->method == next_element_from_buffer) + { + /* Check that character and byte positions agree. */ + xassert (IT_CHARPOS (*it) == BYTE_TO_CHAR (IT_BYTEPOS (*it))); + } } if (it->dpvec) @@ -2020,6 +2066,8 @@ init_iterator (it, w, charpos, bytepos, row, base_face_id) it->current.overlay_string_index = -1; it->current.dpvec_index = -1; it->base_face_id = base_face_id; + it->string = Qnil; + IT_STRING_CHARPOS (*it) = IT_STRING_BYTEPOS (*it) = -1; /* The window in which we iterate over current_buffer: */ XSETWINDOW (it->window, w); @@ -2032,8 +2080,12 @@ init_iterator (it, w, charpos, bytepos, row, base_face_id) { if (NATNUMP (current_buffer->extra_line_spacing)) it->extra_line_spacing = XFASTINT (current_buffer->extra_line_spacing); + else if (FLOATP (current_buffer->extra_line_spacing)) + it->extra_line_spacing = (XFLOAT_DATA (current_buffer->extra_line_spacing) + * FRAME_LINE_HEIGHT (it->f)); else if (it->f->extra_line_spacing > 0) it->extra_line_spacing = it->f->extra_line_spacing; + it->max_extra_line_spacing = 0; } /* If realized faces have been removed, e.g. because of face @@ -2045,9 +2097,11 @@ init_iterator (it, w, charpos, bytepos, row, base_face_id) if (FRAME_FACE_CACHE (it->f)->used == 0) recompute_basic_faces (it->f); - /* Current value of the `space-width', and 'height' properties. */ + /* Current value of the `slice', `space-width', and 'height' properties. */ + it->slice.x = it->slice.y = it->slice.width = it->slice.height = Qnil; it->space_width = Qnil; it->font_height = Qnil; + it->override_ascent = -1; /* Are control characters displayed as `^C'? */ it->ctl_arrow_p = !NILP (current_buffer->ctl_arrow); @@ -2688,19 +2742,10 @@ next_overlay_change (pos) int noverlays; int endpos; Lisp_Object *overlays; - int len; int i; /* Get all overlays at the given position. */ - len = 10; - overlays = (Lisp_Object *) alloca (len * sizeof *overlays); - noverlays = overlays_at (pos, 0, &overlays, &len, &endpos, NULL, 1); - if (noverlays > len) - { - len = noverlays; - overlays = (Lisp_Object *) alloca (len * sizeof *overlays); - noverlays = overlays_at (pos, 0, &overlays, &len, &endpos, NULL, 1); - } + GET_OVERLAYS_AT (pos, overlays, noverlays, &endpos, 1); /* If any of these overlays ends before endpos, use its ending point instead. */ @@ -3187,7 +3232,7 @@ handle_invisible_prop (it) it->stack[it->sp - 1].display_ellipsis_p = display_ellipsis_p; } else if (display_ellipsis_p) - setup_for_ellipsis (it); + setup_for_ellipsis (it, 0); } } @@ -3195,14 +3240,17 @@ handle_invisible_prop (it) } -/* Make iterator IT return `...' next. */ +/* Make iterator IT return `...' next. + Replaces LEN characters from buffer. */ static void -setup_for_ellipsis (it) +setup_for_ellipsis (it, len) struct it *it; + int len; { - if (it->dp - && VECTORP (DISP_INVIS_VECTOR (it->dp))) + /* Use the display table definition for `...'. Invalid glyphs + will be handled by the method returning elements from dpvec. */ + if (it->dp && VECTORP (DISP_INVIS_VECTOR (it->dp))) { struct Lisp_Vector *v = XVECTOR (DISP_INVIS_VECTOR (it->dp)); it->dpvec = v->contents; @@ -3215,12 +3263,12 @@ setup_for_ellipsis (it) it->dpend = default_invis_vector + 3; } - /* The ellipsis display does not replace the display of the - character at the new position. Indicate this by setting - IT->dpvec_char_len to zero. */ - it->dpvec_char_len = 0; - + it->dpvec_char_len = len; it->current.dpvec_index = 0; + + /* Remember the current face id in case glyphs specify faces. + IT's face is restored in set_iterator_to_next. */ + it->saved_face_id = it->face_id; it->method = next_element_from_display_vector; } @@ -3231,7 +3279,10 @@ setup_for_ellipsis (it) ***********************************************************************/ /* Set up iterator IT from `display' property at its current position. - Called from handle_stop. */ + Called from handle_stop. + We return HANDLED_RETURN if some part of the display property + overrides the display of the buffer text itself. + Otherwise we return HANDLED_NORMALLY. */ static enum prop_handled handle_display_prop (it) @@ -3239,6 +3290,7 @@ handle_display_prop (it) { Lisp_Object prop, object; struct text_pos *position; + /* Nonzero if some property replaces the display of the text itself. */ int display_replaced_p = 0; if (STRINGP (it->string)) @@ -3253,8 +3305,9 @@ handle_display_prop (it) } /* Reset those iterator values set from display property values. */ - it->font_height = Qnil; + it->slice.x = it->slice.y = it->slice.width = it->slice.height = Qnil; it->space_width = Qnil; + it->font_height = Qnil; it->voffset = 0; /* We don't support recursive `display' properties, i.e. string @@ -3273,6 +3326,7 @@ handle_display_prop (it) && !EQ (XCAR (prop), Qimage) && !EQ (XCAR (prop), Qspace) && !EQ (XCAR (prop), Qwhen) + && !EQ (XCAR (prop), Qslice) && !EQ (XCAR (prop), Qspace_width) && !EQ (XCAR (prop), Qheight) && !EQ (XCAR (prop), Qraise) @@ -3284,7 +3338,7 @@ handle_display_prop (it) { for (; CONSP (prop); prop = XCDR (prop)) { - if (handle_single_display_prop (it, XCAR (prop), object, + if (handle_single_display_spec (it, XCAR (prop), object, position, display_replaced_p)) display_replaced_p = 1; } @@ -3293,13 +3347,13 @@ handle_display_prop (it) { int i; for (i = 0; i < ASIZE (prop); ++i) - if (handle_single_display_prop (it, AREF (prop, i), object, + if (handle_single_display_spec (it, AREF (prop, i), object, position, display_replaced_p)) display_replaced_p = 1; } else { - if (handle_single_display_prop (it, prop, object, position, 0)) + if (handle_single_display_spec (it, prop, object, position, 0)) display_replaced_p = 1; } @@ -3331,42 +3385,44 @@ display_prop_end (it, object, start_pos) } -/* Set up IT from a single `display' sub-property value PROP. OBJECT +/* Set up IT from a single `display' specification PROP. OBJECT is the object in which the `display' property was found. *POSITION is the position at which it was found. DISPLAY_REPLACED_P non-zero - means that we previously saw a display sub-property which already + means that we previously saw a display specification which already replaced text display with something else, for example an image; - ignore such properties after the first one has been processed. + we ignore such properties after the first one has been processed. - If PROP is a `space' or `image' sub-property, set *POSITION to the - end position of the `display' 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. Value is non-zero if something was found which replaces the display of buffer or string text. */ static int -handle_single_display_prop (it, prop, object, position, +handle_single_display_spec (it, spec, object, position, display_replaced_before_p) struct it *it; - Lisp_Object prop; + Lisp_Object spec; Lisp_Object object; struct text_pos *position; int display_replaced_before_p; { - Lisp_Object value; - int replaces_text_display_p = 0; Lisp_Object form; + Lisp_Object location, value; + struct text_pos start_pos; + int valid_p; - /* If PROP is a list of the form `(when FORM . VALUE)', FORM is - evaluated. If the result is nil, VALUE is ignored. */ + /* If SPEC is a list of the form `(when FORM . VALUE)', evaluate FORM. + If the result is non-nil, use VALUE instead of SPEC. */ form = Qt; - if (CONSP (prop) && EQ (XCAR (prop), Qwhen)) + if (CONSP (spec) && EQ (XCAR (spec), Qwhen)) { - prop = XCDR (prop); - if (!CONSP (prop)) + spec = XCDR (spec); + if (!CONSP (spec)) return 0; - form = XCAR (prop); - prop = XCDR (prop); + form = XCAR (spec); + spec = XCDR (spec); } if (!NILP (form) && !EQ (form, Qt)) @@ -3392,15 +3448,15 @@ handle_single_display_prop (it, prop, object, position, if (NILP (form)) return 0; - if (CONSP (prop) - && EQ (XCAR (prop), Qheight) - && CONSP (XCDR (prop))) + /* Handle `(height HEIGHT)' specifications. */ + if (CONSP (spec) + && EQ (XCAR (spec), Qheight) + && CONSP (XCDR (spec))) { if (FRAME_TERMCAP_P (it->f) || FRAME_MSDOS_P (it->f)) return 0; - - /* `(height HEIGHT)'. */ - it->font_height = XCAR (XCDR (prop)); + + it->font_height = XCAR (XCDR (spec)); if (!NILP (it->font_height)) { struct face *face = FACE_FROM_ID (it->f, it->face_id); @@ -3441,7 +3497,6 @@ handle_single_display_prop (it, prop, object, position, { /* Evaluate IT->font_height with `height' bound to the current specified height to get the new height. */ - Lisp_Object value; int count = SPECPDL_INDEX (); specbind (Qheight, face->lface[LFACE_HEIGHT_INDEX]); @@ -3455,29 +3510,62 @@ handle_single_display_prop (it, prop, object, position, if (new_height > 0) it->face_id = face_with_height (it->f, it->face_id, new_height); } + + return 0; } - else if (CONSP (prop) - && EQ (XCAR (prop), Qspace_width) - && CONSP (XCDR (prop))) + + /* Handle `(space_width WIDTH)'. */ + if (CONSP (spec) + && EQ (XCAR (spec), Qspace_width) + && CONSP (XCDR (spec))) { - /* `(space_width WIDTH)'. */ if (FRAME_TERMCAP_P (it->f) || FRAME_MSDOS_P (it->f)) return 0; - value = XCAR (XCDR (prop)); + value = XCAR (XCDR (spec)); if (NUMBERP (value) && XFLOATINT (value) > 0) it->space_width = value; + + return 0; + } + + /* Handle `(slice X Y WIDTH HEIGHT)'. */ + if (CONSP (spec) + && EQ (XCAR (spec), Qslice)) + { + Lisp_Object tem; + + if (FRAME_TERMCAP_P (it->f) || FRAME_MSDOS_P (it->f)) + return 0; + + if (tem = XCDR (spec), CONSP (tem)) + { + it->slice.x = XCAR (tem); + if (tem = XCDR (tem), CONSP (tem)) + { + it->slice.y = XCAR (tem); + if (tem = XCDR (tem), CONSP (tem)) + { + it->slice.width = XCAR (tem); + if (tem = XCDR (tem), CONSP (tem)) + it->slice.height = XCAR (tem); + } + } + } + + return 0; } - else if (CONSP (prop) - && EQ (XCAR (prop), Qraise) - && CONSP (XCDR (prop))) + + /* Handle `(raise FACTOR)'. */ + if (CONSP (spec) + && EQ (XCAR (spec), Qraise) + && CONSP (XCDR (spec))) { - /* `(raise FACTOR)'. */ if (FRAME_TERMCAP_P (it->f) || FRAME_MSDOS_P (it->f)) return 0; #ifdef HAVE_WINDOW_SYSTEM - value = XCAR (XCDR (prop)); + value = XCAR (XCDR (spec)); if (NUMBERP (value)) { struct face *face = FACE_FROM_ID (it->f, it->face_id); @@ -3485,169 +3573,194 @@ handle_single_display_prop (it, prop, object, position, * (FONT_HEIGHT (face->font))); } #endif /* HAVE_WINDOW_SYSTEM */ + + return 0; } - else if (CONSP (prop) - && (EQ (XCAR (prop), Qleft_fringe) - || EQ (XCAR (prop), Qright_fringe)) - && CONSP (XCDR (prop))) + + /* Don't handle the other kinds of display specifications + inside a string that we got from a `display' property. */ + if (it->string_from_display_prop_p) + return 0; + + /* Characters having this form of property are not displayed, so + we have to find the end of the property. */ + start_pos = *position; + *position = display_prop_end (it, object, start_pos); + value = Qnil; + + /* Stop the scan at that end position--we assume that all + text properties change there. */ + it->stop_charpos = position->charpos; + + /* Handle `(left-fringe BITMAP [FACE])' + and `(right-fringe BITMAP [FACE])'. */ + if (CONSP (spec) + && (EQ (XCAR (spec), Qleft_fringe) + || EQ (XCAR (spec), Qright_fringe)) + && CONSP (XCDR (spec))) { - unsigned face_id = DEFAULT_FACE_ID; + int face_id = DEFAULT_FACE_ID; + int fringe_bitmap; - /* `(left-fringe BITMAP FACE)'. */ if (FRAME_TERMCAP_P (it->f) || FRAME_MSDOS_P (it->f)) + /* If we return here, POSITION has been advanced + across the text with this property. */ return 0; #ifdef HAVE_WINDOW_SYSTEM - value = XCAR (XCDR (prop)); - if (!NUMBERP (value) - || !valid_fringe_bitmap_id_p (XINT (value))) + value = XCAR (XCDR (spec)); + if (!SYMBOLP (value) + || !(fringe_bitmap = lookup_fringe_bitmap (value))) + /* If we return here, POSITION has been advanced + across the text with this property. */ return 0; - if (CONSP (XCDR (XCDR (prop)))) + if (CONSP (XCDR (XCDR (spec)))) { - Lisp_Object face_name = XCAR (XCDR (XCDR (prop))); - face_id = lookup_named_face (it->f, face_name, 'A'); - if (face_id < 0) - return 0; + Lisp_Object face_name = XCAR (XCDR (XCDR (spec))); + int face_id2 = lookup_named_face (it->f, face_name, 'A', 0); + if (face_id2 >= 0) + face_id = face_id2; } - if (EQ (XCAR (prop), Qleft_fringe)) + /* Save current settings of IT so that we can restore them + when we are finished with the glyph property value. */ + + push_it (it); + + it->area = TEXT_AREA; + it->what = IT_IMAGE; + it->image_id = -1; /* no image */ + it->position = start_pos; + it->object = NILP (object) ? it->w->buffer : object; + it->method = next_element_from_image; + it->face_id = face_id; + + /* 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 (EQ (XCAR (spec), Qleft_fringe)) { - it->left_user_fringe_bitmap = value; + it->left_user_fringe_bitmap = fringe_bitmap; it->left_user_fringe_face_id = face_id; } else { - it->right_user_fringe_bitmap = value; + it->right_user_fringe_bitmap = fringe_bitmap; it->right_user_fringe_face_id = face_id; } #endif /* HAVE_WINDOW_SYSTEM */ + return 1; } - else if (!it->string_from_display_prop_p) - { - /* `((margin left-margin) VALUE)' or `((margin right-margin) - VALUE) or `((margin nil) VALUE)' or VALUE. */ - Lisp_Object location, value; - struct text_pos start_pos; - int valid_p; - /* Characters having this form of property are not displayed, so - we have to find the end of the property. */ - start_pos = *position; - *position = display_prop_end (it, object, start_pos); - value = Qnil; + /* Prepare to handle `((margin left-margin) ...)', + `((margin right-margin) ...)' and `((margin nil) ...)' + prefixes for display specifications. */ + location = Qunbound; + if (CONSP (spec) && CONSP (XCAR (spec))) + { + Lisp_Object tem; - /* Let's stop at the new position and assume that all - text properties change there. */ - it->stop_charpos = position->charpos; + value = XCDR (spec); + if (CONSP (value)) + value = XCAR (value); - location = Qunbound; - if (CONSP (prop) && CONSP (XCAR (prop))) - { - Lisp_Object tem; + tem = XCAR (spec); + if (EQ (XCAR (tem), Qmargin) + && (tem = XCDR (tem), + tem = CONSP (tem) ? XCAR (tem) : Qnil, + (NILP (tem) + || EQ (tem, Qleft_margin) + || EQ (tem, Qright_margin)))) + location = tem; + } - value = XCDR (prop); - if (CONSP (value)) - value = XCAR (value); + if (EQ (location, Qunbound)) + { + location = Qnil; + value = spec; + } - tem = XCAR (prop); - if (EQ (XCAR (tem), Qmargin) - && (tem = XCDR (tem), - tem = CONSP (tem) ? XCAR (tem) : Qnil, - (NILP (tem) - || EQ (tem, Qleft_margin) - || EQ (tem, Qright_margin)))) - location = tem; - } + /* After this point, VALUE is the property after any + margin prefix has been stripped. It must be a string, + an image specification, or `(space ...)'. - if (EQ (location, Qunbound)) - { - location = Qnil; - value = prop; - } + LOCATION specifies where to display: `left-margin', + `right-margin' or nil. */ + valid_p = (STRINGP (value) #ifdef HAVE_WINDOW_SYSTEM - if (FRAME_TERMCAP_P (it->f)) - valid_p = STRINGP (value); - else - valid_p = (STRINGP (value) - || (CONSP (value) && EQ (XCAR (value), Qspace)) - || valid_image_p (value)); -#else /* not HAVE_WINDOW_SYSTEM */ - valid_p = STRINGP (value); + || (!FRAME_TERMCAP_P (it->f) && valid_image_p (value)) #endif /* not HAVE_WINDOW_SYSTEM */ + || (CONSP (value) && EQ (XCAR (value), Qspace))); - if ((EQ (location, Qleft_margin) - || EQ (location, Qright_margin) - || NILP (location)) - && valid_p - && !display_replaced_before_p) - { - replaces_text_display_p = 1; - - /* Save current settings of IT so that we can restore them - when we are finished with the glyph property value. */ - push_it (it); + if (valid_p && !display_replaced_before_p) + { + /* Save current settings of IT so that we can restore them + when we are finished with the glyph property value. */ + push_it (it); - if (NILP (location)) - it->area = TEXT_AREA; - else if (EQ (location, Qleft_margin)) - it->area = LEFT_MARGIN_AREA; - else - it->area = RIGHT_MARGIN_AREA; + if (NILP (location)) + it->area = TEXT_AREA; + else if (EQ (location, Qleft_margin)) + it->area = LEFT_MARGIN_AREA; + else + it->area = RIGHT_MARGIN_AREA; - if (STRINGP (value)) - { - it->string = value; - it->multibyte_p = STRING_MULTIBYTE (it->string); - it->current.overlay_string_index = -1; - IT_STRING_CHARPOS (*it) = IT_STRING_BYTEPOS (*it) = 0; - it->end_charpos = it->string_nchars = SCHARS (it->string); - it->method = next_element_from_string; - it->stop_charpos = 0; - it->string_from_display_prop_p = 1; - /* 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; - } - else if (CONSP (value) && EQ (XCAR (value), Qspace)) - { - it->method = next_element_from_stretch; - it->object = value; - it->current.pos = it->position = start_pos; - } -#ifdef HAVE_WINDOW_SYSTEM - else - { - it->what = IT_IMAGE; - it->image_id = lookup_image (it->f, value); - it->position = start_pos; - it->object = NILP (object) ? it->w->buffer : object; - it->method = next_element_from_image; - - /* 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; - } -#endif /* HAVE_WINDOW_SYSTEM */ + if (STRINGP (value)) + { + it->string = value; + it->multibyte_p = STRING_MULTIBYTE (it->string); + it->current.overlay_string_index = -1; + IT_STRING_CHARPOS (*it) = IT_STRING_BYTEPOS (*it) = 0; + it->end_charpos = it->string_nchars = SCHARS (it->string); + it->method = next_element_from_string; + it->stop_charpos = 0; + it->string_from_display_prop_p = 1; + /* 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; + } + else if (CONSP (value) && EQ (XCAR (value), Qspace)) + { + it->method = next_element_from_stretch; + it->object = value; + it->current.pos = it->position = start_pos; } +#ifdef HAVE_WINDOW_SYSTEM else - /* Invalid property or property not supported. Restore - the position to what it was before. */ - *position = start_pos; + { + it->what = IT_IMAGE; + it->image_id = lookup_image (it->f, value); + it->position = start_pos; + it->object = NILP (object) ? it->w->buffer : object; + it->method = next_element_from_image; + + /* 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; + } +#endif /* HAVE_WINDOW_SYSTEM */ + + return 1; } - return replaces_text_display_p; + /* Invalid property or property not supported. Restore + POSITION to what it was before. */ + *position = start_pos; + return 0; } -/* Check if PROP is a display sub-property value whose text should be +/* Check if SPEC is a display specification value whose text should be treated as intangible. */ static int -single_display_prop_intangible_p (prop) +single_display_spec_intangible_p (prop) Lisp_Object prop; { /* Skip over `when FORM'. */ @@ -3700,7 +3813,7 @@ display_prop_intangible_p (prop) /* A list of sub-properties. */ while (CONSP (prop)) { - if (single_display_prop_intangible_p (XCAR (prop))) + if (single_display_spec_intangible_p (XCAR (prop))) return 1; prop = XCDR (prop); } @@ -3710,11 +3823,11 @@ display_prop_intangible_p (prop) /* A vector of sub-properties. */ int i; for (i = 0; i < ASIZE (prop); ++i) - if (single_display_prop_intangible_p (AREF (prop, i))) + if (single_display_spec_intangible_p (AREF (prop, i))) return 1; } else - return single_display_prop_intangible_p (prop); + return single_display_spec_intangible_p (prop); return 0; } @@ -3723,7 +3836,7 @@ display_prop_intangible_p (prop) /* Return 1 if PROP is a display sub-property value containing STRING. */ static int -single_display_prop_string_p (prop, string) +single_display_spec_string_p (prop, string) Lisp_Object prop, string; { if (EQ (string, prop)) @@ -3768,7 +3881,7 @@ display_prop_string_p (prop, string) /* A list of sub-properties. */ while (CONSP (prop)) { - if (single_display_prop_string_p (XCAR (prop), string)) + if (single_display_spec_string_p (XCAR (prop), string)) return 1; prop = XCDR (prop); } @@ -3778,11 +3891,11 @@ display_prop_string_p (prop, string) /* A vector of sub-properties. */ int i; for (i = 0; i < ASIZE (prop); ++i) - if (single_display_prop_string_p (AREF (prop, i), string)) + if (single_display_spec_string_p (AREF (prop, i), string)) return 1; } else - return single_display_prop_string_p (prop, string); + return single_display_spec_string_p (prop, string); return 0; } @@ -3966,7 +4079,7 @@ next_overlay_string (it) /* If we have to display `...' for invisible text, set the iterator up for that. */ if (display_ellipsis_p) - setup_for_ellipsis (it); + setup_for_ellipsis (it, 0); } else { @@ -4293,6 +4406,7 @@ push_it (it) p->string_nchars = it->string_nchars; p->area = it->area; p->multibyte_p = it->multibyte_p; + p->slice = it->slice; p->space_width = it->space_width; p->font_height = it->font_height; p->voffset = it->voffset; @@ -4325,6 +4439,7 @@ pop_it (it) it->string_nchars = p->string_nchars; it->area = p->area; it->multibyte_p = p->multibyte_p; + it->slice = p->slice; it->space_width = p->space_width; it->font_height = p->font_height; it->voffset = p->voffset; @@ -4476,12 +4591,21 @@ back_to_previous_visible_line_start (it) { Lisp_Object prop; - prop = Fget_char_property (make_number (IT_CHARPOS (*it)), + /* Check the newline before point for invisibility. */ + prop = Fget_char_property (make_number (IT_CHARPOS (*it) - 1), Qinvisible, it->window); if (TEXT_PROP_MEANS_INVISIBLE (prop)) visible_p = 0; } + if (visible_p) + { + struct it it2 = *it; + + if (handle_display_prop (&it2) == HANDLED_RETURN) + visible_p = 0; + } + /* Back one more newline if the current one is invisible. */ if (!visible_p) back_to_previous_line_start (it); @@ -4499,7 +4623,7 @@ back_to_previous_visible_line_start (it) selective display. At the end, update IT's overlay information, face information etc. */ -static void +void reseat_at_previous_visible_line_start (it) struct it *it; { @@ -4747,7 +4871,10 @@ get_next_display_element (it) we hit the end of what we iterate over. Performance note: the function pointer `method' used here turns out to be faster than using a sequence of if-statements. */ - int success_p = (*it->method) (it); + int success_p; + + get_next: + success_p = (*it->method) (it); if (it->what == IT_CHARACTER) { @@ -4779,14 +4906,14 @@ get_next_display_element (it) it->dpvec = v->contents; it->dpend = v->contents + v->size; it->current.dpvec_index = 0; + it->saved_face_id = it->face_id; it->method = next_element_from_display_vector; - success_p = get_next_display_element (it); } else { set_iterator_to_next (it, 0); - success_p = get_next_display_element (it); } + goto get_next; } /* Translate control characters into `\003' or `^C' form. @@ -4804,13 +4931,19 @@ get_next_display_element (it) translated to octal form. */ else if ((it->c < ' ' && (it->area != TEXT_AREA + /* In mode line, treat \n like other crl chars. */ + || (it->c != '\n' + && it->glyph_row && it->glyph_row->mode_line_p) || (it->c != '\n' && it->c != '\t'))) || (it->multibyte_p ? ((it->c >= 127 && it->len == 1) - || !CHAR_PRINTABLE_P (it->c)) + || !CHAR_PRINTABLE_P (it->c) + || it->c == 0x8ad + || it->c == 0x8a0) : (it->c >= 127 - && it->c == unibyte_char_to_multibyte (it->c)))) + && (!unibyte_display_via_language_environment + || it->c == unibyte_char_to_multibyte (it->c))))) { /* IT->c is a control character which must be displayed either as '\003' or as `^C' where the '\\' and '^' @@ -4818,6 +4951,22 @@ get_next_display_element (it) IT->ctl_chars with glyphs for what we have to display. Then, set IT->dpvec to these glyphs. */ GLYPH g; + int ctl_len; + int face_id = escape_glyph_face; + + /* Find the face id if `escape-glyph' unless we recently did. */ + if (face_id < 0) + { + Lisp_Object tem = Fget (Qescape_glyph, Qface); + if (INTEGERP (tem)) + face_id = XINT (tem); + else + face_id = 0; + /* If there's overflow, use 0 instead. */ + if (FAST_GLYPH_FACE (FAST_MAKE_GLYPH (0, face_id)) != face_id) + face_id = 0; + escape_glyph_face = face_id; + } if (it->c < 128 && it->ctl_arrow_p) { @@ -4827,19 +4976,27 @@ get_next_display_element (it) && GLYPH_CHAR_VALID_P (XINT (DISP_CTRL_GLYPH (it->dp)))) g = XINT (DISP_CTRL_GLYPH (it->dp)); else - g = FAST_MAKE_GLYPH ('^', 0); + g = FAST_MAKE_GLYPH ('^', face_id); XSETINT (it->ctl_chars[0], g); - g = FAST_MAKE_GLYPH (it->c ^ 0100, 0); + g = FAST_MAKE_GLYPH (it->c ^ 0100, face_id); XSETINT (it->ctl_chars[1], g); + ctl_len = 2; + } + else if (it->c == 0x8a0 || it->c == 0x8ad) + { + /* Set IT->ctl_chars[0] to the glyph for `\\'. */ + if (it->dp + && INTEGERP (DISP_ESCAPE_GLYPH (it->dp)) + && GLYPH_CHAR_VALID_P (XINT (DISP_ESCAPE_GLYPH (it->dp)))) + g = XINT (DISP_ESCAPE_GLYPH (it->dp)); + else + g = FAST_MAKE_GLYPH ('\\', face_id); + XSETINT (it->ctl_chars[0], g); - /* Set up IT->dpvec and return first character from it. */ - it->dpvec_char_len = it->len; - it->dpvec = it->ctl_chars; - it->dpend = it->dpvec + 2; - it->current.dpvec_index = 0; - it->method = next_element_from_display_vector; - get_next_display_element (it); + g = FAST_MAKE_GLYPH (it->c == 0x8ad ? '-' : ' ', face_id); + XSETINT (it->ctl_chars[1], g); + ctl_len = 2; } else { @@ -4854,7 +5011,7 @@ get_next_display_element (it) && GLYPH_CHAR_VALID_P (XFASTINT (DISP_ESCAPE_GLYPH (it->dp)))) escape_glyph = XFASTINT (DISP_ESCAPE_GLYPH (it->dp)); else - escape_glyph = FAST_MAKE_GLYPH ('\\', 0); + escape_glyph = FAST_MAKE_GLYPH ('\\', face_id); if (SINGLE_BYTE_CHAR_P (it->c)) str[0] = it->c, len = 1; @@ -4881,23 +5038,27 @@ get_next_display_element (it) XSETINT (it->ctl_chars[i * 4], escape_glyph); /* Insert three more glyphs into IT->ctl_chars for the octal display of the character. */ - g = FAST_MAKE_GLYPH (((str[i] >> 6) & 7) + '0', 0); + g = FAST_MAKE_GLYPH (((str[i] >> 6) & 7) + '0', + face_id); XSETINT (it->ctl_chars[i * 4 + 1], g); - g = FAST_MAKE_GLYPH (((str[i] >> 3) & 7) + '0', 0); + g = FAST_MAKE_GLYPH (((str[i] >> 3) & 7) + '0', + face_id); XSETINT (it->ctl_chars[i * 4 + 2], g); - g = FAST_MAKE_GLYPH ((str[i] & 7) + '0', 0); + g = FAST_MAKE_GLYPH ((str[i] & 7) + '0', + face_id); XSETINT (it->ctl_chars[i * 4 + 3], g); } - - /* Set up IT->dpvec and return the first character - from it. */ - it->dpvec_char_len = it->len; - it->dpvec = it->ctl_chars; - it->dpend = it->dpvec + len * 4; - it->current.dpvec_index = 0; - it->method = next_element_from_display_vector; - get_next_display_element (it); + ctl_len = len * 4; } + + /* Set up IT->dpvec and return first character from it. */ + it->dpvec_char_len = it->len; + it->dpvec = it->ctl_chars; + it->dpend = it->dpvec + ctl_len; + it->current.dpvec_index = 0; + it->saved_face_id = it->face_id; + it->method = next_element_from_display_vector; + goto get_next; } } @@ -5019,6 +5180,9 @@ set_iterator_to_next (it, reseat_p) it->dpvec = NULL; it->current.dpvec_index = -1; + /* Recheck faces after display vector */ + it->stop_charpos = 0; + /* Skip over characters which were displayed via IT->dpvec. */ if (it->dpvec_char_len < 0) reseat_at_next_visible_line_start (it, 1); @@ -5087,11 +5251,14 @@ set_iterator_to_next (it, reseat_p) && IT_STRING_CHARPOS (*it) >= 0)); } - /* Load IT's display element fields with information about the next display element which comes from a display table entry or from the result of translating a control character to one of the forms `^C' - or `\003'. IT->dpvec holds the glyphs to return as characters. */ + or `\003'. + + IT->dpvec holds the glyphs to return as characters. + IT->saved_face_id holds the face id before the display vector-- + it is restored into IT->face_idin set_iterator_to_next. */ static int next_element_from_display_vector (it) @@ -5100,10 +5267,6 @@ next_element_from_display_vector (it) /* Precondition. */ xassert (it->dpvec && it->current.dpvec_index >= 0); - /* Remember the current face id in case glyphs specify faces. - IT's face is restored in set_iterator_to_next. */ - it->saved_face_id = it->face_id; - if (INTEGERP (*it->dpvec) && GLYPH_CHAR_VALID_P (XFASTINT (*it->dpvec))) { @@ -5287,28 +5450,7 @@ next_element_from_ellipsis (it) struct it *it; { if (it->selective_display_ellipsis_p) - { - if (it->dp && VECTORP (DISP_INVIS_VECTOR (it->dp))) - { - /* Use the display table definition for `...'. Invalid glyphs - will be handled by the method returning elements from dpvec. */ - struct Lisp_Vector *v = XVECTOR (DISP_INVIS_VECTOR (it->dp)); - it->dpvec_char_len = it->len; - it->dpvec = v->contents; - it->dpend = v->contents + v->size; - it->current.dpvec_index = 0; - it->method = next_element_from_display_vector; - } - else - { - /* Use default `...' which is stored in default_invis_vector. */ - it->dpvec_char_len = it->len; - it->dpvec = default_invis_vector; - it->dpend = default_invis_vector + 3; - it->current.dpvec_index = 0; - it->method = next_element_from_display_vector; - } - } + setup_for_ellipsis (it, it->len); else { /* The face at the current position may be different from the @@ -5557,15 +5699,22 @@ move_it_in_display_line_to (it, to_charpos, to_x, op) saved_glyph_row = it->glyph_row; it->glyph_row = NULL; +#define BUFFER_POS_REACHED_P() \ + ((op & MOVE_TO_POS) != 0 \ + && BUFFERP (it->object) \ + && IT_CHARPOS (*it) >= to_charpos) + while (1) { int x, i, ascent = 0, descent = 0; - /* Stop when ZV or TO_CHARPOS reached. */ + /* Stop when ZV reached. + We used to stop here when TO_CHARPOS reached as well, but that is + too soon if this glyph does not fit on this line. So we handle it + explicitly below. */ if (!get_next_display_element (it) - || ((op & MOVE_TO_POS) != 0 - && BUFFERP (it->object) - && IT_CHARPOS (*it) >= to_charpos)) + || (it->truncate_lines_p + && BUFFER_POS_REACHED_P ())) { result = MOVE_POS_MATCH_OR_ZV; break; @@ -5625,6 +5774,8 @@ move_it_in_display_line_to (it, to_charpos, to_x, op) /* We want to leave anything reaching TO_X to the caller. */ if ((op & MOVE_TO_X) && new_x > to_x) { + if (BUFFER_POS_REACHED_P ()) + goto buffer_pos_reached; it->current_x = x; result = MOVE_X_REACHED; break; @@ -5657,6 +5808,14 @@ move_it_in_display_line_to (it, to_charpos, to_x, op) result = MOVE_POS_MATCH_OR_ZV; break; } + if (BUFFER_POS_REACHED_P ()) + { + if (ITERATOR_AT_END_OF_LINE_P (it)) + result = MOVE_POS_MATCH_OR_ZV; + else + result = MOVE_LINE_CONTINUED; + break; + } if (ITERATOR_AT_END_OF_LINE_P (it)) { result = MOVE_NEWLINE_OR_CR; @@ -5678,6 +5837,8 @@ move_it_in_display_line_to (it, to_charpos, to_x, op) result = MOVE_LINE_CONTINUED; break; } + else if (BUFFER_POS_REACHED_P ()) + goto buffer_pos_reached; else if (new_x > it->first_visible_x) { /* Glyph is visible. Increment number of glyphs that @@ -5694,6 +5855,15 @@ move_it_in_display_line_to (it, to_charpos, to_x, op) if (result != MOVE_UNDEFINED) break; } + else if (BUFFER_POS_REACHED_P ()) + { + buffer_pos_reached: + it->current_x = x; + it->max_ascent = ascent; + it->max_descent = descent; + result = MOVE_POS_MATCH_OR_ZV; + break; + } else if ((op & MOVE_TO_X) && it->current_x >= to_x) { /* Stop when TO_X specified and reached. This check is @@ -5724,7 +5894,8 @@ move_it_in_display_line_to (it, to_charpos, to_x, op) #ifdef HAVE_WINDOW_SYSTEM if (IT_OVERFLOW_NEWLINE_INTO_FRINGE (it)) { - if (!get_next_display_element (it)) + if (!get_next_display_element (it) + || BUFFER_POS_REACHED_P ()) { result = MOVE_POS_MATCH_OR_ZV; break; @@ -5741,6 +5912,8 @@ move_it_in_display_line_to (it, to_charpos, to_x, op) } } +#undef BUFFER_POS_REACHED_P + /* Restore the iterator settings altered at the beginning of this function. */ it->glyph_row = saved_glyph_row; @@ -5945,10 +6118,13 @@ move_it_vertically_backward (it, dy) { int nlines, h; struct it it2, it3; - int start_pos = IT_CHARPOS (*it); + int start_pos; + move_further_back: xassert (dy >= 0); + start_pos = IT_CHARPOS (*it); + /* Estimate how many newlines we must move back. */ nlines = max (1, dy / FRAME_LINE_HEIGHT (it->f)); @@ -6014,13 +6190,13 @@ move_it_vertically_backward (it, dy) a line height of 13 pixels each, recentering with point on the bottom line will try to move -39/2 = 19 pixels backward. Try to avoid moving into the first line. */ - && it->current_y - target_y > line_height / 3 * 2 + && it->current_y - target_y > line_height * 2 / 3 && IT_CHARPOS (*it) > BEGV) { TRACE_MOVE ((stderr, " not far enough -> move_vert %d\n", target_y - it->current_y)); - move_it_vertically (it, target_y - it->current_y); - xassert (IT_CHARPOS (*it) >= BEGV); + dy = it->current_y - target_y; + goto move_further_back; } else if (target_y >= it->current_y + line_height && IT_CHARPOS (*it) < ZV) @@ -6061,7 +6237,7 @@ move_it_vertically (it, dy) { if (dy <= 0) move_it_vertically_backward (it, -dy); - else if (dy > 0) + else { TRACE_MOVE ((stderr, "move_it_v: from %d, %d\n", IT_CHARPOS (*it), dy)); move_it_to (it, ZV, -1, it->current_y + dy, -1, @@ -6158,6 +6334,8 @@ move_it_by_lines (it, dvpos, need_y_p) /* DVPOS == 0 means move to the start of the screen line. */ move_it_vertically_backward (it, 0); xassert (it->current_x == 0 && it->hpos == 0); + /* Let next call to line_bottom_y calculate real line height */ + last_height = 0; } else if (dvpos > 0) move_it_to (it, -1, -1, -1, it->vpos + dvpos, MOVE_TO_VPOS); @@ -6225,6 +6403,7 @@ add_to_log (format, arg1, arg2) char *buffer; int len; struct gcpro gcpro1, gcpro2, gcpro3, gcpro4; + USE_SAFE_ALLOCA; /* Do nothing if called asynchronously. Inserting text into a buffer may call after-change-functions and alike and @@ -6241,10 +6420,12 @@ add_to_log (format, arg1, arg2) msg = Fformat (3, args); len = SBYTES (msg) + 1; - buffer = (char *) alloca (len); + SAFE_ALLOCA (buffer, char *, len); bcopy (SDATA (msg), buffer, len); message_dolog (buffer, len - 1, 1, 0); + SAFE_FREE (); + UNGCPRO; } @@ -6467,7 +6648,7 @@ message_log_check_duplicate (prev_bol, prev_bol_byte, this_bol, this_bol_byte) } return 0; } - + /* Display an echo area message M with a specified length of NBYTES bytes. The string may include null characters. If M is 0, clear @@ -6566,6 +6747,7 @@ message3 (m, nbytes, multibyte) struct gcpro gcpro1; GCPRO1 (m); + clear_message (1,1); /* First flush out any partial line written with print. */ message_log_maybe_newline (); @@ -7298,7 +7480,7 @@ resize_mini_window (w, exact_p) height = it.current_y + last_height; else height = it.current_y + it.max_ascent + it.max_descent; - height -= it.extra_line_spacing; + height -= min (it.extra_line_spacing, it.max_extra_line_spacing); height = (height + unit - 1) / unit; } @@ -7854,7 +8036,7 @@ store_frame_title (str, field_width, precision) /* Copy at most PRECISION chars from STR. */ nbytes = strlen (str); - n+= c_string_width (str, nbytes, precision, &dummy, &nbytes); + n += c_string_width (str, nbytes, precision, &dummy, &nbytes); while (nbytes--) store_frame_title_char (*str++); @@ -8292,7 +8474,8 @@ update_tool_bar (f, save_match_data) { struct buffer *prev = current_buffer; int count = SPECPDL_INDEX (); - Lisp_Object old_tool_bar; + Lisp_Object new_tool_bar; + int new_n_tool_bar; struct gcpro gcpro1; /* Set current_buffer to the buffer of the selected @@ -8311,19 +8494,25 @@ update_tool_bar (f, save_match_data) specbind (Qoverriding_local_map, Qnil); } - old_tool_bar = f->tool_bar_items; - GCPRO1 (old_tool_bar); + GCPRO1 (new_tool_bar); /* Build desired tool-bar items from keymaps. */ - BLOCK_INPUT; - f->tool_bar_items - = tool_bar_items (f->tool_bar_items, &f->n_tool_bar_items); - UNBLOCK_INPUT; + new_tool_bar = tool_bar_items (Fcopy_sequence (f->tool_bar_items), + &new_n_tool_bar); /* Redisplay the tool-bar if we changed it. */ - if (! NILP (Fequal (old_tool_bar, f->tool_bar_items))) - w->update_mode_line = Qt; - + if (NILP (Fequal (new_tool_bar, f->tool_bar_items))) + { + /* Redisplay that happens asynchronously due to an expose event + may access f->tool_bar_items. Make sure we update both + variables within BLOCK_INPUT so no such event interrupts. */ + BLOCK_INPUT; + f->tool_bar_items = new_tool_bar; + f->n_tool_bar_items = new_n_tool_bar; + w->update_mode_line = Qt; + UNBLOCK_INPUT; + } + UNGCPRO; unbind_to (count, Qnil); @@ -8569,6 +8758,7 @@ display_tool_bar_line (it) { row->height = row->phys_height = it->last_visible_y - row->y; row->ascent = row->phys_ascent = 0; + row->extra_line_spacing = 0; } row->full_width_p = 1; @@ -9293,6 +9483,156 @@ redisplay () } +static Lisp_Object +overlay_arrow_string_or_property (var, pbitmap) + Lisp_Object var; + int *pbitmap; +{ + Lisp_Object pstr = Fget (var, Qoverlay_arrow_string); + Lisp_Object bitmap; + + if (pbitmap) + { + *pbitmap = 0; + if (bitmap = Fget (var, Qoverlay_arrow_bitmap), INTEGERP (bitmap)) + *pbitmap = XINT (bitmap); + } + + if (!NILP (pstr)) + return pstr; + return Voverlay_arrow_string; +} + +/* Return 1 if there are any overlay-arrows in current_buffer. */ +static int +overlay_arrow_in_current_buffer_p () +{ + Lisp_Object vlist; + + for (vlist = Voverlay_arrow_variable_list; + CONSP (vlist); + vlist = XCDR (vlist)) + { + Lisp_Object var = XCAR (vlist); + Lisp_Object val; + + if (!SYMBOLP (var)) + continue; + val = find_symbol_value (var); + if (MARKERP (val) + && current_buffer == XMARKER (val)->buffer) + return 1; + } + return 0; +} + + +/* Return 1 if any overlay_arrows have moved or overlay-arrow-string + has changed. */ + +static int +overlay_arrows_changed_p () +{ + Lisp_Object vlist; + + for (vlist = Voverlay_arrow_variable_list; + CONSP (vlist); + vlist = XCDR (vlist)) + { + Lisp_Object var = XCAR (vlist); + Lisp_Object val, pstr; + + if (!SYMBOLP (var)) + continue; + val = find_symbol_value (var); + if (!MARKERP (val)) + continue; + if (! EQ (COERCE_MARKER (val), + Fget (var, Qlast_arrow_position)) + || ! (pstr = overlay_arrow_string_or_property (var, 0), + EQ (pstr, Fget (var, Qlast_arrow_string)))) + return 1; + } + return 0; +} + +/* Mark overlay arrows to be updated on next redisplay. */ + +static void +update_overlay_arrows (up_to_date) + int up_to_date; +{ + Lisp_Object vlist; + + for (vlist = Voverlay_arrow_variable_list; + CONSP (vlist); + vlist = XCDR (vlist)) + { + Lisp_Object var = XCAR (vlist); + + if (!SYMBOLP (var)) + continue; + + if (up_to_date > 0) + { + Lisp_Object val = find_symbol_value (var); + Fput (var, Qlast_arrow_position, + COERCE_MARKER (val)); + Fput (var, Qlast_arrow_string, + overlay_arrow_string_or_property (var, 0)); + } + else if (up_to_date < 0 + || !NILP (Fget (var, Qlast_arrow_position))) + { + Fput (var, Qlast_arrow_position, Qt); + Fput (var, Qlast_arrow_string, Qt); + } + } +} + + +/* Return overlay arrow string to display at row. + Return t if display as bitmap in left fringe. + Return nil if no overlay arrow. */ + +static Lisp_Object +overlay_arrow_at_row (it, row, pbitmap) + struct it *it; + struct glyph_row *row; + int *pbitmap; +{ + Lisp_Object vlist; + + for (vlist = Voverlay_arrow_variable_list; + CONSP (vlist); + vlist = XCDR (vlist)) + { + Lisp_Object var = XCAR (vlist); + Lisp_Object val; + + if (!SYMBOLP (var)) + continue; + + val = find_symbol_value (var); + + if (MARKERP (val) + && current_buffer == XMARKER (val)->buffer + && (MATRIX_ROW_START_CHARPOS (row) == marker_position (val))) + { + val = overlay_arrow_string_or_property (var, pbitmap); + if (FRAME_WINDOW_P (it->f) + && WINDOW_LEFT_FRINGE_WIDTH (it->w) > 0) + return Qt; + if (STRINGP (val)) + return val; + break; + } + } + + *pbitmap = 0; + return Qnil; +} + /* Return 1 if point moved out of or into a composition. Otherwise return 0. PREV_BUF and PREV_PT are the last point buffer and position. BUF and PT are the current point buffer and position. */ @@ -9382,7 +9722,7 @@ select_frame_for_redisplay (frame) { Lisp_Object tail, sym, val; Lisp_Object old = selected_frame; - + selected_frame = frame; for (tail = XFRAME (frame)->param_alist; CONSP (tail); tail = XCDR (tail)) @@ -9572,8 +9912,7 @@ redisplay_internal (preserve_echo_area) /* If specs for an arrow have changed, do thorough redisplay to ensure we remove any arrow that should no longer exist. */ - if (! EQ (COERCE_MARKER (Voverlay_arrow_position), last_arrow_position) - || ! EQ (Voverlay_arrow_string, last_arrow_string)) + if (overlay_arrows_changed_p ()) consider_all_windows_p = windows_or_buffers_changed = 1; /* Normally the message* functions will have already displayed and @@ -10033,11 +10372,7 @@ redisplay_internal (preserve_echo_area) CHARPOS (this_line_start_pos) = 0; /* Let the overlay arrow be updated the next time. */ - if (!NILP (last_arrow_position)) - { - last_arrow_position = Qt; - last_arrow_string = Qt; - } + update_overlay_arrows (0); /* If we pause after scrolling, some rows in the current matrices of some windows are not valid. */ @@ -10053,8 +10388,8 @@ redisplay_internal (preserve_echo_area) consider_all_windows_p is set. */ mark_window_display_accurate_1 (w, 1); - last_arrow_position = COERCE_MARKER (Voverlay_arrow_position); - last_arrow_string = Voverlay_arrow_string; + /* Say overlay arrows are up to date. */ + update_overlay_arrows (1); if (frame_up_to_date_hook != 0) frame_up_to_date_hook (sf); @@ -10122,7 +10457,7 @@ redisplay_internal (preserve_echo_area) This is useful in situations where you need to redisplay but no user action has occurred, making it inappropriate for the message area to be cleared. See tracking_off and - wait_reading_process_input for examples of these situations. + wait_reading_process_output for examples of these situations. FROM_WHERE is an integer saying from where this function was called. This is useful for debugging. */ @@ -10143,6 +10478,9 @@ redisplay_preserve_echo_area (from_where) } else redisplay_internal (1); + + if (rif != NULL && rif->flush_display_optional) + rif->flush_display_optional (NULL); } @@ -10250,16 +10588,14 @@ mark_window_display_accurate (window, accurate_p) if (accurate_p) { - last_arrow_position = COERCE_MARKER (Voverlay_arrow_position); - last_arrow_string = Voverlay_arrow_string; + update_overlay_arrows (1); } else { /* Force a thorough redisplay the next time by setting last_arrow_position and last_arrow_string to t, which is unequal to any useful value of Voverlay_arrow_... */ - last_arrow_position = Qt; - last_arrow_string = Qt; + update_overlay_arrows (-1); } } @@ -10390,6 +10726,7 @@ set_cursor_from_row (w, row, matrix, delta, delta_bytes, dy, dvpos) { struct glyph *glyph = row->glyphs[TEXT_AREA]; struct glyph *end = glyph + row->used[TEXT_AREA]; + struct glyph *cursor = NULL; /* The first glyph that starts a sequence of glyphs from string. */ struct glyph *string_start; /* The X coordinate of string_start. */ @@ -10399,6 +10736,8 @@ set_cursor_from_row (w, row, matrix, delta, delta_bytes, dy, dvpos) /* The last known character position before string_start. */ int string_before_pos; int x = row->x; + int cursor_x = x; + int cursor_from_overlay_pos = 0; int pt_old = PT - delta; /* Skip over glyphs not having an object at the start of the row. @@ -10424,19 +10763,53 @@ set_cursor_from_row (w, row, matrix, delta, delta_bytes, dy, dvpos) string_start = NULL; x += glyph->pixel_width; ++glyph; - } + if (cursor_from_overlay_pos + && last_pos > cursor_from_overlay_pos) + { + cursor_from_overlay_pos = 0; + cursor = 0; + } + } else { string_before_pos = last_pos; string_start = glyph; string_start_x = x; /* Skip all glyphs from string. */ - SKIP_GLYPHS (glyph, end, x, STRINGP (glyph->object)); + do + { + int pos; + if ((cursor == NULL || glyph > cursor) + && !NILP (Fget_char_property (make_number ((glyph)->charpos), + Qcursor, (glyph)->object)) + && (pos = string_buffer_position (w, glyph->object, + string_before_pos), + (pos == 0 /* From overlay */ + || pos == pt_old))) + { + /* Estimate overlay buffer position from the buffer + positions of the glyphs before and after the overlay. + Add 1 to last_pos so that if point corresponds to the + glyph right after the overlay, we still use a 'cursor' + property found in that overlay. */ + cursor_from_overlay_pos = pos == 0 ? last_pos+1 : 0; + cursor = glyph; + cursor_x = x; + } + x += glyph->pixel_width; + ++glyph; + } + while (glyph < end && STRINGP (glyph->object)); } } - if (string_start - && (glyph == end || !BUFFERP (glyph->object) || last_pos > pt_old)) + if (cursor != NULL) + { + glyph = cursor; + x = cursor_x; + } + else if (string_start + && (glyph == end || !BUFFERP (glyph->object) || last_pos > pt_old)) { /* We may have skipped over point because the previous glyphs are from string. As there's no easy way to know the @@ -10549,17 +10922,25 @@ run_window_scroll_functions (window, startp) A value of 1 means there is nothing to be done. (Either the line is fully visible, or it cannot be made so, or we cannot tell.) + + If FORCE_P is non-zero, return 0 even if partial visible cursor row + is higher than window. + A value of 0 means the caller should do scrolling as if point had gone off the screen. */ static int -make_cursor_line_fully_visible (w) +make_cursor_line_fully_visible (w, force_p) struct window *w; + int force_p; { struct glyph_matrix *matrix; struct glyph_row *row; int window_height; + if (!make_cursor_line_fully_visible_p) + return 1; + /* It's not always possible to find the cursor, e.g, when a window is full of overlay strings. Don't do anything in that case. */ if (w->cursor.vpos < 0) @@ -10569,15 +10950,17 @@ make_cursor_line_fully_visible (w) row = MATRIX_ROW (matrix, w->cursor.vpos); /* If the cursor row is not partially visible, there's nothing to do. */ - if (!MATRIX_ROW_PARTIALLY_VISIBLE_P (row)) + if (!MATRIX_ROW_PARTIALLY_VISIBLE_P (w, row)) return 1; /* If the row the cursor is in is taller than the window's height, it's not clear what to do, so do nothing. */ window_height = window_box_height (w); if (row->height >= window_height) - return 1; - + { + if (!force_p || w->vscroll) + return 1; + } return 0; #if 0 @@ -10668,7 +11051,7 @@ try_scrolling (window, just_this_one_p, scroll_conservatively, int amount_to_scroll = 0; Lisp_Object aggressive; int height; - int end_scroll_margin; + int extra_scroll_margin_lines = last_line_misfit ? 1 : 0; #if GLYPH_DEBUG debug_method_add (w, "try_scrolling"); @@ -10686,6 +11069,12 @@ try_scrolling (window, just_this_one_p, scroll_conservatively, else this_scroll_margin = 0; + /* Force scroll_conservatively to have a reasonable value so it doesn't + cause an overflow while computing how much to scroll. */ + if (scroll_conservatively) + scroll_conservatively = min (scroll_conservatively, + MOST_POSITIVE_FIXNUM / FRAME_LINE_HEIGHT (f)); + /* Compute how much we should try to scroll maximally to bring point into view. */ if (scroll_step || scroll_conservatively || temp_scroll_step) @@ -10711,11 +11100,13 @@ try_scrolling (window, just_this_one_p, scroll_conservatively, CHARPOS (scroll_margin_pos) = XINT (window_end); BYTEPOS (scroll_margin_pos) = CHAR_TO_BYTE (CHARPOS (scroll_margin_pos)); - end_scroll_margin = this_scroll_margin + !!last_line_misfit; - if (end_scroll_margin) + if (this_scroll_margin || extra_scroll_margin_lines) { start_display (&it, w, scroll_margin_pos); - move_it_vertically (&it, - end_scroll_margin); + if (this_scroll_margin) + move_it_vertically_backward (&it, this_scroll_margin); + if (extra_scroll_margin_lines) + move_it_by_lines (&it, - extra_scroll_margin_lines, 0); scroll_margin_pos = it.current.pos; } @@ -10759,7 +11150,12 @@ try_scrolling (window, just_this_one_p, scroll_conservatively, aggressive = current_buffer->scroll_up_aggressively; height = WINDOW_BOX_TEXT_HEIGHT (w); if (NUMBERP (aggressive)) - amount_to_scroll = XFLOATINT (aggressive) * height; + { + double float_amount = XFLOATINT (aggressive) * height; + amount_to_scroll = float_amount; + if (amount_to_scroll == 0 && float_amount > 0) + amount_to_scroll = 1; + } } if (amount_to_scroll <= 0) @@ -10808,8 +11204,8 @@ try_scrolling (window, just_this_one_p, scroll_conservatively, start_display (&it, w, startp); if (scroll_conservatively) - amount_to_scroll = - max (dy, FRAME_LINE_HEIGHT (f) * max (scroll_step, temp_scroll_step)); + amount_to_scroll + = max (dy, FRAME_LINE_HEIGHT (f) * max (scroll_step, temp_scroll_step)); else if (scroll_step || temp_scroll_step) amount_to_scroll = scroll_max; else @@ -10817,13 +11213,18 @@ try_scrolling (window, just_this_one_p, scroll_conservatively, aggressive = current_buffer->scroll_down_aggressively; height = WINDOW_BOX_TEXT_HEIGHT (w); if (NUMBERP (aggressive)) - amount_to_scroll = XFLOATINT (aggressive) * height; + { + double float_amount = XFLOATINT (aggressive) * height; + amount_to_scroll = float_amount; + if (amount_to_scroll == 0 && float_amount > 0) + amount_to_scroll = 1; + } } if (amount_to_scroll <= 0) return SCROLLING_FAILED; - move_it_vertically (&it, - amount_to_scroll); + move_it_vertically_backward (&it, amount_to_scroll); startp = it.current.pos; } } @@ -10850,10 +11251,10 @@ try_scrolling (window, just_this_one_p, scroll_conservatively, /* If cursor ends up on a partially visible line, treat that as being off the bottom of the screen. */ - if (! make_cursor_line_fully_visible (w)) + if (! make_cursor_line_fully_visible (w, extra_scroll_margin_lines <= 1)) { clear_glyph_matrix (w->desired_matrix); - last_line_misfit = 1; + ++extra_scroll_margin_lines; goto too_near_end; } rc = SCROLLING_SUCCESS; @@ -11010,10 +11411,9 @@ try_cursor_movement (window, startp, scroll_step) && INTEGERP (w->window_end_vpos) && XFASTINT (w->window_end_vpos) < w->current_matrix->nrows && (FRAME_WINDOW_P (f) - || !MARKERP (Voverlay_arrow_position) - || current_buffer != XMARKER (Voverlay_arrow_position)->buffer)) + || !overlay_arrow_in_current_buffer_p ())) { - int this_scroll_margin; + int this_scroll_margin, top_scroll_margin; struct glyph_row *row = NULL; #if GLYPH_DEBUG @@ -11026,6 +11426,10 @@ try_cursor_movement (window, startp, scroll_step) this_scroll_margin = min (this_scroll_margin, WINDOW_TOTAL_LINES (w) / 4); this_scroll_margin *= FRAME_LINE_HEIGHT (f); + top_scroll_margin = this_scroll_margin; + if (WINDOW_WANTS_HEADER_LINE_P (w)) + top_scroll_margin += CURRENT_HEADER_LINE_HEIGHT (w); + /* Start with the row the cursor was displayed during the last not paused redisplay. Give up if that row is not valid. */ if (w->last_cursor.vpos < 0 @@ -11080,13 +11484,12 @@ try_cursor_movement (window, startp, scroll_step) else if (PT < XFASTINT (w->last_point)) { /* Cursor has to be moved backward. Note that PT >= - CHARPOS (startp) because of the outer - if-statement. */ + CHARPOS (startp) because of the outer if-statement. */ while (!row->mode_line_p && (MATRIX_ROW_START_CHARPOS (row) > PT || (MATRIX_ROW_START_CHARPOS (row) == PT && MATRIX_ROW_STARTS_IN_MIDDLE_OF_CHAR_P (row))) - && (row->y > this_scroll_margin + && (row->y > top_scroll_margin || CHARPOS (startp) == BEGV)) { xassert (row->enabled_p); @@ -11114,7 +11517,7 @@ try_cursor_movement (window, startp, scroll_step) ++row; /* If within the scroll margin, scroll. */ - if (row->y < this_scroll_margin + if (row->y < top_scroll_margin && CHARPOS (startp) != BEGV) scroll_p = 1; } @@ -11125,7 +11528,8 @@ try_cursor_movement (window, startp, scroll_step) /* if PT is not in the glyph row, give up. */ rc = CURSOR_MOVEMENT_MUST_SCROLL; } - else if (MATRIX_ROW_PARTIALLY_VISIBLE_P (row)) + else if (MATRIX_ROW_PARTIALLY_VISIBLE_P (w, row) + && make_cursor_line_fully_visible_p) { if (PT == MATRIX_ROW_END_CHARPOS (row) && !row->ends_at_zv_p @@ -11143,7 +11547,7 @@ try_cursor_movement (window, startp, scroll_step) else { set_cursor_from_row (w, row, w->current_matrix, 0, 0, 0, 0); - if (!make_cursor_line_fully_visible (w)) + if (!make_cursor_line_fully_visible (w, 0)) rc = CURSOR_MOVEMENT_MUST_SCROLL; else rc = CURSOR_MOVEMENT_SUCCESS; @@ -11173,7 +11577,7 @@ set_vertical_scroll_bar (w) which reflect the whole buffer size, with special markers indicating narrowing, and scrollbars which reflect only the visible region. - + Note that mini-buffers sometimes aren't displaying any text. */ if (!MINI_WINDOW_P (w) || (w == XWINDOW (minibuf_window) @@ -11185,7 +11589,7 @@ set_vertical_scroll_bar (w) /* I don't think this is guaranteed to be right. For the moment, we'll pretend it is. */ end = BUF_Z (buf) - XFASTINT (w->window_end_pos) - BUF_BEGV (buf); - + if (end < start) end = start; if (whole < (end - start)) @@ -11240,6 +11644,9 @@ redisplay_window (window, just_this_one_p) *w->desired_matrix->method = 0; #endif + /* Force this to be looked up again for each redisp of each window. */ + escape_glyph_face = -1; + specbind (Qinhibit_point_motion_hooks, Qt); reconsider_clip_changes (w, buffer); @@ -11474,7 +11881,7 @@ redisplay_window (window, just_this_one_p) new_vpos = window_box_height (w) / 2; } - if (!make_cursor_line_fully_visible (w)) + if (!make_cursor_line_fully_visible (w, 0)) { /* Point does appear, but on a line partly visible at end of window. Move it back to a fully-visible line. */ @@ -11593,8 +12000,8 @@ redisplay_window (window, just_this_one_p) buffer. */ || !NILP (Vwindow_scroll_functions) || MINI_WINDOW_P (w) - || !(used_current_matrix_p = - try_window_reusing_current_matrix (w))) + || !(used_current_matrix_p + = try_window_reusing_current_matrix (w))) { IF_DEBUG (debug_method_add (w, "1")); try_window (window, startp); @@ -11611,7 +12018,7 @@ redisplay_window (window, just_this_one_p) /* Forget any recorded base line for line number display. */ w->base_line_number = Qnil; - if (!make_cursor_line_fully_visible (w)) + if (!make_cursor_line_fully_visible (w, 1)) { clear_glyph_matrix (w->desired_matrix); last_line_misfit = 1; @@ -11700,7 +12107,7 @@ redisplay_window (window, just_this_one_p) if (it.current_y <= 0) { init_iterator (&it, w, PT, PT_BYTE, NULL, DEFAULT_FACE_ID); - move_it_vertically (&it, 0); + move_it_vertically_backward (&it, 0); xassert (IT_CHARPOS (it) <= PT); it.current_y = 0; } @@ -11723,8 +12130,8 @@ redisplay_window (window, just_this_one_p) || !NILP (Vwindow_scroll_functions) || !just_this_one_p || MINI_WINDOW_P (w) - || !(used_current_matrix_p = - try_window_reusing_current_matrix (w))) + || !(used_current_matrix_p + = try_window_reusing_current_matrix (w))) try_window (window, startp); /* If new fonts have been loaded (due to fontsets), give up. We @@ -11771,7 +12178,7 @@ redisplay_window (window, just_this_one_p) set_cursor_from_row (w, row, w->current_matrix, 0, 0, 0, 0); } - if (!make_cursor_line_fully_visible (w)) + if (!make_cursor_line_fully_visible (w, centering_position > 0)) { /* If vscroll is enabled, disable it and try again. */ if (w->vscroll) @@ -11784,6 +12191,7 @@ redisplay_window (window, just_this_one_p) /* If centering point failed to make the whole line visible, put point at the top instead. That has to make the whole line visible, if it can be done. */ + clear_glyph_matrix (w->desired_matrix); centering_position = 0; goto point_at_top; } @@ -11887,14 +12295,16 @@ redisplay_window (window, just_this_one_p) } #ifdef HAVE_WINDOW_SYSTEM - if (update_window_fringes (w, 0) + if (FRAME_WINDOW_P (f) + && update_window_fringes (w, 0) && !just_this_one_p && (used_current_matrix_p || overlay_arrow_seen) && !w->pseudo_window_p) { update_begin (f); BLOCK_INPUT; - draw_window_fringes (w); + if (draw_window_fringes (w, 1)) + x_draw_vertical_border (w); UNBLOCK_INPUT; update_end (f); } @@ -12046,7 +12456,7 @@ try_window_reusing_current_matrix (w) /* Give up if old or new display is scrolled vertically. We could make this function handle this, but right now it doesn't. */ start_row = MATRIX_FIRST_TEXT_ROW (w->current_matrix); - if (w->vscroll || MATRIX_ROW_PARTIALLY_VISIBLE_P (start_row)) + if (w->vscroll || MATRIX_ROW_PARTIALLY_VISIBLE_P (w, start_row)) return 0; /* The variable new_start now holds the new window start. The old @@ -12081,10 +12491,36 @@ try_window_reusing_current_matrix (w) last_text_row = last_reused_text_row = NULL; while (it.current_y < it.last_visible_y - && IT_CHARPOS (it) < CHARPOS (start) && !fonts_changed_p) - if (display_line (&it)) - last_text_row = it.glyph_row - 1; + { + /* If we have reached into the characters in the START row, + that means the line boundaries have changed. So we + can't start copying with the row START. Maybe it will + work to start copying with the following row. */ + while (IT_CHARPOS (it) > CHARPOS (start)) + { + /* Advance to the next row as the "start". */ + start_row++; + start = start_row->start.pos; + /* If there are no more rows to try, or just one, give up. */ + if (start_row == MATRIX_MODE_LINE_ROW (w->current_matrix) - 1 + || w->vscroll || MATRIX_ROW_PARTIALLY_VISIBLE_P (w, start_row) + || CHARPOS (start) == ZV) + { + clear_glyph_matrix (w->desired_matrix); + return 0; + } + + start_vpos = MATRIX_ROW_VPOS (start_row, w->current_matrix); + } + /* If we have reached alignment, + we can copy the rest of the rows. */ + if (IT_CHARPOS (it) == CHARPOS (start)) + break; + + if (display_line (&it)) + last_text_row = it.glyph_row - 1; + } /* A value of current_y < last_visible_y means that we stopped at the previous window start, which in turn means that we @@ -12092,12 +12528,12 @@ try_window_reusing_current_matrix (w) if (it.current_y < it.last_visible_y) { /* IT.vpos always starts from 0; it counts text lines. */ - nrows_scrolled = it.vpos; + nrows_scrolled = it.vpos - (start_row - MATRIX_FIRST_TEXT_ROW (w->current_matrix)); /* Find PT if not already found in the lines displayed. */ if (w->cursor.vpos < 0) { - int dy = it.current_y - first_row_y; + int dy = it.current_y - start_row->y; row = MATRIX_FIRST_TEXT_ROW (w->current_matrix); row = row_containing_pos (w, PT, row, NULL, dy); @@ -12117,7 +12553,7 @@ try_window_reusing_current_matrix (w) scroll_run_hook will clear the cursor, and use the current matrix to get the height of the row the cursor is in. */ - run.current_y = first_row_y; + run.current_y = start_row->y; run.desired_y = it.current_y; run.height = it.last_visible_y - it.current_y; @@ -12283,9 +12719,8 @@ try_window_reusing_current_matrix (w) position. */ if (pt_row) { - w->cursor.vpos -= MATRIX_ROW_VPOS (first_reusable_row, - w->current_matrix); - w->cursor.y -= first_reusable_row->y; + w->cursor.vpos -= nrows_scrolled; + w->cursor.y -= first_reusable_row->y - start_row->y; } /* Scroll the display. */ @@ -12330,6 +12765,29 @@ try_window_reusing_current_matrix (w) for (row -= nrows_scrolled; row < bottom_row; ++row) row->enabled_p = 0; + /* Point may have moved to a different line, so we cannot assume that + the previous cursor position is valid; locate the correct row. */ + if (pt_row) + { + for (row = MATRIX_ROW (w->current_matrix, w->cursor.vpos); + row < bottom_row && PT >= MATRIX_ROW_END_CHARPOS (row); + row++) + { + w->cursor.vpos++; + w->cursor.y = row->y; + } + if (row < bottom_row) + { + struct glyph *glyph = row->glyphs[TEXT_AREA] + w->cursor.hpos; + while (glyph->charpos < PT) + { + w->cursor.hpos++; + w->cursor.x += glyph->pixel_width; + glyph++; + } + } + } + /* Adjust window end. A null value of last_text_row means that the window end is in reused rows which in turn means that only its vpos can have changed. */ @@ -12760,8 +13218,7 @@ try_window_id (w) GIVE_UP (10); /* Can use this if overlay arrow position and or string have changed. */ - if (!EQ (last_arrow_position, COERCE_MARKER (Voverlay_arrow_position)) - || !EQ (last_arrow_string, Voverlay_arrow_string)) + if (overlay_arrows_changed_p ()) GIVE_UP (12); @@ -13114,9 +13571,11 @@ try_window_id (w) if ((w->cursor.y < this_scroll_margin && CHARPOS (start) > BEGV) - /* Don't take scroll margin into account at the bottom because - old redisplay didn't do it either. */ - || w->cursor.y + cursor_height > it.last_visible_y) + /* Old redisplay didn't take scroll margin into account at the bottom, + but then global-hl-line-mode doesn't scroll. KFS 2004-06-14 */ + || (w->cursor.y + (make_cursor_line_fully_visible_p + ? cursor_height + this_scroll_margin + : 1)) > it.last_visible_y) { w->cursor.vpos = -1; clear_glyph_matrix (w->desired_matrix); @@ -13694,18 +14153,19 @@ usage: (trace-to-stderr STRING &rest OBJECTS) */) Building Desired Matrix Rows ***********************************************************************/ -/* Return a temporary glyph row holding the glyphs of an overlay - arrow. Only used for non-window-redisplay windows. */ +/* Return a temporary glyph row holding the glyphs of an overlay arrow. + Used for non-window-redisplay windows, and for windows w/o left fringe. */ static struct glyph_row * -get_overlay_arrow_glyph_row (w) +get_overlay_arrow_glyph_row (w, overlay_arrow_string) struct window *w; + Lisp_Object overlay_arrow_string; { struct frame *f = XFRAME (WINDOW_FRAME (w)); struct buffer *buffer = XBUFFER (w->buffer); struct buffer *old = current_buffer; - const unsigned char *arrow_string = SDATA (Voverlay_arrow_string); - int arrow_len = SCHARS (Voverlay_arrow_string); + const unsigned char *arrow_string = SDATA (overlay_arrow_string); + int arrow_len = SCHARS (overlay_arrow_string); const unsigned char *arrow_end = arrow_string + arrow_len; const unsigned char *p; struct it it; @@ -13732,7 +14192,7 @@ get_overlay_arrow_glyph_row (w) /* Get its face. */ ilisp = make_number (p - arrow_string); - face = Fget_text_property (ilisp, Qface, Voverlay_arrow_string); + face = Fget_text_property (ilisp, Qface, overlay_arrow_string); it.face_id = compute_char_face (f, it.c, face); /* Compute its width, get its glyphs. */ @@ -13840,6 +14300,7 @@ compute_line_metrics (it) row->height = it->max_ascent + it->max_descent; row->phys_ascent = it->max_phys_ascent; row->phys_height = it->max_phys_ascent + it->max_phys_descent; + row->extra_line_spacing = it->max_extra_line_spacing; } /* Compute the width of this line. */ @@ -13883,6 +14344,7 @@ compute_line_metrics (it) row->pixel_width -= it->truncation_pixel_width; row->ascent = row->phys_ascent = 0; row->height = row->phys_height = row->visible_height = 1; + row->extra_line_spacing = 0; } /* Compute a hash code for this row. */ @@ -13901,8 +14363,7 @@ compute_line_metrics (it) /* Append one space to the glyph row of iterator IT if doing a - window-based redisplay. DEFAULT_FACE_P non-zero means let the - space have the default face, otherwise let it have the same face as + window-based redisplay. The space has the same face as IT->face_id. Value is non-zero if a space was added. This function is called to make sure that there is always one glyph @@ -13914,7 +14375,7 @@ compute_line_metrics (it) end of the line if the row ends in italic text. */ static int -append_space (it, default_face_p) +append_space_for_newline (it, default_face_p) struct it *it; int default_face_p; { @@ -13928,7 +14389,7 @@ append_space (it, default_face_p) /* Save some values that must not be changed. Must save IT->c and IT->len because otherwise ITERATOR_AT_END_P wouldn't work anymore after - append_space has been called. */ + append_space_for_newline has been called. */ enum display_element_type saved_what = it->what; int saved_c = it->c, saved_len = it->len; int saved_x = it->current_x; @@ -13955,6 +14416,8 @@ append_space (it, default_face_p) PRODUCE_GLYPHS (it); + it->override_ascent = -1; + it->constrain_row_ascent_descent_p = 0; it->current_x = saved_x; it->object = saved_object; it->position = saved_pos; @@ -14116,7 +14579,9 @@ highlight_trailing_whitespace (f, row) && glyph->u.ch == ' ')) && trailing_whitespace_p (glyph->charpos)) { - int face_id = lookup_named_face (f, Qtrailing_whitespace, 0); + int face_id = lookup_named_face (f, Qtrailing_whitespace, 0, 0); + if (face_id < 0) + return; while (glyph >= start && BUFFERP (glyph->object) @@ -14171,13 +14636,19 @@ display_line (it) struct it *it; { struct glyph_row *row = it->glyph_row; + int overlay_arrow_bitmap; + Lisp_Object overlay_arrow_string; /* We always start displaying at hpos zero even if hscrolled. */ xassert (it->hpos == 0 && it->current_x == 0); - /* We must not display in a row that's not a text row. */ - xassert (MATRIX_ROW_VPOS (row, it->w->desired_matrix) - < it->w->desired_matrix->nrows); + if (MATRIX_ROW_VPOS (row, it->w->desired_matrix) + >= it->w->desired_matrix->nrows) + { + it->w->nrows_scale_factor++; + fonts_changed_p = 1; + return 0; + } /* Is IT->w showing the region? */ it->w->region_showing = it->region_beg_charpos > 0 ? Qt : Qnil; @@ -14203,8 +14674,10 @@ display_line (it) hscrolled. This may stop at an x-position < IT->first_visible_x if the first glyph is partially visible or if we hit a line end. */ if (it->current_x < it->first_visible_x) - move_it_in_display_line_to (it, ZV, it->first_visible_x, - MOVE_TO_POS | MOVE_TO_X); + { + move_it_in_display_line_to (it, ZV, it->first_visible_x, + MOVE_TO_POS | MOVE_TO_X); + } /* Get the initial row height. This is either the height of the text hscrolled, if there is any, or zero. */ @@ -14212,6 +14685,7 @@ display_line (it) row->height = it->max_ascent + it->max_descent; row->phys_ascent = it->max_phys_ascent; row->phys_height = it->max_phys_ascent + it->max_phys_descent; + row->extra_line_spacing = it->max_extra_line_spacing; /* Loop generating characters. The loop is left with IT on the next character to display. */ @@ -14234,7 +14708,7 @@ display_line (it) row->exact_window_width_line_p = 1; else #endif /* HAVE_WINDOW_SYSTEM */ - if ((append_space (it, 1) && row->used[TEXT_AREA] == 1) + if ((append_space_for_newline (it, 1) && row->used[TEXT_AREA] == 1) || row->used[TEXT_AREA] == 0) { row->glyphs[TEXT_AREA]->charpos = -1; @@ -14277,6 +14751,8 @@ display_line (it) row->phys_ascent = max (row->phys_ascent, it->max_phys_ascent); row->phys_height = max (row->phys_height, it->max_phys_ascent + it->max_phys_descent); + row->extra_line_spacing = max (row->extra_line_spacing, + it->max_extra_line_spacing); set_iterator_to_next (it, 1); continue; } @@ -14305,6 +14781,8 @@ display_line (it) row->phys_ascent = max (row->phys_ascent, it->max_phys_ascent); row->phys_height = max (row->phys_height, it->max_phys_ascent + it->max_phys_descent); + row->extra_line_spacing = max (row->extra_line_spacing, + it->max_extra_line_spacing); if (it->current_x - it->pixel_width < it->first_visible_x) row->x = x - it->first_visible_x; } @@ -14456,6 +14934,8 @@ display_line (it) row->phys_ascent = max (row->phys_ascent, it->max_phys_ascent); row->phys_height = max (row->phys_height, it->max_phys_ascent + it->max_phys_descent); + row->extra_line_spacing = max (row->extra_line_spacing, + it->max_extra_line_spacing); /* End of this display line if row is continued. */ if (row->continued_p || row->ends_at_zv_p) @@ -14476,7 +14956,7 @@ display_line (it) /* Add a space at the end of the line that is used to display the cursor there. */ if (!IT_OVERFLOW_NEWLINE_INTO_FRINGE (it)) - append_space (it, 0); + append_space_for_newline (it, 0); #endif /* HAVE_WINDOW_SYSTEM */ /* Extend the face to the end of the line. */ @@ -14526,12 +15006,10 @@ display_line (it) { if (!get_next_display_element (it)) { -#ifdef HAVE_WINDOW_SYSTEM it->continuation_lines_width = 0; row->ends_at_zv_p = 1; row->exact_window_width_line_p = 1; break; -#endif /* HAVE_WINDOW_SYSTEM */ } if (ITERATOR_AT_END_OF_LINE_P (it)) { @@ -14566,17 +15044,16 @@ display_line (it) mark this glyph row as the one containing the overlay arrow. This is clearly a mess with variable size fonts. It would be better to let it be displayed like cursors under X. */ - if (MARKERP (Voverlay_arrow_position) - && current_buffer == XMARKER (Voverlay_arrow_position)->buffer - && (MATRIX_ROW_START_CHARPOS (row) - == marker_position (Voverlay_arrow_position)) - && STRINGP (Voverlay_arrow_string) - && ! overlay_arrow_seen) + if (! overlay_arrow_seen + && (overlay_arrow_string + = overlay_arrow_at_row (it, row, &overlay_arrow_bitmap), + !NILP (overlay_arrow_string))) { /* Overlay arrow in window redisplay is a fringe bitmap. */ - if (!FRAME_WINDOW_P (it->f)) + if (STRINGP (overlay_arrow_string)) { - struct glyph_row *arrow_row = get_overlay_arrow_glyph_row (it->w); + struct glyph_row *arrow_row + = get_overlay_arrow_glyph_row (it->w, overlay_arrow_string); struct glyph *glyph = arrow_row->glyphs[TEXT_AREA]; struct glyph *arrow_end = glyph + arrow_row->used[TEXT_AREA]; struct glyph *p = row->glyphs[TEXT_AREA]; @@ -14598,9 +15075,12 @@ display_line (it) row->used[TEXT_AREA] = p2 - row->glyphs[TEXT_AREA]; } } - + else + { + it->w->overlay_arrow_bitmap = overlay_arrow_bitmap; + row->overlay_arrow_p = 1; + } overlay_arrow_seen = 1; - row->overlay_arrow_p = 1; } /* Compute pixel dimensions of this line. */ @@ -14883,6 +15363,8 @@ display_mode_line (w, face_id, format) init_iterator (&it, w, -1, -1, NULL, face_id); prepare_desired_row (it.glyph_row); + it.glyph_row->mode_line_p = 1; + if (! mode_line_inverse_video) /* Force the mode-line to be displayed in the default face. */ it.base_face_id = it.face_id = DEFAULT_FACE_ID; @@ -14899,7 +15381,6 @@ display_mode_line (w, face_id, format) compute_line_metrics (&it); it.glyph_row->full_width_p = 1; - it.glyph_row->mode_line_p = 1; it.glyph_row->continued_p = 0; it.glyph_row->truncated_on_left_p = 0; it.glyph_row->truncated_on_right_p = 0; @@ -14982,6 +15463,10 @@ display_mode_element (it, depth, field_width, precision, elt, props, risky) Lisp_Object oprops, aelt; oprops = Ftext_properties_at (make_number (0), elt); + /* If the starting string's properties are not what + we want, translate the string. Also, if the string + is risky, do that anyway. */ + if (NILP (Fequal (props, oprops)) || risky) { /* If the starting string has properties, @@ -15060,14 +15545,15 @@ display_mode_element (it, depth, field_width, precision, elt, props, risky) if (this - 1 != last) { + int nchars, nbytes; + /* Output to end of string or up to '%'. Field width is length of string. Don't output more than PRECISION allows us. */ --this; - prec = chars_in_text (last, this - last); - if (precision > 0 && prec > precision - n) - prec = precision - n; + prec = c_string_width (last, this - last, precision - n, + &nchars, &nbytes); if (frame_title_ptr) n += store_frame_title (last, 0, prec); @@ -15075,9 +15561,14 @@ display_mode_element (it, depth, field_width, precision, elt, props, risky) { int bytepos = last - lisp_string; int charpos = string_byte_to_char (elt, bytepos); + int endpos = (precision <= 0 + ? string_byte_to_char (elt, + this - lisp_string) + : charpos + nchars); + n += store_mode_line_string (NULL, Fsubstring (elt, make_number (charpos), - make_number (charpos + prec)), + make_number (endpos)), 0, 0, 0, Qnil); } else @@ -15358,7 +15849,8 @@ display_mode_element (it, depth, field_width, precision, elt, props, risky) The mode_line_string_face face property is always added to the string. */ -static int store_mode_line_string (string, lisp_string, copy_string, field_width, precision, props) +static int +store_mode_line_string (string, lisp_string, copy_string, field_width, precision, props) char *string; Lisp_Object lisp_string; int copy_string; @@ -15379,7 +15871,7 @@ static int store_mode_line_string (string, lisp_string, copy_string, field_width props = mode_line_string_face_prop; else if (!NILP (mode_line_string_face)) { - Lisp_Object face = Fplist_get (props, Qface); + Lisp_Object face = Fsafe_plist_get (props, Qface); props = Fcopy_sequence (props); if (NILP (face)) face = mode_line_string_face; @@ -15404,7 +15896,7 @@ static int store_mode_line_string (string, lisp_string, copy_string, field_width Lisp_Object face; if (NILP (props)) props = Ftext_properties_at (make_number (0), lisp_string); - face = Fplist_get (props, Qface); + face = Fsafe_plist_get (props, Qface); if (NILP (face)) face = mode_line_string_face; else @@ -15440,15 +15932,16 @@ static int store_mode_line_string (string, lisp_string, copy_string, field_width DEFUN ("format-mode-line", Fformat_mode_line, Sformat_mode_line, - 0, 3, 0, + 0, 4, 0, doc: /* Return the mode-line of selected window as a string. First optional arg FORMAT specifies a different format string (see `mode-line-format' for details) to use. If FORMAT is t, return the buffer's header-line. Second optional arg WINDOW specifies a different window to use as the context for the formatting. -If third optional arg NO-PROPS is non-nil, string is not propertized. */) - (format, window, no_props) - Lisp_Object format, window, no_props; +If third optional arg NO-PROPS is non-nil, string is not propertized. +Fourth optional arg BUFFER specifies which buffer to use. */) + (format, window, no_props, buffer) + Lisp_Object format, window, no_props, buffer; { struct it it; int len; @@ -15460,42 +15953,46 @@ If third optional arg NO-PROPS is non-nil, string is not propertized. */) window = selected_window; CHECK_WINDOW (window); w = XWINDOW (window); - CHECK_BUFFER (w->buffer); - if (XBUFFER (w->buffer) != current_buffer) + if (NILP (buffer)) + buffer = w->buffer; + + CHECK_BUFFER (buffer); + + if (XBUFFER (buffer) != current_buffer) { old_buffer = current_buffer; - set_buffer_internal_1 (XBUFFER (w->buffer)); + set_buffer_internal_1 (XBUFFER (buffer)); } if (NILP (format) || EQ (format, Qt)) { - face_id = NILP (format) - ? CURRENT_MODE_LINE_FACE_ID (w) : - HEADER_LINE_FACE_ID; - format = NILP (format) - ? current_buffer->mode_line_format - : current_buffer->header_line_format; + face_id = (NILP (format) + ? CURRENT_MODE_LINE_FACE_ID (w) + : HEADER_LINE_FACE_ID); + format = (NILP (format) + ? current_buffer->mode_line_format + : current_buffer->header_line_format); } init_iterator (&it, w, -1, -1, NULL, face_id); if (NILP (no_props)) { - mode_line_string_face = - (face_id == MODE_LINE_FACE_ID ? Qmode_line : - face_id == MODE_LINE_INACTIVE_FACE_ID ? Qmode_line_inactive : - face_id == HEADER_LINE_FACE_ID ? Qheader_line : Qnil); + mode_line_string_face + = (face_id == MODE_LINE_FACE_ID ? Qmode_line + : face_id == MODE_LINE_INACTIVE_FACE_ID ? Qmode_line_inactive + : face_id == HEADER_LINE_FACE_ID ? Qheader_line : Qnil); - mode_line_string_face_prop = - NILP (mode_line_string_face) ? Qnil : - Fcons (Qface, Fcons (mode_line_string_face, Qnil)); + mode_line_string_face_prop + = (NILP (mode_line_string_face) ? Qnil + : Fcons (Qface, Fcons (mode_line_string_face, Qnil))); /* We need a dummy last element in mode_line_string_list to indicate we are building the propertized mode-line string. Using mode_line_string_face_prop here GC protects it. */ - mode_line_string_list = - Fcons (mode_line_string_face_prop, Qnil); + mode_line_string_list + = Fcons (mode_line_string_face_prop, Qnil); frame_title_ptr = NULL; } else @@ -15624,27 +16121,31 @@ pint2hrstr (buf, width, d) { tenths = remainder / 100; if (50 <= remainder % 100) - if (tenths < 9) - tenths++; - else - { - quotient++; - if (quotient == 10) - tenths = -1; - else - tenths = 0; - } + { + if (tenths < 9) + tenths++; + else + { + quotient++; + if (quotient == 10) + tenths = -1; + else + tenths = 0; + } + } } else if (500 <= remainder) - if (quotient < 999) - quotient++; - else - { - quotient = 1; - exponent++; - tenths = 0; - } + { + if (quotient < 999) + quotient++; + else + { + quotient = 1; + exponent++; + tenths = 0; + } + } } /* Calculate the LENGTH of QUOTIENT.TENTHS as a string. */ @@ -15768,7 +16269,10 @@ decode_mode_spec_coding (coding_system, buf, eol_flag) generated by character C. PRECISION >= 0 means don't return a string longer than that value. FIELD_WIDTH > 0 means pad the string returned with spaces to that value. Return 1 in *MULTIBYTE - if the result is multibyte text. */ + if the result is multibyte text. + + Note we operate on the current buffer for most purposes, + the exception being w->base_line_pos. */ static char lots_of_dashes[] = "--------------------------------------------------------------------------------------------------------------------------------------------"; @@ -15782,7 +16286,7 @@ decode_mode_spec (w, c, field_width, precision, multibyte) Lisp_Object obj; struct frame *f = XFRAME (WINDOW_FRAME (w)); char *decode_mode_spec_buf = f->decode_mode_spec_buffer; - struct buffer *b = XBUFFER (w->buffer); + struct buffer *b = current_buffer; obj = Qnil; *multibyte = 0; @@ -16084,7 +16588,7 @@ decode_mode_spec (w, c, field_width, precision, multibyte) case 's': /* status of process */ - obj = Fget_buffer_process (w->buffer); + obj = Fget_buffer_process (Fcurrent_buffer ()); if (NILP (obj)) return "no process"; #ifdef subprocesses @@ -16343,6 +16847,7 @@ display_string (string, lisp_string, face_string, face_string_pos, row->height = it->max_ascent + it->max_descent; row->phys_ascent = it->max_phys_ascent; row->phys_height = it->max_phys_ascent + it->max_phys_descent; + row->extra_line_spacing = it->max_extra_line_spacing; /* This condition is for the case that we are called with current_x past last_visible_x. */ @@ -16402,6 +16907,8 @@ display_string (string, lisp_string, face_string, face_string_pos, row->phys_ascent = max (row->phys_ascent, it->max_phys_ascent); row->phys_height = max (row->phys_height, it->max_phys_ascent + it->max_phys_descent); + row->extra_line_spacing = max (row->extra_line_spacing, + it->max_extra_line_spacing); x += glyph->pixel_width; ++i; } @@ -16513,147 +17020,394 @@ invisible_p (propval, list) return 0; } - -/*********************************************************************** - Glyph Display - ***********************************************************************/ - -#ifdef HAVE_WINDOW_SYSTEM - -#if GLYPH_DEBUG +/* Calculate a width or height in pixels from a specification using + the following elements: -void -dump_glyph_string (s) - struct glyph_string *s; -{ - fprintf (stderr, "glyph string\n"); - fprintf (stderr, " x, y, w, h = %d, %d, %d, %d\n", - s->x, s->y, s->width, s->height); - fprintf (stderr, " ybase = %d\n", s->ybase); - fprintf (stderr, " hl = %d\n", s->hl); - fprintf (stderr, " left overhang = %d, right = %d\n", - s->left_overhang, s->right_overhang); - fprintf (stderr, " nchars = %d\n", s->nchars); - fprintf (stderr, " extends to end of line = %d\n", - s->extends_to_end_of_line_p); - fprintf (stderr, " font height = %d\n", FONT_HEIGHT (s->font)); - fprintf (stderr, " bg width = %d\n", s->background_width); -} + SPEC ::= + NUM - a (fractional) multiple of the default font width/height + (NUM) - specifies exactly NUM pixels + UNIT - a fixed number of pixels, see below. + ELEMENT - size of a display element in pixels, see below. + (NUM . SPEC) - equals NUM * SPEC + (+ SPEC SPEC ...) - add pixel values + (- SPEC SPEC ...) - subtract pixel values + (- SPEC) - negate pixel value -#endif /* GLYPH_DEBUG */ + NUM ::= + INT or FLOAT - a number constant + SYMBOL - use symbol's (buffer local) variable binding. -/* Initialize glyph string S. CHAR2B is a suitably allocated vector - of XChar2b structures for S; it can't be allocated in - init_glyph_string because it must be allocated via `alloca'. W - is the window on which S is drawn. ROW and AREA are the glyph row - and area within the row from which S is constructed. START is the - index of the first glyph structure covered by S. HL is a - face-override for drawing S. */ + UNIT ::= + in - pixels per inch *) + mm - pixels per 1/1000 meter *) + cm - pixels per 1/100 meter *) + width - width of current font in pixels. + height - height of current font in pixels. -#ifdef HAVE_NTGUI -#define OPTIONAL_HDC(hdc) hdc, -#define DECLARE_HDC(hdc) HDC hdc; -#define ALLOCATE_HDC(hdc, f) hdc = get_frame_dc ((f)) -#define RELEASE_HDC(hdc, f) release_frame_dc ((f), (hdc)) -#endif + *) using the ratio(s) defined in display-pixels-per-inch. -#ifndef OPTIONAL_HDC -#define OPTIONAL_HDC(hdc) -#define DECLARE_HDC(hdc) -#define ALLOCATE_HDC(hdc, f) -#define RELEASE_HDC(hdc, f) -#endif + ELEMENT ::= -static void -init_glyph_string (s, OPTIONAL_HDC (hdc) char2b, w, row, area, start, hl) - struct glyph_string *s; - DECLARE_HDC (hdc) - XChar2b *char2b; - struct window *w; - struct glyph_row *row; - enum glyph_row_area area; - int start; - enum draw_glyphs_face hl; -{ - bzero (s, sizeof *s); - s->w = w; - s->f = XFRAME (w->frame); -#ifdef HAVE_NTGUI - s->hdc = hdc; -#endif - s->display = FRAME_X_DISPLAY (s->f); - s->window = FRAME_X_WINDOW (s->f); - s->char2b = char2b; - s->hl = hl; - s->row = row; - s->area = area; - s->first_glyph = row->glyphs[area] + start; - s->height = row->height; - s->y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y); + left-fringe - left fringe width in pixels + right-fringe - right fringe width in pixels - /* Display the internal border below the tool-bar window. */ - if (s->w == XWINDOW (s->f->tool_bar_window)) - s->y -= FRAME_INTERNAL_BORDER_WIDTH (s->f); + left-margin - left margin width in pixels + right-margin - right margin width in pixels - s->ybase = s->y + row->ascent; -} + scroll-bar - scroll-bar area width in pixels + Examples: -/* Append the list of glyph strings with head H and tail T to the list - with head *HEAD and tail *TAIL. Set *HEAD and *TAIL to the result. */ + Pixels corresponding to 5 inches: + (5 . in) -static INLINE void -append_glyph_string_lists (head, tail, h, t) - struct glyph_string **head, **tail; - struct glyph_string *h, *t; -{ - if (h) - { - if (*head) - (*tail)->next = h; - else - *head = h; - h->prev = *tail; - *tail = t; - } -} + Total width of non-text areas on left side of window (if scroll-bar is on left): + '(space :width (+ left-fringe left-margin scroll-bar)) + Align to first text column (in header line): + '(space :align-to 0) -/* Prepend the list of glyph strings with head H and tail T to the - list with head *HEAD and tail *TAIL. Set *HEAD and *TAIL to the - result. */ + Align to middle of text area minus half the width of variable `my-image' + containing a loaded image: + '(space :align-to (0.5 . (- text my-image))) -static INLINE void -prepend_glyph_string_lists (head, tail, h, t) - struct glyph_string **head, **tail; - struct glyph_string *h, *t; -{ - if (h) - { - if (*head) - (*head)->prev = t; - else - *tail = t; - t->next = *head; - *head = h; - } -} + Width of left margin minus width of 1 character in the default font: + '(space :width (- left-margin 1)) + Width of left margin minus width of 2 characters in the current font: + '(space :width (- left-margin (2 . width))) -/* Append glyph string S to the list with head *HEAD and tail *TAIL. - Set *HEAD and *TAIL to the resulting list. */ + Center 1 character over left-margin (in header line): + '(space :align-to (+ left-margin (0.5 . left-margin) -0.5)) -static INLINE void -append_glyph_string (head, tail, s) - struct glyph_string **head, **tail; - struct glyph_string *s; -{ - s->next = s->prev = NULL; - append_glyph_string_lists (head, tail, s, s); -} + Different ways to express width of left fringe plus left margin minus one pixel: + '(space :width (- (+ left-fringe left-margin) (1))) + '(space :width (+ left-fringe left-margin (- (1)))) + '(space :width (+ left-fringe left-margin (-1))) +*/ -/* Get face and two-byte form of character glyph GLYPH on frame F. +#define NUMVAL(X) \ + ((INTEGERP (X) || FLOATP (X)) \ + ? XFLOATINT (X) \ + : - 1) + +int +calc_pixel_width_or_height (res, it, prop, font, width_p, align_to) + double *res; + struct it *it; + Lisp_Object prop; + void *font; + int width_p, *align_to; +{ + double pixels; + +#define OK_PIXELS(val) ((*res = (double)(val)), 1) +#define OK_ALIGN_TO(val) ((*align_to = (int)(val)), 1) + + if (NILP (prop)) + return OK_PIXELS (0); + + if (SYMBOLP (prop)) + { + if (SCHARS (SYMBOL_NAME (prop)) == 2) + { + char *unit = SDATA (SYMBOL_NAME (prop)); + + if (unit[0] == 'i' && unit[1] == 'n') + pixels = 1.0; + else if (unit[0] == 'm' && unit[1] == 'm') + pixels = 25.4; + else if (unit[0] == 'c' && unit[1] == 'm') + pixels = 2.54; + else + pixels = 0; + if (pixels > 0) + { + double ppi; + if ((ppi = NUMVAL (Vdisplay_pixels_per_inch), ppi > 0) + || (CONSP (Vdisplay_pixels_per_inch) + && (ppi = (width_p + ? NUMVAL (XCAR (Vdisplay_pixels_per_inch)) + : NUMVAL (XCDR (Vdisplay_pixels_per_inch))), + ppi > 0))) + return OK_PIXELS (ppi / pixels); + + return 0; + } + } + +#ifdef HAVE_WINDOW_SYSTEM + if (EQ (prop, Qheight)) + return OK_PIXELS (font ? FONT_HEIGHT ((XFontStruct *)font) : FRAME_LINE_HEIGHT (it->f)); + if (EQ (prop, Qwidth)) + return OK_PIXELS (font ? FONT_WIDTH ((XFontStruct *)font) : FRAME_COLUMN_WIDTH (it->f)); +#else + if (EQ (prop, Qheight) || EQ (prop, Qwidth)) + return OK_PIXELS (1); +#endif + + if (EQ (prop, Qtext)) + return OK_PIXELS (width_p + ? window_box_width (it->w, TEXT_AREA) + : WINDOW_BOX_HEIGHT_NO_MODE_LINE (it->w)); + + if (align_to && *align_to < 0) + { + *res = 0; + if (EQ (prop, Qleft)) + return OK_ALIGN_TO (window_box_left_offset (it->w, TEXT_AREA)); + if (EQ (prop, Qright)) + return OK_ALIGN_TO (window_box_right_offset (it->w, TEXT_AREA)); + if (EQ (prop, Qcenter)) + return OK_ALIGN_TO (window_box_left_offset (it->w, TEXT_AREA) + + window_box_width (it->w, TEXT_AREA) / 2); + if (EQ (prop, Qleft_fringe)) + return OK_ALIGN_TO (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (it->w) + ? WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (it->w) + : window_box_right_offset (it->w, LEFT_MARGIN_AREA)); + if (EQ (prop, Qright_fringe)) + return OK_ALIGN_TO (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (it->w) + ? window_box_right_offset (it->w, RIGHT_MARGIN_AREA) + : window_box_right_offset (it->w, TEXT_AREA)); + if (EQ (prop, Qleft_margin)) + return OK_ALIGN_TO (window_box_left_offset (it->w, LEFT_MARGIN_AREA)); + if (EQ (prop, Qright_margin)) + return OK_ALIGN_TO (window_box_left_offset (it->w, RIGHT_MARGIN_AREA)); + if (EQ (prop, Qscroll_bar)) + return OK_ALIGN_TO (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (it->w) + ? 0 + : (window_box_right_offset (it->w, RIGHT_MARGIN_AREA) + + (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (it->w) + ? WINDOW_RIGHT_FRINGE_WIDTH (it->w) + : 0))); + } + else + { + if (EQ (prop, Qleft_fringe)) + return OK_PIXELS (WINDOW_LEFT_FRINGE_WIDTH (it->w)); + if (EQ (prop, Qright_fringe)) + return OK_PIXELS (WINDOW_RIGHT_FRINGE_WIDTH (it->w)); + if (EQ (prop, Qleft_margin)) + return OK_PIXELS (WINDOW_LEFT_MARGIN_WIDTH (it->w)); + if (EQ (prop, Qright_margin)) + return OK_PIXELS (WINDOW_RIGHT_MARGIN_WIDTH (it->w)); + if (EQ (prop, Qscroll_bar)) + return OK_PIXELS (WINDOW_SCROLL_BAR_AREA_WIDTH (it->w)); + } + + prop = Fbuffer_local_value (prop, it->w->buffer); + } + + if (INTEGERP (prop) || FLOATP (prop)) + { + int base_unit = (width_p + ? FRAME_COLUMN_WIDTH (it->f) + : FRAME_LINE_HEIGHT (it->f)); + return OK_PIXELS (XFLOATINT (prop) * base_unit); + } + + if (CONSP (prop)) + { + Lisp_Object car = XCAR (prop); + Lisp_Object cdr = XCDR (prop); + + if (SYMBOLP (car)) + { +#ifdef HAVE_WINDOW_SYSTEM + if (valid_image_p (prop)) + { + int id = lookup_image (it->f, prop); + struct image *img = IMAGE_FROM_ID (it->f, id); + + return OK_PIXELS (width_p ? img->width : img->height); + } +#endif + if (EQ (car, Qplus) || EQ (car, Qminus)) + { + int first = 1; + double px; + + pixels = 0; + while (CONSP (cdr)) + { + if (!calc_pixel_width_or_height (&px, it, XCAR (cdr), + font, width_p, align_to)) + return 0; + if (first) + pixels = (EQ (car, Qplus) ? px : -px), first = 0; + else + pixels += px; + cdr = XCDR (cdr); + } + if (EQ (car, Qminus)) + pixels = -pixels; + return OK_PIXELS (pixels); + } + + car = Fbuffer_local_value (car, it->w->buffer); + } + + if (INTEGERP (car) || FLOATP (car)) + { + double fact; + pixels = XFLOATINT (car); + if (NILP (cdr)) + return OK_PIXELS (pixels); + if (calc_pixel_width_or_height (&fact, it, cdr, + font, width_p, align_to)) + return OK_PIXELS (pixels * fact); + return 0; + } + + return 0; + } + + return 0; +} + + +/*********************************************************************** + Glyph Display + ***********************************************************************/ + +#ifdef HAVE_WINDOW_SYSTEM + +#if GLYPH_DEBUG + +void +dump_glyph_string (s) + struct glyph_string *s; +{ + fprintf (stderr, "glyph string\n"); + fprintf (stderr, " x, y, w, h = %d, %d, %d, %d\n", + s->x, s->y, s->width, s->height); + fprintf (stderr, " ybase = %d\n", s->ybase); + fprintf (stderr, " hl = %d\n", s->hl); + fprintf (stderr, " left overhang = %d, right = %d\n", + s->left_overhang, s->right_overhang); + fprintf (stderr, " nchars = %d\n", s->nchars); + fprintf (stderr, " extends to end of line = %d\n", + s->extends_to_end_of_line_p); + fprintf (stderr, " font height = %d\n", FONT_HEIGHT (s->font)); + fprintf (stderr, " bg width = %d\n", s->background_width); +} + +#endif /* GLYPH_DEBUG */ + +/* Initialize glyph string S. CHAR2B is a suitably allocated vector + of XChar2b structures for S; it can't be allocated in + init_glyph_string because it must be allocated via `alloca'. W + is the window on which S is drawn. ROW and AREA are the glyph row + and area within the row from which S is constructed. START is the + index of the first glyph structure covered by S. HL is a + face-override for drawing S. */ + +#ifdef HAVE_NTGUI +#define OPTIONAL_HDC(hdc) hdc, +#define DECLARE_HDC(hdc) HDC hdc; +#define ALLOCATE_HDC(hdc, f) hdc = get_frame_dc ((f)) +#define RELEASE_HDC(hdc, f) release_frame_dc ((f), (hdc)) +#endif + +#ifndef OPTIONAL_HDC +#define OPTIONAL_HDC(hdc) +#define DECLARE_HDC(hdc) +#define ALLOCATE_HDC(hdc, f) +#define RELEASE_HDC(hdc, f) +#endif + +static void +init_glyph_string (s, OPTIONAL_HDC (hdc) char2b, w, row, area, start, hl) + struct glyph_string *s; + DECLARE_HDC (hdc) + XChar2b *char2b; + struct window *w; + struct glyph_row *row; + enum glyph_row_area area; + int start; + enum draw_glyphs_face hl; +{ + bzero (s, sizeof *s); + s->w = w; + s->f = XFRAME (w->frame); +#ifdef HAVE_NTGUI + s->hdc = hdc; +#endif + s->display = FRAME_X_DISPLAY (s->f); + s->window = FRAME_X_WINDOW (s->f); + s->char2b = char2b; + s->hl = hl; + s->row = row; + s->area = area; + s->first_glyph = row->glyphs[area] + start; + s->height = row->height; + s->y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y); + + /* Display the internal border below the tool-bar window. */ + if (WINDOWP (s->f->tool_bar_window) + && s->w == XWINDOW (s->f->tool_bar_window)) + s->y -= FRAME_INTERNAL_BORDER_WIDTH (s->f); + + s->ybase = s->y + row->ascent; +} + + +/* Append the list of glyph strings with head H and tail T to the list + with head *HEAD and tail *TAIL. Set *HEAD and *TAIL to the result. */ + +static INLINE void +append_glyph_string_lists (head, tail, h, t) + struct glyph_string **head, **tail; + struct glyph_string *h, *t; +{ + if (h) + { + if (*head) + (*tail)->next = h; + else + *head = h; + h->prev = *tail; + *tail = t; + } +} + + +/* Prepend the list of glyph strings with head H and tail T to the + list with head *HEAD and tail *TAIL. Set *HEAD and *TAIL to the + result. */ + +static INLINE void +prepend_glyph_string_lists (head, tail, h, t) + struct glyph_string **head, **tail; + struct glyph_string *h, *t; +{ + if (h) + { + if (*head) + (*head)->prev = t; + else + *tail = t; + t->next = *head; + *head = h; + } +} + + +/* Append glyph string S to the list with head *HEAD and tail *TAIL. + Set *HEAD and *TAIL to the resulting list. */ + +static INLINE void +append_glyph_string (head, tail, s) + struct glyph_string **head, **tail; + struct glyph_string *s; +{ + s->next = s->prev = NULL; + append_glyph_string_lists (head, tail, s, s); +} + + +/* Get face and two-byte form of character glyph GLYPH on frame F. The encoding of GLYPH->u.ch is returned in *CHAR2B. Value is a pointer to a realized face that is ready for display. */ @@ -16852,6 +17606,7 @@ fill_image_glyph_string (s) xassert (s->first_glyph->type == IMAGE_GLYPH); s->img = IMAGE_FROM_ID (s->f, s->first_glyph->u.img_id); xassert (s->img); + s->slice = s->first_glyph->slice; s->face = FACE_FROM_ID (s->f, s->first_glyph->face_id); s->font = s->face->font; s->width = s->first_glyph->pixel_width; @@ -17563,6 +18318,19 @@ draw_glyphs (w, x, row, area, start, end, hl, overlaps_p) return x_reached; } +/* Expand row matrix if too narrow. Don't expand if area + is not present. */ + +#define IT_EXPAND_MATRIX_WIDTH(it, area) \ + { \ + if (!fonts_changed_p \ + && (it->glyph_row->glyphs[area] \ + < it->glyph_row->glyphs[area + 1])) \ + { \ + it->w->ncols_scale_factor++; \ + fonts_changed_p = 1; \ + } \ + } /* Store one glyph for IT->char_to_display in IT->glyph_row. Called from x_produce_glyphs when IT->glyph_row is non-null. */ @@ -17596,9 +18364,12 @@ append_glyph (it) glyph->glyph_not_available_p = it->glyph_not_available_p; glyph->face_id = it->face_id; glyph->u.ch = it->char_to_display; + glyph->slice = null_glyph_slice; glyph->font_type = FONT_TYPE_UNKNOWN; ++it->glyph_row->used[area]; } + else + IT_EXPAND_MATRIX_WIDTH (it, area); } /* Store one glyph for the composition IT->cmp_id in IT->glyph_row. @@ -17632,9 +18403,12 @@ append_composite_glyph (it) glyph->glyph_not_available_p = 0; glyph->face_id = it->face_id; glyph->u.cmp_id = it->cmp_id; + glyph->slice = null_glyph_slice; glyph->font_type = FONT_TYPE_UNKNOWN; ++it->glyph_row->used[area]; } + else + IT_EXPAND_MATRIX_WIDTH (it, area); } @@ -17650,7 +18424,7 @@ take_vertical_position_into_account (it) if (it->voffset < 0) /* Increase the ascent so that we can display the text higher in the line. */ - it->ascent += abs (it->voffset); + it->ascent -= it->voffset; else /* Increase the descent so that we can display the text lower in the line. */ @@ -17669,319 +18443,191 @@ produce_image_glyph (it) { struct image *img; struct face *face; - int face_ascent, glyph_ascent; + int glyph_ascent; + struct glyph_slice slice; xassert (it->what == IT_IMAGE); face = FACE_FROM_ID (it->f, it->face_id); - img = IMAGE_FROM_ID (it->f, it->image_id); - xassert (img); - - /* Make sure X resources of the face and image are loaded. */ + xassert (face); + /* Make sure X resources of the face is loaded. */ PREPARE_FACE_FOR_DISPLAY (it->f, face); - prepare_image_for_display (it->f, img); - - it->ascent = it->phys_ascent = glyph_ascent = image_ascent (img, face); - it->descent = it->phys_descent = img->height + 2 * img->vmargin - it->ascent; - it->pixel_width = img->width + 2 * img->hmargin; - - /* If this glyph is alone on the last line, adjust it.ascent to minimum row ascent. */ - face_ascent = face->font ? FONT_BASE (face->font) : FRAME_BASELINE_OFFSET (it->f); - if (face_ascent > it->ascent) - it->ascent = it->phys_ascent = face_ascent; - - it->nglyphs = 1; - - if (face->box != FACE_NO_BOX) - { - if (face->box_line_width > 0) - { - it->ascent += face->box_line_width; - it->descent += face->box_line_width; - } - - if (it->start_of_box_run_p) - it->pixel_width += abs (face->box_line_width); - if (it->end_of_box_run_p) - it->pixel_width += abs (face->box_line_width); - } - - take_vertical_position_into_account (it); - if (it->glyph_row) + if (it->image_id < 0) { - struct glyph *glyph; - enum glyph_row_area area = it->area; - - glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area]; - if (glyph < it->glyph_row->glyphs[area + 1]) - { - glyph->charpos = CHARPOS (it->position); - glyph->object = it->object; - glyph->pixel_width = it->pixel_width; - glyph->ascent = glyph_ascent; - glyph->descent = it->descent; - glyph->voffset = it->voffset; - glyph->type = IMAGE_GLYPH; - glyph->multibyte_p = it->multibyte_p; - glyph->left_box_line_p = it->start_of_box_run_p; - glyph->right_box_line_p = it->end_of_box_run_p; - glyph->overlaps_vertically_p = 0; - glyph->padding_p = 0; - glyph->glyph_not_available_p = 0; - glyph->face_id = it->face_id; - glyph->u.img_id = img->id; - glyph->font_type = FONT_TYPE_UNKNOWN; - ++it->glyph_row->used[area]; - } - } -} - - -/* Append a stretch glyph to IT->glyph_row. OBJECT is the source - of the glyph, WIDTH and HEIGHT are the width and height of the - stretch. ASCENT is the ascent of the glyph (0 <= ASCENT <= HEIGHT). */ - -static void -append_stretch_glyph (it, object, width, height, ascent) - struct it *it; - Lisp_Object object; - int width, height; - int ascent; -{ - struct glyph *glyph; - enum glyph_row_area area = it->area; - - xassert (ascent >= 0 && ascent <= height); - - glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area]; - if (glyph < it->glyph_row->glyphs[area + 1]) - { - glyph->charpos = CHARPOS (it->position); - glyph->object = object; - glyph->pixel_width = width; - glyph->ascent = ascent; - glyph->descent = height - ascent; - glyph->voffset = it->voffset; - glyph->type = STRETCH_GLYPH; - glyph->multibyte_p = it->multibyte_p; - glyph->left_box_line_p = it->start_of_box_run_p; - glyph->right_box_line_p = it->end_of_box_run_p; - glyph->overlaps_vertically_p = 0; - glyph->padding_p = 0; - glyph->glyph_not_available_p = 0; - glyph->face_id = it->face_id; - glyph->u.stretch.ascent = ascent; - glyph->u.stretch.height = height; - glyph->font_type = FONT_TYPE_UNKNOWN; - ++it->glyph_row->used[area]; + /* Fringe bitmap. */ + it->ascent = it->phys_ascent = 0; + it->descent = it->phys_descent = 0; + it->pixel_width = 0; + it->nglyphs = 0; + return; } -} - - -/* Calculate a width or height in pixels from a specification using - the following elements: - - SPEC ::= - NUM - a (fractional) multiple of the default font width/height - (NUM) - specifies exactly NUM pixels - UNIT - a fixed number of pixels, see below. - ELEMENT - size of a display element in pixels, see below. - (NUM . SPEC) - equals NUM * SPEC - (+ SPEC SPEC ...) - add pixel values - (- SPEC SPEC ...) - subtract pixel values - (- SPEC) - negate pixel value - - NUM ::= - INT or FLOAT - a number constant - SYMBOL - use symbol's (buffer local) variable binding. - - UNIT ::= - in - pixels per inch *) - mm - pixels per 1/1000 meter *) - cm - pixels per 1/100 meter *) - width - width of current font in pixels. - height - height of current font in pixels. - - *) using the ratio(s) defined in display-pixels-per-inch. - - ELEMENT ::= - - left-fringe - left fringe width in pixels - (left-fringe . nil) - left fringe width if inside margins, else 0 - (left-fringe . t) - left fringe width if outside margins, else 0 - - right-fringe - right fringe width in pixels - (right-fringe . nil) - right fringe width if inside margins, else 0 - (right-fringe . t) - right fringe width if outside margins, else 0 - - left-margin - left margin width in pixels - right-margin - right margin width in pixels - - scroll-bar - scroll-bar area width in pixels - (scroll-bar . left) - scroll-bar width if on left, else 0 - (scroll-bar . right) - scroll-bar width if on right, else 0 - - Examples: - - Pixels corresponding to 5 inches: - (5 . in) - - Total width of non-text areas on left side of window: - (+ left-fringe left-margin (scroll-bar . left)) - Total width of fringes if inside display margins: - (+ (left-fringe) (right-fringe)) + img = IMAGE_FROM_ID (it->f, it->image_id); + xassert (img); + /* Make sure X resources of the image is loaded. */ + prepare_image_for_display (it->f, img); - Width of left margin minus width of 1 character in the default font: - (- left-margin 1) + slice.x = slice.y = 0; + slice.width = img->width; + slice.height = img->height; + + if (INTEGERP (it->slice.x)) + slice.x = XINT (it->slice.x); + else if (FLOATP (it->slice.x)) + slice.x = XFLOAT_DATA (it->slice.x) * img->width; + + if (INTEGERP (it->slice.y)) + slice.y = XINT (it->slice.y); + else if (FLOATP (it->slice.y)) + slice.y = XFLOAT_DATA (it->slice.y) * img->height; + + if (INTEGERP (it->slice.width)) + slice.width = XINT (it->slice.width); + else if (FLOATP (it->slice.width)) + slice.width = XFLOAT_DATA (it->slice.width) * img->width; + + if (INTEGERP (it->slice.height)) + slice.height = XINT (it->slice.height); + else if (FLOATP (it->slice.height)) + slice.height = XFLOAT_DATA (it->slice.height) * img->height; + + if (slice.x >= img->width) + slice.x = img->width; + if (slice.y >= img->height) + slice.y = img->height; + if (slice.x + slice.width >= img->width) + slice.width = img->width - slice.x; + if (slice.y + slice.height > img->height) + slice.height = img->height - slice.y; + + if (slice.width == 0 || slice.height == 0) + return; - Width of left margin minus width of 2 characters in the current font: - (- left-margin (2 . width)) + it->ascent = it->phys_ascent = glyph_ascent = image_ascent (img, face, &slice); - Width of left fringe plus left margin minus one pixel: - (- (+ left-fringe left-margin) (1)) - (+ left-fringe left-margin (- (1))) - (+ left-fringe left-margin (-1)) + it->descent = slice.height - glyph_ascent; + if (slice.y == 0) + it->descent += img->vmargin; + if (slice.y + slice.height == img->height) + it->descent += img->vmargin; + it->phys_descent = it->descent; -*/ + it->pixel_width = slice.width; + if (slice.x == 0) + it->pixel_width += img->hmargin; + if (slice.x + slice.width == img->width) + it->pixel_width += img->hmargin; -#define NUMVAL(X) \ - ((INTEGERP (X) || FLOATP (X)) \ - ? XFLOATINT (X) \ - : - 1) + /* It's quite possible for images to have an ascent greater than + their height, so don't get confused in that case. */ + if (it->descent < 0) + it->descent = 0; -static int -calc_pixel_width_or_height (res, it, prop, font, width_p) - double *res; - struct it *it; - Lisp_Object prop; - XFontStruct *font; - int width_p; -{ - double pixels; +#if 0 /* this breaks image tiling */ + /* If this glyph is alone on the last line, adjust it.ascent to minimum row ascent. */ + int face_ascent = face->font ? FONT_BASE (face->font) : FRAME_BASELINE_OFFSET (it->f); + if (face_ascent > it->ascent) + it->ascent = it->phys_ascent = face_ascent; +#endif -#define OK_PIXELS(val) ((*res = (val)), 1) + it->nglyphs = 1; - if (SYMBOLP (prop)) + if (face->box != FACE_NO_BOX) { - if (SCHARS (SYMBOL_NAME (prop)) == 2) + if (face->box_line_width > 0) { - char *unit = SDATA (SYMBOL_NAME (prop)); - - if (unit[0] == 'i' && unit[1] == 'n') - pixels = 1.0; - else if (unit[0] == 'm' && unit[1] == 'm') - pixels = 25.4; - else if (unit[0] == 'c' && unit[1] == 'm') - pixels = 2.54; - else - pixels = 0; - if (pixels > 0) - { - double ppi; - if ((ppi = NUMVAL (Vdisplay_pixels_per_inch), ppi > 0) - || (CONSP (Vdisplay_pixels_per_inch) - && (ppi = (width_p - ? NUMVAL (XCAR (Vdisplay_pixels_per_inch)) - : NUMVAL (XCDR (Vdisplay_pixels_per_inch))), - ppi > 0))) - return OK_PIXELS (ppi / pixels); - - return 0; - } + if (slice.y == 0) + it->ascent += face->box_line_width; + if (slice.y + slice.height == img->height) + it->descent += face->box_line_width; } - if (EQ (prop, Qheight)) - return OK_PIXELS (font ? FONT_HEIGHT (font) : FRAME_LINE_HEIGHT (it->f)); - if (EQ (prop, Qwidth)) - return OK_PIXELS (font ? FONT_WIDTH (font) : FRAME_COLUMN_WIDTH (it->f)); - if (EQ (prop, Qleft_fringe)) - return OK_PIXELS (WINDOW_LEFT_FRINGE_WIDTH (it->w)); - if (EQ (prop, Qright_fringe)) - return OK_PIXELS (WINDOW_RIGHT_FRINGE_WIDTH (it->w)); - if (EQ (prop, Qleft_margin)) - return OK_PIXELS (WINDOW_LEFT_MARGIN_WIDTH (it->w)); - if (EQ (prop, Qright_margin)) - return OK_PIXELS (WINDOW_RIGHT_MARGIN_WIDTH (it->w)); - if (EQ (prop, Qscroll_bar)) - return OK_PIXELS (WINDOW_SCROLL_BAR_AREA_WIDTH (it->w)); - - prop = Fbuffer_local_value (prop, it->w->buffer); + if (it->start_of_box_run_p && slice.x == 0) + it->pixel_width += abs (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); } - if (INTEGERP (prop) || FLOATP (prop)) - { - int base_unit = (width_p - ? FRAME_COLUMN_WIDTH (it->f) - : FRAME_LINE_HEIGHT (it->f)); - return OK_PIXELS (XFLOATINT (prop) * base_unit); - } + take_vertical_position_into_account (it); - if (CONSP (prop)) + if (it->glyph_row) { - Lisp_Object car = XCAR (prop); - Lisp_Object cdr = XCDR (prop); + struct glyph *glyph; + enum glyph_row_area area = it->area; - if (SYMBOLP (car)) + glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area]; + if (glyph < it->glyph_row->glyphs[area + 1]) { - if (EQ (car, Qplus) || EQ (car, Qminus)) - { - int first = 1; - double px; + glyph->charpos = CHARPOS (it->position); + glyph->object = it->object; + glyph->pixel_width = it->pixel_width; + glyph->ascent = glyph_ascent; + glyph->descent = it->descent; + glyph->voffset = it->voffset; + glyph->type = IMAGE_GLYPH; + glyph->multibyte_p = it->multibyte_p; + glyph->left_box_line_p = it->start_of_box_run_p; + glyph->right_box_line_p = it->end_of_box_run_p; + glyph->overlaps_vertically_p = 0; + glyph->padding_p = 0; + glyph->glyph_not_available_p = 0; + glyph->face_id = it->face_id; + glyph->u.img_id = img->id; + glyph->slice = slice; + glyph->font_type = FONT_TYPE_UNKNOWN; + ++it->glyph_row->used[area]; + } + else + IT_EXPAND_MATRIX_WIDTH (it, area); + } +} - pixels = 0; - while (CONSP (cdr)) - { - if (!calc_pixel_width_or_height (&px, it, XCAR (cdr), font, width_p)) - return 0; - if (first) - pixels = (EQ (car, Qplus) ? px : -px), first = 0; - else - pixels += px; - cdr = XCDR (cdr); - } - if (EQ (car, Qminus)) - pixels = -pixels; - return OK_PIXELS (pixels); - } - if (EQ (car, Qleft_fringe)) - return OK_PIXELS ((WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (it->w) - == !NILP (cdr)) - ? WINDOW_LEFT_FRINGE_WIDTH (it->w) - : 0); - if (EQ (car, Qright_fringe)) - return OK_PIXELS ((WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (it->w) - == !NILP (cdr)) - ? WINDOW_RIGHT_FRINGE_WIDTH (it->w) - : 0); - if (EQ (car, Qscroll_bar)) - return OK_PIXELS ((WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (it->w) - == EQ (cdr, Qleft)) - ? WINDOW_SCROLL_BAR_AREA_WIDTH (it->w) - : 0); +/* Append a stretch glyph to IT->glyph_row. OBJECT is the source + of the glyph, WIDTH and HEIGHT are the width and height of the + stretch. ASCENT is the ascent of the glyph (0 <= ASCENT <= HEIGHT). */ - car = Fbuffer_local_value (car, it->w->buffer); - } +static void +append_stretch_glyph (it, object, width, height, ascent) + struct it *it; + Lisp_Object object; + int width, height; + int ascent; +{ + struct glyph *glyph; + enum glyph_row_area area = it->area; - if (INTEGERP (car) || FLOATP (car)) - { - double fact; - pixels = XFLOATINT (car); - if (NILP (cdr)) - return OK_PIXELS (pixels); - if (calc_pixel_width_or_height (&fact, it, cdr, font, width_p)) - return OK_PIXELS (pixels * fact); - return 0; - } + xassert (ascent >= 0 && ascent <= height); - return 0; + glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area]; + if (glyph < it->glyph_row->glyphs[area + 1]) + { + glyph->charpos = CHARPOS (it->position); + glyph->object = object; + glyph->pixel_width = width; + glyph->ascent = ascent; + glyph->descent = height - ascent; + glyph->voffset = it->voffset; + glyph->type = STRETCH_GLYPH; + glyph->multibyte_p = it->multibyte_p; + glyph->left_box_line_p = it->start_of_box_run_p; + glyph->right_box_line_p = it->end_of_box_run_p; + glyph->overlaps_vertically_p = 0; + glyph->padding_p = 0; + glyph->glyph_not_available_p = 0; + glyph->face_id = it->face_id; + glyph->u.stretch.ascent = ascent; + glyph->u.stretch.height = height; + glyph->slice = null_glyph_slice; + glyph->font_type = FONT_TYPE_UNKNOWN; + ++it->glyph_row->used[area]; } - - return 0; + else + IT_EXPAND_MATRIX_WIDTH (it, area); } + /* Produce a stretch glyph for iterator IT. IT->object is the value of the glyph property displayed. The value must be a list `(space KEYWORD VALUE ...)' with the following KEYWORD/VALUE pairs @@ -18019,7 +18665,7 @@ produce_stretch_glyph (it) { /* (space :width WIDTH :height HEIGHT ...) */ Lisp_Object prop, plist; - int width = 0, height = 0; + int width = 0, height = 0, align_to = -1; int zero_width_ok_p = 0, zero_height_ok_p = 0; int ascent = 0; double tem; @@ -18033,14 +18679,14 @@ produce_stretch_glyph (it) plist = XCDR (it->object); /* Compute the width of the stretch. */ - if ((prop = Fplist_get (plist, QCwidth), !NILP (prop)) - && calc_pixel_width_or_height (&tem, it, prop, font, 1)) + if ((prop = Fsafe_plist_get (plist, QCwidth), !NILP (prop)) + && calc_pixel_width_or_height (&tem, it, prop, font, 1, 0)) { /* Absolute width `:width WIDTH' specified and valid. */ zero_width_ok_p = 1; width = (int)tem; } - else if (prop = Fplist_get (plist, QCrelative_width), + else if (prop = Fsafe_plist_get (plist, QCrelative_width), NUMVAL (prop) > 0) { /* Relative width `:relative-width FACTOR' specified and valid. @@ -18064,10 +18710,16 @@ produce_stretch_glyph (it) x_produce_glyphs (&it2); width = NUMVAL (prop) * it2.pixel_width; } - else if ((prop = Fplist_get (plist, QCalign_to), !NILP (prop)) - && calc_pixel_width_or_height (&tem, it, prop, font, 1)) + else if ((prop = Fsafe_plist_get (plist, QCalign_to), !NILP (prop)) + && calc_pixel_width_or_height (&tem, it, prop, font, 1, &align_to)) { - width = max (0, (int)tem - it->current_x); + if (it->glyph_row == NULL || !it->glyph_row->mode_line_p) + align_to = (align_to < 0 + ? 0 + : align_to - window_box_left_offset (it->w, TEXT_AREA)); + else if (align_to < 0) + align_to = window_box_left_offset (it->w, TEXT_AREA); + width = max (0, (int)tem + align_to - it->current_x); zero_width_ok_p = 1; } else @@ -18078,13 +18730,13 @@ produce_stretch_glyph (it) width = 1; /* Compute height. */ - if ((prop = Fplist_get (plist, QCheight), !NILP (prop)) - && calc_pixel_width_or_height (&tem, it, prop, font, 0)) + if ((prop = Fsafe_plist_get (plist, QCheight), !NILP (prop)) + && calc_pixel_width_or_height (&tem, it, prop, font, 0, 0)) { height = (int)tem; zero_height_ok_p = 1; } - else if (prop = Fplist_get (plist, QCrelative_height), + else if (prop = Fsafe_plist_get (plist, QCrelative_height), NUMVAL (prop) > 0) height = FONT_HEIGHT (font) * NUMVAL (prop); else @@ -18096,11 +18748,11 @@ produce_stretch_glyph (it) /* Compute percentage of height used for ascent. If `:ascent ASCENT' is present and valid, use that. Otherwise, derive the ascent from the font in use. */ - if (prop = Fplist_get (plist, QCascent), + if (prop = Fsafe_plist_get (plist, QCascent), NUMVAL (prop) > 0 && NUMVAL (prop) <= 100) ascent = height * NUMVAL (prop) / 100.0; else if (!NILP (prop) - && calc_pixel_width_or_height (&tem, it, prop, font, 0)) + && calc_pixel_width_or_height (&tem, it, prop, font, 0, 0)) ascent = min (max (0, (int)tem), height); else ascent = (height * FONT_BASE (font)) / FONT_HEIGHT (font); @@ -18135,6 +18787,109 @@ produce_stretch_glyph (it) take_vertical_position_into_account (it); } +/* Calculate line-height and line-spacing properties. + An integer value specifies explicit pixel value. + A float value specifies relative value to current face height. + A cons (float . face-name) specifies relative value to + height of specified face font. + + Returns height in pixels, or nil. */ + +static Lisp_Object +calc_line_height_property (it, prop, font, boff, total) + struct it *it; + Lisp_Object prop; + XFontStruct *font; + int boff, *total; +{ + Lisp_Object position, val; + Lisp_Object face_name = Qnil; + int ascent, descent, height, override; + + if (STRINGP (it->object)) + position = make_number (IT_STRING_CHARPOS (*it)); + else if (BUFFERP (it->object)) + position = make_number (IT_CHARPOS (*it)); + else + return Qnil; + + val = Fget_char_property (position, prop, it->object); + + if (NILP (val)) + return val; + + if (total && CONSP (val) && EQ (XCAR (val), Qtotal)) + { + *total = 1; + val = XCDR (val); + } + + if (INTEGERP (val)) + return val; + + if (CONSP (val)) + { + face_name = XCDR (val); + val = XCAR (val); + } + else if (SYMBOLP (val)) + { + face_name = val; + val = Qnil; + } + + override = EQ (prop, Qline_height); + + if (NILP (face_name)) + { + font = FRAME_FONT (it->f); + boff = FRAME_BASELINE_OFFSET (it->f); + } + else if (EQ (face_name, Qt)) + { + override = 0; + } + else + { + int face_id; + struct face *face; + struct font_info *font_info; + + face_id = lookup_named_face (it->f, face_name, ' ', 0); + if (face_id < 0) + return make_number (-1); + + face = FACE_FROM_ID (it->f, face_id); + font = face->font; + if (font == NULL) + return make_number (-1); + + font_info = FONT_INFO_FROM_ID (it->f, face->font_info_id); + boff = font_info->baseline_offset; + if (font_info->vertical_centering) + boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff; + } + + ascent = FONT_BASE (font) + boff; + descent = FONT_DESCENT (font) - boff; + + if (override) + { + it->override_ascent = ascent; + it->override_descent = descent; + it->override_boff = boff; + } + + height = ascent + descent; + if (FLOATP (val)) + height = (int)(XFLOAT_DATA (val) * height); + else if (INTEGERP (val)) + height *= XINT (val); + + return make_number (height); +} + + /* RIF: Produce glyphs/get display metrics for the display element IT is loaded with. See the description of struct display_iterator in @@ -18144,6 +18899,8 @@ void x_produce_glyphs (it) struct it *it; { + int extra_line_spacing = it->extra_line_spacing; + it->glyph_not_available_p = 0; if (it->what == IT_CHARACTER) @@ -18221,8 +18978,18 @@ x_produce_glyphs (it) pcm = rif->per_char_metric (font, &char2b, FONT_TYPE_FOR_UNIBYTE (font, it->char_to_display)); - it->ascent = FONT_BASE (font) + boff; - it->descent = FONT_DESCENT (font) - boff; + + if (it->override_ascent >= 0) + { + it->ascent = it->override_ascent; + it->descent = it->override_descent; + boff = it->override_boff; + } + else + { + it->ascent = FONT_BASE (font) + boff; + it->descent = FONT_DESCENT (font) - boff; + } if (pcm) { @@ -18233,11 +19000,28 @@ x_produce_glyphs (it) else { it->glyph_not_available_p = 1; - it->phys_ascent = FONT_BASE (font) + boff; - it->phys_descent = FONT_DESCENT (font) - boff; + it->phys_ascent = it->ascent; + it->phys_descent = it->descent; it->pixel_width = FONT_WIDTH (font); } + if (it->constrain_row_ascent_descent_p) + { + if (it->descent > it->max_descent) + { + it->ascent += it->descent - it->max_descent; + it->descent = it->max_descent; + } + if (it->ascent > it->max_ascent) + { + it->descent = min (it->max_descent, it->descent + it->ascent - it->max_ascent); + it->ascent = it->max_ascent; + } + it->phys_ascent = min (it->phys_ascent, it->ascent); + it->phys_descent = min (it->phys_descent, it->descent); + extra_line_spacing = 0; + } + /* If this is a space inside a region of text with `space-width' property, change its width. */ stretched_p = it->char_to_display == ' ' && !NILP (it->space_width); @@ -18270,6 +19054,14 @@ x_produce_glyphs (it) if (face->overline_p) it->ascent += 2; + if (it->constrain_row_ascent_descent_p) + { + if (it->ascent > it->max_ascent) + it->ascent = it->max_ascent; + if (it->descent > it->max_descent) + it->descent = it->max_descent; + } + take_vertical_position_into_account (it); /* If we have to actually produce glyphs, do it. */ @@ -18296,17 +19088,73 @@ x_produce_glyphs (it) } else if (it->char_to_display == '\n') { - /* A newline has no width but we need the height of the line. */ + /* A newline has no width but we need the height of the line. + But if previous part of the line set a height, don't + increase that height */ + + Lisp_Object height; + + it->override_ascent = -1; it->pixel_width = 0; it->nglyphs = 0; - it->ascent = it->phys_ascent = FONT_BASE (font) + boff; - it->descent = it->phys_descent = FONT_DESCENT (font) - boff; - if (face->box != FACE_NO_BOX - && face->box_line_width > 0) + height = calc_line_height_property(it, Qline_height, font, boff, 0); + + if (it->override_ascent >= 0) + { + it->ascent = it->override_ascent; + it->descent = it->override_descent; + boff = it->override_boff; + } + else + { + it->ascent = FONT_BASE (font) + boff; + it->descent = FONT_DESCENT (font) - boff; + } + + if (EQ (height, make_number(0))) { - it->ascent += face->box_line_width; - it->descent += face->box_line_width; + if (it->descent > it->max_descent) + { + it->ascent += it->descent - it->max_descent; + it->descent = it->max_descent; + } + if (it->ascent > it->max_ascent) + { + it->descent = min (it->max_descent, it->descent + it->ascent - it->max_ascent); + it->ascent = it->max_ascent; + } + it->phys_ascent = min (it->phys_ascent, it->ascent); + it->phys_descent = min (it->phys_descent, it->descent); + it->constrain_row_ascent_descent_p = 1; + extra_line_spacing = 0; + } + else + { + Lisp_Object spacing; + int total = 0; + + it->phys_ascent = it->ascent; + it->phys_descent = it->descent; + + if ((it->max_ascent > 0 || it->max_descent > 0) + && face->box != FACE_NO_BOX + && face->box_line_width > 0) + { + it->ascent += face->box_line_width; + it->descent += face->box_line_width; + } + if (!NILP (height) + && XINT (height) > it->ascent + it->descent) + it->ascent = XINT (height) - it->descent; + + spacing = calc_line_height_property(it, Qline_spacing, font, boff, &total); + if (INTEGERP (spacing)) + { + extra_line_spacing = XINT (spacing); + if (total) + extra_line_spacing -= (it->phys_ascent + it->phys_descent); + } } } else if (it->char_to_display == '\t') @@ -18684,7 +19532,12 @@ x_produce_glyphs (it) if (it->area == TEXT_AREA) it->current_x += it->pixel_width; - it->descent += it->extra_line_spacing; + if (extra_line_spacing > 0) + { + it->descent += extra_line_spacing; + if (extra_line_spacing > it->max_extra_line_spacing) + it->max_extra_line_spacing = extra_line_spacing; + } it->max_ascent = max (it->max_ascent, it->ascent); it->max_descent = max (it->max_descent, it->descent); @@ -19031,7 +19884,7 @@ get_window_cursor_type (w, glyph, width, active_cursor) /* Use normal cursor if not blinked off. */ if (!w->cursor_off_p) { - if (glyph->type == IMAGE_GLYPH) { + if (glyph != NULL && glyph->type == IMAGE_GLYPH) { if (cursor_type == FILLED_BOX_CURSOR) cursor_type = HOLLOW_BOX_CURSOR; } @@ -19266,6 +20119,11 @@ erase_phys_cursor (w) if (!cursor_row->enabled_p) goto mark_cursor_off; + /* If line spacing is > 0, old cursor may only be partially visible in + window after split-window. So adjust visible height. */ + cursor_row->visible_height = min (cursor_row->visible_height, + window_text_bottom_y (w) - cursor_row->y); + /* If row is completely invisible, don't attempt to delete a cursor which isn't there. This can happen if cursor is at top of a window, and we switch to a buffer with a header line in that window. */ @@ -19309,6 +20167,7 @@ erase_phys_cursor (w) { int x, y; int header_line_height = WINDOW_HEADER_LINE_HEIGHT (w); + int width; cursor_glyph = get_phys_cursor_glyph (w); if (cursor_glyph == NULL) @@ -19316,9 +20175,10 @@ erase_phys_cursor (w) x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x); y = WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height, cursor_row->y)); + width = min (cursor_glyph->pixel_width, + window_box_width (w, TEXT_AREA) - w->phys_cursor.x); - rif->clear_frame_area (f, x, y, - cursor_glyph->pixel_width, cursor_row->visible_height); + rif->clear_frame_area (f, x, y, width, cursor_row->visible_height); } /* Erase the cursor by redrawing the character underneath it. */ @@ -19348,7 +20208,6 @@ display_and_set_cursor (w, on, hpos, vpos, x, y) int new_cursor_type; int new_cursor_width; int active_cursor; - struct glyph_matrix *current_glyphs; struct glyph_row *glyph_row; struct glyph *glyph; @@ -19366,10 +20225,7 @@ display_and_set_cursor (w, on, hpos, vpos, x, y) if (!on && !w->phys_cursor_on_p) return; - current_glyphs = w->current_matrix; - glyph_row = MATRIX_ROW (current_glyphs, vpos); - glyph = glyph_row->glyphs[TEXT_AREA] + hpos; - + glyph_row = MATRIX_ROW (w->current_matrix, vpos); /* If cursor row is not enabled, we don't really know where to display the cursor. */ if (!glyph_row->enabled_p) @@ -19378,6 +20234,11 @@ display_and_set_cursor (w, on, hpos, vpos, x, y) return; } + glyph = NULL; + if (!glyph_row->exact_window_width_line_p + || hpos < glyph_row->used[TEXT_AREA]) + glyph = glyph_row->glyphs[TEXT_AREA] + hpos; + xassert (interrupt_input_blocked); /* Set new_cursor_type to the cursor we want to be displayed. */ @@ -19579,7 +20440,7 @@ clear_mouse_face (dpyinfo) { int cleared = 0; - if (!NILP (dpyinfo->mouse_face_window)) + if (!dpyinfo->mouse_face_hidden && !NILP (dpyinfo->mouse_face_window)) { show_mouse_face (dpyinfo, DRAW_NORMAL_TEXT); cleared = 1; @@ -19650,19 +20511,20 @@ fast_find_position (w, charpos, hpos, vpos, x, y, stop) int past_end = 0; first = MATRIX_FIRST_TEXT_ROW (w->current_matrix); + if (charpos < MATRIX_ROW_START_CHARPOS (first)) + { + *x = first->x; + *y = first->y; + *hpos = 0; + *vpos = MATRIX_ROW_VPOS (first, w->current_matrix); + return 1; + } + row = row_containing_pos (w, charpos, first, NULL, 0); if (row == NULL) { - if (charpos < MATRIX_ROW_START_CHARPOS (first)) - { - *x = *y = *hpos = *vpos = 0; - return 0; - } - else - { - row = MATRIX_ROW (w->current_matrix, XFASTINT (w->window_end_vpos)); - past_end = 1; - } + row = MATRIX_ROW (w->current_matrix, XFASTINT (w->window_end_vpos)); + past_end = 1; } *x = row->x; @@ -19696,7 +20558,7 @@ fast_find_position (w, charpos, hpos, vpos, x, y, stop) } *hpos = glyph - row->glyphs[TEXT_AREA]; - return past_end; + return !past_end; } #else /* not 1 */ @@ -19944,7 +20806,7 @@ on_hot_spot_p (hot_spot, x, y) int x0, y0; /* Need an even number of coordinates, and at least 3 edges. */ - if (n < 6 || n & 1) + if (n < 6 || n & 1) return 0; /* Count edge segments intersecting line from (X,Y) to (X,infinity). @@ -19979,8 +20841,8 @@ on_hot_spot_p (hot_spot, x, y) return inside; } } - else - return 0; + /* If we don't understand the format, pretend we're not in the hot-spot. */ + return 0; } Lisp_Object @@ -19995,13 +20857,13 @@ find_hot_spot (map, x, y) return XCAR (map); map = XCDR (map); } - + return Qnil; } DEFUN ("lookup-image-map", Flookup_image_map, Slookup_image_map, 3, 3, 0, - doc: /* Lookup in image map MAP coordinates X and Y. + doc: /* Lookup in image map MAP coordinates X and Y. An image map is an alist where each element has the format (AREA ID PLIST). An AREA is specified as either a rectangle, a circle, or a polygon: A rectangle is a cons (rect . ((x0 . y0) . (x1 . y1))) specifying the @@ -20015,7 +20877,6 @@ Returns the alist element for the first matching AREA in MAP. */) Lisp_Object map; Lisp_Object x, y; { - int ix, iy; if (NILP (map)) return Qnil; @@ -20033,6 +20894,10 @@ define_frame_cursor1 (f, cursor, pointer) Cursor cursor; Lisp_Object pointer; { + /* Do not change cursor shape while dragging mouse. */ + if (!NILP (do_mouse_tracking)) + return; + if (!NILP (pointer)) { if (EQ (pointer, Qarrow)) @@ -20055,11 +20920,7 @@ define_frame_cursor1 (f, cursor, pointer) cursor = FRAME_X_OUTPUT (f)->nontext_cursor; } -#ifndef HAVE_CARBON if (cursor != No_Cursor) -#else - if (bcmp (&cursor, &No_Cursor, sizeof (Cursor))) -#endif rif->define_frame_cursor (f, cursor); } @@ -20081,7 +20942,7 @@ note_mode_line_or_margin_highlight (w, x, y, area) Lisp_Object pointer = Qnil; int charpos, dx, dy, width, height; Lisp_Object string, object = Qnil; - Lisp_Object pos, help, image; + Lisp_Object pos, help; if (area == ON_MODE_LINE || area == ON_HEADER_LINE) string = mode_line_string (w, area, &x, &y, &charpos, @@ -20098,7 +20959,7 @@ note_mode_line_or_margin_highlight (w, x, y, area) if (IMAGEP (object)) { Lisp_Object image_map, hotspot; - if ((image_map = Fplist_get (XCDR (object), QCmap), + if ((image_map = Fsafe_plist_get (XCDR (object), QCmap), !NILP (image_map)) && (hotspot = find_hot_spot (image_map, dx, dy), CONSP (hotspot)) @@ -20110,12 +20971,14 @@ note_mode_line_or_margin_highlight (w, x, y, area) /* Could check AREA_ID to see if we enter/leave this hot-spot. If so, we could look for mouse-enter, mouse-leave properties in PLIST (and do something...). */ - if ((plist = XCDR (hotspot), CONSP (plist))) + hotspot = XCDR (hotspot); + if (CONSP (hotspot) + && (plist = XCAR (hotspot), CONSP (plist))) { - pointer = Fplist_get (plist, Qpointer); + pointer = Fsafe_plist_get (plist, Qpointer); if (NILP (pointer)) pointer = Qhand; - help = Fplist_get (plist, Qhelp_echo); + help = Fsafe_plist_get (plist, Qhelp_echo); if (!NILP (help)) { help_echo_string = help; @@ -20126,7 +20989,7 @@ note_mode_line_or_margin_highlight (w, x, y, area) } } if (NILP (pointer)) - pointer = Fplist_get (XCDR (object), QCpointer); + pointer = Fsafe_plist_get (XCDR (object), QCpointer); } } @@ -20136,20 +20999,23 @@ note_mode_line_or_margin_highlight (w, x, y, area) /* If we're on a string with `help-echo' text property, arrange for the help to be displayed. This is done by setting the global variable help_echo_string to the help string. */ - help = Fget_text_property (pos, Qhelp_echo, string); - if (!NILP (help)) + if (NILP (help)) { - help_echo_string = help; - XSETWINDOW (help_echo_window, w); - help_echo_object = string; - help_echo_pos = charpos; + help = Fget_text_property (pos, Qhelp_echo, string); + if (!NILP (help)) + { + help_echo_string = help; + XSETWINDOW (help_echo_window, w); + help_echo_object = string; + help_echo_pos = charpos; + } } if (NILP (pointer)) pointer = Fget_text_property (pos, Qpointer, string); /* Change the mouse pointer according to what is under X/Y. */ - if (NILP (pointer) && area == ON_MODE_LINE) + if (NILP (pointer) && ((area == ON_MODE_LINE) || (area == ON_HEADER_LINE))) { Lisp_Object map; map = Fget_text_property (pos, Qlocal_map, string); @@ -20209,8 +21075,10 @@ note_mouse_highlight (f, x, y) /* Which window is that in? */ window = window_from_coordinates (f, x, y, &part, 0, 0, 1); - /* If we were displaying active text in another window, clear that. */ - if (! EQ (window, dpyinfo->mouse_face_window)) + /* If we were displaying active text in another window, clear that. + Also clear if we move out of text area in same window. */ + if (! EQ (window, dpyinfo->mouse_face_window) + || (part != ON_TEXT && !NILP (dpyinfo->mouse_face_window))) clear_mouse_face (dpyinfo); /* Not on a window -> return. */ @@ -20242,7 +21110,8 @@ note_mouse_highlight (f, x, y) if (part == ON_VERTICAL_BORDER) cursor = FRAME_X_OUTPUT (f)->horizontal_drag_cursor; - else if (part == ON_LEFT_FRINGE || part == ON_RIGHT_FRINGE) + else if (part == ON_LEFT_FRINGE || part == ON_RIGHT_FRINGE + || part == ON_SCROLL_BAR) cursor = FRAME_X_OUTPUT (f)->nontext_cursor; else cursor = FRAME_X_OUTPUT (f)->text_cursor; @@ -20260,7 +21129,7 @@ note_mouse_highlight (f, x, y) Lisp_Object object; Lisp_Object mouse_face = Qnil, overlay = Qnil, position; Lisp_Object *overlay_vec = NULL; - int len, noverlays; + int noverlays; struct buffer *obuf; int obegv, ozv, same_region; @@ -20274,9 +21143,11 @@ note_mouse_highlight (f, x, y) if (img != NULL && IMAGEP (img->spec)) { Lisp_Object image_map, hotspot; - if ((image_map = Fplist_get (XCDR (img->spec), QCmap), + if ((image_map = Fsafe_plist_get (XCDR (img->spec), QCmap), !NILP (image_map)) - && (hotspot = find_hot_spot (image_map, dx, dy), + && (hotspot = find_hot_spot (image_map, + glyph->slice.x + dx, + glyph->slice.y + dy), CONSP (hotspot)) && (hotspot = XCDR (hotspot), CONSP (hotspot))) { @@ -20286,12 +21157,14 @@ note_mouse_highlight (f, x, y) /* Could check AREA_ID to see if we enter/leave this hot-spot. If so, we could look for mouse-enter, mouse-leave properties in PLIST (and do something...). */ - if ((plist = XCDR (hotspot), CONSP (plist))) + hotspot = XCDR (hotspot); + if (CONSP (hotspot) + && (plist = XCAR (hotspot), CONSP (plist))) { - pointer = Fplist_get (plist, Qpointer); + pointer = Fsafe_plist_get (plist, Qpointer); if (NILP (pointer)) pointer = Qhand; - help_echo_string = Fplist_get (plist, Qhelp_echo); + help_echo_string = Fsafe_plist_get (plist, Qhelp_echo); if (!NILP (help_echo_string)) { help_echo_window = window; @@ -20301,7 +21174,7 @@ note_mouse_highlight (f, x, y) } } if (NILP (pointer)) - pointer = Fplist_get (XCDR (img->spec), QCpointer); + pointer = Fsafe_plist_get (XCDR (img->spec), QCpointer); } } @@ -20345,19 +21218,8 @@ note_mouse_highlight (f, x, y) if (BUFFERP (object)) { - /* Put all the overlays we want in a vector in overlay_vec. - Store the length in len. If there are more than 10, make - enough space for all, and try again. */ - len = 10; - overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object)); - noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL, 0); - if (noverlays > len) - { - len = noverlays; - overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object)); - noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL,0); - } - + /* Put all the overlays we want in a vector in overlay_vec. */ + GET_OVERLAYS_AT (pos, overlay_vec, noverlays, NULL, 0); /* Sort overlays into increasing priority order. */ noverlays = sort_overlays (overlay_vec, noverlays, w); } @@ -20875,13 +21737,13 @@ phys_cursor_in_rect_p (w, r) cursor_glyph = get_phys_cursor_glyph (w); if (cursor_glyph) { - /* r is relative to W's box, but w->phys_cursor.x is relative + /* r is relative to W's box, but w->phys_cursor.x is relative to left edge of W's TEXT area. Adjust it. */ cr.x = window_box_left_offset (w, TEXT_AREA) + w->phys_cursor.x; cr.y = w->phys_cursor.y; cr.width = cursor_glyph->pixel_width; cr.height = w->phys_cursor_height; - /* ++KFS: W32 version used W32-specific IntersectRect here, but + /* ++KFS: W32 version used W32-specific IntersectRect here, but I assume the effect is the same -- and this is portable. */ return x_intersect_rectangles (&cr, r, &result); } @@ -20899,13 +21761,16 @@ x_draw_vertical_border (w) struct window *w; { /* We could do better, if we knew what type of scroll-bar the adjacent - windows (on either side) have... But we don't :-( + windows (on either side) have... But we don't :-( However, I think this works ok. ++KFS 2003-04-25 */ /* Redraw borders between horizontally adjacent windows. Don't do it for frames with vertical scroll bars because either the right scroll bar of a window, or the left scroll bar of its neighbor will suffice as a border. */ + if (FRAME_HAS_VERTICAL_SCROLL_BARS (XFRAME (w->frame))) + return; + if (!WINDOW_RIGHTMOST_P (w) && !WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT (w)) { @@ -21313,6 +22178,8 @@ syms_of_xdisp () staticpro (&Qspace_width); Qraise = intern ("raise"); staticpro (&Qraise); + Qslice = intern ("slice"); + staticpro (&Qslice); Qspace = intern ("space"); staticpro (&Qspace); Qmargin = intern ("margin"); @@ -21323,6 +22190,12 @@ syms_of_xdisp () staticpro (&Qleft_margin); Qright_margin = intern ("right-margin"); staticpro (&Qright_margin); + Qcenter = intern ("center"); + staticpro (&Qcenter); + Qline_height = intern ("line-height"); + staticpro (&Qline_height); + Qtotal = intern ("total"); + staticpro (&Qtotal); QCalign_to = intern (":align-to"); staticpro (&QCalign_to); QCrelative_width = intern (":relative-width"); @@ -21341,6 +22214,8 @@ syms_of_xdisp () staticpro (&Qfontification_functions); Qtrailing_whitespace = intern ("trailing-whitespace"); staticpro (&Qtrailing_whitespace); + Qescape_glyph = intern ("escape-glyph"); + staticpro (&Qescape_glyph); Qimage = intern ("image"); staticpro (&Qimage); QCmap = intern (":map"); @@ -21388,13 +22263,20 @@ syms_of_xdisp () Qinhibit_free_realized_faces = intern ("inhibit-free-realized-faces"); staticpro (&Qinhibit_free_realized_faces); - list_of_error = Fcons (intern ("error"), Qnil); + list_of_error = Fcons (Fcons (intern ("error"), + Fcons (intern ("void-variable"), Qnil)), + Qnil); staticpro (&list_of_error); - last_arrow_position = Qnil; - last_arrow_string = Qnil; - staticpro (&last_arrow_position); - staticpro (&last_arrow_string); + Qlast_arrow_position = intern ("last-arrow-position"); + staticpro (&Qlast_arrow_position); + Qlast_arrow_string = intern ("last-arrow-string"); + staticpro (&Qlast_arrow_string); + + Qoverlay_arrow_string = intern ("overlay-arrow-string"); + staticpro (&Qoverlay_arrow_string); + Qoverlay_arrow_bitmap = intern ("overlay-arrow-bitmap"); + staticpro (&Qoverlay_arrow_bitmap); echo_buffer[0] = echo_buffer[1] = Qnil; staticpro (&echo_buffer[0]); @@ -21439,7 +22321,7 @@ The face used for trailing whitespace is `trailing-whitespace'. */); DEFVAR_LISP ("void-text-area-pointer", &Vvoid_text_area_pointer, doc: /* *The pointer shape to show in void text areas. Nil means to show the text pointer. Other options are `arrow', `text', -`hand', `vdrag', `hdrag', `modeline', and `hourglass'. */); +`hand', `vdrag', `hdrag', `modeline', and `hourglass'. */); Vvoid_text_area_pointer = Qarrow; DEFVAR_LISP ("inhibit-redisplay", &Vinhibit_redisplay, @@ -21458,9 +22340,17 @@ See also `overlay-arrow-string'. */); Voverlay_arrow_position = Qnil; DEFVAR_LISP ("overlay-arrow-string", &Voverlay_arrow_string, - doc: /* String to display as an arrow. See also `overlay-arrow-position'. */); + doc: /* String to display as an arrow in non-window frames. +See also `overlay-arrow-position'. */); Voverlay_arrow_string = Qnil; + DEFVAR_LISP ("overlay-arrow-variable-list", &Voverlay_arrow_variable_list, + doc: /* List of variables (symbols) which hold markers for overlay arrows. +The symbols on this list are examined during redisplay to determine +where to display overlay arrows. */); + Voverlay_arrow_variable_list + = Fcons (intern ("overlay-arrow-position"), Qnil); + DEFVAR_INT ("scroll-step", &scroll_step, doc: /* *The number of lines to try scrolling a window by when point moves out. If that fails to bring point back on frame, point is centered instead. @@ -21562,7 +22452,7 @@ all the functions in the list are called, with the frame as argument. */); Vwindow_size_change_functions = Qnil; DEFVAR_LISP ("window-scroll-functions", &Vwindow_scroll_functions, - doc: /* List of Functions to call before redisplaying a window with scrolling. + doc: /* List of functions to call before redisplaying a window with scrolling. Each function is called with two arguments, the window and its new display-start position. Note that the value of `window-end' is not valid when these functions are called. */); @@ -21583,6 +22473,10 @@ otherwise. */); doc: /* *Non-nil means raise tool-bar buttons when the mouse moves over them. */); auto_raise_tool_bar_buttons_p = 1; + DEFVAR_BOOL ("make-cursor-line-fully-visible", &make_cursor_line_fully_visible_p, + doc: /* *Non-nil means to scroll (recenter) cursor line if it is not fully visible. */); + make_cursor_line_fully_visible_p = 1; + DEFVAR_LISP ("tool-bar-button-margin", &Vtool_bar_button_margin, doc: /* *Margin around tool-bar buttons in pixels. If an integer, use that for both horizontal and vertical margins. @@ -21668,11 +22562,6 @@ Note that the lower bound for automatic hscrolling specified by `scroll-left' and `scroll-right' overrides this variable's effect. */); Vhscroll_step = make_number (0); - DEFVAR_LISP ("image-types", &Vimage_types, - doc: /* List of supported image types. -Each element of the list is a symbol for a supported image type. */); - Vimage_types = Qnil; - DEFVAR_BOOL ("message-truncate-lines", &message_truncate_lines, doc: /* If non-nil, messages are truncated instead of resizing the echo area. Bind this around calls to `message' to let it take effect. */);