X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/bf7f1d30f5e15d96df040bffe931275de92b5ebb..61e1d1ca4f04460699287e66a57e722328a641be:/src/xdisp.c?ds=sidebyside diff --git a/src/xdisp.c b/src/xdisp.c index 0a038ea7e6..8dc34b776c 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -256,9 +256,9 @@ Lisp_Object list_of_error; Lisp_Object Vfontification_functions; Lisp_Object Qfontification_functions; -/* Non-zero means automatically select any window when the mouse +/* Non-nil means automatically select any window when the mouse cursor moves into it. */ -int mouse_autoselect_window; +Lisp_Object Vmouse_autoselect_window; /* Non-zero means draw tool bar buttons raised when the mouse moves over them. */ @@ -269,6 +269,12 @@ int auto_raise_tool_bar_buttons_p; int make_cursor_line_fully_visible_p; +/* Margin below tool bar in pixels. 0 or nil means no margin. + If value is `internal-border-width' or `border-width', + the corresponding frame parameter is used. */ + +Lisp_Object Vtool_bar_border; + /* Margin around tool bar buttons in pixels. */ Lisp_Object Vtool_bar_button_margin; @@ -609,6 +615,11 @@ int message_buf_print; Lisp_Object Qinhibit_menubar_update; int inhibit_menubar_update; +/* When evaluating expressions from menu bar items (enable conditions, + for instance), this is the frame they are being processed for. */ + +Lisp_Object Vmenu_updating_frame; + /* Maximum height for resizing mini-windows. Either a float specifying a fraction of the available height, or an integer specifying a number of lines. */ @@ -704,6 +715,10 @@ Lisp_Object Vresize_mini_windows; struct buffer *displayed_buffer; +/* Space between overline and text. */ + +EMACS_INT overline_margin; + /* Value returned from text property handlers (see below). */ enum prop_handled @@ -852,7 +867,7 @@ static void store_mode_line_noprop_char P_ ((char)); static int store_mode_line_noprop P_ ((const unsigned char *, int, int)); static void x_consider_frame_title P_ ((Lisp_Object)); static void handle_stop P_ ((struct it *)); -static int tool_bar_lines_needed P_ ((struct frame *)); +static int tool_bar_lines_needed P_ ((struct frame *, int *)); static int single_display_spec_intangible_p P_ ((Lisp_Object)); static void ensure_echo_area_buffers P_ ((void)); static Lisp_Object unwind_with_echo_area_buffer P_ ((Lisp_Object)); @@ -894,7 +909,7 @@ static void redisplay_window P_ ((Lisp_Object, int)); static Lisp_Object redisplay_window_error (); static Lisp_Object redisplay_window_0 P_ ((Lisp_Object)); static Lisp_Object redisplay_window_1 P_ ((Lisp_Object)); -static void update_menu_bar P_ ((struct frame *, int)); +static int update_menu_bar P_ ((struct frame *, int, int)); static int try_window_reusing_current_matrix P_ ((struct window *)); static int try_window_id P_ ((struct window *)); static int display_line P_ ((struct it *)); @@ -910,6 +925,7 @@ static int display_string P_ ((unsigned char *, Lisp_Object, Lisp_Object, static void compute_line_metrics P_ ((struct it *)); static void run_redisplay_end_trigger_hook P_ ((struct it *)); static int get_overlay_strings P_ ((struct it *, int)); +static int get_overlay_strings_1 P_ ((struct it *, int, int)); 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)); @@ -963,7 +979,7 @@ static int in_ellipses_for_invisible_text_p P_ ((struct display_pos *, static void update_tool_bar P_ ((struct frame *, int)); static void build_desired_tool_bar_string P_ ((struct frame *f)); static int redisplay_tool_bar P_ ((struct frame *)); -static void display_tool_bar_line P_ ((struct it *)); +static void display_tool_bar_line P_ ((struct it *, int)); static void notice_overwritten_cursor P_ ((struct window *, enum glyph_row_area, int, int, int, int)); @@ -1259,15 +1275,15 @@ line_bottom_y (it) /* Return 1 if position CHARPOS is visible in window W. + CHARPOS < 0 means return info about WINDOW_END position. If visible, set *X and *Y to pixel coordinates of top left corner. Set *RTOP and *RBOT to pixel height of an invisible area of glyph at POS. - EXACT_MODE_LINE_HEIGHTS_P non-zero means compute exact mode-line - and header-lines heights. */ + Set *ROWH and *VPOS to row's visible height and VPOS (row number). */ int -pos_visible_p (w, charpos, x, y, rtop, rbot, exact_mode_line_heights_p) +pos_visible_p (w, charpos, x, y, rtop, rbot, rowh, vpos) struct window *w; - int charpos, *x, *y, *rtop, *rbot, exact_mode_line_heights_p; + int charpos, *x, *y, *rtop, *rbot, *rowh, *vpos; { struct it it; struct text_pos top; @@ -1285,26 +1301,23 @@ pos_visible_p (w, charpos, x, y, rtop, rbot, exact_mode_line_heights_p) SET_TEXT_POS_FROM_MARKER (top, w->start); - /* Compute exact mode line heights, if requested. */ - if (exact_mode_line_heights_p) - { - if (WINDOW_WANTS_MODELINE_P (w)) - current_mode_line_height - = display_mode_line (w, CURRENT_MODE_LINE_FACE_ID (w), - current_buffer->mode_line_format); + /* Compute exact mode line heights. */ + if (WINDOW_WANTS_MODELINE_P (w)) + current_mode_line_height + = display_mode_line (w, CURRENT_MODE_LINE_FACE_ID (w), + current_buffer->mode_line_format); - if (WINDOW_WANTS_HEADER_LINE_P (w)) - current_header_line_height - = display_mode_line (w, HEADER_LINE_FACE_ID, + if (WINDOW_WANTS_HEADER_LINE_P (w)) + current_header_line_height + = display_mode_line (w, HEADER_LINE_FACE_ID, current_buffer->header_line_format); - } start_display (&it, w, top); - move_it_to (&it, charpos, -1, it.last_visible_y, -1, - MOVE_TO_POS | MOVE_TO_Y); + move_it_to (&it, charpos, -1, it.last_visible_y-1, -1, + (charpos >= 0 ? MOVE_TO_POS : 0) | MOVE_TO_Y); /* Note that we may overshoot because of invisible text. */ - if (IT_CHARPOS (it) >= charpos) + if (charpos >= 0 && IT_CHARPOS (it) >= charpos) { int top_x = it.current_x; int top_y = it.current_y; @@ -1321,6 +1334,9 @@ pos_visible_p (w, charpos, x, y, rtop, rbot, exact_mode_line_heights_p) *y = max (top_y + max (0, it.max_ascent - it.ascent), window_top_y); *rtop = max (0, window_top_y - top_y); *rbot = max (0, bottom_y - it.last_visible_y); + *rowh = max (0, (min (bottom_y, it.last_visible_y) + - max (top_y, window_top_y))); + *vpos = it.vpos; } } else @@ -1330,7 +1346,8 @@ pos_visible_p (w, charpos, x, y, rtop, rbot, exact_mode_line_heights_p) it2 = it; if (IT_CHARPOS (it) < ZV && FETCH_BYTE (IT_BYTEPOS (it)) != '\n') move_it_by_lines (&it, 1, 0); - if (charpos < IT_CHARPOS (it)) + if (charpos < IT_CHARPOS (it) + || (it.what == IT_EOB && charpos == IT_CHARPOS (it))) { visible_p = 1; move_it_to (&it2, charpos, -1, -1, -1, MOVE_TO_POS); @@ -1339,6 +1356,11 @@ pos_visible_p (w, charpos, x, y, rtop, rbot, exact_mode_line_heights_p) *rtop = max (0, -it2.current_y); *rbot = max (0, ((it2.current_y + it2.max_ascent + it2.max_descent) - it.last_visible_y)); + *rowh = max (0, (min (it2.current_y + it2.max_ascent + it2.max_descent, + it.last_visible_y) + - max (it2.current_y, + WINDOW_HEADER_LINE_HEIGHT (w)))); + *vpos = it2.vpos; } } @@ -1350,6 +1372,15 @@ pos_visible_p (w, charpos, x, y, rtop, rbot, exact_mode_line_heights_p) if (visible_p && XFASTINT (w->hscroll) > 0) *x -= XFASTINT (w->hscroll) * WINDOW_FRAME_COLUMN_WIDTH (w); +#if 0 + /* Debugging code. */ + if (visible_p) + fprintf (stderr, "+pv pt=%d vs=%d --> x=%d y=%d rt=%d rb=%d rh=%d vp=%d\n", + charpos, w->vscroll, *x, *y, *rtop, *rbot, *rowh, *vpos); + else + fprintf (stderr, "-pv pt=%d vs=%d\n", charpos, w->vscroll); +#endif + return visible_p; } @@ -1904,7 +1935,7 @@ get_glyph_string_clip_rects (s, rects, n) } if ((s->for_overlaps & OVERLAPS_BOTH) == 0 - || (s->for_overlaps & OVERLAPS_BOTH) == OVERLAPS_BOTH && n == 1) + || ((s->for_overlaps & OVERLAPS_BOTH) == OVERLAPS_BOTH && n == 1)) { #ifdef CONVERT_FROM_XRECT CONVERT_FROM_XRECT (r, *rects); @@ -1930,23 +1961,27 @@ get_glyph_string_clip_rects (s, rects, n) { rs[i] = r; if (r.y + r.height > row_y) - if (r.y < row_y) - rs[i].height = row_y - r.y; - else - rs[i].height = 0; + { + if (r.y < row_y) + rs[i].height = row_y - r.y; + else + rs[i].height = 0; + } i++; } if (s->for_overlaps & OVERLAPS_SUCC) { rs[i] = r; if (r.y < row_y + s->row->visible_height) - if (r.y + r.height > row_y + s->row->visible_height) - { - rs[i].y = row_y + s->row->visible_height; - rs[i].height = r.y + r.height - rs[i].y; - } - else - rs[i].height = 0; + { + if (r.y + r.height > row_y + s->row->visible_height) + { + rs[i].y = row_y + s->row->visible_height; + rs[i].height = r.y + r.height - rs[i].y; + } + else + rs[i].height = 0; + } i++; } @@ -1976,15 +2011,15 @@ get_glyph_string_clip_rect (s, nr) Set w->phys_cursor_width to width of phys cursor. */ -int -get_phys_cursor_geometry (w, row, glyph, heightp) +void +get_phys_cursor_geometry (w, row, glyph, xp, yp, heightp) struct window *w; struct glyph_row *row; struct glyph *glyph; - int *heightp; + int *xp, *yp, *heightp; { struct frame *f = XFRAME (WINDOW_FRAME (w)); - int y, wd, h, h0, y0; + int x, y, wd, h, h0, y0; /* Compute the width of the rectangle to draw. If on a stretch glyph, and `x-stretch-block-cursor' is nil, don't draw a @@ -1994,6 +2029,14 @@ get_phys_cursor_geometry (w, row, glyph, heightp) #ifdef HAVE_NTGUI wd++; /* Why? */ #endif + + x = w->phys_cursor.x; + if (x < 0) + { + wd += x; + x = 0; + } + if (glyph->type == STRETCH_GLYPH && !x_stretch_cursor_p) wd = min (FRAME_COLUMN_WIDTH (f), wd); @@ -2023,8 +2066,9 @@ get_phys_cursor_geometry (w, row, glyph, heightp) } } - *heightp = h - 1; - return WINDOW_TO_FRAME_PIXEL_Y (w, y); + *xp = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, x); + *yp = WINDOW_TO_FRAME_PIXEL_Y (w, y); + *heightp = h; } /* @@ -2047,8 +2091,9 @@ remember_mouse_glyph (f, gx, gy, rect) /* Try to determine frame pixel position and size of the glyph under frame pixel coordinates X/Y on frame F. */ - window = window_from_coordinates (f, gx, gy, &part, &x, &y, 0); - if (NILP (window)) + if (!f->glyphs_initialized_p + || (window = window_from_coordinates (f, gx, gy, &part, &x, &y, 0), + NILP (window))) { width = FRAME_SMALLEST_CHAR_WIDTH (f); height = FRAME_SMALLEST_FONT_HEIGHT (f); @@ -2890,8 +2935,8 @@ init_from_display_pos (it, w, pos) also ``processed'' overlay strings at ZV. */ while (it->sp) pop_it (it); - it->current.overlay_string_index = -1; - it->method = GET_FROM_BUFFER; + xassert (it->current.overlay_string_index == -1); + xassert (it->method == GET_FROM_BUFFER); if (CHARPOS (pos->pos) == ZV) it->overlay_strings_at_end_processed_p = 1; } @@ -3002,7 +3047,19 @@ handle_stop (it) if (handled == HANDLED_RECOMPUTE_PROPS) break; else if (handled == HANDLED_RETURN) - return; + { + /* We still want to show before and after strings from + overlays even if the actual buffer text is replaced. */ + if (!handle_overlay_change_p || it->sp > 1) + return; + if (!get_overlay_strings_1 (it, 0, 0)) + return; + it->ignore_overlay_strings_at_pos_p = 1; + it->string_from_display_prop_p = 0; + handle_overlay_change_p = 0; + handled = HANDLED_RECOMPUTE_PROPS; + break; + } else if (handled == HANDLED_OVERLAY_STRING_CONSUMED) handle_overlay_change_p = 0; } @@ -3191,7 +3248,9 @@ handle_fontified_prop (it) && !NILP (Vrun_hooks) && (pos = make_number (IT_CHARPOS (*it)), prop = Fget_char_property (pos, Qfontified, Qnil), - NILP (prop))) + /* Ignore the special cased nil value always present at EOB since + no amount of fontifying will be able to change it. */ + NILP (prop) && IT_CHARPOS (*it) < Z)) { int count = SPECPDL_INDEX (); Lisp_Object val; @@ -3652,8 +3711,11 @@ handle_invisible_prop (it) the invisible text. Otherwise the cursor would be placed _after_ the ellipsis when the point is after the first invisible character. */ - it->position.charpos = IT_CHARPOS (*it) - 1; - it->position.bytepos = CHAR_TO_BYTE (it->position.charpos); + if (!STRINGP (it->object)) + { + it->position.charpos = IT_CHARPOS (*it) - 1; + it->position.bytepos = CHAR_TO_BYTE (it->position.charpos); + } setup_for_ellipsis (it, 0); } } @@ -3845,7 +3907,7 @@ handle_single_display_spec (it, spec, object, position, { Lisp_Object form; Lisp_Object location, value; - struct text_pos start_pos; + struct text_pos start_pos, save_pos; int valid_p; /* If SPEC is a list of the form `(when FORM . VALUE)', evaluate FORM. @@ -4062,7 +4124,10 @@ handle_single_display_spec (it, spec, object, position, /* Save current settings of IT so that we can restore them when we are finished with the glyph property value. */ + save_pos = it->position; + it->position = *position; push_it (it); + it->position = save_pos; it->area = TEXT_AREA; it->what = IT_IMAGE; @@ -4136,7 +4201,10 @@ handle_single_display_spec (it, spec, object, position, { /* Save current settings of IT so that we can restore them when we are finished with the glyph property value. */ + save_pos = it->position; + it->position = *position; push_it (it); + it->position = save_pos; if (NILP (location)) it->area = TEXT_AREA; @@ -4434,6 +4502,28 @@ handle_composition_prop (it) if (id >= 0) { + struct composition *cmp = composition_table[id]; + + if (cmp->glyph_len == 0) + { + /* No glyph. */ + if (STRINGP (it->string)) + { + IT_STRING_CHARPOS (*it) = end; + IT_STRING_BYTEPOS (*it) = string_char_to_byte (it->string, + end); + } + else + { + IT_CHARPOS (*it) = end; + IT_BYTEPOS (*it) = CHAR_TO_BYTE (end); + } + return HANDLED_RECOMPUTE_PROPS; + } + + it->stop_charpos = end; + push_it (it); + it->method = GET_FROM_COMPOSITION; it->cmp_id = id; it->cmp_len = COMPOSITION_LENGTH (prop); @@ -4443,7 +4533,6 @@ handle_composition_prop (it) it->len = (STRINGP (it->string) ? string_char_to_byte (it->string, end) : CHAR_TO_BYTE (end)) - pos_byte; - it->stop_charpos = end; handled = HANDLED_RETURN; } } @@ -4503,13 +4592,14 @@ next_overlay_string (it) int display_ellipsis_p = it->stack[it->sp - 1].display_ellipsis_p; pop_it (it); - xassert (it->stop_charpos >= BEGV - && it->stop_charpos <= it->end_charpos); - it->string = Qnil; + xassert (it->sp > 0 + || it->method == GET_FROM_COMPOSITION + || (NILP (it->string) + && it->method == GET_FROM_BUFFER + && it->stop_charpos >= BEGV + && it->stop_charpos <= it->end_charpos)); it->current.overlay_string_index = -1; - SET_TEXT_POS (it->current.string_pos, -1, -1); it->n_overlay_strings = 0; - it->method = GET_FROM_BUFFER; /* If we're at the end of the buffer, record that we have processed the overlay strings there already, so that @@ -4765,7 +4855,7 @@ load_overlay_strings (it, charpos) least one overlay string was found. */ static int -get_overlay_strings (it, charpos) +get_overlay_strings_1 (it, charpos, compute_stop_p) struct it *it; int charpos; { @@ -4787,12 +4877,13 @@ get_overlay_strings (it, charpos) /* Make sure we know settings in current_buffer, so that we can restore meaningful values when we're done with the overlay strings. */ - compute_stop_pos (it); + if (compute_stop_p) + compute_stop_pos (it); xassert (it->face_id >= 0); /* Save IT's settings. They are restored after all overlay strings have been processed. */ - xassert (it->sp == 0); + xassert (!compute_stop_p || it->sp == 0); push_it (it); /* Set up IT to deliver display elements from the first overlay @@ -4804,13 +4895,22 @@ get_overlay_strings (it, charpos) it->end_charpos = SCHARS (it->string); it->multibyte_p = STRING_MULTIBYTE (it->string); it->method = GET_FROM_STRING; + return 1; } - else - { - it->string = Qnil; - it->current.overlay_string_index = -1; - it->method = GET_FROM_BUFFER; - } + + it->current.overlay_string_index = -1; + return 0; +} + +static int +get_overlay_strings (it, charpos) + struct it *it; + int charpos; +{ + it->string = Qnil; + it->method = GET_FROM_BUFFER; + + (void) get_overlay_strings_1 (it, charpos, 1); CHECK_IT (it); @@ -4835,19 +4935,38 @@ push_it (it) { struct iterator_stack_entry *p; - xassert (it->sp < 2); + xassert (it->sp < IT_STACK_SIZE); p = it->stack + it->sp; p->stop_charpos = it->stop_charpos; xassert (it->face_id >= 0); p->face_id = it->face_id; p->string = it->string; - p->pos = it->current; + p->method = it->method; + switch (p->method) + { + case GET_FROM_IMAGE: + p->u.image.object = it->object; + p->u.image.image_id = it->image_id; + p->u.image.slice = it->slice; + break; + case GET_FROM_COMPOSITION: + p->u.comp.object = it->object; + p->u.comp.c = it->c; + p->u.comp.len = it->len; + p->u.comp.cmp_id = it->cmp_id; + p->u.comp.cmp_len = it->cmp_len; + break; + case GET_FROM_STRETCH: + p->u.stretch.object = it->object; + break; + } + p->position = it->position; + p->current = it->current; p->end_charpos = it->end_charpos; 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; @@ -4874,13 +4993,40 @@ pop_it (it) p = it->stack + it->sp; it->stop_charpos = p->stop_charpos; it->face_id = p->face_id; + it->current = p->current; + it->position = p->position; it->string = p->string; - it->current = p->pos; + if (NILP (it->string)) + SET_TEXT_POS (it->current.string_pos, -1, -1); + it->method = p->method; + switch (it->method) + { + case GET_FROM_IMAGE: + it->image_id = p->u.image.image_id; + it->object = p->u.image.object; + it->slice = p->u.image.slice; + break; + case GET_FROM_COMPOSITION: + it->object = p->u.comp.object; + it->c = p->u.comp.c; + it->len = p->u.comp.len; + it->cmp_id = p->u.comp.cmp_id; + it->cmp_len = p->u.comp.cmp_len; + break; + case GET_FROM_STRETCH: + it->object = p->u.comp.object; + break; + case GET_FROM_BUFFER: + it->object = it->w->buffer; + break; + case GET_FROM_STRING: + it->object = it->string; + break; + } it->end_charpos = p->end_charpos; 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; @@ -5012,6 +5158,7 @@ back_to_previous_visible_line_start (it) while (IT_CHARPOS (*it) > BEGV) { back_to_previous_line_start (it); + if (IT_CHARPOS (*it) <= BEGV) break; @@ -5031,37 +5178,47 @@ back_to_previous_visible_line_start (it) continue; } - /* If newline has a display property that replaces the newline with something - else (image or text), find start of overlay or interval and continue search - from that point. */ - if (IT_CHARPOS (*it) > BEGV) - { - struct it it2 = *it; - int pos; - int beg, end; - Lisp_Object val, overlay; - - pos = --IT_CHARPOS (it2); - --IT_BYTEPOS (it2); - it2.sp = 0; - if (handle_display_prop (&it2) == HANDLED_RETURN - && !NILP (val = get_char_property_and_overlay - (make_number (pos), Qdisplay, Qnil, &overlay)) - && (OVERLAYP (overlay) - ? (beg = OVERLAY_POSITION (OVERLAY_START (overlay))) - : get_property_and_range (pos, Qdisplay, &val, &beg, &end, Qnil))) - { - if (beg < BEGV) - beg = BEGV; - IT_CHARPOS (*it) = beg; - IT_BYTEPOS (*it) = buf_charpos_to_bytepos (current_buffer, beg); - continue; - } - } + if (IT_CHARPOS (*it) <= BEGV) + break; - break; + { + struct it it2; + int pos; + int beg, end; + Lisp_Object val, overlay; + + /* If newline is part of a composition, continue from start of composition */ + if (find_composition (IT_CHARPOS (*it), -1, &beg, &end, &val, Qnil) + && beg < IT_CHARPOS (*it)) + goto replaced; + + /* If newline is replaced by a display property, find start of overlay + or interval and continue search from that point. */ + it2 = *it; + pos = --IT_CHARPOS (it2); + --IT_BYTEPOS (it2); + it2.sp = 0; + if (handle_display_prop (&it2) == HANDLED_RETURN + && !NILP (val = get_char_property_and_overlay + (make_number (pos), Qdisplay, Qnil, &overlay)) + && (OVERLAYP (overlay) + ? (beg = OVERLAY_POSITION (OVERLAY_START (overlay))) + : get_property_and_range (pos, Qdisplay, &val, &beg, &end, Qnil))) + goto replaced; + + /* Newline is not replaced by anything -- so we are done. */ + break; + + replaced: + if (beg < BEGV) + beg = BEGV; + IT_CHARPOS (*it) = beg; + IT_BYTEPOS (*it) = buf_charpos_to_bytepos (current_buffer, beg); + } } + it->continuation_lines_width = 0; + xassert (IT_CHARPOS (*it) >= BEGV); xassert (IT_CHARPOS (*it) == BEGV || FETCH_BYTE (IT_BYTEPOS (*it) - 1) == '\n'); @@ -5184,7 +5341,6 @@ reseat_1 (it, pos, set_stop_p) xassert (CHARPOS (pos) >= BEGV && CHARPOS (pos) <= ZV); it->current.pos = it->position = pos; - XSETBUFFER (it->object, current_buffer); it->end_charpos = ZV; it->dpvec = NULL; it->current.dpvec_index = -1; @@ -5193,15 +5349,11 @@ reseat_1 (it, pos, set_stop_p) IT_STRING_BYTEPOS (*it) = -1; it->string = Qnil; it->method = GET_FROM_BUFFER; - /* RMS: I added this to fix a bug in move_it_vertically_backward - where it->area continued to relate to the starting point - for the backward motion. Bug report from - Nick Roberts on 19 May 2003. - However, I am not sure whether reseat still does the right thing - in general after this change. */ + it->object = it->w->buffer; it->area = TEXT_AREA; it->multibyte_p = !NILP (current_buffer->enable_multibyte_characters); it->sp = 0; + it->string_from_display_prop_p = 0; it->face_before_selective_p = 0; if (set_stop_p) @@ -5329,6 +5481,10 @@ static int (* get_next_element[NUM_IT_METHODS]) P_ ((struct it *it)) = display element from the current position of IT. Value is zero if end of buffer (or C string) is reached. */ +static struct frame *last_escape_glyph_frame = NULL; +static unsigned last_escape_glyph_face_id = (1 << FACE_ID_BITS); +static int last_escape_glyph_merged_face_id = 0; + int get_next_display_element (it) struct it *it; @@ -5445,11 +5601,19 @@ get_next_display_element (it) face_id = merge_faces (it->f, Qt, lface_id, it->face_id); } + else if (it->f == last_escape_glyph_frame + && it->face_id == last_escape_glyph_face_id) + { + face_id = last_escape_glyph_merged_face_id; + } else { /* Merge the escape-glyph face into the current face. */ face_id = merge_faces (it->f, Qescape_glyph, 0, it->face_id); + last_escape_glyph_frame = it->f; + last_escape_glyph_face_id = it->face_id; + last_escape_glyph_merged_face_id = face_id; } XSETINT (it->ctl_chars[0], g); @@ -5496,11 +5660,19 @@ get_next_display_element (it) face_id = merge_faces (it->f, Qt, lface_id, it->face_id); } + else if (it->f == last_escape_glyph_frame + && it->face_id == last_escape_glyph_face_id) + { + face_id = last_escape_glyph_merged_face_id; + } else { /* Merge the escape-glyph face into the current face. */ face_id = merge_faces (it->f, Qescape_glyph, 0, it->face_id); + last_escape_glyph_frame = it->f; + last_escape_glyph_face_id = it->face_id; + last_escape_glyph_merged_face_id = face_id; } /* Handle soft hyphens in the mode where they only get @@ -5660,18 +5832,18 @@ set_iterator_to_next (it, reseat_p) case GET_FROM_COMPOSITION: xassert (it->cmp_id >= 0 && it->cmp_id < n_compositions); - if (STRINGP (it->string)) + xassert (it->sp > 0); + pop_it (it); + if (it->method == GET_FROM_STRING) { IT_STRING_BYTEPOS (*it) += it->len; IT_STRING_CHARPOS (*it) += it->cmp_len; - it->method = GET_FROM_STRING; goto consider_string_end; } - else + else if (it->method == GET_FROM_BUFFER) { IT_BYTEPOS (*it) += it->len; IT_CHARPOS (*it) += it->cmp_len; - it->method = GET_FROM_BUFFER; } break; @@ -5694,12 +5866,17 @@ set_iterator_to_next (it, reseat_p) if (it->dpvec + it->current.dpvec_index == it->dpend) { + int recheck_faces = it->ellipsis_p; + if (it->s) it->method = GET_FROM_C_STRING; else if (STRINGP (it->string)) it->method = GET_FROM_STRING; else - it->method = GET_FROM_BUFFER; + { + it->method = GET_FROM_BUFFER; + it->object = it->w->buffer; + } it->dpvec = NULL; it->current.dpvec_index = -1; @@ -5716,8 +5893,9 @@ set_iterator_to_next (it, reseat_p) set_iterator_to_next (it, reseat_p); } - /* Recheck faces after display vector */ - it->stop_charpos = IT_CHARPOS (*it); + /* Maybe recheck faces after display vector */ + if (recheck_faces) + it->stop_charpos = IT_CHARPOS (*it); } break; @@ -5746,9 +5924,8 @@ set_iterator_to_next (it, reseat_p) && it->sp > 0) { pop_it (it); - if (STRINGP (it->string)) + if (it->method == GET_FROM_STRING) goto consider_string_end; - it->method = GET_FROM_BUFFER; } } break; @@ -5760,13 +5937,8 @@ set_iterator_to_next (it, reseat_p) if the `display' property takes up the whole string. */ xassert (it->sp > 0); pop_it (it); - it->image_id = 0; - if (STRINGP (it->string)) - { - it->method = GET_FROM_STRING; - goto consider_string_end; - } - it->method = GET_FROM_BUFFER; + if (it->method == GET_FROM_STRING) + goto consider_string_end; break; default: @@ -5911,9 +6083,7 @@ next_element_from_string (it) } } - /* Record what we have and where it came from. Note that we store a - buffer position in IT->position although it could arguably be a - string position. */ + /* Record what we have and where it came from. */ it->what = IT_CHARACTER; it->object = it->string; it->position = position; @@ -5989,6 +6159,7 @@ next_element_from_ellipsis (it) setting face_before_selective_p. */ it->saved_face_id = it->face_id; it->method = GET_FROM_BUFFER; + it->object = it->w->buffer; reseat_at_next_visible_line_start (it, 1); it->face_before_selective_p = 1; } @@ -6175,6 +6346,10 @@ next_element_from_composition (it) it->position = (STRINGP (it->string) ? it->current.string_pos : it->current.pos); + if (STRINGP (it->string)) + it->object = it->string; + else + it->object = it->w->buffer; return 1; } @@ -6623,6 +6798,10 @@ move_it_to (it, to_charpos, to_x, to_y, to_vpos, op) if (reached) break; } + else if (BUFFERP (it->object) + && it->method == GET_FROM_BUFFER + && IT_CHARPOS (*it) >= to_charpos) + skip = MOVE_POS_MATCH_OR_ZV; else skip = move_it_in_display_line_to (it, to_charpos, -1, MOVE_TO_POS); @@ -8884,6 +9063,9 @@ prepare_menu_bars () { Lisp_Object tail, frame; int count = SPECPDL_INDEX (); + /* 1 means that update_menu_bar has run its hooks + so any further calls to update_menu_bar shouldn't do so again. */ + int menu_bar_hooks_run = 0; record_unwind_save_match_data (); @@ -8915,9 +9097,12 @@ prepare_menu_bars () } GCPRO1 (tail); - update_menu_bar (f, 0); + menu_bar_hooks_run = update_menu_bar (f, 0, menu_bar_hooks_run); #ifdef HAVE_WINDOW_SYSTEM update_tool_bar (f, 0); +#ifdef MAC_OS + mac_update_title_bar (f, 0); +#endif #endif UNGCPRO; } @@ -8927,9 +9112,12 @@ prepare_menu_bars () else { struct frame *sf = SELECTED_FRAME (); - update_menu_bar (sf, 1); + update_menu_bar (sf, 1, 0); #ifdef HAVE_WINDOW_SYSTEM update_tool_bar (sf, 1); +#ifdef MAC_OS + mac_update_title_bar (sf, 1); +#endif #endif } @@ -8945,12 +9133,18 @@ prepare_menu_bars () before we start to fill in any display lines, because it can call eval. - If SAVE_MATCH_DATA is non-zero, we must save and restore it here. */ + If SAVE_MATCH_DATA is non-zero, we must save and restore it here. -static void -update_menu_bar (f, save_match_data) + If HOOKS_RUN is 1, that means a previous call to update_menu_bar + already ran the menu bar hooks for this redisplay, so there + is no need to run them again. The return value is the + updated value of this flag, to pass to the next call. */ + +static int +update_menu_bar (f, save_match_data, hooks_run) struct frame *f; int save_match_data; + int hooks_run; { Lisp_Object window; register struct window *w; @@ -8959,7 +9153,7 @@ update_menu_bar (f, save_match_data) happen when, for instance, an activate-menubar-hook causes a redisplay. */ if (inhibit_menubar_update) - return; + return hooks_run; window = FRAME_SELECTED_WINDOW (f); w = XWINDOW (window); @@ -9015,28 +9209,36 @@ update_menu_bar (f, save_match_data) specbind (Qoverriding_local_map, Qnil); } - /* Run the Lucid hook. */ - safe_run_hooks (Qactivate_menubar_hook); + if (!hooks_run) + { + /* Run the Lucid hook. */ + safe_run_hooks (Qactivate_menubar_hook); + + /* If it has changed current-menubar from previous value, + really recompute the menu-bar from the value. */ + if (! NILP (Vlucid_menu_bar_dirty_flag)) + call0 (Qrecompute_lucid_menubar); + + safe_run_hooks (Qmenu_bar_update_hook); - /* If it has changed current-menubar from previous value, - really recompute the menu-bar from the value. */ - if (! NILP (Vlucid_menu_bar_dirty_flag)) - call0 (Qrecompute_lucid_menubar); + hooks_run = 1; + } - safe_run_hooks (Qmenu_bar_update_hook); + XSETFRAME (Vmenu_updating_frame, f); FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f)); /* Redisplay the menu bar in case we changed it. */ #if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (MAC_OS) \ || defined (USE_GTK) - if (FRAME_WINDOW_P (f) -#if defined (MAC_OS) - /* All frames on Mac OS share the same menubar. So only the - selected frame should be allowed to set it. */ - && f == SELECTED_FRAME () + if (FRAME_WINDOW_P (f)) + { +#ifdef MAC_OS + /* All frames on Mac OS share the same menubar. So only + the selected frame should be allowed to set it. */ + if (f == SELECTED_FRAME ()) #endif - ) - set_frame_menubar (f, 0, 0); + set_frame_menubar (f, 0, 0); + } else /* On a terminal screen, the menu bar is an ordinary screen line, and this makes it get updated. */ @@ -9051,6 +9253,8 @@ update_menu_bar (f, save_match_data) set_buffer_internal_1 (prev); } } + + return hooks_run; } @@ -9215,7 +9419,8 @@ update_tool_bar (f, save_match_data) &new_n_tool_bar); /* Redisplay the tool-bar if we changed it. */ - if (NILP (Fequal (new_tool_bar, f->tool_bar_items))) + if (new_n_tool_bar != f->n_tool_bar_items + || 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 @@ -9400,11 +9605,22 @@ build_desired_tool_bar_string (f) } -/* Display one line of the tool-bar of frame IT->f. */ +/* Display one line of the tool-bar of frame IT->f. + + HEIGHT specifies the desired height of the tool-bar line. + If the actual height of the glyph row is less than HEIGHT, the + row's height is increased to HEIGHT, and the icons are centered + vertically in the new height. + + If HEIGHT is -1, we are counting needed tool-bar lines, so don't + count a final empty row in case the tool-bar width exactly matches + the window width. +*/ static void -display_tool_bar_line (it) +display_tool_bar_line (it, height) struct it *it; + int height; { struct glyph_row *row = it->glyph_row; int max_x = it->last_visible_x; @@ -9419,29 +9635,42 @@ display_tool_bar_line (it) while (it->current_x < max_x) { - int x_before, x, n_glyphs_before, i, nglyphs; + int x, n_glyphs_before, i, nglyphs; + struct it it_before; /* Get the next display element. */ if (!get_next_display_element (it)) - break; + { + /* Don't count empty row if we are counting needed tool-bar lines. */ + if (height < 0 && !it->hpos) + return; + break; + } /* Produce glyphs. */ - x_before = it->current_x; - n_glyphs_before = it->glyph_row->used[TEXT_AREA]; + n_glyphs_before = row->used[TEXT_AREA]; + it_before = *it; + PRODUCE_GLYPHS (it); - nglyphs = it->glyph_row->used[TEXT_AREA] - n_glyphs_before; + nglyphs = row->used[TEXT_AREA] - n_glyphs_before; i = 0; - x = x_before; + x = it_before.current_x; while (i < nglyphs) { struct glyph *glyph = row->glyphs[TEXT_AREA] + n_glyphs_before + i; if (x + glyph->pixel_width > max_x) { - /* Glyph doesn't fit on line. */ - it->glyph_row->used[TEXT_AREA] = n_glyphs_before + i; - it->current_x = x; + /* Glyph doesn't fit on line. Backtrack. */ + row->used[TEXT_AREA] = n_glyphs_before; + *it = it_before; + /* If this is the only glyph on this line, it will never fit on the + toolbar, so skip it. But ensure there is at least one glyph, + so we don't accidentally disable the tool-bar. */ + if (n_glyphs_before == 0 + && (it->vpos > 0 || IT_STRING_CHARPOS (*it) < it->end_charpos-1)) + break; goto out; } @@ -9460,11 +9689,24 @@ display_tool_bar_line (it) out:; row->displays_text_p = row->used[TEXT_AREA] != 0; + /* Use default face for the border below the tool bar. */ + if (!row->displays_text_p) + it->face_id = DEFAULT_FACE_ID; extend_face_to_end_of_line (it); last = row->glyphs[TEXT_AREA] + row->used[TEXT_AREA] - 1; last->right_box_line_p = 1; if (last == row->glyphs[TEXT_AREA]) last->left_box_line_p = 1; + + /* Make line the desired height and center it vertically. */ + if ((height -= it->max_ascent + it->max_descent) > 0) + { + /* Don't add more than one line height. */ + height %= FRAME_LINE_HEIGHT (it->f); + it->max_ascent += height / 2; + it->max_descent += (height + 1) / 2; + } + compute_line_metrics (it); /* If line is empty, make it occupy the rest of the tool-bar. */ @@ -9487,29 +9729,45 @@ display_tool_bar_line (it) } +/* Max tool-bar height. */ + +#define MAX_FRAME_TOOL_BAR_HEIGHT(f) \ + ((FRAME_LINE_HEIGHT (f) * FRAME_LINES (f))) + /* Value is the number of screen lines needed to make all tool-bar - items of frame F visible. */ + items of frame F visible. The number of actual rows needed is + returned in *N_ROWS if non-NULL. */ static int -tool_bar_lines_needed (f) +tool_bar_lines_needed (f, n_rows) struct frame *f; + int *n_rows; { struct window *w = XWINDOW (f->tool_bar_window); struct it it; + /* tool_bar_lines_needed is called from redisplay_tool_bar after building + the desired matrix, so use (unused) mode-line row as temporary row to + avoid destroying the first tool-bar row. */ + struct glyph_row *temp_row = MATRIX_MODE_LINE_ROW (w->desired_matrix); /* Initialize an iterator for iteration over F->desired_tool_bar_string in the tool-bar window of frame F. */ - init_iterator (&it, w, -1, -1, w->desired_matrix->rows, TOOL_BAR_FACE_ID); + init_iterator (&it, w, -1, -1, temp_row, TOOL_BAR_FACE_ID); it.first_visible_x = 0; it.last_visible_x = FRAME_TOTAL_COLS (f) * FRAME_COLUMN_WIDTH (f); reseat_to_string (&it, NULL, f->desired_tool_bar_string, 0, 0, 0, -1); while (!ITERATOR_AT_END_P (&it)) { - it.glyph_row = w->desired_matrix->rows; - clear_glyph_row (it.glyph_row); - display_tool_bar_line (&it); + clear_glyph_row (temp_row); + it.glyph_row = temp_row; + display_tool_bar_line (&it, -1); } + clear_glyph_row (temp_row); + + /* f->n_tool_bar_rows == 0 means "unknown"; -1 means no tool-bar. */ + if (n_rows) + *n_rows = it.vpos > 0 ? it.vpos : -1; return (it.current_y + FRAME_LINE_HEIGHT (f) - 1) / FRAME_LINE_HEIGHT (f); } @@ -9539,7 +9797,7 @@ DEFUN ("tool-bar-lines-needed", Ftool_bar_lines_needed, Stool_bar_lines_needed, if (f->n_tool_bar_items) { build_desired_tool_bar_string (f); - nlines = tool_bar_lines_needed (f); + nlines = tool_bar_lines_needed (f, NULL); } } @@ -9584,9 +9842,68 @@ redisplay_tool_bar (f) build_desired_tool_bar_string (f); reseat_to_string (&it, NULL, f->desired_tool_bar_string, 0, 0, 0, -1); + if (f->n_tool_bar_rows == 0) + { + int nlines; + + if ((nlines = tool_bar_lines_needed (f, &f->n_tool_bar_rows), + nlines != WINDOW_TOTAL_LINES (w))) + { + extern Lisp_Object Qtool_bar_lines; + Lisp_Object frame; + int old_height = WINDOW_TOTAL_LINES (w); + + XSETFRAME (frame, f); + Fmodify_frame_parameters (frame, + Fcons (Fcons (Qtool_bar_lines, + make_number (nlines)), + Qnil)); + if (WINDOW_TOTAL_LINES (w) != old_height) + { + clear_glyph_matrix (w->desired_matrix); + fonts_changed_p = 1; + return 1; + } + } + } + /* Display as many lines as needed to display all tool-bar items. */ - while (it.current_y < it.last_visible_y) - display_tool_bar_line (&it); + + if (f->n_tool_bar_rows > 0) + { + int border, rows, height, extra; + + if (INTEGERP (Vtool_bar_border)) + border = XINT (Vtool_bar_border); + else if (EQ (Vtool_bar_border, Qinternal_border_width)) + border = FRAME_INTERNAL_BORDER_WIDTH (f); + else if (EQ (Vtool_bar_border, Qborder_width)) + border = f->border_width; + else + border = 0; + if (border < 0) + border = 0; + + rows = f->n_tool_bar_rows; + height = max (1, (it.last_visible_y - border) / rows); + extra = it.last_visible_y - border - height * rows; + + while (it.current_y < it.last_visible_y) + { + int h = 0; + if (extra > 0 && rows-- > 0) + { + h = (extra + rows - 1) / rows; + extra -= h; + } + display_tool_bar_line (&it, height + h); + } + } + else + { + while (it.current_y < it.last_visible_y) + display_tool_bar_line (&it, 0); + } /* It doesn't make much sense to try scrolling in the tool-bar window, so don't do it. */ @@ -9595,17 +9912,20 @@ redisplay_tool_bar (f) if (auto_resize_tool_bars_p) { - int nlines; + int nlines, nrows; + int max_tool_bar_height = MAX_FRAME_TOOL_BAR_HEIGHT (f); /* If we couldn't display everything, change the tool-bar's - height. */ - if (IT_STRING_CHARPOS (it) < it.end_charpos) + height if there is room for more. */ + if (IT_STRING_CHARPOS (it) < it.end_charpos + && it.current_y < max_tool_bar_height) change_height_p = 1; + row = it.glyph_row - 1; + /* If there are blank lines at the end, except for a partially visible blank line at the end that is smaller than FRAME_LINE_HEIGHT, change the tool-bar's height. */ - row = it.glyph_row - 1; if (!row->displays_text_p && row->height >= FRAME_LINE_HEIGHT (f)) change_height_p = 1; @@ -9613,13 +9933,14 @@ redisplay_tool_bar (f) /* If row displays tool-bar items, but is partially visible, change the tool-bar's height. */ if (row->displays_text_p - && MATRIX_ROW_BOTTOM_Y (row) > it.last_visible_y) + && MATRIX_ROW_BOTTOM_Y (row) > it.last_visible_y + && MATRIX_ROW_BOTTOM_Y (row) < max_tool_bar_height) change_height_p = 1; /* Resize windows as needed by changing the `tool-bar-lines' frame parameter. */ if (change_height_p - && (nlines = tool_bar_lines_needed (f), + && (nlines = tool_bar_lines_needed (f, &nrows), nlines != WINDOW_TOTAL_LINES (w))) { extern Lisp_Object Qtool_bar_lines; @@ -9627,13 +9948,16 @@ redisplay_tool_bar (f) int old_height = WINDOW_TOTAL_LINES (w); XSETFRAME (frame, f); - clear_glyph_matrix (w->desired_matrix); Fmodify_frame_parameters (frame, Fcons (Fcons (Qtool_bar_lines, make_number (nlines)), Qnil)); if (WINDOW_TOTAL_LINES (w) != old_height) - fonts_changed_p = 1; + { + clear_glyph_matrix (w->desired_matrix); + f->n_tool_bar_rows = nrows; + fonts_changed_p = 1; + } } } @@ -10482,13 +10806,13 @@ redisplay_internal (preserve_echo_area) int preserve_echo_area; { struct window *w = XWINDOW (selected_window); - struct frame *f = XFRAME (w->frame); + struct frame *f; int pause; int must_finish = 0; struct text_pos tlbufpos, tlendpos; int number_of_visible_frames; int count; - struct frame *sf = SELECTED_FRAME (); + struct frame *sf; int polling_stopped_here = 0; /* Non-zero means redisplay has to consider all windows on all @@ -10501,8 +10825,16 @@ redisplay_internal (preserve_echo_area) initialized, or redisplay is explicitly turned off by setting Vinhibit_redisplay. */ if (noninteractive - || !NILP (Vinhibit_redisplay) - || !f->glyphs_initialized_p) + || !NILP (Vinhibit_redisplay)) + return; + + /* Don't examine these until after testing Vinhibit_redisplay. + When Emacs is shutting down, perhaps because its connection to + X has dropped, we should not look at them at all. */ + f = XFRAME (w->frame); + sf = SELECTED_FRAME (); + + if (!f->glyphs_initialized_p) return; /* The flag redisplay_performed_directly_p is set by @@ -10545,6 +10877,8 @@ redisplay_internal (preserve_echo_area) retry: pause = 0; reconsider_clip_changes (w, current_buffer); + last_escape_glyph_frame = NULL; + last_escape_glyph_face_id = (1 << FACE_ID_BITS); /* If new fonts have been loaded that make a glyph matrix adjustment necessary, do it. */ @@ -11450,9 +11784,11 @@ redisplay_window_1 (window) /* Set cursor position of W. PT is assumed to be displayed in ROW. DELTA is the number of bytes by which positions recorded in ROW - differ from current buffer positions. */ + differ from current buffer positions. -void + Return 0 if cursor is not on this row. 1 otherwise. */ + +int set_cursor_from_row (w, row, matrix, delta, delta_bytes, dy, dvpos) struct window *w; struct glyph_row *row; @@ -11499,7 +11835,7 @@ set_cursor_from_row (w, row, matrix, delta, delta_bytes, dy, dvpos) x += glyph->pixel_width; ++glyph; if (cursor_from_overlay_pos - && last_pos > cursor_from_overlay_pos) + && last_pos >= cursor_from_overlay_pos) { cursor_from_overlay_pos = 0; cursor = 0; @@ -11507,16 +11843,21 @@ set_cursor_from_row (w, row, matrix, delta, delta_bytes, dy, dvpos) } else { - string_before_pos = last_pos; - string_start = glyph; - string_start_x = x; + if (string_start == NULL) + { + string_before_pos = last_pos; + string_start = glyph; + string_start_x = x; + } /* Skip all glyphs from string. */ do { + Lisp_Object cprop; int pos; if ((cursor == NULL || glyph > cursor) - && !NILP (Fget_char_property (make_number ((glyph)->charpos), - Qcursor, (glyph)->object)) + && (cprop = Fget_char_property (make_number ((glyph)->charpos), + Qcursor, (glyph)->object), + !NILP (cprop)) && (pos = string_buffer_position (w, glyph->object, string_before_pos), (pos == 0 /* From overlay */ @@ -11527,14 +11868,15 @@ set_cursor_from_row (w, row, matrix, delta, delta_bytes, dy, dvpos) 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_from_overlay_pos = (pos ? 0 : last_pos + + (INTEGERP (cprop) ? XINT (cprop) : 0)); cursor = glyph; cursor_x = x; } x += glyph->pixel_width; ++glyph; } - while (glyph < end && STRINGP (glyph->object)); + while (glyph < end && EQ (glyph->object, string_start->object)); } } @@ -11564,25 +11906,25 @@ set_cursor_from_row (w, row, matrix, delta, delta_bytes, dy, dvpos) glyph on point by scanning from string_start again. */ Lisp_Object limit; Lisp_Object string; + struct glyph *stop = glyph; int pos; limit = make_number (pt_old + 1); - end = glyph; glyph = string_start; x = string_start_x; string = glyph->object; pos = string_buffer_position (w, string, string_before_pos); /* If STRING is from overlay, LAST_POS == 0. We skip such glyphs because we always put cursor after overlay strings. */ - while (pos == 0 && glyph < end) + while (pos == 0 && glyph < stop) { string = glyph->object; - SKIP_GLYPHS (glyph, end, x, EQ (glyph->object, string)); - if (glyph < end) + SKIP_GLYPHS (glyph, stop, x, EQ (glyph->object, string)); + if (glyph < stop) pos = string_buffer_position (w, glyph->object, string_before_pos); } - while (glyph < end) + while (glyph < stop) { pos = XINT (Fnext_single_char_property_change (make_number (pos), Qdisplay, Qnil, limit)); @@ -11590,15 +11932,20 @@ set_cursor_from_row (w, row, matrix, delta, delta_bytes, dy, dvpos) break; /* Skip glyphs from the same string. */ string = glyph->object; - SKIP_GLYPHS (glyph, end, x, EQ (glyph->object, string)); + SKIP_GLYPHS (glyph, stop, x, EQ (glyph->object, string)); /* Skip glyphs from an overlay. */ - while (glyph < end + while (glyph < stop && ! string_buffer_position (w, glyph->object, pos)) { string = glyph->object; - SKIP_GLYPHS (glyph, end, x, EQ (glyph->object, string)); + SKIP_GLYPHS (glyph, stop, x, EQ (glyph->object, string)); } } + + /* If we reached the end of the line, and end was from a string, + cursor is not on this line. */ + if (glyph == end && row->continued_p) + return 0; } w->cursor.hpos = glyph - row->glyphs[TEXT_AREA]; @@ -11632,6 +11979,8 @@ set_cursor_from_row (w, row, matrix, delta, delta_bytes, dy, dvpos) else CHARPOS (this_line_start_pos) = 0; } + + return 1; } @@ -11706,7 +12055,8 @@ cursor_row_fully_visible_p (w, force_p, current_matrix_p) window_height = window_box_height (w); if (row->height >= window_height) { - if (!force_p || MINI_WINDOW_P (w) || w->vscroll) + if (!force_p || MINI_WINDOW_P (w) + || w->vscroll || w->cursor.vpos == 0) return 1; } return 0; @@ -12315,8 +12665,18 @@ try_cursor_movement (window, startp, scroll_step) rc = CURSOR_MOVEMENT_MUST_SCROLL; else { - set_cursor_from_row (w, row, w->current_matrix, 0, 0, 0, 0); - rc = CURSOR_MOVEMENT_SUCCESS; + do + { + if (set_cursor_from_row (w, row, w->current_matrix, 0, 0, 0, 0)) + { + rc = CURSOR_MOVEMENT_SUCCESS; + break; + } + ++row; + } + while (MATRIX_ROW_BOTTOM_Y (row) < last_y + && MATRIX_ROW_START_CHARPOS (row) == PT + && cursor_row_p (w, row)); } } } @@ -12577,8 +12937,6 @@ redisplay_window (window, just_this_one_p) /* 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, @@ -12748,6 +13106,36 @@ redisplay_window (window, just_this_one_p) || (XFASTINT (w->last_modified) >= MODIFF && XFASTINT (w->last_overlay_modified) >= OVERLAY_MODIFF))) { + + /* If first window line is a continuation line, and window start + is inside the modified region, but the first change is before + current window start, we must select a new window start.*/ + if (NILP (w->start_at_line_beg) + && CHARPOS (startp) > BEGV) + { + /* Make sure beg_unchanged and end_unchanged are up to date. + Do it only if buffer has really changed. This may or may + not have been done by try_window_id (see which) already. */ + if (MODIFF > SAVE_MODIFF + /* This seems to happen sometimes after saving a buffer. */ + || BEG_UNCHANGED + END_UNCHANGED > Z_BYTE) + { + if (GPT - BEG < BEG_UNCHANGED) + BEG_UNCHANGED = GPT - BEG; + if (Z - GPT < END_UNCHANGED) + END_UNCHANGED = Z - GPT; + } + + if (CHARPOS (startp) > BEG + BEG_UNCHANGED + && CHARPOS (startp) <= Z - END_UNCHANGED) + { + /* There doesn't seems to be a simple way to find a new + window start that is near the old window start, so + we just recenter. */ + goto recenter; + } + } + #if GLYPH_DEBUG debug_method_add (w, "same window start"); #endif @@ -13152,7 +13540,8 @@ try_window (window, pos, check_margins) this_scroll_margin = min (this_scroll_margin, WINDOW_TOTAL_LINES (w) / 4); this_scroll_margin *= FRAME_LINE_HEIGHT (it.f); - if ((w->cursor.y < this_scroll_margin + if ((w->cursor.y >= 0 /* not vscrolled */ + && w->cursor.y < this_scroll_margin && CHARPOS (pos) > BEGV && IT_CHARPOS (it) < ZV) /* rms: considering make_cursor_line_fully_visible_p here @@ -14741,6 +15130,25 @@ dump_glyph (row, glyph, area) glyph->left_box_line_p, glyph->right_box_line_p); } + else if (glyph->type == COMPOSITE_GLYPH) + { + fprintf (stderr, + " %5d %4c %6d %c %3d 0x%05x %c %4d %1.1d%1.1d\n", + glyph - row->glyphs[TEXT_AREA], + '+', + glyph->charpos, + (BUFFERP (glyph->object) + ? 'B' + : (STRINGP (glyph->object) + ? 'S' + : '-')), + glyph->pixel_width, + glyph->u.cmp_id, + '.', + glyph->face_id, + glyph->left_box_line_p, + glyph->right_box_line_p); + } } @@ -14756,7 +15164,7 @@ dump_glyph_row (row, vpos, glyphs) { if (glyphs != 1) { - fprintf (stderr, "Row Start End Used oEI><\\CTZFesm X Y W H V A P\n"); + fprintf (stderr, "Row Start End Used oE><\\CTZFesm X Y W H V A P\n"); fprintf (stderr, "======================================================================\n"); fprintf (stderr, "%3d %5d %5d %4d %1.1d%1.1d%1.1d%1.1d\ @@ -15260,6 +15668,7 @@ extend_face_to_end_of_line (it) face = FACE_FROM_ID (f, it->face_id); if (FRAME_WINDOW_P (f) + && it->glyph_row->displays_text_p && face->box == FACE_NO_BOX && face->background == FRAME_BACKGROUND_PIXEL (f) && !face->stipple) @@ -16183,6 +16592,9 @@ display_mode_line (w, face_id, format) int count = SPECPDL_INDEX (); init_iterator (&it, w, -1, -1, NULL, face_id); + /* Don't extend on a previously drawn mode-line. + This may happen if called from pos_visible_p. */ + it.glyph_row->enabled_p = 0; prepare_desired_row (it.glyph_row); it.glyph_row->mode_line_p = 1; @@ -16200,6 +16612,7 @@ display_mode_line (w, face_id, format) kboard-local variables in the mode_line_format will get the right values. */ push_frame_kboard (it.f); + record_unwind_save_match_data (); display_mode_element (&it, 0, 0, 0, format, Qnil, 0); pop_frame_kboard (); @@ -16452,8 +16865,11 @@ display_mode_element (it, depth, field_width, precision, elt, props, risky) { int bytepos = last_offset; int charpos = string_byte_to_char (elt, bytepos); + + if (precision <= 0) + nchars = string_byte_to_char (elt, offset) - charpos; n += display_string (NULL, elt, Qnil, 0, charpos, - it, 0, prec, 0, + it, 0, nchars, 0, STRING_MULTIBYTE (elt)); } break; @@ -17268,12 +17684,20 @@ decode_mode_spec (w, c, field_width, precision, multibyte) break; case 'c': - { - int col = (int) current_column (); /* iftc */ - w->column_number_displayed = make_number (col); - pint2str (decode_mode_spec_buf, field_width, col); - return decode_mode_spec_buf; - } + /* %c and %l are ignored in `frame-title-format'. + (In redisplay_internal, the frame title is drawn _before_ the + windows are updated, so the stuff which depends on actual + window contents (such as %l) may fail to render properly, or + even crash emacs.) */ + if (mode_line_target == MODE_LINE_TITLE) + return ""; + else + { + int col = (int) current_column (); /* iftc */ + w->column_number_displayed = make_number (col); + pint2str (decode_mode_spec_buf, field_width, col); + return decode_mode_spec_buf; + } case 'e': #ifndef SYSTEM_MALLOC @@ -17315,11 +17739,16 @@ decode_mode_spec (w, c, field_width, precision, multibyte) case 'l': { - int startpos = XMARKER (w->start)->charpos; - int startpos_byte = marker_byte_position (w->start); - int line, linepos, linepos_byte, topline; - int nlines, junk; - int height = WINDOW_TOTAL_LINES (w); + int startpos, startpos_byte, line, linepos, linepos_byte; + int topline, nlines, junk, height; + + /* %c and %l are ignored in `frame-title-format'. */ + if (mode_line_target == MODE_LINE_TITLE) + return ""; + + startpos = XMARKER (w->start)->charpos; + startpos_byte = marker_byte_position (w->start); + height = WINDOW_TOTAL_LINES (w); /* If we decided that this buffer isn't suitable for line numbers, don't forget that too fast. */ @@ -17702,7 +18131,7 @@ display_count_lines (start, start_byte, limit_byte, count, byte_pos_ptr) display them, and < 0 means obey the current buffer's value of enable_multibyte_characters. - Value is the number of glyphs produced. */ + Value is the number of columns displayed. */ static int display_string (string, lisp_string, face_string, face_string_pos, @@ -18352,8 +18781,7 @@ get_glyph_face_and_encoding (f, glyph, char2b, two_byte_p) sure to use a face suitable for unibyte. */ STORE_XCHAR2B (char2b, 0, glyph->u.ch); } - else if (glyph->u.ch < 128 - && glyph->face_id < BASIC_FACE_ID_SENTINEL) + else if (glyph->u.ch < 128) { /* Case of ASCII in a face known to fit ASCII. */ STORE_XCHAR2B (char2b, 0, glyph->u.ch); @@ -18564,6 +18992,7 @@ fill_stretch_glyph_string (s, row, area, start, end) s->font = s->face->font; s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id); s->width = glyph->pixel_width; + s->nchars = 1; voffset = glyph->voffset; for (++glyph; @@ -18754,7 +19183,7 @@ get_char_face_and_encoding (f, c, face_id, char2b, multibyte_p, display_p) face_id = FACE_FOR_CHAR (f, face, c); face = FACE_FROM_ID (f, face_id); } - else if (c < 128 && face_id < BASIC_FACE_ID_SENTINEL) + else if (c < 128) { /* Case of ASCII in a face known to fit ASCII. */ STORE_XCHAR2B (char2b, 0, c); @@ -19378,7 +19807,7 @@ produce_image_glyph (it) { struct image *img; struct face *face; - int glyph_ascent; + int glyph_ascent, crop; struct glyph_slice slice; xassert (it->what == IT_IMAGE); @@ -19486,6 +19915,15 @@ produce_image_glyph (it) take_vertical_position_into_account (it); + /* Automatically crop wide image glyphs at right edge so we can + draw the cursor on same display row. */ + if ((crop = it->pixel_width - (it->last_visible_x - it->current_x), crop > 0) + && (it->hpos == 0 || it->pixel_width > it->last_visible_x / 4)) + { + it->pixel_width -= crop; + slice.width -= crop; + } + if (it->glyph_row) { struct glyph *glyph; @@ -19709,20 +20147,6 @@ produce_stretch_glyph (it) it->descent = it->phys_descent = height - it->ascent; it->nglyphs = width > 0 && height > 0 ? 1 : 0; - if (width > 0 && height > 0 && face->box != FACE_NO_BOX) - { - if (face->box_line_width > 0) - { - it->ascent += face->box_line_width; - it->descent += face->box_line_width; - } - - if (it->start_of_box_run_p) - it->pixel_width += abs (face->box_line_width); - if (it->end_of_box_run_p) - it->pixel_width += abs (face->box_line_width); - } - take_vertical_position_into_account (it); } @@ -19996,7 +20420,7 @@ x_produce_glyphs (it) /* If face has an overline, add the height of the overline (1 pixel) and a 1 pixel margin to the character height. */ if (face->overline_p) - it->ascent += 2; + it->ascent += overline_margin; if (it->constrain_row_ascent_descent_p) { @@ -20198,7 +20622,7 @@ x_produce_glyphs (it) /* If face has an overline, add the height of the overline (1 pixel) and a 1 pixel margin to the character height. */ if (face->overline_p) - it->ascent += 2; + it->ascent += overline_margin; take_vertical_position_into_account (it); @@ -20473,7 +20897,7 @@ x_produce_glyphs (it) /* If face has an overline, add the height of the overline (1 pixel) and a 1 pixel margin to the character height. */ if (face->overline_p) - it->ascent += 2; + it->ascent += overline_margin; take_vertical_position_into_account (it); @@ -20848,10 +21272,35 @@ get_window_cursor_type (w, glyph, width, active_cursor) /* Use normal cursor if not blinked off. */ if (!w->cursor_off_p) { - if (glyph != NULL && glyph->type == IMAGE_GLYPH) { - if (cursor_type == FILLED_BOX_CURSOR) - cursor_type = HOLLOW_BOX_CURSOR; +#ifdef HAVE_WINDOW_SYSTEM + if (glyph != NULL && glyph->type == IMAGE_GLYPH) + { + if (cursor_type == FILLED_BOX_CURSOR) + { + /* Using a block cursor on large images can be very annoying. + So use a hollow cursor for "large" images. + If image is not transparent (no mask), also use hollow cursor. */ + struct image *img = IMAGE_FROM_ID (f, glyph->u.img_id); + if (img != NULL && IMAGEP (img->spec)) + { + /* Arbitrarily, interpret "Large" as >32x32 and >NxN + where N = size of default frame font size. + This should cover most of the "tiny" icons people may use. */ + if (!img->mask + || img->width > max (32, WINDOW_FRAME_COLUMN_WIDTH (w)) + || img->height > max (32, WINDOW_FRAME_LINE_HEIGHT (w))) + cursor_type = HOLLOW_BOX_CURSOR; + } + } + else if (cursor_type != NO_CURSOR) + { + /* Display current only supports BOX and HOLLOW cursors for images. + So for now, unconditionally use a HOLLOW cursor when cursor is + not a solid box cursor. */ + cursor_type = HOLLOW_BOX_CURSOR; + } } +#endif return cursor_type; } @@ -21137,7 +21586,7 @@ erase_phys_cursor (w) /* Maybe clear the display under the cursor. */ if (w->phys_cursor_type == HOLLOW_BOX_CURSOR) { - int x, y; + int x, y, left_x; int header_line_height = WINDOW_HEADER_LINE_HEIGHT (w); int width; @@ -21145,11 +21594,16 @@ erase_phys_cursor (w) if (cursor_glyph == NULL) goto mark_cursor_off; - x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x); + width = cursor_glyph->pixel_width; + left_x = window_box_left_offset (w, TEXT_AREA); + x = w->phys_cursor.x; + if (x < left_x) + width -= left_x - x; + width = min (width, window_box_width (w, TEXT_AREA) - 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); + x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, max (x, left_x)); + if (width > 0) rif->clear_frame_area (f, x, y, width, cursor_row->visible_height); } @@ -22182,7 +22636,7 @@ note_mouse_highlight (f, x, y) struct buffer *b; /* When a menu is active, don't highlight because this looks odd. */ -#if defined (USE_X_TOOLKIT) || defined (USE_GTK) || defined (HAVE_NTGUI) +#if defined (USE_X_TOOLKIT) || defined (USE_GTK) if (popup_activated ()) return; #endif @@ -22242,7 +22696,10 @@ note_mouse_highlight (f, x, y) } if (part == ON_VERTICAL_BORDER) - cursor = FRAME_X_OUTPUT (f)->horizontal_drag_cursor; + { + cursor = FRAME_X_OUTPUT (f)->horizontal_drag_cursor; + help_echo_string = build_string ("drag-mouse-1: resize"); + } else if (part == ON_LEFT_FRINGE || part == ON_RIGHT_FRINGE || part == ON_SCROLL_BAR) cursor = FRAME_X_OUTPUT (f)->nontext_cursor; @@ -23546,9 +24003,10 @@ This variable is not guaranteed to be accurate except while processing DEFVAR_LISP ("frame-title-format", &Vframe_title_format, doc: /* Template for displaying the title bar of visible frames. \(Assuming the window manager supports this feature.) -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'). */); + +This variable has the same structure as `mode-line-format', except that +the %c and %l constructs are ignored. It 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. @@ -23594,9 +24052,22 @@ Each function is called with two arguments, the window and the end trigger value See `set-window-redisplay-end-trigger'. */); Vredisplay_end_trigger_functions = Qnil; - DEFVAR_BOOL ("mouse-autoselect-window", &mouse_autoselect_window, - doc: /* *Non-nil means autoselect window with mouse pointer. */); - mouse_autoselect_window = 0; + DEFVAR_LISP ("mouse-autoselect-window", &Vmouse_autoselect_window, + doc: /* *Non-nil means autoselect window with mouse pointer. +If nil, do not autoselect windows. +A positive number means delay autoselection by that many seconds: a +window is autoselected only after the mouse has remained in that +window for the duration of the delay. +A negative number has a similar effect, but causes windows to be +autoselected only after the mouse has stopped moving. \(Because of +the way Emacs compares mouse events, you will occasionally wait twice +that time before the window gets selected.\) +Any other value means to autoselect window instantaneously when the +mouse pointer enters it. + +Autoselection selects the minibuffer only if it is active, and never +unselects the minibuffer if it is active. */); + Vmouse_autoselect_window = Qnil; DEFVAR_BOOL ("auto-resize-tool-bars", &auto_resize_tool_bars_p, doc: /* *Non-nil means automatically resize tool-bars. @@ -23613,6 +24084,14 @@ otherwise. */); 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-border", &Vtool_bar_border, + doc: /* *Border below tool-bar in pixels. +If an integer, use it as the height of the border. +If it is one of `internal-border-width' or `border-width', use the +value of the corresponding frame parameter. +Otherwise, no border is added below the tool-bar. */); + Vtool_bar_border = Qinternal_border_width; + 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. @@ -23680,7 +24159,7 @@ before automatic hscrolling will horizontally scroll the window. */); DEFVAR_LISP ("hscroll-step", &Vhscroll_step, doc: /* *How many columns to scroll the window when point gets too close to the edge. -When point is less than `automatic-hscroll-margin' columns from the window +When point is less than `hscroll-margin' columns from the window edge, automatic hscrolling will scroll the window by the amount of columns determined by this variable. If its value is a positive integer, scroll that many columns. If it's a positive floating-point number, it specifies the @@ -23708,6 +24187,11 @@ This is used to update submenus such as Buffers, whose contents depend on various data. */); Vmenu_bar_update_hook = Qnil; + DEFVAR_LISP ("menu-updating-frame", &Vmenu_updating_frame, + doc: /* Frame for which we are updating a menu. +The enable predicate for a menu binding should check this variable. */); + Vmenu_updating_frame = Qnil; + DEFVAR_BOOL ("inhibit-menubar-update", &inhibit_menubar_update, doc: /* Non-nil means don't update menu bars. Internal use only. */); inhibit_menubar_update = 0; @@ -23733,6 +24217,12 @@ whose contents depend on various data. */); doc: /* Inhibit try_cursor_movement display optimization. */); inhibit_try_cursor_movement = 0; #endif /* GLYPH_DEBUG */ + + DEFVAR_INT ("overline-margin", &overline_margin, + doc: /* *Space between overline and text, in pixels. +The default value is 2: the height of the overline (1 pixel) plus 1 pixel +margin to the caracter height. */); + overline_margin = 2; }