X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/81a17683620b3efc785bb70d20b2554e10c7e39d..af6ea8ad8d62810d901561ae4a56d89f22ebacf0:/src/xdisp.c diff --git a/src/xdisp.c b/src/xdisp.c index bdef9cd448..0e60020f11 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -202,6 +202,12 @@ Boston, MA 02110-1301, USA. */ #include "macterm.h" #endif +#ifdef HAVE_WINDOW_SYSTEM +#ifdef USE_FONT_BACKEND +#include "font.h" +#endif /* USE_FONT_BACKEND */ +#endif /* HAVE_WINDOW_SYSTEM */ + #ifndef FRAME_X_OUTPUT #define FRAME_X_OUTPUT(f) ((f)->output_data.x) #endif @@ -270,6 +276,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; @@ -705,6 +717,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 @@ -743,13 +759,13 @@ static enum prop_handled handle_auto_composed_prop P_ ((struct it *)); static struct props it_props[] = { - {&Qauto_composed, AUTO_COMPOSED_PROP_IDX, handle_auto_composed_prop}, {&Qfontified, FONTIFIED_PROP_IDX, handle_fontified_prop}, /* Handle `face' before `display' because some sub-properties of `display' need to know the face. */ {&Qface, FACE_PROP_IDX, handle_face_prop}, {&Qdisplay, DISPLAY_PROP_IDX, handle_display_prop}, {&Qinvisible, INVISIBLE_PROP_IDX, handle_invisible_prop}, + {&Qauto_composed, AUTO_COMPOSED_PROP_IDX, handle_auto_composed_prop}, {&Qcomposition, COMPOSITION_PROP_IDX, handle_composition_prop}, {NULL, 0, NULL} }; @@ -855,7 +871,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)); @@ -897,7 +913,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 *)); @@ -913,6 +929,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)); @@ -966,7 +983,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)); @@ -1907,7 +1924,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); @@ -1933,23 +1950,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++; } @@ -1979,15 +2000,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 @@ -1997,6 +2018,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); @@ -2026,8 +2055,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; } /* @@ -2893,8 +2923,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; } @@ -3005,7 +3035,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; } @@ -3655,8 +3697,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); } } @@ -3848,7 +3893,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. @@ -4065,7 +4110,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; @@ -4139,7 +4187,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; @@ -4432,7 +4483,7 @@ handle_auto_composed_prop (it) limit = make_number (find_next_newline_no_quit (pos, 1)); next = (Fnext_single_property_change - (make_number (pos), Qauto_composed, it->string, limit)); + (make_number (pos), Qauto_composed, it->string, limit)); if (XINT (next) < XINT (limit)) { /* The current point is auto-composed, but there exist @@ -4460,13 +4511,40 @@ handle_auto_composed_prop (it) if (NILP (val)) { int count = SPECPDL_INDEX (); - Lisp_Object args[3]; + Lisp_Object args[4]; args[0] = Vauto_composition_function; specbind (Qauto_composition_function, Qnil); args[1] = make_number (pos); args[2] = it->string; - safe_call (3, args); +#ifdef USE_FONT_BACKEND + if (enable_font_backend) + { + struct face *face = FACE_FROM_ID (it->f, it->face_id); + int c; + + if (STRINGP (it->string)) + { + EMACS_INT pos_byte = IT_STRING_BYTEPOS (*it); + const unsigned char *s = SDATA (it->string) + pos_byte; + + if (STRING_MULTIBYTE (it->string)) + it->c = STRING_CHAR (s, 0); + else + it->c = *s; + } + else + { + EMACS_INT pos_byte = IT_BYTEPOS (*it); + + it->c = FETCH_CHAR (pos_byte); + } + args[3] = font_at (it->c, this_pos, face, it->w, it->string); + } + else +#endif /* USE_FONT_BACKEND */ + args[3] = Qnil; + safe_call (4, args); unbind_to (count, Qnil); if (this_pos == pos) @@ -4530,16 +4608,52 @@ 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); +#ifdef USE_FONT_BACKEND + if (composition_table[id]->method == COMPOSITION_WITH_GLYPH_STRING) + { + Lisp_Object lgstring = AREF (XHASH_TABLE (composition_hash_table) + ->key_and_value, + cmp->hash_index * 2); + Lisp_Object font_object = LGSTRING_FONT (lgstring); + struct font *font = XSAVE_VALUE (font_object)->pointer; + struct face *face = FACE_FROM_ID (it->f, it->face_id); + + it->face_id = face_for_font (it->f, font, face); + it->c = ' '; + } + else +#endif /* USE_FONT_BACKEND */ /* For a terminal, draw only the first character of the components. */ it->c = COMPOSITION_GLYPH (composition_table[id], 0); 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; } } @@ -4599,13 +4713,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 @@ -4861,7 +4976,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; { @@ -4883,12 +4998,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 @@ -4900,13 +5016,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); @@ -4931,19 +5056,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; @@ -4970,13 +5114,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; @@ -5108,6 +5279,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; @@ -5127,37 +5299,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'); @@ -5280,7 +5462,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; @@ -5289,15 +5470,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) @@ -5774,18 +5951,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; @@ -5815,7 +5992,10 @@ set_iterator_to_next (it, reseat_p) 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; @@ -5863,9 +6043,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; @@ -5877,13 +6056,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: @@ -6028,9 +6202,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; @@ -6106,6 +6278,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; } @@ -6292,6 +6465,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; } @@ -6750,6 +6927,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); @@ -9013,6 +9194,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 (); @@ -9044,9 +9228,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; } @@ -9056,9 +9243,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 } @@ -9074,12 +9264,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; @@ -9144,28 +9340,35 @@ 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); - /* 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); + + hooks_run = 1; + } - safe_run_hooks (Qmenu_bar_update_hook); 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. */ @@ -9180,6 +9383,8 @@ update_menu_bar (f, save_match_data) set_buffer_internal_1 (prev); } } + + return hooks_run; } @@ -9344,7 +9549,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 @@ -9529,11 +9735,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; @@ -9548,29 +9765,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; } @@ -9589,11 +9819,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. */ @@ -9616,29 +9859,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); } @@ -9668,7 +9927,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); } } @@ -9713,9 +9972,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. */ @@ -9724,17 +10042,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; @@ -9742,13 +10063,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; @@ -9756,13 +10078,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; + } } } @@ -11570,9 +11895,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; @@ -11619,7 +11946,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; @@ -11627,16 +11954,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 */ @@ -11647,14 +11979,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)); } } @@ -11684,25 +12017,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)); @@ -11710,15 +12043,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]; @@ -11752,6 +12090,8 @@ set_cursor_from_row (w, row, matrix, delta, delta_bytes, dy, dvpos) else CHARPOS (this_line_start_pos) = 0; } + + return 1; } @@ -12435,8 +12775,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)); } } } @@ -12697,8 +13047,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, @@ -12868,6 +13216,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 @@ -14861,6 +15239,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); + } } @@ -14876,7 +15273,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\ @@ -15380,6 +15777,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) @@ -16320,6 +16718,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 (); @@ -16572,8 +16971,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; @@ -17825,7 +18227,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, @@ -18469,14 +18871,30 @@ get_glyph_face_and_encoding (f, glyph, char2b, two_byte_p) if (two_byte_p) *two_byte_p = 0; +#ifdef USE_FONT_BACKEND + if (enable_font_backend) + { + struct font *font = (struct font *) face->font_info; + + if (font) + { + unsigned code = font->driver->encode_char (font, glyph->u.ch); + + if (code != FONT_INVALID_CODE) + STORE_XCHAR2B (char2b, (code >> 8), (code & 0xFF)); + else + STORE_XCHAR2B (char2b, 0, code); + } + } + else +#endif /* USE_FONT_BACKEND */ if (!glyph->multibyte_p) { /* Unibyte case. We don't have to encode, but we have to make sure to use a face suitable for unibyte. */ STORE_XCHAR2B (char2b, 0, 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); @@ -18535,20 +18953,55 @@ fill_composite_glyph_string (s, faces, overlaps) s->for_overlaps = overlaps; s->face = faces[s->gidx]; - s->font = s->face->font; - s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id); + if (s->face == NULL) + { + s->font = NULL; + s->font_info = NULL; + } + else + { + s->font = s->face->font; + s->font_info = FONT_INFO_FROM_FACE (s->f, s->face); + } + +#ifdef USE_FONT_BACKEND + if (enable_font_backend && s->cmp->method == COMPOSITION_WITH_GLYPH_STRING) + { + Lisp_Object gstring + = AREF (XHASH_TABLE (composition_hash_table)->key_and_value, + s->cmp->hash_index * 2); + for (i = 0, s->nchars = 0; i < s->cmp->glyph_len; i++, s->nchars++) + { + Lisp_Object g = LGSTRING_GLYPH (gstring, i); + unsigned code; + + if (NILP (LGLYPH_FROM (g))) + break; + code = XUINT (LGLYPH_CODE (g)); + STORE_XCHAR2B (s->char2b + i, code >> 8, code & 0xFF); + } + s->width = s->cmp->pixel_width; + } + else + { +#endif /* USE_FONT_BACKEND */ /* For all glyphs of this composition, starting at the offset S->gidx, until we reach the end of the definition or encounter a glyph that requires the different face, add it to S. */ ++s->nchars; - for (i = s->gidx + 1; i < s->cmp->glyph_len && faces[i] == s->face; ++i) + for (i = s->gidx + 1; + i < s->cmp->glyph_len && (faces[i] == s->face || ! faces[i] || ! s->face); + ++i) ++s->nchars; /* All glyph strings for the same composition has the same width, i.e. the width set for the first component of the composition. */ s->width = s->first_glyph->pixel_width; +#ifdef USE_FONT_BACKEND + } +#endif /* USE_FONT_BACKEND */ /* If the specified font could not be loaded, use the frame's default font, but record the fact that we couldn't load it in @@ -18563,8 +19016,6 @@ fill_composite_glyph_string (s, faces, overlaps) /* Adjust base line for subscript/superscript text. */ s->ybase += s->first_glyph->voffset; - xassert (s->face && s->face->gc); - /* This glyph string must always be drawn with 16-bit functions. */ s->two_byte_p = 1; @@ -18622,7 +19073,7 @@ fill_glyph_string (s, face_id, start, end, overlaps) } s->font = s->face->font; - s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id); + s->font_info = FONT_INFO_FROM_FACE (s->f, s->face); /* If the specified font could not be loaded, use the frame's font, but record the fact that we couldn't load it in @@ -18686,8 +19137,9 @@ fill_stretch_glyph_string (s, row, area, start, end) face_id = glyph->face_id; s->face = FACE_FROM_ID (s->f, face_id); s->font = s->face->font; - s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id); + s->font_info = FONT_INFO_FROM_FACE (s->f, s->face); s->width = glyph->pixel_width; + s->nchars = 1; voffset = glyph->voffset; for (++glyph; @@ -18707,6 +19159,35 @@ fill_stretch_glyph_string (s, row, area, start, end) return glyph - s->row->glyphs[s->area]; } +static XCharStruct * +get_per_char_metric (font, font_info, char2b, font_type) + XFontStruct *font; + struct font_info *font_info; + XChar2b *char2b; + int font_type; +{ +#ifdef USE_FONT_BACKEND + if (enable_font_backend) + { + static XCharStruct pcm_value; + unsigned code = (XCHAR2B_BYTE1 (char2b) << 8) | XCHAR2B_BYTE2 (char2b); + struct font *fontp; + struct font_metrics metrics; + + if (! font_info || code == FONT_INVALID_CODE) + return NULL; + fontp = (struct font *) font_info; + fontp->driver->text_extents (fontp, &code, 1, &metrics); + pcm_value.lbearing = metrics.lbearing; + pcm_value.rbearing = metrics.rbearing; + pcm_value.ascent = metrics.ascent; + pcm_value.descent = metrics.descent; + pcm_value.width = metrics.width; + return &pcm_value; + } +#endif /* USE_FONT_BACKEND */ + return rif->per_char_metric (font, char2b, font_type); +} /* EXPORT for RIF: Set *LEFT and *RIGHT to the left and right overhang of GLYPH on @@ -18731,9 +19212,9 @@ x_get_glyph_overhangs (glyph, f, left, right) face = get_glyph_face_and_encoding (f, glyph, &char2b, NULL); font = face->font; - font_info = FONT_INFO_FROM_ID (f, face->font_info_id); + font_info = FONT_INFO_FROM_FACE (f, face); if (font /* ++KFS: Should this be font_info ? */ - && (pcm = rif->per_char_metric (font, &char2b, glyph->font_type))) + && (pcm = get_per_char_metric (font, font_info, &char2b, glyph->font_type))) { if (pcm->rbearing > pcm->width) *right = pcm->rbearing - pcm->width; @@ -18877,6 +19358,23 @@ get_char_face_and_encoding (f, c, face_id, char2b, multibyte_p, display_p) { struct face *face = FACE_FROM_ID (f, face_id); +#ifdef USE_FONT_BACKEND + if (enable_font_backend) + { + struct font *font = (struct font *) face->font_info; + + if (font) + { + unsigned code = font->driver->encode_char (font, c); + + if (code != FONT_INVALID_CODE) + STORE_XCHAR2B (char2b, (code >> 8), (code & 0xFF)); + else + STORE_XCHAR2B (char2b, 0, 0); + } + } + else +#endif /* USE_FONT_BACKEND */ if (!multibyte_p) { /* Unibyte case. We don't have to encode, but we have to make @@ -18885,7 +19383,7 @@ get_char_face_and_encoding (f, c, face_id, char2b, multibyte_p, display_p) face_id = FACE_FOR_CHAR (f, face, c, -1, Qnil); 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); @@ -19093,6 +19591,14 @@ compute_overhangs_and_x (s, x, backward_p) struct glyph_string *first_s = NULL; \ int n; \ \ + if (cmp->method > COMPOSITION_WITH_RULE_ALTCHARS) \ + { \ + /* This happens only when USE_FONT_BACKEND is defined. */ \ + char2b = (XChar2b *) alloca ((sizeof *char2b) * glyph_len); \ + faces = &base_face; \ + } \ + else \ + { \ base_face = base_face->ascii_face; \ char2b = (XChar2b *) alloca ((sizeof *char2b) * glyph_len); \ faces = (struct face **) alloca ((sizeof *faces) * glyph_len); \ @@ -19100,11 +19606,18 @@ compute_overhangs_and_x (s, x, backward_p) for (n = 0; n < glyph_len; n++) \ { \ int c = COMPOSITION_GLYPH (cmp, n); \ - int this_face_id = FACE_FOR_CHAR (f, base_face, c, -1, Qnil); \ - faces[n] = FACE_FROM_ID (f, this_face_id); \ - get_char_face_and_encoding (f, c, this_face_id, \ + \ + if (c == '\t') \ + faces[n] = NULL; \ + else \ + { \ + int this_face_id = FACE_FOR_CHAR (f, base_face, c, -1, Qnil); \ + faces[n] = FACE_FROM_ID (f, this_face_id); \ + get_char_face_and_encoding (f, c, this_face_id, \ char2b + n, 1, 1); \ + } \ } \ + } \ \ /* Make glyph_strings for each glyph sequence that is drawable by \ the same face, and append them to HEAD/TAIL. */ \ @@ -19836,20 +20349,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); } @@ -19933,7 +20432,7 @@ calc_line_height_property (it, val, font, boff, override) if (font == NULL) return make_number (-1); - font_info = FONT_INFO_FROM_ID (it->f, face->font_info_id); + font_info = FONT_INFO_FROM_FACE (it->f, face); boff = font_info->baseline_offset; if (font_info->vertical_centering) boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff; @@ -20027,7 +20526,7 @@ x_produce_glyphs (it) } else { - font_info = FONT_INFO_FROM_ID (it->f, face->font_info_id); + font_info = FONT_INFO_FROM_FACE (it->f, face); boff = font_info->baseline_offset; if (font_info->vertical_centering) boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff; @@ -20041,7 +20540,7 @@ x_produce_glyphs (it) it->nglyphs = 1; - pcm = rif->per_char_metric (font, &char2b, + pcm = get_per_char_metric (font, font_info, &char2b, FONT_TYPE_FOR_UNIBYTE (font, it->char_to_display)); if (it->override_ascent >= 0) @@ -20117,7 +20616,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) { @@ -20272,7 +20771,7 @@ x_produce_glyphs (it) multiplying the width of font by the width of the character. */ - pcm = rif->per_char_metric (font, &char2b, + pcm = get_per_char_metric (font, font_info, &char2b, FONT_TYPE_FOR_MULTIBYTE (font, it->c)); if (font_not_found_p || !pcm) @@ -20317,7 +20816,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); @@ -20348,6 +20847,10 @@ x_produce_glyphs (it) it->char_to_display = unibyte_char_to_multibyte (it->c); } +#ifdef USE_FONT_BACKEND + if (cmp->method != COMPOSITION_WITH_GLYPH_STRING) + { +#endif /* USE_FONT_BACKEND */ /* Get face and font to use. Encode IT->char_to_display. */ pos = STRINGP (it->string) ? IT_STRING_CHARPOS (*it) : IT_CHARPOS (*it); it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display, @@ -20367,11 +20870,14 @@ x_produce_glyphs (it) } else { - font_info = FONT_INFO_FROM_ID (it->f, face->font_info_id); + font_info = FONT_INFO_FROM_FACE (it->f, face); boff = font_info->baseline_offset; if (font_info->vertical_centering) boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff; } +#ifdef USE_FONT_BACKEND + } +#endif /* There are no padding glyphs, so there is only one glyph to produce for the composition. Important is that pixel_width, @@ -20391,6 +20897,13 @@ x_produce_glyphs (it) cmp->lbearing = cmp->rbearing = 0; cmp->pixel_width = cmp->ascent = cmp->descent = 0; } +#ifdef USE_FONT_BACKEND + else if (cmp->method == COMPOSITION_WITH_GLYPH_STRING) + { + if (! cmp->font) + font_prepare_composition (cmp); + } +#endif /* USE_FONT_BACKEND */ else if (cmp->font != (void *) font) { /* Ascent and descent of the font of the first character of @@ -20410,7 +20923,7 @@ x_produce_glyphs (it) /* Initialize the bounding box. */ if (font_info - && (pcm = rif->per_char_metric (font, &char2b, + && (pcm = get_per_char_metric (font, font_info, &char2b, FONT_TYPE_FOR_MULTIBYTE (font, it->c)))) { width = pcm->width; @@ -20462,6 +20975,8 @@ x_produce_glyphs (it) if (ch == '\t') { fully_padded = 1; + cmp->offsets[i * 2] = 0; + cmp->offsets[i * 2 + 1] = boff; continue; } @@ -20479,14 +20994,14 @@ x_produce_glyphs (it) else { font_info - = FONT_INFO_FROM_ID (it->f, face->font_info_id); + = FONT_INFO_FROM_FACE (it->f, face); boff = font_info->baseline_offset; if (font_info->vertical_centering) boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff; } if (font_info - && (pcm = rif->per_char_metric (font, &char2b, + && (pcm = get_per_char_metric (font, font_info, &char2b, FONT_TYPE_FOR_MULTIBYTE (font, ch)))) { width = pcm->width; @@ -20656,7 +21171,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); @@ -21032,10 +21547,33 @@ 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. */ + 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->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; } @@ -21321,7 +21859,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; @@ -21329,11 +21867,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); } @@ -22426,7 +22969,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; @@ -23797,6 +24343,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. @@ -23864,7 +24418,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 @@ -23917,6 +24471,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; }