X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/a24d4cb27a5ef18009ce05dde83d5d6b1b67911d..e1dca3678d5b062a59e923af0b1e9cf56ffa22a5:/src/xdisp.c diff --git a/src/xdisp.c b/src/xdisp.c index 9b3fc08877..3b7b9d39f8 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -1,5 +1,5 @@ /* Display generation from window structure and buffer text. - Copyright (C) 1985,86,87,88,93,94,95,97,98,99,2000,01,02,03 + Copyright (C) 1985,86,87,88,93,94,95,97,98,99,2000,01,02,03,04 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -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; @@ -242,6 +242,9 @@ Lisp_Object Qbuffer_position, Qposition, Qobject; /* Cursor shapes */ Lisp_Object Qbar, Qhbar, Qbox, Qhollow; +/* Pointer shapes */ +Lisp_Object Qarrow, Qhand, Qtext; + Lisp_Object Qrisky_local_variable; /* Holds the list (error). */ @@ -261,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; @@ -290,21 +297,47 @@ int inhibit_eval_during_redisplay; /* Names of text properties relevant for redisplay. */ -Lisp_Object Qdisplay, Qrelative_width, Qalign_to; +Lisp_Object Qdisplay; extern Lisp_Object Qface, Qinvisible, Qwidth; /* Symbols used in text property values. */ +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 Qmargin; +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. */ Lisp_Object Vshow_trailing_whitespace; +#ifdef HAVE_WINDOW_SYSTEM +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. */ + +#define IT_OVERFLOW_NEWLINE_INTO_FRINGE(it) \ + (!NILP (Voverflow_newline_into_fringe) \ + && FRAME_WINDOW_P (it->f) \ + && WINDOW_RIGHT_FRINGE_WIDTH (it->w) > 0 \ + && it->current_x == it->last_visible_x) + +#endif /* HAVE_WINDOW_SYSTEM */ + +/* Non-nil means show the text cursor in void text areas + i.e. in blank areas after eol and eob. This used to be + the default in 21.3. */ + +Lisp_Object Vvoid_text_area_pointer; + /* Name of the face used to highlight trailing whitespace. */ Lisp_Object Qtrailing_whitespace; @@ -314,6 +347,10 @@ Lisp_Object Qtrailing_whitespace; Lisp_Object Qimage; +/* The image map types. */ +Lisp_Object QCmap, QCpointer; +Lisp_Object Qrect, Qcircle, Qpoly; + /* Non-zero means print newline to stdout before next mini-buffer message. */ @@ -374,6 +411,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; @@ -382,11 +426,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. */ @@ -627,10 +677,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 @@ -754,6 +800,9 @@ 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. */ @@ -772,6 +821,7 @@ static int invisible_text_between_p P_ ((struct it *, int, int)); static int next_element_from_ellipsis P_ ((struct it *)); static void pint2str P_ ((char *, int, int)); +static void pint2hrstr P_ ((char *, int, int)); static struct text_pos run_window_scroll_functions P_ ((Lisp_Object, struct text_pos)); static void reconsider_clip_changes P_ ((struct window *, struct buffer *)); @@ -802,10 +852,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)); @@ -813,6 +864,7 @@ static int message_log_check_duplicate P_ ((int, int, int, int)); static void push_it P_ ((struct it *)); static void pop_it P_ ((struct it *)); static void sync_frame_with_window_matrix_rows P_ ((struct window *)); +static void select_frame_for_redisplay P_ ((Lisp_Object)); static void redisplay_internal P_ ((int)); static int echo_area_display P_ ((int)); static void redisplay_windows P_ ((Lisp_Object)); @@ -840,7 +892,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 *)); @@ -1189,9 +1241,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; @@ -1239,14 +1291,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; + } } } @@ -1254,6 +1319,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; } @@ -1537,6 +1603,10 @@ glyph_to_pixel_coords (w, hpos, vpos, frame_x, frame_y) ++glyph; } + /* If first glyph is partially visible, its first visible position is still 0. */ + if (hpos < 0) + hpos = 0; + success_p = 1; } else @@ -1568,11 +1638,10 @@ glyph_to_pixel_coords (w, hpos, vpos, frame_x, frame_y) date. */ static struct glyph * -x_y_to_hpos_vpos (w, x, y, hpos, vpos, area, buffer_only_p) +x_y_to_hpos_vpos (w, x, y, hpos, vpos, dx, dy, area) struct window *w; int x, y; - int *hpos, *vpos, *area; - int buffer_only_p; + int *hpos, *vpos, *dx, *dy, *area; { struct glyph *glyph, *end; struct glyph_row *row = NULL; @@ -1611,7 +1680,7 @@ x_y_to_hpos_vpos (w, x, y, hpos, vpos, area, buffer_only_p) else if (x < window_box_right_offset (w, TEXT_AREA)) { *area = TEXT_AREA; - x0 = window_box_left_offset (w, TEXT_AREA); + x0 = window_box_left_offset (w, TEXT_AREA) + min (row->x, 0); } else { @@ -1623,23 +1692,22 @@ x_y_to_hpos_vpos (w, x, y, hpos, vpos, area, buffer_only_p) /* Find glyph containing X. */ glyph = row->glyphs[*area]; end = glyph + row->used[*area]; - while (glyph < end) + x -= x0; + while (glyph < end && x >= glyph->pixel_width) { - if (x < x0 + glyph->pixel_width) - { - if (w->pseudo_window_p) - break; - else if (!buffer_only_p || BUFFERP (glyph->object)) - break; - } - - x0 += glyph->pixel_width; + x -= glyph->pixel_width; ++glyph; } if (glyph == end) return NULL; + if (dx) + { + *dx = x; + *dy = y - (row->y + row->ascent - glyph->ascent); + } + *hpos = glyph - row->glyphs[*area]; return glyph; } @@ -1721,26 +1789,36 @@ 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); } r.y = WINDOW_TO_FRAME_PIXEL_Y (s->w, r.y); -#ifdef HAVE_NTGUI - /* ++KFS: From W32 port, but it looks ok for all platforms to me. */ /* If drawing the cursor, don't let glyph draw outside its advertised boundaries. Cleartype does this under some circumstances. */ if (s->hl == DRAW_CURSOR) { + struct glyph *glyph = s->first_glyph; + int height; + if (s->x > r.x) { r.width -= s->x - r.x; r.x = s->x; } - r.width = min (r.width, s->first_glyph->pixel_width); + r.width = min (r.width, glyph->pixel_width); + + /* Don't draw cursor glyph taller than our actual glyph. */ + height = max (FRAME_LINE_HEIGHT (s->f), glyph->ascent + glyph->descent); + if (height < r.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); + } } -#endif #ifdef CONVERT_FROM_XRECT CONVERT_FROM_XRECT (r, *nr); @@ -1863,10 +1941,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) @@ -1979,6 +2061,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); @@ -1991,8 +2075,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 @@ -2004,9 +2092,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); @@ -2178,6 +2268,8 @@ init_iterator (it, w, charpos, bytepos, row, base_face_id) else IT_BYTEPOS (*it) = bytepos; + it->start = it->current; + /* Compute faces etc. */ reseat (it, it->current.pos, 1); } @@ -2199,6 +2291,7 @@ start_display (it, w, pos) row = w->desired_matrix->rows + first_vpos; init_iterator (it, w, CHARPOS (pos), BYTEPOS (pos), row, DEFAULT_FACE_ID); + it->first_vpos = first_vpos; if (!it->truncate_lines_p) { @@ -2440,6 +2533,7 @@ init_to_row_start (it, w, row) struct glyph_row *row; { init_from_display_pos (it, w, &row->start); + it->start = row->start; it->continuation_lines_width = row->continuation_lines_width; CHECK_IT (it); } @@ -2643,19 +2737,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. */ @@ -3208,8 +3293,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 @@ -3228,11 +3314,14 @@ 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) /* Marginal area specifications. */ && !(CONSP (XCAR (prop)) && EQ (XCAR (XCAR (prop)), Qmargin)) + && !EQ (XCAR (prop), Qleft_fringe) + && !EQ (XCAR (prop), Qright_fringe) && !NILP (XCAR (prop))) { for (; CONSP (prop); prop = XCDR (prop)) @@ -3421,6 +3510,30 @@ handle_single_display_prop (it, prop, object, position, if (NUMBERP (value) && XFLOATINT (value) > 0) it->space_width = value; } + else if (CONSP (prop) + && EQ (XCAR (prop), Qslice)) + { + /* `(slice X Y WIDTH HEIGHT)'. */ + Lisp_Object tem; + + if (FRAME_TERMCAP_P (it->f) || FRAME_MSDOS_P (it->f)) + return 0; + + if (tem = XCDR (prop), 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); + } + } + } + } else if (CONSP (prop) && EQ (XCAR (prop), Qraise) && CONSP (XCDR (prop))) @@ -3457,6 +3570,65 @@ handle_single_display_prop (it, prop, object, position, text properties change there. */ it->stop_charpos = position->charpos; + if (CONSP (prop) + && (EQ (XCAR (prop), Qleft_fringe) + || EQ (XCAR (prop), Qright_fringe)) + && CONSP (XCDR (prop))) + { + unsigned face_id = DEFAULT_FACE_ID; + int fringe_bitmap; + + /* Save current settings of IT so that we can restore them + when we are finished with the glyph property value. */ + + /* `(left-fringe BITMAP FACE)'. */ + if (FRAME_TERMCAP_P (it->f) || FRAME_MSDOS_P (it->f)) + return 0; + +#ifdef HAVE_WINDOW_SYSTEM + value = XCAR (XCDR (prop)); + if (!SYMBOLP (value) + || !(fringe_bitmap = lookup_fringe_bitmap (value))) + return 0; + + if (CONSP (XCDR (XCDR (prop)))) + { + Lisp_Object face_name = XCAR (XCDR (XCDR (prop))); + + face_id = lookup_named_face (it->f, face_name, 'A'); + if (face_id < 0) + return 0; + } + + 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 (prop), Qleft_fringe)) + { + it->left_user_fringe_bitmap = fringe_bitmap; + it->left_user_fringe_face_id = face_id; + } + else + { + it->right_user_fringe_bitmap = fringe_bitmap; + it->right_user_fringe_face_id = face_id; + } +#endif /* HAVE_WINDOW_SYSTEM */ + return 1; + } + location = Qunbound; if (CONSP (prop) && CONSP (XCAR (prop))) { @@ -3482,16 +3654,11 @@ handle_single_display_prop (it, prop, object, position, value = prop; } + 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) @@ -4209,6 +4376,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; @@ -4241,6 +4409,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; @@ -4392,12 +4561,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); @@ -4415,7 +4593,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; { @@ -4720,13 +4898,17 @@ 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)) : (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 '^' @@ -5473,15 +5655,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; @@ -5541,6 +5730,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; @@ -5563,7 +5754,34 @@ move_it_in_display_line_to (it, to_charpos, to_x, op) ++it->hpos; it->current_x = new_x; if (i == it->nglyphs - 1) - set_iterator_to_next (it, 1); + { + set_iterator_to_next (it, 1); +#ifdef HAVE_WINDOW_SYSTEM + if (IT_OVERFLOW_NEWLINE_INTO_FRINGE (it)) + { + if (!get_next_display_element (it)) + { + 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; + break; + } + if (it->method == next_element_from_display_vector) + it->face_id = it->saved_face_id; + } +#endif /* HAVE_WINDOW_SYSTEM */ + } } else { @@ -5577,6 +5795,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 @@ -5593,6 +5813,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 @@ -5620,11 +5849,29 @@ move_it_in_display_line_to (it, to_charpos, to_x, op) if (it->truncate_lines_p && it->current_x >= it->last_visible_x) { +#ifdef HAVE_WINDOW_SYSTEM + if (IT_OVERFLOW_NEWLINE_INTO_FRINGE (it)) + { + if (!get_next_display_element (it) + || BUFFER_POS_REACHED_P ()) + { + result = MOVE_POS_MATCH_OR_ZV; + break; + } + if (ITERATOR_AT_END_OF_LINE_P (it)) + { + result = MOVE_NEWLINE_OR_CR; + break; + } + } +#endif /* HAVE_WINDOW_SYSTEM */ result = MOVE_LINE_TRUNCATED; break; } } +#undef BUFFER_POS_REACHED_P + /* Restore the iterator settings altered at the beginning of this function. */ it->glyph_row = saved_glyph_row; @@ -5829,10 +6076,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)); @@ -5898,13 +6148,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) @@ -5945,7 +6195,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, @@ -6042,6 +6292,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); @@ -6109,6 +6361,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 @@ -6125,10 +6378,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; } @@ -6450,6 +6705,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 (); @@ -7182,7 +7438,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; } @@ -7548,7 +7804,10 @@ clear_garbaged_frames () if (FRAME_VISIBLE_P (f) && FRAME_GARBAGED_P (f)) { if (f->resized_p) - Fredraw_frame (frame); + { + Fredraw_frame (frame); + f->force_flush_display_p = 1; + } clear_current_matrices (f); changed_count++; f->garbaged = 0; @@ -7735,7 +7994,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++); @@ -8140,7 +8399,7 @@ update_tool_bar (f, save_match_data) int save_match_data; { #ifdef USE_GTK - int do_update = FRAME_EXTERNAL_TOOL_BAR(f); + int do_update = FRAME_EXTERNAL_TOOL_BAR (f); #else int do_update = WINDOWP (f->tool_bar_window) && WINDOW_TOTAL_LINES (XWINDOW (f->tool_bar_window)) > 0; @@ -8173,7 +8432,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 @@ -8192,19 +8452,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); @@ -8261,7 +8527,7 @@ build_desired_tool_bar_string (f) int enabled_p = !NILP (PROP (TOOL_BAR_ITEM_ENABLED_P)); int selected_p = !NILP (PROP (TOOL_BAR_ITEM_SELECTED_P)); int hmargin, vmargin, relief, idx, end; - extern Lisp_Object QCrelief, QCmargin, QCconversion, Qimage; + extern Lisp_Object QCrelief, QCmargin, QCconversion; /* If image is a vector, choose the image according to the button state. */ @@ -8450,6 +8716,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; @@ -8537,7 +8804,7 @@ redisplay_tool_bar (f) int change_height_p = 0; #ifdef USE_GTK - if (FRAME_EXTERNAL_TOOL_BAR(f)) + if (FRAME_EXTERNAL_TOOL_BAR (f)) update_frame_tool_bar (f); return 0; #endif @@ -8678,7 +8945,7 @@ get_tool_bar_item (f, x, y, glyph, hpos, vpos, prop_idx) int area; /* Find the glyph under X/Y. */ - *glyph = x_y_to_hpos_vpos (w, x, y, hpos, vpos, &area, 0); + *glyph = x_y_to_hpos_vpos (w, x, y, hpos, vpos, 0, 0, &area); if (*glyph == NULL) return -1; @@ -8861,283 +9128,6 @@ note_tool_bar_highlight (f, x, y) #endif /* HAVE_WINDOW_SYSTEM */ - -/*********************************************************************** - Fringes - ***********************************************************************/ - -#ifdef HAVE_WINDOW_SYSTEM - -/* An arrow like this: `<-'. */ -static unsigned char left_bits[] = { - 0x18, 0x0c, 0x06, 0x3f, 0x3f, 0x06, 0x0c, 0x18}; - -/* Right truncation arrow bitmap `->'. */ -static unsigned char right_bits[] = { - 0x18, 0x30, 0x60, 0xfc, 0xfc, 0x60, 0x30, 0x18}; - -/* Marker for continued lines. */ -static unsigned char continued_bits[] = { - 0x3c, 0x7c, 0xc0, 0xe4, 0xfc, 0x7c, 0x3c, 0x7c}; - -/* Marker for continuation lines. */ -static unsigned char continuation_bits[] = { - 0x3c, 0x3e, 0x03, 0x27, 0x3f, 0x3e, 0x3c, 0x3e}; - -/* Overlay arrow bitmap. A triangular arrow. */ -static unsigned char ov_bits[] = { - 0x03, 0x0f, 0x1f, 0x3f, 0x3f, 0x1f, 0x0f, 0x03}; - -/* Bitmap drawn to indicate lines not displaying text if - `indicate-empty-lines' is non-nil. */ -static unsigned char zv_bits[] = { - 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, - 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, - 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, - 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, - 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, - 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, - 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, - 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00}; - -struct fringe_bitmap fringe_bitmaps[MAX_FRINGE_BITMAPS] = -{ - { 0, 0, 0, NULL /* NO_FRINGE_BITMAP */ }, - { 8, sizeof (left_bits), 0, left_bits }, - { 8, sizeof (right_bits), 0, right_bits }, - { 8, sizeof (continued_bits), 0, continued_bits }, - { 8, sizeof (continuation_bits), 0, continuation_bits }, - { 8, sizeof (ov_bits), 0, ov_bits }, - { 8, sizeof (zv_bits), 3, zv_bits } -}; - - -/* Draw the bitmap WHICH in one of the left or right fringes of - window W. ROW is the glyph row for which to display the bitmap; it - determines the vertical position at which the bitmap has to be - drawn. */ - -static void -draw_fringe_bitmap (w, row, which, left_p) - struct window *w; - struct glyph_row *row; - enum fringe_bitmap_type which; - int left_p; -{ - struct frame *f = XFRAME (WINDOW_FRAME (w)); - struct draw_fringe_bitmap_params p; - - /* Convert row to frame coordinates. */ - p.y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y); - - p.which = which; - p.wd = fringe_bitmaps[which].width; - - p.h = fringe_bitmaps[which].height; - p.dh = (fringe_bitmaps[which].period - ? (p.y % fringe_bitmaps[which].period) - : 0); - p.h -= p.dh; - /* Clip bitmap if too high. */ - if (p.h > row->height) - p.h = row->height; - - p.face = FACE_FROM_ID (f, FRINGE_FACE_ID); - PREPARE_FACE_FOR_DISPLAY (f, p.face); - - /* Clear left fringe if no bitmap to draw or if bitmap doesn't fill - the fringe. */ - p.bx = -1; - if (left_p) - { - int wd = WINDOW_LEFT_FRINGE_WIDTH (w); - int x = window_box_left (w, (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w) - ? LEFT_MARGIN_AREA - : TEXT_AREA)); - if (p.wd > wd) - p.wd = wd; - p.x = x - p.wd - (wd - p.wd) / 2; - - if (p.wd < wd || row->height > p.h) - { - /* If W has a vertical border to its left, don't draw over it. */ - wd -= ((!WINDOW_LEFTMOST_P (w) - && !WINDOW_HAS_VERTICAL_SCROLL_BAR (w)) - ? 1 : 0); - p.bx = x - wd; - p.nx = wd; - } - } - else - { - int x = window_box_right (w, - (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w) - ? RIGHT_MARGIN_AREA - : TEXT_AREA)); - int wd = WINDOW_RIGHT_FRINGE_WIDTH (w); - if (p.wd > wd) - p.wd = wd; - p.x = x + (wd - p.wd) / 2; - /* Clear right fringe if no bitmap to draw of if bitmap doesn't fill - the fringe. */ - if (p.wd < wd || row->height > p.h) - { - p.bx = x; - p.nx = wd; - } - } - - if (p.bx >= 0) - { - int header_line_height = WINDOW_HEADER_LINE_HEIGHT (w); - - p.by = WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height, row->y)); - p.ny = row->visible_height; - } - - /* Adjust y to the offset in the row to start drawing the bitmap. */ - p.y += (row->height - p.h) / 2; - - rif->draw_fringe_bitmap (w, row, &p); -} - -/* Draw fringe bitmaps for glyph row ROW on window W. Call this - function with input blocked. */ - -void -draw_row_fringe_bitmaps (w, row) - struct window *w; - struct glyph_row *row; -{ - enum fringe_bitmap_type bitmap; - - xassert (interrupt_input_blocked); - - /* If row is completely invisible, because of vscrolling, we - don't have to draw anything. */ - if (row->visible_height <= 0) - return; - - if (WINDOW_LEFT_FRINGE_WIDTH (w) != 0) - { - /* Decide which bitmap to draw in the left fringe. */ - if (row->overlay_arrow_p) - bitmap = OVERLAY_ARROW_BITMAP; - else if (row->truncated_on_left_p) - bitmap = LEFT_TRUNCATION_BITMAP; - else if (MATRIX_ROW_CONTINUATION_LINE_P (row)) - bitmap = CONTINUATION_LINE_BITMAP; - else if (row->indicate_empty_line_p) - bitmap = ZV_LINE_BITMAP; - else - bitmap = NO_FRINGE_BITMAP; - - draw_fringe_bitmap (w, row, bitmap, 1); - } - - if (WINDOW_RIGHT_FRINGE_WIDTH (w) != 0) - { - /* Decide which bitmap to draw in the right fringe. */ - if (row->truncated_on_right_p) - bitmap = RIGHT_TRUNCATION_BITMAP; - else if (row->continued_p) - bitmap = CONTINUED_LINE_BITMAP; - else if (row->indicate_empty_line_p && WINDOW_LEFT_FRINGE_WIDTH (w) == 0) - bitmap = ZV_LINE_BITMAP; - else - bitmap = NO_FRINGE_BITMAP; - - draw_fringe_bitmap (w, row, bitmap, 0); - } -} - - -/* Compute actual fringe widths */ - -void -compute_fringe_widths (f, redraw) - struct frame *f; - int redraw; -{ - int o_left = FRAME_LEFT_FRINGE_WIDTH (f); - int o_right = FRAME_RIGHT_FRINGE_WIDTH (f); - int o_cols = FRAME_FRINGE_COLS (f); - - Lisp_Object left_fringe = Fassq (Qleft_fringe, f->param_alist); - Lisp_Object right_fringe = Fassq (Qright_fringe, f->param_alist); - int left_fringe_width, right_fringe_width; - - if (!NILP (left_fringe)) - left_fringe = Fcdr (left_fringe); - if (!NILP (right_fringe)) - right_fringe = Fcdr (right_fringe); - - left_fringe_width = ((NILP (left_fringe) || !INTEGERP (left_fringe)) ? 8 : - XINT (left_fringe)); - right_fringe_width = ((NILP (right_fringe) || !INTEGERP (right_fringe)) ? 8 : - XINT (right_fringe)); - - if (left_fringe_width || right_fringe_width) - { - int left_wid = left_fringe_width >= 0 ? left_fringe_width : -left_fringe_width; - int right_wid = right_fringe_width >= 0 ? right_fringe_width : -right_fringe_width; - int conf_wid = left_wid + right_wid; - int font_wid = FRAME_COLUMN_WIDTH (f); - int cols = (left_wid + right_wid + font_wid-1) / font_wid; - int real_wid = cols * font_wid; - if (left_wid && right_wid) - { - if (left_fringe_width < 0) - { - /* Left fringe width is fixed, adjust right fringe if necessary */ - FRAME_LEFT_FRINGE_WIDTH (f) = left_wid; - FRAME_RIGHT_FRINGE_WIDTH (f) = real_wid - left_wid; - } - else if (right_fringe_width < 0) - { - /* Right fringe width is fixed, adjust left fringe if necessary */ - FRAME_LEFT_FRINGE_WIDTH (f) = real_wid - right_wid; - FRAME_RIGHT_FRINGE_WIDTH (f) = right_wid; - } - else - { - /* Adjust both fringes with an equal amount. - Note that we are doing integer arithmetic here, so don't - lose a pixel if the total width is an odd number. */ - int fill = real_wid - conf_wid; - FRAME_LEFT_FRINGE_WIDTH (f) = left_wid + fill/2; - FRAME_RIGHT_FRINGE_WIDTH (f) = right_wid + fill - fill/2; - } - } - else if (left_fringe_width) - { - FRAME_LEFT_FRINGE_WIDTH (f) = real_wid; - FRAME_RIGHT_FRINGE_WIDTH (f) = 0; - } - else - { - FRAME_LEFT_FRINGE_WIDTH (f) = 0; - FRAME_RIGHT_FRINGE_WIDTH (f) = real_wid; - } - FRAME_FRINGE_COLS (f) = cols; - } - else - { - FRAME_LEFT_FRINGE_WIDTH (f) = 0; - FRAME_RIGHT_FRINGE_WIDTH (f) = 0; - FRAME_FRINGE_COLS (f) = 0; - } - - if (redraw && FRAME_VISIBLE_P (f)) - if (o_left != FRAME_LEFT_FRINGE_WIDTH (f) || - o_right != FRAME_RIGHT_FRINGE_WIDTH (f) || - o_cols != FRAME_FRINGE_COLS (f)) - redraw_frame (f); -} - -#endif /* HAVE_WINDOW_SYSTEM */ - - /************************************************************************ Horizontal scrolling @@ -9239,7 +9229,10 @@ hscroll_window_tree (window) /* Position cursor in window. */ if (!hscroll_relative_p && hscroll_step_abs == 0) - hscroll = max (0, it.current_x - text_area_width / 2) + hscroll = max (0, (it.current_x + - (ITERATOR_AT_END_OF_LINE_P (&it) + ? (text_area_width - 4 * FRAME_COLUMN_WIDTH (it.f)) + : (text_area_width / 2)))) / FRAME_COLUMN_WIDTH (it.f); else if (w->cursor.x >= text_area_width - h_margin) { @@ -9448,42 +9441,192 @@ redisplay () } -/* 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. */ - -int -check_point_in_composition (prev_buf, prev_pt, buf, pt) - struct buffer *prev_buf, *buf; - int prev_pt, pt; +static Lisp_Object +overlay_arrow_string_or_property (var, pbitmap) + Lisp_Object var; + int *pbitmap; { - int start, end; - Lisp_Object prop; - Lisp_Object buffer; + Lisp_Object pstr = Fget (var, Qoverlay_arrow_string); + Lisp_Object bitmap; - XSETBUFFER (buffer, buf); - /* Check a composition at the last point if point moved within the - same buffer. */ - if (prev_buf == buf) + if (pbitmap) { - if (prev_pt == pt) - /* Point didn't move. */ - return 0; - - if (prev_pt > BUF_BEGV (buf) && prev_pt < BUF_ZV (buf) - && find_composition (prev_pt, -1, &start, &end, &prop, buffer) - && COMPOSITION_VALID_P (start, end, prop) - && start < prev_pt && end > prev_pt) - /* The last point was within the composition. Return 1 iff - point moved out of the composition. */ - return (pt <= start || pt >= end); + *pbitmap = 0; + if (bitmap = Fget (var, Qoverlay_arrow_bitmap), INTEGERP (bitmap)) + *pbitmap = XINT (bitmap); } - /* Check a composition at the current point. */ - return (pt > BUF_BEGV (buf) && pt < BUF_ZV (buf) - && find_composition (pt, -1, &start, &end, &prop, buffer) - && COMPOSITION_VALID_P (start, end, prop) - && start < pt && end > pt); + 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. */ + +int +check_point_in_composition (prev_buf, prev_pt, buf, pt) + struct buffer *prev_buf, *buf; + int prev_pt, pt; +{ + int start, end; + Lisp_Object prop; + Lisp_Object buffer; + + XSETBUFFER (buffer, buf); + /* Check a composition at the last point if point moved within the + same buffer. */ + if (prev_buf == buf) + { + if (prev_pt == pt) + /* Point didn't move. */ + return 0; + + if (prev_pt > BUF_BEGV (buf) && prev_pt < BUF_ZV (buf) + && find_composition (prev_pt, -1, &start, &end, &prop, buffer) + && COMPOSITION_VALID_P (start, end, prop) + && start < prev_pt && end > prev_pt) + /* The last point was within the composition. Return 1 iff + point moved out of the composition. */ + return (pt <= start || pt >= end); + } + + /* Check a composition at the current point. */ + return (pt > BUF_BEGV (buf) && pt < BUF_ZV (buf) + && find_composition (pt, -1, &start, &end, &prop, buffer) + && COMPOSITION_VALID_P (start, end, prop) + && start < pt && end > pt); } @@ -9526,6 +9669,44 @@ reconsider_clip_changes (w, b) } } + +/* Select FRAME to forward the values of frame-local variables into C + variables so that the redisplay routines can access those values + directly. */ + +static void +select_frame_for_redisplay (frame) + Lisp_Object 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)) + if (CONSP (XCAR (tail)) + && (sym = XCAR (XCAR (tail)), + SYMBOLP (sym)) + && (sym = indirect_variable (sym), + val = SYMBOL_VALUE (sym), + (BUFFER_LOCAL_VALUEP (val) + || SOME_BUFFER_LOCAL_VALUEP (val))) + && XBUFFER_LOCAL_VALUE (val)->check_frame) + Fsymbol_value (sym); + + for (tail = XFRAME (old)->param_alist; CONSP (tail); tail = XCDR (tail)) + if (CONSP (XCAR (tail)) + && (sym = XCAR (XCAR (tail)), + SYMBOLP (sym)) + && (sym = indirect_variable (sym), + val = SYMBOL_VALUE (sym), + (BUFFER_LOCAL_VALUEP (val) + || SOME_BUFFER_LOCAL_VALUEP (val))) + && XBUFFER_LOCAL_VALUE (val)->check_frame) + Fsymbol_value (sym); +} + + #define STOP_POLLING \ do { if (! polling_stopped_here) stop_polling (); \ polling_stopped_here = 1; } while (0) @@ -9591,7 +9772,8 @@ redisplay_internal (preserve_echo_area) /* Record a function that resets redisplaying_p to its old value when we leave this function. */ count = SPECPDL_INDEX (); - record_unwind_protect (unwind_redisplay, make_number (redisplaying_p)); + record_unwind_protect (unwind_redisplay, + Fcons (make_number (redisplaying_p), selected_frame)); ++redisplaying_p; specbind (Qinhibit_free_realized_faces, Qnil); @@ -9688,8 +9870,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 @@ -9900,6 +10081,9 @@ redisplay_internal (preserve_echo_area) #if GLYPH_DEBUG *w->desired_matrix->method = 0; debug_method_add (w, "optimization 1"); +#endif +#ifdef HAVE_WINDOW_SYSTEM + update_window_fringes (w, 0); #endif goto update; } @@ -10005,6 +10189,11 @@ redisplay_internal (preserve_echo_area) if (FRAME_WINDOW_P (f) || f == sf) { + if (! EQ (frame, selected_frame)) + /* Select the frame, for the sake of frame-local + variables. */ + select_frame_for_redisplay (frame); + #ifdef HAVE_WINDOW_SYSTEM if (clear_face_cache_count % 50 == 0 && FRAME_WINDOW_P (f)) @@ -10141,11 +10330,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. */ @@ -10161,8 +10346,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); @@ -10230,7 +10415,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. */ @@ -10251,19 +10436,29 @@ redisplay_preserve_echo_area (from_where) } else redisplay_internal (1); + + if (rif != NULL && rif->flush_display_optional) + rif->flush_display_optional (NULL); } /* Function registered with record_unwind_protect in redisplay_internal. Reset redisplaying_p to the value it had before redisplay_internal was called, and clear - prevent_freeing_realized_faces_p. */ + prevent_freeing_realized_faces_p. It also selects the previously + selected frame. */ static Lisp_Object -unwind_redisplay (old_redisplaying_p) - Lisp_Object old_redisplaying_p; +unwind_redisplay (val) + Lisp_Object val; { + Lisp_Object old_redisplaying_p, old_frame; + + old_redisplaying_p = XCAR (val); redisplaying_p = XFASTINT (old_redisplaying_p); + old_frame = XCDR (val); + if (! EQ (old_frame, selected_frame)) + select_frame_for_redisplay (old_frame); return Qnil; } @@ -10351,16 +10546,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); } } @@ -10491,6 +10684,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. */ @@ -10500,6 +10694,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. @@ -10525,6 +10721,12 @@ 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 { @@ -10532,12 +10734,40 @@ set_cursor_from_row (w, row, matrix, delta, delta_bytes, dy, dvpos) 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 @@ -10650,17 +10880,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) @@ -10670,15 +10908,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 @@ -10769,7 +11009,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"); @@ -10787,6 +11027,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) @@ -10812,11 +11058,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; } @@ -10860,7 +11108,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) @@ -10909,8 +11162,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 @@ -10918,13 +11171,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; } } @@ -10951,10 +11209,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; @@ -11111,10 +11369,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 @@ -11127,6 +11384,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 @@ -11181,13 +11442,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); @@ -11215,7 +11475,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; } @@ -11226,7 +11486,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 @@ -11244,7 +11505,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; @@ -11274,7 +11535,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) @@ -11286,7 +11547,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)) @@ -11299,6 +11560,7 @@ set_vertical_scroll_bar (w) set_vertical_scroll_bar_hook (w, end - start, whole, start); } + /* Redisplay leaf window WINDOW. JUST_THIS_ONE_P non-zero means only selected_window is redisplayed. @@ -11321,6 +11583,7 @@ redisplay_window (window, just_this_one_p) struct it it; /* Record it now because it's overwritten. */ int current_matrix_up_to_date_p = 0; + int used_current_matrix_p = 0; /* This is less strict than current_matrix_up_to_date_p. It indictes that the buffer contents and narrowing are unchanged. */ int buffer_unchanged_p = 0; @@ -11511,6 +11774,11 @@ redisplay_window (window, just_this_one_p) MOVE_TO_POS | MOVE_TO_X | MOVE_TO_Y); if (IT_CHARPOS (it) == PT) w->force_start = Qt; + /* IT may overshoot PT if text at PT is invisible. */ + else if (IT_CHARPOS (it) > PT && CHARPOS (startp) <= PT) + w->force_start = Qt; + + } /* Handle case where place to start displaying has been specified, @@ -11568,7 +11836,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. */ @@ -11622,6 +11890,7 @@ redisplay_window (window, just_this_one_p) switch (rc) { case CURSOR_MOVEMENT_SUCCESS: + used_current_matrix_p = 1; goto done; #if 0 /* try_cursor_movement never returns this value. */ @@ -11686,7 +11955,8 @@ redisplay_window (window, just_this_one_p) buffer. */ || !NILP (Vwindow_scroll_functions) || MINI_WINDOW_P (w) - || !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); @@ -11703,7 +11973,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; @@ -11792,7 +12062,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; } @@ -11815,7 +12085,8 @@ redisplay_window (window, just_this_one_p) || !NILP (Vwindow_scroll_functions) || !just_this_one_p || MINI_WINDOW_P (w) - || !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 @@ -11862,7 +12133,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) @@ -11875,6 +12146,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; } @@ -11977,6 +12249,22 @@ redisplay_window (window, just_this_one_p) #endif } +#ifdef HAVE_WINDOW_SYSTEM + 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; + if (draw_window_fringes (w, 1)) + x_draw_vertical_border (w); + UNBLOCK_INPUT; + update_end (f); + } +#endif /* HAVE_WINDOW_SYSTEM */ + /* We go to this label, with fonts_changed_p nonzero, if it is necessary to try again using larger glyph matrices. We have to redeem the scroll bar even in this case, @@ -12123,7 +12411,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 @@ -12158,10 +12446,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 @@ -12169,12 +12483,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); @@ -12194,7 +12508,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; @@ -12233,6 +12547,7 @@ try_window_reusing_current_matrix (w) row->visible_height -= min_y - row->y; if (row->y + row->height > max_y) row->visible_height -= row->y + row->height - max_y; + row->redraw_fringe_bitmaps_p = 1; it.current_y += row->height; @@ -12359,9 +12674,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. */ @@ -12372,7 +12686,6 @@ try_window_reusing_current_matrix (w) if (run.height) { - struct frame *f = XFRAME (WINDOW_FRAME (w)); update_begin (f); rif->update_window_begin_hook (w); rif->clear_window_mouse_face (w); @@ -12393,6 +12706,7 @@ try_window_reusing_current_matrix (w) row->visible_height -= min_y - row->y; if (row->y + row->height > max_y) row->visible_height -= row->y + row->height - max_y; + row->redraw_fringe_bitmaps_p = 1; } /* Scroll the current matrix. */ @@ -12406,6 +12720,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. */ @@ -12515,7 +12852,8 @@ find_last_unchanged_at_beg_row (w) row is not unchanged because it may be no longer continued. */ && !(MATRIX_ROW_END_CHARPOS (row) == first_changed_pos - && row->continued_p)) + && (row->continued_p + || row->exact_window_width_line_p))) row_found = row; /* Stop if last visible row. */ @@ -12835,8 +13173,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); @@ -13024,8 +13361,9 @@ try_window_id (w) else { /* There are no reusable lines at the start of the window. - Start displaying in the first line. */ + Start displaying in the first text line. */ start_display (&it, w, start); + it.vpos = it.first_vpos; start_pos = it.current.pos; } @@ -13188,9 +13526,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); @@ -13768,18 +14108,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; @@ -13806,7 +14147,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. */ @@ -13914,6 +14255,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. */ @@ -13957,6 +14299,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. */ @@ -13975,8 +14318,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 @@ -13988,7 +14330,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; { @@ -14002,7 +14344,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; @@ -14029,6 +14371,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; @@ -14245,13 +14589,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; @@ -14260,7 +14610,7 @@ display_line (it) prepare_desired_row (row); row->y = it->current_y; - row->start = it->current; + row->start = it->start; row->continuation_lines_width = it->continuation_lines_width; row->displays_text_p = 1; row->starts_in_middle_of_char_p = it->starts_in_middle_of_char_p; @@ -14286,6 +14636,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. */ @@ -14303,7 +14654,12 @@ display_line (it) display the cursor there under X. Set the charpos of the first glyph of blank lines not corresponding to any text to -1. */ - if ((append_space (it, 1) && row->used[TEXT_AREA] == 1) +#ifdef HAVE_WINDOW_SYSTEM + if (IT_OVERFLOW_NEWLINE_INTO_FRINGE (it)) + row->exact_window_width_line_p = 1; + else +#endif /* HAVE_WINDOW_SYSTEM */ + if ((append_space_for_newline (it, 1) && row->used[TEXT_AREA] == 1) || row->used[TEXT_AREA] == 0) { row->glyphs[TEXT_AREA]->charpos = -1; @@ -14346,6 +14702,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; } @@ -14374,6 +14732,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; } @@ -14410,7 +14770,28 @@ display_line (it) it->continuation_lines_width += new_x; ++it->hpos; if (i == nglyphs - 1) - set_iterator_to_next (it, 1); + { + set_iterator_to_next (it, 1); +#ifdef HAVE_WINDOW_SYSTEM + if (IT_OVERFLOW_NEWLINE_INTO_FRINGE (it)) + { + if (!get_next_display_element (it)) + { + row->exact_window_width_line_p = 1; + it->continuation_lines_width = 0; + row->continued_p = 0; + row->ends_at_zv_p = 1; + } + else if (ITERATOR_AT_END_OF_LINE_P (it)) + { + row->continued_p = 0; + row->exact_window_width_line_p = 1; + } + else if (it->method == next_element_from_display_vector) + it->face_id = it->saved_face_id; + } +#endif /* HAVE_WINDOW_SYSTEM */ + } } else if (CHAR_GLYPH_PADDING_P (*glyph) && !FRAME_WINDOW_P (it->f)) @@ -14506,12 +14887,15 @@ 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) + if (row->continued_p || row->ends_at_zv_p) break; } + at_end_of_line: /* Is this a line end? If yes, we're also done, after making sure that a non-default face is extended up to the right margin of the window. */ @@ -14521,9 +14905,12 @@ display_line (it) row->ends_in_newline_from_string_p = STRINGP (it->object); +#ifdef HAVE_WINDOW_SYSTEM /* Add a space at the end of the line that is used to display the cursor there. */ - append_space (it, 0); + if (!IT_OVERFLOW_NEWLINE_INTO_FRINGE (it)) + append_space_for_newline (it, 0); +#endif /* HAVE_WINDOW_SYSTEM */ /* Extend the face to the end of the line. */ extend_face_to_end_of_line (it); @@ -14564,6 +14951,27 @@ display_line (it) produce_special_glyphs (it, IT_TRUNCATION); } } +#ifdef HAVE_WINDOW_SYSTEM + else + { + /* Don't truncate if we can overflow newline into fringe. */ + if (IT_OVERFLOW_NEWLINE_INTO_FRINGE (it)) + { + if (!get_next_display_element (it)) + { + it->continuation_lines_width = 0; + row->ends_at_zv_p = 1; + row->exact_window_width_line_p = 1; + break; + } + if (ITERATOR_AT_END_OF_LINE_P (it)) + { + row->exact_window_width_line_p = 1; + goto at_end_of_line; + } + } + } +#endif /* HAVE_WINDOW_SYSTEM */ row->truncated_on_right_p = 1; it->continuation_lines_width = 0; @@ -14589,17 +14997,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]; @@ -14621,9 +15028,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. */ @@ -14632,6 +15042,17 @@ display_line (it) /* Remember the position at which this line ends. */ row->end = it->current; + /* Save fringe bitmaps in this row. */ + row->left_user_fringe_bitmap = it->left_user_fringe_bitmap; + row->left_user_fringe_face_id = it->left_user_fringe_face_id; + row->right_user_fringe_bitmap = it->right_user_fringe_bitmap; + row->right_user_fringe_face_id = it->right_user_fringe_face_id; + + it->left_user_fringe_bitmap = 0; + it->left_user_fringe_face_id = 0; + it->right_user_fringe_bitmap = 0; + it->right_user_fringe_face_id = 0; + /* Maybe set the cursor. */ if (it->w->cursor.vpos < 0 && PT >= MATRIX_ROW_START_CHARPOS (row) @@ -14651,6 +15072,7 @@ display_line (it) it->current_y += row->height; ++it->vpos; ++it->glyph_row; + it->start = it->current; return row->displays_text_p; } @@ -14894,6 +15316,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; @@ -14910,7 +15334,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; @@ -14993,6 +15416,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, @@ -15071,14 +15498,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); @@ -15086,9 +15514,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 @@ -15369,7 +15802,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; @@ -15390,7 +15824,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; @@ -15415,7 +15849,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 @@ -15451,15 +15885,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; @@ -15471,42 +15906,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 @@ -15582,37 +16021,152 @@ pint2str (buf, width, d) } } -/* Set a mnemonic character for coding_system (Lisp symbol) in BUF. - If EOL_FLAG is 1, set also a mnemonic character for end-of-line - type of CODING_SYSTEM. Return updated pointer into BUF. */ +/* Write a null-terminated, right justified decimal and "human + readable" representation of the nonnegative integer D to BUF using + a minimal field width WIDTH. D should be smaller than 999.5e24. */ -static unsigned char invalid_eol_type[] = "(*invalid*)"; +static const char power_letter[] = + { + 0, /* not used */ + 'k', /* kilo */ + 'M', /* mega */ + 'G', /* giga */ + 'T', /* tera */ + 'P', /* peta */ + 'E', /* exa */ + 'Z', /* zetta */ + 'Y' /* yotta */ + }; -static char * -decode_mode_spec_coding (coding_system, buf, eol_flag) - Lisp_Object coding_system; - register char *buf; - int eol_flag; +static void +pint2hrstr (buf, width, d) + char *buf; + int width; + int d; { - Lisp_Object val; - int multibyte = !NILP (current_buffer->enable_multibyte_characters); - const unsigned char *eol_str; - int eol_str_len; - /* The EOL conversion we are using. */ - Lisp_Object eoltype; + /* We aim to represent the nonnegative integer D as + QUOTIENT.TENTHS * 10 ^ (3 * EXPONENT). */ + int quotient = d; + int remainder = 0; + /* -1 means: do not use TENTHS. */ + int tenths = -1; + int exponent = 0; - val = Fget (coding_system, Qcoding_system); - eoltype = Qnil; + /* Length of QUOTIENT.TENTHS as a string. */ + int length; - if (!VECTORP (val)) /* Not yet decided. */ + char * psuffix; + char * p; + + if (1000 <= quotient) { - if (multibyte) - *buf++ = '-'; - if (eol_flag) - eoltype = eol_mnemonic_undecided; - /* Don't mention EOL conversion if it isn't decided. */ - } - else + /* Scale to the appropriate EXPONENT. */ + do + { + remainder = quotient % 1000; + quotient /= 1000; + exponent++; + } + while (1000 <= quotient); + + /* Round to nearest and decide whether to use TENTHS or not. */ + if (quotient <= 9) + { + tenths = remainder / 100; + if (50 <= remainder % 100) + { + 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; + } + } + } + + /* Calculate the LENGTH of QUOTIENT.TENTHS as a string. */ + if (tenths == -1 && quotient <= 99) + if (quotient <= 9) + length = 1; + else + length = 2; + else + length = 3; + p = psuffix = buf + max (width, length); + + /* Print EXPONENT. */ + if (exponent) + *psuffix++ = power_letter[exponent]; + *psuffix = '\0'; + + /* Print TENTHS. */ + if (tenths >= 0) + { + *--p = '0' + tenths; + *--p = '.'; + } + + /* Print QUOTIENT. */ + do + { + int digit = quotient % 10; + *--p = '0' + digit; + } + while ((quotient /= 10) != 0); + + /* Print leading spaces. */ + while (buf < p) + *--p = ' '; +} + +/* Set a mnemonic character for coding_system (Lisp symbol) in BUF. + If EOL_FLAG is 1, set also a mnemonic character for end-of-line + type of CODING_SYSTEM. Return updated pointer into BUF. */ + +static unsigned char invalid_eol_type[] = "(*invalid*)"; + +static char * +decode_mode_spec_coding (coding_system, buf, eol_flag) + Lisp_Object coding_system; + register char *buf; + int eol_flag; +{ + Lisp_Object val; + int multibyte = !NILP (current_buffer->enable_multibyte_characters); + const unsigned char *eol_str; + int eol_str_len; + /* The EOL conversion we are using. */ + Lisp_Object eoltype; + + val = Fget (coding_system, Qcoding_system); + eoltype = Qnil; + + if (!VECTORP (val)) /* Not yet decided. */ + { + if (multibyte) + *buf++ = '-'; + if (eol_flag) + eoltype = eol_mnemonic_undecided; + /* Don't mention EOL conversion if it isn't decided. */ + } + else { Lisp_Object eolvalue; @@ -15668,7 +16222,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[] = "--------------------------------------------------------------------------------------------------------------------------------------------"; @@ -15682,7 +16239,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; @@ -15784,6 +16341,20 @@ decode_mode_spec (w, c, field_width, precision, multibyte) obj = b->filename; break; + case 'i': + { + int size = ZV - BEGV; + pint2str (decode_mode_spec_buf, field_width, size); + return decode_mode_spec_buf; + } + + case 'I': + { + int size = ZV - BEGV; + pint2hrstr (decode_mode_spec_buf, field_width, size); + return decode_mode_spec_buf; + } + case 'l': { int startpos = XMARKER (w->start)->charpos; @@ -15970,7 +16541,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 @@ -16229,6 +16800,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. */ @@ -16288,6 +16860,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; } @@ -16399,6 +16973,252 @@ invisible_p (propval, list) return 0; } +/* 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 + right-fringe - right fringe width in pixels + + left-margin - left margin width in pixels + right-margin - right margin width in pixels + + scroll-bar - scroll-bar area width in pixels + + Examples: + + Pixels corresponding to 5 inches: + (5 . in) + + 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) + + 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))) + + 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))) + + Center 1 character over left-margin (in header line): + '(space :align-to (+ left-margin (0.5 . left-margin) -0.5)) + + 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))) + +*/ + +#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 @@ -16478,7 +17298,8 @@ init_glyph_string (s, OPTIONAL_HDC (hdc) char2b, w, row, area, start, hl) s->y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y); /* Display the internal border below the tool-bar 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)) s->y -= FRAME_INTERNAL_BORDER_WIDTH (s->f); s->ybase = s->y + row->ascent; @@ -16738,6 +17559,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; @@ -17449,6 +18271,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. */ @@ -17469,6 +18304,8 @@ append_glyph (it) glyph->charpos = CHARPOS (it->position); glyph->object = it->object; glyph->pixel_width = it->pixel_width; + glyph->ascent = it->ascent; + glyph->descent = it->descent; glyph->voffset = it->voffset; glyph->type = CHAR_GLYPH; glyph->multibyte_p = it->multibyte_p; @@ -17480,9 +18317,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. @@ -17503,6 +18343,8 @@ append_composite_glyph (it) glyph->charpos = CHARPOS (it->position); glyph->object = it->object; glyph->pixel_width = it->pixel_width; + glyph->ascent = it->ascent; + glyph->descent = it->descent; glyph->voffset = it->voffset; glyph->type = COMPOSITE_GLYPH; glyph->multibyte_p = it->multibyte_p; @@ -17514,9 +18356,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); } @@ -17532,7 +18377,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. */ @@ -17551,20 +18396,93 @@ produce_image_glyph (it) { struct image *img; struct face *face; + int glyph_ascent; + struct glyph_slice slice; xassert (it->what == IT_IMAGE); face = FACE_FROM_ID (it->f, it->face_id); + xassert (face); + /* Make sure X resources of the face is loaded. */ + PREPARE_FACE_FOR_DISPLAY (it->f, face); + + if (it->image_id < 0) + { + /* Fringe bitmap. */ + it->ascent = it->phys_ascent = 0; + it->descent = it->phys_descent = 0; + it->pixel_width = 0; + it->nglyphs = 0; + return; + } + img = IMAGE_FROM_ID (it->f, it->image_id); xassert (img); - - /* Make sure X resources of the face and image are loaded. */ - PREPARE_FACE_FOR_DISPLAY (it->f, face); + /* Make sure X resources of the image is loaded. */ prepare_image_for_display (it->f, img); - it->ascent = it->phys_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; + 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; + + it->ascent = it->phys_ascent = glyph_ascent = image_ascent (img, face, &slice); + + 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; + + /* 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; + +#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 it->nglyphs = 1; @@ -17572,13 +18490,15 @@ produce_image_glyph (it) { if (face->box_line_width > 0) { - it->ascent += face->box_line_width; - it->descent += face->box_line_width; + if (slice.y == 0) + it->ascent += face->box_line_width; + if (slice.y + slice.height == img->height) + it->descent += face->box_line_width; } - if (it->start_of_box_run_p) + 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) + if (it->end_of_box_run_p && slice.x + slice.width == img->width) it->pixel_width += abs (face->box_line_width); } @@ -17595,6 +18515,8 @@ produce_image_glyph (it) 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; @@ -17605,29 +18527,31 @@ produce_image_glyph (it) 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); } } /* 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 percentage/100 of HEIGHT to use for the - ascent of the glyph (0 <= ASCENT <= 1). */ + 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; - double ascent; + int ascent; { struct glyph *glyph; enum glyph_row_area area = it->area; - xassert (ascent >= 0 && ascent <= 1); + xassert (ascent >= 0 && ascent <= height); glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area]; if (glyph < it->glyph_row->glyphs[area + 1]) @@ -17635,6 +18559,8 @@ append_stretch_glyph (it, object, width, height, ascent) 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; @@ -17644,11 +18570,14 @@ append_stretch_glyph (it, object, width, height, ascent) glyph->padding_p = 0; glyph->glyph_not_available_p = 0; glyph->face_id = it->face_id; - glyph->u.stretch.ascent = height * ascent; + 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]; } + else + IT_EXPAND_MATRIX_WIDTH (it, area); } @@ -17683,20 +18612,16 @@ append_stretch_glyph (it, object, width, height, ascent) of the stretch should be used for the ascent of the stretch. ASCENT must be in the range 0 <= ASCENT <= 100. */ -#define NUMVAL(X) \ - ((INTEGERP (X) || FLOATP (X)) \ - ? XFLOATINT (X) \ - : - 1) - - static void produce_stretch_glyph (it) struct it *it; { - /* (space :width WIDTH :height HEIGHT. */ + /* (space :width WIDTH :height HEIGHT ...) */ Lisp_Object prop, plist; - int width = 0, height = 0; - double ascent = 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; struct face *face = FACE_FROM_ID (it->f, it->face_id); XFontStruct *font = face->font ? face->font : FRAME_FONT (it->f); @@ -17707,11 +18632,14 @@ produce_stretch_glyph (it) plist = XCDR (it->object); /* Compute the width of the stretch. */ - if (prop = Fplist_get (plist, QCwidth), - NUMVAL (prop) > 0) - /* Absolute width `:width WIDTH' specified and valid. */ - width = NUMVAL (prop) * FRAME_COLUMN_WIDTH (it->f); - else if (prop = Fplist_get (plist, QCrelative_width), + 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 = Fsafe_plist_get (plist, QCrelative_width), NUMVAL (prop) > 0) { /* Relative width `:relative-width FACTOR' specified and valid. @@ -17735,38 +18663,54 @@ produce_stretch_glyph (it) x_produce_glyphs (&it2); width = NUMVAL (prop) * it2.pixel_width; } - else if (prop = Fplist_get (plist, QCalign_to), - NUMVAL (prop) > 0) - width = NUMVAL (prop) * FRAME_COLUMN_WIDTH (it->f) - it->current_x; + else if ((prop = Fsafe_plist_get (plist, QCalign_to), !NILP (prop)) + && calc_pixel_width_or_height (&tem, it, prop, font, 1, &align_to)) + { + 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 /* Nothing specified -> width defaults to canonical char width. */ width = FRAME_COLUMN_WIDTH (it->f); + if (width <= 0 && (width < 0 || !zero_width_ok_p)) + width = 1; + /* Compute height. */ - if (prop = Fplist_get (plist, QCheight), - NUMVAL (prop) > 0) - height = NUMVAL (prop) * FRAME_LINE_HEIGHT (it->f); - else if (prop = Fplist_get (plist, QCrelative_height), + 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 = Fsafe_plist_get (plist, QCrelative_height), NUMVAL (prop) > 0) height = FONT_HEIGHT (font) * NUMVAL (prop); else height = FONT_HEIGHT (font); + if (height <= 0 && (height < 0 || !zero_height_ok_p)) + height = 1; + /* 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 = NUMVAL (prop) / 100.0; + ascent = height * NUMVAL (prop) / 100.0; + else if (!NILP (prop) + && calc_pixel_width_or_height (&tem, it, prop, font, 0, 0)) + ascent = min (max (0, (int)tem), height); else - ascent = (double) FONT_BASE (font) / FONT_HEIGHT (font); + ascent = (height * FONT_BASE (font)) / FONT_HEIGHT (font); - if (width <= 0) - width = 1; - if (height <= 0) - height = 1; - - if (it->glyph_row) + if (width > 0 && height > 0 && it->glyph_row) { Lisp_Object object = it->stack[it->sp - 1].string; if (!STRINGP (object)) @@ -17775,11 +18719,11 @@ produce_stretch_glyph (it) } it->pixel_width = width; - it->ascent = it->phys_ascent = height * ascent; + it->ascent = it->phys_ascent = ascent; it->descent = it->phys_descent = height - it->ascent; - it->nglyphs = 1; + it->nglyphs = width > 0 && height > 0 ? 1 : 0; - if (face->box != FACE_NO_BOX) + if (width > 0 && height > 0 && face->box != FACE_NO_BOX) { if (face->box_line_width > 0) { @@ -17796,6 +18740,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, ' '); + 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 @@ -17805,6 +18852,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) @@ -17882,8 +18931,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) { @@ -17894,11 +18953,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); @@ -17931,6 +19007,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. */ @@ -17940,8 +19024,8 @@ x_produce_glyphs (it) { /* Translate a space with a `space-width' property into a stretch glyph. */ - double ascent = (double) FONT_BASE (font) - / FONT_HEIGHT (font); + int ascent = (((it->ascent + it->descent) * FONT_BASE (font)) + / FONT_HEIGHT (font)); append_stretch_glyph (it, it->object, it->pixel_width, it->ascent + it->descent, ascent); } @@ -17957,17 +19041,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))) + { + 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 { - it->ascent += face->box_line_width; - it->descent += face->box_line_width; + 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') @@ -17989,9 +19129,8 @@ x_produce_glyphs (it) if (it->glyph_row) { - double ascent = (double) it->ascent / (it->ascent + it->descent); append_stretch_glyph (it, it->object, it->pixel_width, - it->ascent + it->descent, ascent); + it->ascent + it->descent, it->ascent); } } else @@ -18346,7 +19485,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); @@ -18534,7 +19678,7 @@ x_clear_end_of_line (to_x) ARG. If type is BAR_CURSOR, return in *WIDTH the specified width of the bar cursor. */ -enum text_cursor_kinds +static enum text_cursor_kinds get_specified_cursor_type (arg, width) Lisp_Object arg; int *width; @@ -18625,9 +19769,10 @@ set_frame_cursor_types (f, arg) setting of cursor-type. If explicitly marked off, draw no cursor. In all other cases, we want a hollow box cursor. */ -enum text_cursor_kinds -get_window_cursor_type (w, width, active_cursor) +static enum text_cursor_kinds +get_window_cursor_type (w, glyph, width, active_cursor) struct window *w; + struct glyph *glyph; int *width; int *active_cursor; { @@ -18691,7 +19836,13 @@ get_window_cursor_type (w, width, active_cursor) /* Use normal cursor if not blinked off. */ if (!w->cursor_off_p) - return cursor_type; + { + if (glyph != NULL && glyph->type == IMAGE_GLYPH) { + if (cursor_type == FILLED_BOX_CURSOR) + cursor_type = HOLLOW_BOX_CURSOR; + } + return cursor_type; + } /* Cursor is blinked off, so determine how to "toggle" it. */ @@ -18706,6 +19857,11 @@ get_window_cursor_type (w, width, active_cursor) return FRAME_BLINK_OFF_CURSOR (f); } +#if 0 + /* Some people liked having a permanently visible blinking cursor, + while others had very strong opinions against it. So it was + decided to remove it. KFS 2003-09-03 */ + /* Finally perform built-in cursor blinking: filled box <-> hollow box wide [h]bar <-> narrow [h]bar @@ -18720,6 +19876,7 @@ get_window_cursor_type (w, width, active_cursor) *width = 1; return cursor_type; } +#endif return NO_CURSOR; } @@ -18740,36 +19897,53 @@ notice_overwritten_cursor (w, area, x0, x1, y0, y1) enum glyph_row_area area; int x0, y0, x1, y1; { - if (area == TEXT_AREA && w->phys_cursor_on_p) - { - int cx0 = w->phys_cursor.x; - int cx1 = cx0 + w->phys_cursor_width; - int cy0 = w->phys_cursor.y; - int cy1 = cy0 + w->phys_cursor_height; + int cx0, cx1, cy0, cy1; + struct glyph_row *row; - if (x0 <= cx0 && (x1 < 0 || x1 >= cx1)) - { - /* The cursor image will be completely removed from the - screen if the output area intersects the cursor area in - y-direction. When we draw in [y0 y1[, and some part of - the cursor is at y < y0, that part must have been drawn - before. When scrolling, the cursor is erased before - actually scrolling, so we don't come here. When not - scrolling, the rows above the old cursor row must have - changed, and in this case these rows must have written - over the cursor image. + if (!w->phys_cursor_on_p) + return; + if (area != TEXT_AREA) + return; - Likewise if part of the cursor is below y1, with the - exception of the cursor being in the first blank row at - the buffer and window end because update_text_area - doesn't draw that row. (Except when it does, but - that's handled in update_text_area.) */ + row = w->current_matrix->rows + w->phys_cursor.vpos; + if (!row->displays_text_p) + return; - if (((y0 >= cy0 && y0 < cy1) || (y1 > cy0 && y1 < cy1)) - && w->current_matrix->rows[w->phys_cursor.vpos].displays_text_p) - w->phys_cursor_on_p = 0; - } + if (row->cursor_in_fringe_p) + { + row->cursor_in_fringe_p = 0; + draw_fringe_bitmap (w, row, 0); + w->phys_cursor_on_p = 0; + return; } + + cx0 = w->phys_cursor.x; + cx1 = cx0 + w->phys_cursor_width; + if (x0 > cx0 || (x1 >= 0 && x1 < cx1)) + return; + + /* The cursor image will be completely removed from the + screen if the output area intersects the cursor area in + y-direction. When we draw in [y0 y1[, and some part of + the cursor is at y < y0, that part must have been drawn + before. When scrolling, the cursor is erased before + actually scrolling, so we don't come here. When not + scrolling, the rows above the old cursor row must have + changed, and in this case these rows must have written + over the cursor image. + + Likewise if part of the cursor is below y1, with the + exception of the cursor being in the first blank row at + the buffer and window end because update_text_area + doesn't draw that row. (Except when it does, but + that's handled in update_text_area.) */ + + cy0 = w->phys_cursor.y; + cy1 = cy0 + w->phys_cursor_height; + if ((y0 < cy0 || y0 >= cy1) && (y1 <= cy0 || y1 >= cy1)) + return; + + w->phys_cursor_on_p = 0; } #endif /* HAVE_WINDOW_SYSTEM */ @@ -18898,12 +20072,25 @@ 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. */ if (cursor_row->visible_height <= 0) goto mark_cursor_off; + /* If cursor is in the fringe, erase by drawing actual bitmap there. */ + if (cursor_row->cursor_in_fringe_p) + { + cursor_row->cursor_in_fringe_p = 0; + draw_fringe_bitmap (w, cursor_row, 0); + goto mark_cursor_off; + } + /* This can happen when the new row is shorter than the old one. In this case, either draw_glyphs or clear_end_of_line should have cleared the cursor. Note that we wouldn't be @@ -18933,6 +20120,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) @@ -18940,9 +20128,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. */ @@ -18972,7 +20161,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; @@ -18990,10 +20178,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) @@ -19002,10 +20187,16 @@ 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. */ - new_cursor_type = get_window_cursor_type (w, &new_cursor_width, &active_cursor); + new_cursor_type = get_window_cursor_type (w, glyph, + &new_cursor_width, &active_cursor); /* If cursor is currently being shown and we don't want it to be or it is in the wrong place, or the cursor type is not what we want, @@ -19202,7 +20393,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; @@ -19273,19 +20464,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; @@ -19319,7 +20511,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 */ @@ -19505,6 +20697,186 @@ fast_find_string_pos (w, pos, object, hpos, vpos, x, y, right_p) } +/* See if position X, Y is within a hot-spot of an image. */ + +static int +on_hot_spot_p (hot_spot, x, y) + Lisp_Object hot_spot; + int x, y; +{ + if (!CONSP (hot_spot)) + return 0; + + if (EQ (XCAR (hot_spot), Qrect)) + { + /* CDR is (Top-Left . Bottom-Right) = ((x0 . y0) . (x1 . y1)) */ + Lisp_Object rect = XCDR (hot_spot); + Lisp_Object tem; + if (!CONSP (rect)) + return 0; + if (!CONSP (XCAR (rect))) + return 0; + if (!CONSP (XCDR (rect))) + return 0; + if (!(tem = XCAR (XCAR (rect)), INTEGERP (tem) && x >= XINT (tem))) + return 0; + if (!(tem = XCDR (XCAR (rect)), INTEGERP (tem) && y >= XINT (tem))) + return 0; + if (!(tem = XCAR (XCDR (rect)), INTEGERP (tem) && x <= XINT (tem))) + return 0; + if (!(tem = XCDR (XCDR (rect)), INTEGERP (tem) && y <= XINT (tem))) + return 0; + return 1; + } + else if (EQ (XCAR (hot_spot), Qcircle)) + { + /* CDR is (Center . Radius) = ((x0 . y0) . r) */ + Lisp_Object circ = XCDR (hot_spot); + Lisp_Object lr, lx0, ly0; + if (CONSP (circ) + && CONSP (XCAR (circ)) + && (lr = XCDR (circ), INTEGERP (lr) || FLOATP (lr)) + && (lx0 = XCAR (XCAR (circ)), INTEGERP (lx0)) + && (ly0 = XCDR (XCAR (circ)), INTEGERP (ly0))) + { + double r = XFLOATINT (lr); + double dx = XINT (lx0) - x; + double dy = XINT (ly0) - y; + return (dx * dx + dy * dy <= r * r); + } + } + else if (EQ (XCAR (hot_spot), Qpoly)) + { + /* CDR is [x0 y0 x1 y1 x2 y2 ...x(n-1) y(n-1)] */ + if (VECTORP (XCDR (hot_spot))) + { + struct Lisp_Vector *v = XVECTOR (XCDR (hot_spot)); + Lisp_Object *poly = v->contents; + int n = v->size; + int i; + int inside = 0; + Lisp_Object lx, ly; + int x0, y0; + + /* Need an even number of coordinates, and at least 3 edges. */ + if (n < 6 || n & 1) + return 0; + + /* Count edge segments intersecting line from (X,Y) to (X,infinity). + If count is odd, we are inside polygon. Pixels on edges + may or may not be included depending on actual geometry of the + polygon. */ + if ((lx = poly[n-2], !INTEGERP (lx)) + || (ly = poly[n-1], !INTEGERP (lx))) + return 0; + x0 = XINT (lx), y0 = XINT (ly); + for (i = 0; i < n; i += 2) + { + int x1 = x0, y1 = y0; + if ((lx = poly[i], !INTEGERP (lx)) + || (ly = poly[i+1], !INTEGERP (ly))) + return 0; + x0 = XINT (lx), y0 = XINT (ly); + + /* Does this segment cross the X line? */ + if (x0 >= x) + { + if (x1 >= x) + continue; + } + else if (x1 < x) + continue; + if (y > y0 && y > y1) + continue; + if (y < y0 + ((y1 - y0) * (x - x0)) / (x1 - x0)) + inside = !inside; + } + return inside; + } + } + /* If we don't understand the format, pretend we're not in the hot-spot. */ + return 0; +} + +Lisp_Object +find_hot_spot (map, x, y) + Lisp_Object map; + int x, y; +{ + while (CONSP (map)) + { + if (CONSP (XCAR (map)) + && on_hot_spot_p (XCAR (XCAR (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. +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 +pixel coordinates of the upper left and bottom right corners. +A circle is a cons (circle . ((x0 . y0) . r)) specifying the center +and the radius of the circle; r may be a float or integer. +A polygon is a cons (poly . [x0 y0 x1 y1 ...]) where each pair in the +vector describes one corner in the polygon. +Returns the alist element for the first matching AREA in MAP. */) + (map, x, y) + Lisp_Object map; + Lisp_Object x, y; +{ + if (NILP (map)) + return Qnil; + + CHECK_NUMBER (x); + CHECK_NUMBER (y); + + return find_hot_spot (map, XINT (x), XINT (y)); +} + + +/* Display frame CURSOR, optionally using shape defined by POINTER. */ +static void +define_frame_cursor1 (f, cursor, pointer) + struct frame *f; + 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)) + cursor = FRAME_X_OUTPUT (f)->nontext_cursor; + else if (EQ (pointer, Qhand)) + cursor = FRAME_X_OUTPUT (f)->hand_cursor; + else if (EQ (pointer, Qtext)) + cursor = FRAME_X_OUTPUT (f)->text_cursor; + else if (EQ (pointer, intern ("hdrag"))) + cursor = FRAME_X_OUTPUT (f)->horizontal_drag_cursor; +#ifdef HAVE_X_WINDOWS + else if (EQ (pointer, intern ("vdrag"))) + cursor = FRAME_X_DISPLAY_INFO (f)->vertical_scroll_bar_cursor; +#endif + else if (EQ (pointer, intern ("hourglass"))) + cursor = FRAME_X_OUTPUT (f)->hourglass_cursor; + else if (EQ (pointer, Qmodeline)) + cursor = FRAME_X_OUTPUT (f)->modeline_cursor; + else + cursor = FRAME_X_OUTPUT (f)->nontext_cursor; + } + + if (cursor != No_Cursor) + rif->define_frame_cursor (f, cursor); +} + /* Take proper action when mouse has moved to the mode or header line or marginal area AREA of window W, x-position X and y-position Y. X is relative to the start of the text display area of W, so the @@ -19519,40 +20891,95 @@ note_mode_line_or_margin_highlight (w, x, y, area) { struct frame *f = XFRAME (w->frame); Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f); - Cursor cursor = dpyinfo->vertical_scroll_bar_cursor; - int charpos; - Lisp_Object string, help, map, pos; + Cursor cursor = FRAME_X_OUTPUT (f)->nontext_cursor; + Lisp_Object pointer = Qnil; + int charpos, dx, dy, width, height; + Lisp_Object string, object = Qnil; + Lisp_Object pos, help; if (area == ON_MODE_LINE || area == ON_HEADER_LINE) - string = mode_line_string (w, x, y, area, &charpos); + string = mode_line_string (w, area, &x, &y, &charpos, + &object, &dx, &dy, &width, &height); else - string = marginal_area_string (w, x, y, area, &charpos); + { + x -= WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (w); + string = marginal_area_string (w, area, &x, &y, &charpos, + &object, &dx, &dy, &width, &height); + } + + help = Qnil; + + if (IMAGEP (object)) + { + Lisp_Object image_map, hotspot; + if ((image_map = Fsafe_plist_get (XCDR (object), QCmap), + !NILP (image_map)) + && (hotspot = find_hot_spot (image_map, dx, dy), + CONSP (hotspot)) + && (hotspot = XCDR (hotspot), CONSP (hotspot))) + { + Lisp_Object area_id, plist; + + area_id = XCAR (hotspot); + /* 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...). */ + hotspot = XCDR (hotspot); + if (CONSP (hotspot) + && (plist = XCAR (hotspot), CONSP (plist))) + { + pointer = Fsafe_plist_get (plist, Qpointer); + if (NILP (pointer)) + pointer = Qhand; + help = Fsafe_plist_get (plist, Qhelp_echo); + if (!NILP (help)) + { + help_echo_string = help; + /* Is this correct? ++kfs */ + XSETWINDOW (help_echo_window, w); + help_echo_object = w->buffer; + help_echo_pos = charpos; + } + } + if (NILP (pointer)) + pointer = Fsafe_plist_get (XCDR (object), QCpointer); + } + } if (STRINGP (string)) { pos = make_number (charpos); - /* 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. */ - map = Fget_text_property (pos, Qlocal_map, string); - if (!KEYMAPP (map)) - map = Fget_text_property (pos, Qkeymap, string); - if (KEYMAPP (map)) - cursor = FRAME_X_OUTPUT (f)->nontext_cursor; + if (NILP (pointer) && ((area == ON_MODE_LINE) || (area == ON_HEADER_LINE))) + { + Lisp_Object map; + map = Fget_text_property (pos, Qlocal_map, string); + if (!KEYMAPP (map)) + map = Fget_text_property (pos, Qkeymap, string); + if (!KEYMAPP (map)) + cursor = dpyinfo->vertical_scroll_bar_cursor; + } } - rif->define_frame_cursor (f, cursor); + define_frame_cursor1 (f, cursor, pointer); } @@ -19572,6 +20999,7 @@ note_mouse_highlight (f, x, y) Lisp_Object window; struct window *w; Cursor cursor = No_Cursor; + Lisp_Object pointer = Qnil; /* Takes precedence over cursor! */ struct buffer *b; /* When a menu is active, don't highlight because this looks odd. */ @@ -19600,8 +21028,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. */ @@ -19609,7 +21039,6 @@ note_mouse_highlight (f, x, y) return; /* Reset help_echo_string. It will get recomputed below. */ - /* ++KFS: X version didn't do this, but it looks harmless. */ help_echo_string = Qnil; /* Convert to window-relative pixel coordinates. */ @@ -19634,6 +21063,9 @@ 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 + || part == ON_SCROLL_BAR) + cursor = FRAME_X_OUTPUT (f)->nontext_cursor; else cursor = FRAME_X_OUTPUT (f)->text_cursor; @@ -19645,31 +21077,74 @@ note_mouse_highlight (f, x, y) && XFASTINT (w->last_modified) == BUF_MODIFF (b) && XFASTINT (w->last_overlay_modified) == BUF_OVERLAY_MODIFF (b)) { - int hpos, vpos, pos, i, area; + int hpos, vpos, pos, i, dx, dy, area; struct glyph *glyph; 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; /* Find the glyph under X/Y. */ - glyph = x_y_to_hpos_vpos (w, x, y, &hpos, &vpos, &area, 0); + glyph = x_y_to_hpos_vpos (w, x, y, &hpos, &vpos, &dx, &dy, &area); + + /* Look for :pointer property on image. */ + if (glyph != NULL && glyph->type == IMAGE_GLYPH) + { + struct image *img = IMAGE_FROM_ID (f, glyph->u.img_id); + if (img != NULL && IMAGEP (img->spec)) + { + Lisp_Object image_map, hotspot; + if ((image_map = Fsafe_plist_get (XCDR (img->spec), QCmap), + !NILP (image_map)) + && (hotspot = find_hot_spot (image_map, + glyph->slice.x + dx, + glyph->slice.y + dy), + CONSP (hotspot)) + && (hotspot = XCDR (hotspot), CONSP (hotspot))) + { + Lisp_Object area_id, plist; + + area_id = XCAR (hotspot); + /* 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...). */ + hotspot = XCDR (hotspot); + if (CONSP (hotspot) + && (plist = XCAR (hotspot), CONSP (plist))) + { + pointer = Fsafe_plist_get (plist, Qpointer); + if (NILP (pointer)) + pointer = Qhand; + help_echo_string = Fsafe_plist_get (plist, Qhelp_echo); + if (!NILP (help_echo_string)) + { + help_echo_window = window; + help_echo_object = glyph->object; + help_echo_pos = glyph->charpos; + } + } + } + if (NILP (pointer)) + pointer = Fsafe_plist_get (XCDR (img->spec), QCpointer); + } + } /* Clear mouse face if X/Y not over text. */ if (glyph == NULL || area != TEXT_AREA || !MATRIX_ROW (w->current_matrix, vpos)->displays_text_p) { -#if defined (HAVE_NTGUI) - /* ++KFS: Why is this necessary on W32 ? */ - clear_mouse_face (dpyinfo); - cursor = FRAME_X_OUTPUT (f)->nontext_cursor; -#else if (clear_mouse_face (dpyinfo)) cursor = No_Cursor; -#endif + if (NILP (pointer)) + { + if (area != TEXT_AREA) + cursor = FRAME_X_OUTPUT (f)->nontext_cursor; + else + pointer = Vvoid_text_area_pointer; + } goto set_cursor; } @@ -19696,19 +21171,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); } @@ -19925,7 +21389,7 @@ note_mouse_highlight (f, x, y) check_help_echo: /* Look for a `help-echo' property. */ - { + if (NILP (help_echo_string)) { Lisp_Object help, overlay; /* Check overlays first. */ @@ -19991,6 +21455,46 @@ note_mouse_highlight (f, x, y) } } + /* Look for a `pointer' property. */ + if (NILP (pointer)) + { + /* Check overlays first. */ + for (i = noverlays - 1; i >= 0 && NILP (pointer); --i) + pointer = Foverlay_get (overlay_vec[i], Qpointer); + + if (NILP (pointer)) + { + Lisp_Object object = glyph->object; + int charpos = glyph->charpos; + + /* Try text properties. */ + if (STRINGP (object) + && charpos >= 0 + && charpos < SCHARS (object)) + { + pointer = Fget_text_property (make_number (charpos), + Qpointer, object); + if (NILP (pointer)) + { + /* If the string itself doesn't specify a pointer, + see if the buffer text ``under'' it does. */ + struct glyph_row *r + = MATRIX_ROW (w->current_matrix, vpos); + int start = MATRIX_ROW_START_CHARPOS (r); + int pos = string_buffer_position (w, object, start); + if (pos > 0) + pointer = Fget_char_property (make_number (pos), + Qpointer, w->buffer); + } + } + else if (BUFFERP (object) + && charpos >= BEGV + && charpos < ZV) + pointer = Fget_text_property (make_number (charpos), + Qpointer, object); + } + } + BEGV = obegv; ZV = ozv; current_buffer = obuf; @@ -19998,12 +21502,7 @@ note_mouse_highlight (f, x, y) set_cursor: -#ifndef HAVE_CARBON - if (cursor != No_Cursor) -#else - if (bcmp (&cursor, &No_Cursor, sizeof (Cursor))) -#endif - rif->define_frame_cursor (f, cursor); + define_frame_cursor1 (f, cursor, pointer); } @@ -20083,9 +21582,9 @@ expose_area (w, row, r, area) AREA. The first glyph of the text area can be partially visible. The first glyphs of other areas cannot. */ start_x = window_box_left_offset (w, area); - if (area == TEXT_AREA) - start_x += row->x; x = start_x; + if (area == TEXT_AREA) + x += row->x; /* Find the first glyph that must be redrawn. */ while (first < end @@ -20191,13 +21690,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); } @@ -20215,13 +21714,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)) { @@ -20599,6 +22101,7 @@ syms_of_xdisp () #endif #ifdef HAVE_WINDOW_SYSTEM defsubr (&Stool_bar_lines_needed); + defsubr (&Slookup_image_map); #endif defsubr (&Sformat_mode_line); @@ -20628,20 +22131,26 @@ syms_of_xdisp () staticpro (&Qspace_width); Qraise = intern ("raise"); staticpro (&Qraise); + Qslice = intern ("slice"); + staticpro (&Qslice); Qspace = intern ("space"); staticpro (&Qspace); Qmargin = intern ("margin"); staticpro (&Qmargin); + Qpointer = intern ("pointer"); + staticpro (&Qpointer); Qleft_margin = intern ("left-margin"); staticpro (&Qleft_margin); Qright_margin = intern ("right-margin"); staticpro (&Qright_margin); - Qalign_to = intern ("align-to"); - staticpro (&Qalign_to); + 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); - Qrelative_width = intern ("relative-width"); - staticpro (&Qrelative_width); QCrelative_width = intern (":relative-width"); staticpro (&QCrelative_width); QCrelative_height = intern (":relative-height"); @@ -20660,6 +22169,16 @@ syms_of_xdisp () staticpro (&Qtrailing_whitespace); Qimage = intern ("image"); staticpro (&Qimage); + QCmap = intern (":map"); + staticpro (&QCmap); + QCpointer = intern (":pointer"); + staticpro (&QCpointer); + Qrect = intern ("rect"); + staticpro (&Qrect); + Qcircle = intern ("circle"); + staticpro (&Qcircle); + Qpoly = intern ("poly"); + staticpro (&Qpoly); Qmessage_truncate_lines = intern ("message-truncate-lines"); staticpro (&Qmessage_truncate_lines); Qcursor_in_non_selected_windows = intern ("cursor-in-non-selected-windows"); @@ -20684,18 +22203,31 @@ syms_of_xdisp () staticpro (&Qbox); Qhollow = intern ("hollow"); staticpro (&Qhollow); + Qhand = intern ("hand"); + staticpro (&Qhand); + Qarrow = intern ("arrow"); + staticpro (&Qarrow); + Qtext = intern ("text"); + staticpro (&Qtext); Qrisky_local_variable = intern ("risky-local-variable"); staticpro (&Qrisky_local_variable); 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]); @@ -20733,10 +22265,16 @@ wide as that tab on the display. */); #endif DEFVAR_LISP ("show-trailing-whitespace", &Vshow_trailing_whitespace, - doc: /* Non-nil means highlight trailing whitespace. + doc: /* *Non-nil means highlight trailing whitespace. The face used for trailing whitespace is `trailing-whitespace'. */); Vshow_trailing_whitespace = Qnil; + 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'. */); + Vvoid_text_area_pointer = Qarrow; + DEFVAR_LISP ("inhibit-redisplay", &Vinhibit_redisplay, doc: /* Non-nil means don't actually do any redisplay. This is used for internal purposes. */); @@ -20753,9 +22291,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. @@ -20775,6 +22321,11 @@ Recenter the window whenever point gets within this many lines of the top or bottom of the window. */); scroll_margin = 0; + DEFVAR_LISP ("display-pixels-per-inch", &Vdisplay_pixels_per_inch, + doc: /* Pixels per inch on current display. +Value is a number or a cons (WIDTH-DPI . HEIGHT-DPI). */); + Vdisplay_pixels_per_inch = make_float (72.0); + #if GLYPH_DEBUG DEFVAR_INT ("debug-end-pos", &debug_end_pos, doc: /* Don't ask. */); #endif @@ -20819,6 +22370,7 @@ This variable is not guaranteed to be accurate except while processing This variable has the same structure as `mode-line-format' (which see), and is used only on frames for which no explicit name has been set \(see `modify-frame-parameters'). */); + DEFVAR_LISP ("icon-title-format", &Vicon_title_format, doc: /* Template for displaying the title bar of an iconified frame. \(Assuming the window manager supports this feature.) @@ -20851,7 +22403,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. */); @@ -20872,6 +22424,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. @@ -20957,11 +22513,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. */); @@ -21052,3 +22603,5 @@ init_xdisp () } +/* arch-tag: eacc864d-bb6a-4b74-894a-1a4399a1358b + (do not change this comment) */