diff options
Diffstat (limited to 'src/xdisp.c')
-rw-r--r-- | src/xdisp.c | 1488 |
1 files changed, 1104 insertions, 384 deletions
diff --git a/src/xdisp.c b/src/xdisp.c index 2d85a991e77..140d71129f3 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -637,8 +637,8 @@ fill_column_indicator_column (struct it *it, int char_width) if (RANGED_FIXNUMP (0, col, INT_MAX)) { int icol = XFIXNUM (col); - if (!INT_MULTIPLY_WRAPV (char_width, icol, &icol) - && !INT_ADD_WRAPV (it->lnum_pixel_width, icol, &icol)) + if (!ckd_mul (&icol, icol, char_width) + && !ckd_add (&icol, icol, it->lnum_pixel_width)) return icol; } } @@ -1229,6 +1229,7 @@ static void get_cursor_offset_for_mouse_face (struct window *w, #endif /* HAVE_WINDOW_SYSTEM */ static void produce_special_glyphs (struct it *, enum display_element_type); +static void pad_mode_line (struct it *, bool); static void show_mouse_face (Mouse_HLInfo *, enum draw_glyphs_face); static bool coords_in_mouse_face_p (struct window *, int, int); static void reset_box_start_end_flags (struct it *); @@ -2507,7 +2508,7 @@ get_glyph_string_clip_rects (struct glyph_string *s, NativeRectangle *rects, int r.x = s->clip_head->x; } if (s->clip_tail) - if (r.x + r.width > s->clip_tail->x + s->clip_tail->background_width) + if (r.x + (int) r.width > s->clip_tail->x + s->clip_tail->background_width) { if (s->clip_tail->x + s->clip_tail->background_width >= r.x) r.width = s->clip_tail->x + s->clip_tail->background_width - r.x; @@ -2587,7 +2588,7 @@ get_glyph_string_clip_rects (struct glyph_string *s, NativeRectangle *rects, int height = max (FRAME_LINE_HEIGHT (s->f), glyph->ascent + glyph->descent); if (height < r.height) { - max_y = r.y + r.height; + max_y = r.y + (int) r.height; r.y = min (max_y, max (r.y, s->ybase + glyph->descent - height)); r.height = min (max_y - r.y, height); } @@ -2628,7 +2629,7 @@ get_glyph_string_clip_rects (struct glyph_string *s, NativeRectangle *rects, int if (s->for_overlaps & OVERLAPS_PRED) { rs[i] = r; - if (r.y + r.height > row_y) + if (r.y + (int) r.height > row_y) { if (r.y < row_y) rs[i].height = row_y - r.y; @@ -2642,10 +2643,10 @@ get_glyph_string_clip_rects (struct glyph_string *s, NativeRectangle *rects, int rs[i] = r; if (r.y < row_y + s->row->visible_height) { - if (r.y + r.height > row_y + s->row->visible_height) + if (r.y + (int) 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; + rs[i].height = r.y + (int) r.height - rs[i].y; } else rs[i].height = 0; @@ -2758,6 +2759,7 @@ remember_mouse_glyph (struct frame *f, int gx, int gy, NativeRectangle *rect) enum window_part part; enum glyph_row_area area; int x, y, width, height; + int original_gx; if (mouse_fine_grained_tracking) { @@ -2768,13 +2770,15 @@ remember_mouse_glyph (struct frame *f, int gx, int gy, NativeRectangle *rect) /* Try to determine frame pixel position and size of the glyph under frame pixel coordinates X/Y on frame F. */ + original_gx = gx; + if (window_resize_pixelwise) { width = height = 1; goto virtual_glyph; } else if (!f->glyphs_initialized_p - || (window = window_from_coordinates (f, gx, gy, &part, false, false), + || (window = window_from_coordinates (f, gx, gy, &part, false, false, false), NILP (window))) { width = FRAME_SMALLEST_CHAR_WIDTH (f); @@ -2827,7 +2831,7 @@ remember_mouse_glyph (struct frame *f, int gx, int gy, NativeRectangle *rect) text_glyph: gr = 0; gy = 0; for (; r <= end_row && r->enabled_p; ++r) - if (r->y + r->height > y) + if (r->y + (int) r->height > y) { gr = r; gy = r->y; break; @@ -2927,7 +2931,7 @@ remember_mouse_glyph (struct frame *f, int gx, int gy, NativeRectangle *rect) row_glyph: gr = 0, gy = 0; for (; r <= end_row && r->enabled_p; ++r) - if (r->y + r->height > y) + if (r->y + (int) r->height > y) { gr = r; gy = r->y; break; @@ -2983,6 +2987,15 @@ remember_mouse_glyph (struct frame *f, int gx, int gy, NativeRectangle *rect) gy += WINDOW_TOP_EDGE_Y (w); store_rect: + if (mouse_prefer_closest_glyph) + { + int half_width = width / 2; + width = half_width; + + int bisection = gx + half_width; + if (original_gx > bisection) + gx = bisection; + } STORE_NATIVE_RECT (*rect, gx, gy, width, height); /* Visible feedback for debugging. */ @@ -3018,10 +3031,10 @@ hscrolling_current_line_p (struct window *w) Lisp form evaluation ***********************************************************************/ -/* Error handler for safe_eval and safe_call. */ +/* Error handler for dsafe_eval and dsafe_call. */ static Lisp_Object -safe_eval_handler (Lisp_Object arg, ptrdiff_t nargs, Lisp_Object *args) +dsafe_eval_handler (Lisp_Object arg, ptrdiff_t nargs, Lisp_Object *args) { add_to_log ("Error during redisplay: %S signaled %S", Flist (nargs, args), arg); @@ -3032,8 +3045,11 @@ safe_eval_handler (Lisp_Object arg, ptrdiff_t nargs, Lisp_Object *args) following. Return the result, or nil if something went wrong. Prevent redisplay during the evaluation. */ +/* FIXME: What's the guiding principle behind the choice + of which calls should set 'inhibit_quit' and which don't. */ static Lisp_Object -safe__call (bool inhibit_quit, ptrdiff_t nargs, Lisp_Object func, va_list ap) +dsafe__call (bool inhibit_quit, Lisp_Object (f) (ptrdiff_t, Lisp_Object *), + ptrdiff_t nargs, Lisp_Object *args) { Lisp_Object val; @@ -3041,84 +3057,52 @@ safe__call (bool inhibit_quit, ptrdiff_t nargs, Lisp_Object func, va_list ap) val = Qnil; else { - ptrdiff_t i; specpdl_ref count = SPECPDL_INDEX (); - Lisp_Object *args; - USE_SAFE_ALLOCA; - SAFE_ALLOCA_LISP (args, nargs); - - args[0] = func; - for (i = 1; i < nargs; i++) - args[i] = va_arg (ap, Lisp_Object); specbind (Qinhibit_redisplay, Qt); if (inhibit_quit) specbind (Qinhibit_quit, Qt); /* Use Qt to ensure debugger does not run, so there is no possibility of wanting to redisplay. */ - val = internal_condition_case_n (Ffuncall, nargs, args, Qt, - safe_eval_handler); - val = SAFE_FREE_UNBIND_TO (count, val); + val = internal_condition_case_n (f, nargs, args, Qt, + dsafe_eval_handler); + val = unbind_to (count, val); } return val; } -Lisp_Object -safe_call (ptrdiff_t nargs, Lisp_Object func, ...) -{ - Lisp_Object retval; - va_list ap; - - va_start (ap, func); - retval = safe__call (false, nargs, func, ap); - va_end (ap); - return retval; -} - -/* Call function FN with one argument ARG. - Return the result, or nil if something went wrong. */ - -Lisp_Object -safe_call1 (Lisp_Object fn, Lisp_Object arg) -{ - return safe_call (2, fn, arg); -} - static Lisp_Object -safe__call1 (bool inhibit_quit, Lisp_Object fn, ...) +funcall_with_backtraces (ptrdiff_t nargs, Lisp_Object *args) { - Lisp_Object retval; - va_list ap; - - va_start (ap, fn); - retval = safe__call (inhibit_quit, 2, fn, ap); - va_end (ap); - return retval; + /* If an error is signaled during a Lisp hook in redisplay, write a + backtrace into the buffer *Redisplay-trace*. */ + push_handler_bind (list_of_error, Qdebug_early__muted, 0); + Lisp_Object res = Ffuncall (nargs, args); + pop_handler (); + return res; } -Lisp_Object -safe_eval (Lisp_Object sexpr) -{ - return safe__call1 (false, Qeval, sexpr); -} +#define SAFE_CALLMANY(inhibit_quit, f, array) \ + dsafe__call (inhibit_quit, f, ARRAYELTS (array), array) +#define dsafe_calln(inhibit_quit, ...) \ + SAFE_CALLMANY (inhibit_quit, \ + backtrace_on_redisplay_error \ + ? funcall_with_backtraces : Ffuncall, \ + ((Lisp_Object []) {__VA_ARGS__})) static Lisp_Object -safe__eval (bool inhibit_quit, Lisp_Object sexpr) +dsafe_call1 (Lisp_Object f, Lisp_Object arg) { - return safe__call1 (inhibit_quit, Qeval, sexpr); + return dsafe_calln (false, f, arg); } -/* Call function FN with two arguments ARG1 and ARG2. - Return the result, or nil if something went wrong. */ - -Lisp_Object -safe_call2 (Lisp_Object fn, Lisp_Object arg1, Lisp_Object arg2) +static Lisp_Object +dsafe_eval (Lisp_Object sexpr) { - return safe_call (3, fn, arg1, arg2); + return dsafe_calln (true, Qeval, sexpr, Qt); } - /*********************************************************************** Debugging @@ -3753,18 +3737,25 @@ start_display (struct it *it, struct window *w, struct text_pos pos) /* Don't reseat to previous visible line start if current start position is in a string or image. */ - if (it->method == GET_FROM_BUFFER && it->line_wrap != TRUNCATE) + if (it->line_wrap != TRUNCATE) { - int first_y = it->current_y; + enum it_method method = it->method; - /* If window start is not at a line start, skip forward to POS to - get the correct continuation lines width. */ + /* If window start is not at a line start, skip forward to POS + from the beginning of physical line to get the correct + continuation lines width. */ bool start_at_line_beg_p = (CHARPOS (pos) == BEGV || FETCH_BYTE (BYTEPOS (pos) - 1) == '\n'); if (!start_at_line_beg_p) { + int first_y = it->current_y; + int continuation_width; + void *itdata = NULL; + struct it it2; int new_x; + if (method != GET_FROM_BUFFER) + SAVE_IT (it2, *it, itdata); reseat_at_previous_visible_line_start (it); move_it_to (it, CHARPOS (pos), -1, -1, -1, MOVE_TO_POS); @@ -3811,6 +3802,17 @@ start_display (struct it *it, struct window *w, struct text_pos pos) else if (it->current.dpvec_index >= 0) it->current.dpvec_index = 0; + continuation_width = it->continuation_lines_width; + /* If we started from a position in something other than a + buffer, restore the original iterator state, keeping only + the continuation_lines_width, since we could now be very + far from the original position. */ + if (method != GET_FROM_BUFFER) + { + RESTORE_IT (it, &it2, itdata); + it->continuation_lines_width = continuation_width; + } + /* We're starting a new display line, not affected by the height of the continued line, so clear the appropriate fields in the iterator structure. */ @@ -3819,7 +3821,7 @@ start_display (struct it *it, struct window *w, struct text_pos pos) it->current_y = first_y; it->vpos = 0; - it->current_x = it->hpos = 0; + it->current_x = it->hpos = it->wrap_prefix_width = 0; } } } @@ -4212,7 +4214,7 @@ compute_stop_pos (struct it *it) { register INTERVAL iv, next_iv; Lisp_Object object, limit, position; - ptrdiff_t charpos, bytepos; + ptrdiff_t charpos, bytepos, cmp_limit_pos = -1; if (STRINGP (it->string)) { @@ -4282,7 +4284,10 @@ compute_stop_pos (struct it *it) } } if (found) - pos--; + { + pos--; + cmp_limit_pos = pos; + } else if (it->stop_charpos < endpos) pos = it->stop_charpos; else @@ -4344,10 +4349,20 @@ compute_stop_pos (struct it *it) { ptrdiff_t stoppos = it->end_charpos; + /* If we found, above, a buffer position that cannot be part of + an automatic composition, limit the search of composable + characters to that position. */ if (it->bidi_p && it->bidi_it.scan_dir < 0) - stoppos = -1; + stoppos = bidi_level_start (it->bidi_it.resolved_level) - 1; + else if (!STRINGP (it->string) + && it->cmp_it.stop_pos <= IT_CHARPOS (*it) + && cmp_limit_pos > 0) + stoppos = cmp_limit_pos; + /* Force composition_compute_stop_pos avoid the costly search + for static compositions, since those were already found by + looking at text properties, above. */ composition_compute_stop_pos (&it->cmp_it, charpos, bytepos, - stoppos, it->string); + stoppos, it->string, false); } eassert (STRINGP (it->string) @@ -4570,7 +4585,7 @@ handle_fontified_prop (struct it *it) it->f->inhibit_clear_image_cache = true; if (!CONSP (val) || EQ (XCAR (val), Qlambda)) - safe_call1 (val, pos); + dsafe_call1 (val, pos); else { Lisp_Object fns, fn; @@ -4594,11 +4609,11 @@ handle_fontified_prop (struct it *it) { fn = XCAR (fns); if (!EQ (fn, Qt)) - safe_call1 (fn, pos); + dsafe_call1 (fn, pos); } } else - safe_call1 (fn, pos); + dsafe_call1 (fn, pos); } } @@ -5046,31 +5061,169 @@ handle_invisible_prop (struct it *it) { enum prop_handled handled = HANDLED_NORMALLY; int invis; - Lisp_Object prop; + ptrdiff_t curpos, endpos; + Lisp_Object prop, pos, overlay; + /* Get the value of the invisible text property at the current + position. Value will be nil if there is no such property. */ if (STRINGP (it->string)) { - Lisp_Object end_charpos, limit; + curpos = IT_STRING_CHARPOS (*it); + endpos = SCHARS (it->string); + pos = make_fixnum (curpos); + prop = Fget_text_property (pos, Qinvisible, it->string); + } + else /* buffer */ + { + curpos = IT_CHARPOS (*it); + endpos = ZV; + pos = make_fixnum (curpos); + prop = get_char_property_and_overlay (pos, Qinvisible, it->window, + &overlay); + } - /* Get the value of the invisible text property at the - current position. Value will be nil if there is no such - property. */ - end_charpos = make_fixnum (IT_STRING_CHARPOS (*it)); - prop = Fget_text_property (end_charpos, Qinvisible, it->string); - invis = TEXT_PROP_MEANS_INVISIBLE (prop); + /* Do we have anything to do here? */ + invis = TEXT_PROP_MEANS_INVISIBLE (prop); + if (invis == 0 || curpos >= it->end_charpos) + return handled; - if (invis != 0 && IT_STRING_CHARPOS (*it) < it->end_charpos) + /* If not bidi, or the bidi iteration is at base paragraph level, we + can use a faster method; otherwise we need to check invisibility + of every character while bidi-iterating out of invisible text. */ + bool slow = it->bidi_p && !BIDI_AT_BASE_LEVEL (it->bidi_it); + /* Record whether we have to display an ellipsis for the + invisible text. */ + bool display_ellipsis_p = (invis == 2); + + handled = HANDLED_RECOMPUTE_PROPS; + + if (slow) + { + if (it->bidi_it.first_elt && it->bidi_it.charpos < endpos) + bidi_paragraph_init (it->paragraph_embedding, &it->bidi_it, true); + + if (STRINGP (it->string)) { - /* Record whether we have to display an ellipsis for the - invisible text. */ - bool display_ellipsis_p = (invis == 2); - ptrdiff_t len, endpos; + bool done = false; + /* Bidi-iterate out of the invisible part of the string. */ + do + { + bidi_move_to_visually_next (&it->bidi_it); + if (it->bidi_it.charpos < 0 || it->bidi_it.charpos >= endpos) + done = true; + else + { + pos = make_fixnum (it->bidi_it.charpos); + prop = Fget_text_property (pos, Qinvisible, it->string); + invis = TEXT_PROP_MEANS_INVISIBLE (prop); + /* If there are adjacent invisible texts, don't lose + the second one's ellipsis. */ + if (invis == 2) + display_ellipsis_p = true; + } + } + while (!done && invis != 0); - handled = HANDLED_RECOMPUTE_PROPS; + if (display_ellipsis_p) + it->ellipsis_p = true; + IT_STRING_CHARPOS (*it) = it->bidi_it.charpos; + IT_STRING_BYTEPOS (*it) = it->bidi_it.bytepos; + if (IT_STRING_BYTEPOS (*it) >= endpos) + { + /* The rest of the string is invisible. If this is an + overlay string, proceed with the next overlay string + or whatever comes and return a character from there. */ + if (it->current.overlay_string_index >= 0 + && !display_ellipsis_p) + { + next_overlay_string (it); + /* Don't check for overlay strings when we just + finished processing them. */ + handled = HANDLED_OVERLAY_STRING_CONSUMED; + } + } + } + else + { + bool done = false; + /* Bidi-iterate out of the invisible text. */ + do + { + bidi_move_to_visually_next (&it->bidi_it); + if (it->bidi_it.charpos < BEGV || it->bidi_it.charpos >= endpos) + done = true; + else + { + pos = make_fixnum (it->bidi_it.charpos); + prop = Fget_char_property (pos, Qinvisible, it->window); + invis = TEXT_PROP_MEANS_INVISIBLE (prop); + /* If there are adjacent invisible texts, don't lose + the second one's ellipsis. */ + if (invis == 2) + display_ellipsis_p = true; + } + } + while (!done && invis != 0); + + IT_CHARPOS (*it) = it->bidi_it.charpos; + IT_BYTEPOS (*it) = it->bidi_it.bytepos; + if (display_ellipsis_p) + { + /* Make sure that the glyphs of the ellipsis will get + correct `charpos' values. See below for detailed + explanation why this is needed. */ + it->position.charpos = IT_CHARPOS (*it) - 1; + it->position.bytepos = CHAR_TO_BYTE (it->position.charpos); + } + /* If there are before-strings at the start of invisible + text, and the text is invisible because of a text + property, arrange to show before-strings because 20.x did + it that way. (If the text is invisible because of an + overlay property instead of a text property, this is + already handled in the overlay code.) */ + if (NILP (overlay) + && get_overlay_strings (it, it->stop_charpos)) + { + handled = HANDLED_RECOMPUTE_PROPS; + if (it->sp > 0) + { + it->stack[it->sp - 1].display_ellipsis_p = display_ellipsis_p; + /* The call to get_overlay_strings above recomputes + it->stop_charpos, but it only considers changes + in properties and overlays beyond iterator's + current position. This causes us to miss changes + that happen exactly where the invisible property + ended. So we play it safe here and force the + iterator to check for potential stop positions + immediately after the invisible text. Note that + if get_overlay_strings returns true, it + normally also pushed the iterator stack, so we + need to update the stop position in the slot + below the current one. */ + it->stack[it->sp - 1].stop_charpos + = CHARPOS (it->stack[it->sp - 1].current.pos); + } + } + else if (display_ellipsis_p) + { + it->ellipsis_p = true; + /* Let the ellipsis display before + considering any properties of the following char. + Fixes jasonr@gnu.org 01 Oct 07 bug. */ + handled = HANDLED_RETURN; + } + } + } + else if (STRINGP (it->string)) + { + Lisp_Object end_charpos = pos, limit; + + if (invis != 0 && IT_STRING_CHARPOS (*it) < it->end_charpos) + { + ptrdiff_t len = endpos; /* Get the position at which the next visible text can be found in IT->string, if any. */ - endpos = len = SCHARS (it->string); XSETINT (limit, len); do { @@ -5121,7 +5274,7 @@ handle_invisible_prop (struct it *it) IT_STRING_CHARPOS (*it) = it->bidi_it.charpos; IT_STRING_BYTEPOS (*it) = it->bidi_it.bytepos; - if (IT_CHARPOS (*it) >= endpos) + if (IT_STRING_CHARPOS (*it) >= endpos) it->prev_stop = endpos; } else @@ -5151,27 +5304,14 @@ handle_invisible_prop (struct it *it) } } } - else + else /* we are iterating over buffer text at base paragraph level */ { - ptrdiff_t newpos, next_stop, start_charpos, tem; - Lisp_Object pos, overlay; - - /* First of all, is there invisible text at this position? */ - tem = start_charpos = IT_CHARPOS (*it); - pos = make_fixnum (tem); - prop = get_char_property_and_overlay (pos, Qinvisible, it->window, - &overlay); - invis = TEXT_PROP_MEANS_INVISIBLE (prop); + ptrdiff_t newpos, next_stop, tem = curpos; + Lisp_Object pos; /* If we are on invisible text, skip over it. */ - if (invis != 0 && start_charpos < it->end_charpos) + if (invis != 0 && curpos < it->end_charpos) { - /* Record whether we have to display an ellipsis for the - invisible text. */ - bool display_ellipsis_p = invis == 2; - - handled = HANDLED_RECOMPUTE_PROPS; - /* Loop skipping over invisible text. The loop is left at ZV or with IT on the first char being visible again. */ do @@ -5471,9 +5611,6 @@ display_min_width (struct it *it, ptrdiff_t bufpos, if (!NILP (it->min_width_property) && !EQ (width_spec, it->min_width_property)) { - if (!it->glyph_row) - return; - /* When called from display_string (i.e., the mode line), we're being called with a string as the object, and we may be called with many sub-strings belonging to the same @@ -5516,7 +5653,13 @@ display_min_width (struct it *it, ptrdiff_t bufpos, it->object = list3 (Qspace, QCwidth, w); produce_stretch_glyph (it); if (it->area == TEXT_AREA) - it->current_x += it->pixel_width; + { + it->current_x += it->pixel_width; + + if (it->continuation_lines_width + && it->string_from_prefix_prop_p) + it->wrap_prefix_width = it->current_x; + } it->min_width_property = Qnil; } } @@ -5810,7 +5953,7 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object, /* Save and restore the bidi cache, since FORM could be crazy enough to re-enter redisplay, e.g., by calling 'message'. */ itdata = bidi_shelve_cache (); - form = safe_eval (form); + form = dsafe_eval (form); bidi_unshelve_cache (itdata, false); form = unbind_to (count, form); } @@ -5852,7 +5995,7 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object, struct face *face = FACE_FROM_ID (it->f, it->face_id); Lisp_Object height; itdata = bidi_shelve_cache (); - height = safe_call1 (it->font_height, + height = dsafe_call1 (it->font_height, face->lface[LFACE_HEIGHT_INDEX]); bidi_unshelve_cache (itdata, false); if (NUMBERP (height)) @@ -5877,7 +6020,7 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object, specbind (Qheight, face->lface[LFACE_HEIGHT_INDEX]); itdata = bidi_shelve_cache (); - value = safe_eval (it->font_height); + value = dsafe_eval (it->font_height); bidi_unshelve_cache (itdata, false); value = unbind_to (count, value); @@ -6759,7 +6902,7 @@ load_overlay_strings (struct it *it, ptrdiff_t charpos) \ entries[n].string = (STRING); \ entries[n].overlay = (OVERLAY); \ - priority = Foverlay_get ((OVERLAY), Qpriority); \ + priority = Foverlay_get (OVERLAY, Qpriority); \ entries[n].priority = FIXNUMP (priority) ? XFIXNUM (priority) : 0; \ entries[n].after_string_p = (AFTER_P); \ ++n; \ @@ -7877,7 +8020,7 @@ reseat_to_string (struct it *it, const char *s, Lisp_Object string, if (endpos > it->end_charpos) endpos = it->end_charpos; composition_compute_stop_pos (&it->cmp_it, charpos, -1, endpos, - it->string); + it->string, true); } CHECK_IT (it); } @@ -8569,11 +8712,10 @@ set_iterator_to_next (struct it *it, bool reseat_p) ptrdiff_t stop = it->end_charpos; if (it->bidi_it.scan_dir < 0) - /* Now we are scanning backward and don't know - where to stop. */ - stop = -1; + /* Now we are scanning backward; figure out where to stop. */ + stop = bidi_level_start (it->bidi_it.resolved_level) - 1; composition_compute_stop_pos (&it->cmp_it, IT_CHARPOS (*it), - IT_BYTEPOS (*it), stop, Qnil); + IT_BYTEPOS (*it), stop, Qnil, true); } } else @@ -8602,9 +8744,10 @@ set_iterator_to_next (struct it *it, bool reseat_p) re-compute the stop position for composition. */ ptrdiff_t stop = it->end_charpos; if (it->bidi_it.scan_dir < 0) - stop = -1; + stop = bidi_level_start (it->bidi_it.resolved_level) - 1; composition_compute_stop_pos (&it->cmp_it, IT_CHARPOS (*it), - IT_BYTEPOS (*it), stop, Qnil); + IT_BYTEPOS (*it), stop, Qnil, + true); } } eassert (IT_BYTEPOS (*it) == CHAR_TO_BYTE (IT_CHARPOS (*it))); @@ -8760,7 +8903,7 @@ set_iterator_to_next (struct it *it, bool reseat_p) composition_compute_stop_pos (&it->cmp_it, IT_STRING_CHARPOS (*it), IT_STRING_BYTEPOS (*it), stop, - it->string); + it->string, true); } } else @@ -8797,7 +8940,7 @@ set_iterator_to_next (struct it *it, bool reseat_p) composition_compute_stop_pos (&it->cmp_it, IT_STRING_CHARPOS (*it), IT_STRING_BYTEPOS (*it), stop, - it->string); + it->string, true); } } } @@ -9046,9 +9189,11 @@ get_visually_first_element (struct it *it) bytepos = IT_BYTEPOS (*it); } if (it->bidi_it.scan_dir < 0) - stop = -1; + stop = STRINGP (it->string) + ? -1 + : bidi_level_start (it->bidi_it.resolved_level) - 1; composition_compute_stop_pos (&it->cmp_it, charpos, bytepos, stop, - it->string); + it->string, true); } } @@ -9550,9 +9695,10 @@ next_element_from_buffer (struct it *it) && PT < it->end_charpos) ? PT : it->end_charpos; } else - stop = it->bidi_it.scan_dir < 0 ? -1 : it->end_charpos; - if (CHAR_COMPOSED_P (it, IT_CHARPOS (*it), IT_BYTEPOS (*it), - stop) + stop = it->bidi_it.scan_dir < 0 + ? bidi_level_start (it->bidi_it.resolved_level) - 1 + : it->end_charpos; + if (CHAR_COMPOSED_P (it, IT_CHARPOS (*it), IT_BYTEPOS (*it), stop) && next_element_from_composition (it)) { return true; @@ -9716,6 +9862,13 @@ move_it_in_display_line_to (struct it *it, ptrdiff_t prev_pos = IT_CHARPOS (*it); bool saw_smaller_pos = prev_pos < to_charpos; bool line_number_pending = false; + int this_line_subject_to_line_prefix = 0; + +#ifdef GLYPH_DEBUG + /* atx_flag, atpos_flag and wrap_flag are assigned but never used; + these hold information useful while debugging. */ + int atx_flag, atpos_flag, wrap_flag; +#endif /* GLYPH_DEBUG */ /* Don't produce glyphs in produce_glyphs. */ saved_glyph_row = it->glyph_row; @@ -9781,6 +9934,11 @@ move_it_in_display_line_to (struct it *it, /* If there's a line-/wrap-prefix, handle it, if we didn't already. */ if (it->area == TEXT_AREA && !it->string_from_prefix_prop_p) handle_line_prefix (it); + + /* Save whether this line has received a wrap prefix, as this + affects whether Emacs attempts to move glyphs into + continuation lines. */ + this_line_subject_to_line_prefix = it->string_from_prefix_prop_p; } if (IT_CHARPOS (*it) < CHARPOS (this_line_min_pos)) @@ -9824,10 +9982,15 @@ move_it_in_display_line_to (struct it *it, break; } else if (it->line_wrap == WORD_WRAP && atpos_it.sp < 0) - /* If wrap_it is valid, the current position might be in a - word that is wrapped. So, save the iterator in - atpos_it and continue to see if wrapping happens. */ - SAVE_IT (atpos_it, *it, atpos_data); + { + /* If wrap_it is valid, the current position might be in + a word that is wrapped. So, save the iterator in + atpos_it and continue to see if wrapping happens. */ + SAVE_IT (atpos_it, *it, atpos_data); +#ifdef GLYPH_DEBUG + atpos_flag = this_line_subject_to_line_prefix; +#endif /* GLYPH_DEBUG */ + } } /* Stop when ZV reached. @@ -9889,6 +10052,9 @@ move_it_in_display_line_to (struct it *it, } /* Otherwise, we can wrap here. */ SAVE_IT (wrap_it, *it, wrap_data); +#ifdef GLYPH_DEBUG + wrap_flag = this_line_subject_to_line_prefix; +#endif /* GLYPH_DEBUG */ } /* Update may_wrap for the next iteration. */ may_wrap = next_may_wrap; @@ -9967,6 +10133,9 @@ move_it_in_display_line_to (struct it *it, { SAVE_IT (atpos_it, *it, atpos_data); IT_RESET_X_ASCENT_DESCENT (&atpos_it); +#ifdef GLYPH_DEBUG + atpos_flag = this_line_subject_to_line_prefix; +#endif /* GLYPH_DEBUG */ } } else @@ -9981,6 +10150,9 @@ move_it_in_display_line_to (struct it *it, { SAVE_IT (atx_it, *it, atx_data); IT_RESET_X_ASCENT_DESCENT (&atx_it); +#ifdef GLYPH_DEBUG + atx_flag = this_line_subject_to_line_prefix; +#endif /* GLYPH_DEBUG */ } } } @@ -9995,12 +10167,27 @@ move_it_in_display_line_to (struct it *it, && FRAME_WINDOW_P (it->f) && ((it->bidi_p && it->bidi_it.paragraph_dir == R2L) ? WINDOW_LEFT_FRINGE_WIDTH (it->w) - : WINDOW_RIGHT_FRINGE_WIDTH (it->w))))) + : WINDOW_RIGHT_FRINGE_WIDTH (it->w)))) + /* There is no line prefix, next to which the + iterator _must_ produce a minimum of one actual + glyph. */ + && (!this_line_subject_to_line_prefix + /* Or this is the second glyph to be produced + beyond the confines of the line. */ + || (i != 0 + && (x > it->last_visible_x + || (x == it->last_visible_x + && FRAME_WINDOW_P (it->f) + && ((it->bidi_p + && it->bidi_it.paragraph_dir == R2L) + ? WINDOW_LEFT_FRINGE_WIDTH (it->w) + : WINDOW_RIGHT_FRINGE_WIDTH (it->w))))))) { bool moved_forward = false; if (/* IT->hpos == 0 means the very first glyph - doesn't fit on the line, e.g. a wide image. */ + doesn't fit on the line, e.g. a wide + image. */ it->hpos == 0 || (new_x == it->last_visible_x && FRAME_WINDOW_P (it->f))) @@ -10061,6 +10248,9 @@ move_it_in_display_line_to (struct it *it, SAVE_IT (atpos_it, *it, atpos_data); atpos_it.current_x = x_before_this_char; atpos_it.hpos = hpos_before_this_char; +#ifdef GLYPH_DEBUG + atpos_flag = this_line_subject_to_line_prefix; +#endif /* GLYPH_DEBUG */ } } @@ -10158,6 +10348,9 @@ move_it_in_display_line_to (struct it *it, if (it->line_wrap == WORD_WRAP && atpos_it.sp < 0) { SAVE_IT (atpos_it, *it, atpos_data); +#ifdef GLYPH_DEBUG + atpos_flag = this_line_subject_to_line_prefix; +#endif /* GLYPH_DEBUG */ IT_RESET_X_ASCENT_DESCENT (&atpos_it); } } @@ -10256,24 +10449,24 @@ move_it_in_display_line_to (struct it *it, if (it->method == GET_FROM_BUFFER) prev_pos = IT_CHARPOS (*it); - /* Detect overly-wide wrap-prefixes made of (space ...) display - properties. When such a wrap prefix reaches past the right - margin of the window, we need to avoid the call to - set_iterator_to_next below, so that it->line_wrap is left at - its TRUNCATE value wisely set by handle_line_prefix. - Otherwise, set_iterator_to_next will pop the iterator stack, - restore it->line_wrap, and we might miss the opportunity to - exit the loop and return. */ - bool overwide_wrap_prefix = - CONSP (it->object) && EQ (XCAR (it->object), Qspace) - && it->sp > 0 && it->method == GET_FROM_STRETCH - && it->current_x >= it->last_visible_x - && it->continuation_lines_width > 0 - && it->line_wrap == TRUNCATE && it->stack[0].line_wrap != TRUNCATE; - /* The current display element has been consumed. Advance - to the next. */ - if (!overwide_wrap_prefix) - set_iterator_to_next (it, true); + /* The current display element has been consumed. Advance to + the next. */ + set_iterator_to_next (it, true); + + /* If IT has just finished producing glyphs for the wrap prefix + and is proceeding to the next method, there might not be + sufficient space remaining in this line to accommodate its + glyphs, and one real glyph must be produced to prevent an + infinite loop. Next, clear this flag if such a glyph has + already been produced. */ + + if (this_line_subject_to_line_prefix == 1 + && !it->string_from_prefix_prop_p) + this_line_subject_to_line_prefix = 2; + else if (this_line_subject_to_line_prefix == 2 + && !it->string_from_prefix_prop_p) + this_line_subject_to_line_prefix = 0; + if (IT_CHARPOS (*it) < CHARPOS (this_line_min_pos)) SET_TEXT_POS (this_line_min_pos, IT_CHARPOS (*it), IT_BYTEPOS (*it)); if (IT_CHARPOS (*it) < to_charpos) @@ -10357,11 +10550,26 @@ move_it_in_display_line_to (struct it *it, && wrap_it.sp >= 0 && ((atpos_it.sp >= 0 && wrap_it.current_x < atpos_it.current_x) || (atx_it.sp >= 0 && wrap_it.current_x < atx_it.current_x))) - RESTORE_IT (it, &wrap_it, wrap_data); + { +#ifdef GLYPH_DEBUG + this_line_subject_to_line_prefix = wrap_flag; +#endif /* GLYPH_DEBUG */ + RESTORE_IT (it, &wrap_it, wrap_data); + } else if (atpos_it.sp >= 0) - RESTORE_IT (it, &atpos_it, atpos_data); + { +#ifdef GLYPH_DEBUG + this_line_subject_to_line_prefix = atpos_flag; +#endif /* GLYPH_DEBUG */ + RESTORE_IT (it, &atpos_it, atpos_data); + } else if (atx_it.sp >= 0) - RESTORE_IT (it, &atx_it, atx_data); + { +#ifdef GLYPH_DEBUG + this_line_subject_to_line_prefix = atx_flag; +#endif /* GLYPH_DEBUG */ + RESTORE_IT (it, &atx_it, atx_data); + } done: @@ -10435,13 +10643,9 @@ move_it_to (struct it *it, ptrdiff_t to_charpos, int to_x, int to_y, int to_vpos int line_height, line_start_x = 0, reached = 0; int max_current_x = 0; void *backup_data = NULL; - ptrdiff_t orig_charpos = -1; - enum it_method orig_method = NUM_IT_METHODS; for (;;) { - orig_charpos = IT_CHARPOS (*it); - orig_method = it->method; if (op & MOVE_TO_VPOS) { /* If no TO_CHARPOS and no TO_X specified, stop at the @@ -10713,21 +10917,7 @@ move_it_to (struct it *it, ptrdiff_t to_charpos, int to_x, int to_y, int to_vpos } } else - { - /* Make sure we do advance, otherwise we might infloop. - This could happen when the first display element is - wider than the window, or if we have a wrap-prefix - that doesn't leave enough space after it to display - even a single character. We only do this for moving - through buffer text, as with display/overlay strings - we'd need to also compare it->object's, and this is - unlikely to happen in that case anyway. */ - if (IT_CHARPOS (*it) == orig_charpos - && it->method == orig_method - && orig_method == GET_FROM_BUFFER) - set_iterator_to_next (it, false); - it->continuation_lines_width += it->current_x; - } + it->continuation_lines_width += it->current_x; break; default: @@ -10736,6 +10926,7 @@ move_it_to (struct it *it, ptrdiff_t to_charpos, int to_x, int to_y, int to_vpos /* Reset/increment for the next run. */ it->current_x = line_start_x; + it->wrap_prefix_width = 0; line_start_x = 0; it->hpos = 0; it->line_number_produced_p = false; @@ -10766,6 +10957,7 @@ move_it_to (struct it *it, ptrdiff_t to_charpos, int to_x, int to_y, int to_vpos { it->continuation_lines_width += it->current_x; it->current_x = it->hpos = it->max_ascent = it->max_descent = 0; + it->wrap_prefix_width = 0; it->current_y += it->max_ascent + it->max_descent; ++it->vpos; last_height = it->max_ascent + it->max_descent; @@ -10825,6 +11017,7 @@ move_it_vertically_backward (struct it *it, int dy) reseat_1 (it, it->current.pos, true); /* We are now surely at a line start. */ + it->wrap_prefix_width = 0; it->current_x = it->hpos = 0; /* FIXME: this is incorrect when bidi reordering is in effect. */ it->continuation_lines_width = 0; @@ -11103,7 +11296,7 @@ move_it_by_lines (struct it *it, ptrdiff_t dvpos) dvpos--; } - it->current_x = it->hpos = 0; + it->current_x = it->hpos = it->wrap_prefix_width = 0; /* Above call may have moved too far if continuation lines are involved. Scan forward and see if it did. */ @@ -11112,7 +11305,7 @@ move_it_by_lines (struct it *it, ptrdiff_t dvpos) move_it_to (&it2, start_charpos, -1, -1, -1, MOVE_TO_POS); it->vpos -= it2.vpos; it->current_y -= it2.current_y; - it->current_x = it->hpos = 0; + it->current_x = it->hpos = it->wrap_prefix_width = 0; /* If we moved too far back, move IT some lines forward. */ if (it2.vpos > -dvpos) @@ -11390,8 +11583,8 @@ window_text_pixel_size (Lisp_Object window, Lisp_Object from, Lisp_Object to, /* Start at the beginning of the line containing FROM. Otherwise IT.current_x will be incorrectly set to zero at some arbitrary non-zero X coordinate. */ - reseat_at_previous_visible_line_start (&it); - it.current_x = it.hpos = 0; + move_it_by_lines (&it, 0); + it.current_x = it.hpos = it.wrap_prefix_width = 0; if (IT_CHARPOS (it) != start) { void *it1data = NULL; @@ -11444,7 +11637,7 @@ window_text_pixel_size (Lisp_Object window, Lisp_Object from, Lisp_Object to, /* If FROM is on a newline, pretend that we start at the beginning of the next line, because the newline takes no place on display. */ if (FETCH_BYTE (start) == '\n') - it.current_x = 0; + it.current_x = 0, it.wrap_prefix_width = 0; if (!NILP (x_limit)) { it.last_visible_x = max_x; @@ -11467,6 +11660,8 @@ window_text_pixel_size (Lisp_Object window, Lisp_Object from, Lisp_Object to, the width of the last buffer position manually. */ if (IT_CHARPOS (it) > end) { + int end_y = it.current_y; + end--; RESTORE_IT (&it, &it2, it2data); x = move_it_to (&it, end, to_x, max_y, -1, move_op); @@ -11479,14 +11674,29 @@ window_text_pixel_size (Lisp_Object window, Lisp_Object from, Lisp_Object to, /* DTRT if ignore_line_at_end is t. */ if (!NILP (ignore_line_at_end)) - doff = (max (it.max_ascent, it.ascent) - + max (it.max_descent, it.descent)); + { + /* If END-1 is on the previous screen line, we need to + account for the vertical dimensions of previous line. */ + if (it.current_y < end_y) + doff = (max (it.max_ascent, it.ascent) + + max (it.max_descent, it.descent)); + } else { it.max_ascent = max (it.max_ascent, it.ascent); it.max_descent = max (it.max_descent, it.descent); } } + else if (IT_CHARPOS (it) > end + && it.line_wrap == TRUNCATE + && it.current_x - it.first_visible_x >= it.last_visible_x) + { + /* If the display property at END is at the beginning of the + line, and the previous line was truncated, we are at END, + but it.current_y is not yet updated to reflect that. */ + it.current_y += max (it.max_ascent, it.ascent) + + max (it.max_descent, it.descent); + } } else bidi_unshelve_cache (it2data, true); @@ -11677,6 +11887,8 @@ WINDOW. */) set_buffer_internal_1 (b); + ptrdiff_t base_line_pos = w->base_line_pos; + int end_valid = w->window_end_valid; if (!EQ (buffer, w->contents)) { wset_buffer (w, buffer); @@ -11689,6 +11901,11 @@ WINDOW. */) unbind_to (count, Qnil); + /* Restore original values. This is important if this function is + called from some ':eval' form in the middle of redisplay. */ + w->base_line_pos = base_line_pos; + w->window_end_valid = end_valid; + return value; } @@ -11773,7 +11990,7 @@ vadd_to_log (char const *format, va_list ap) eassert (nargs <= ARRAYELTS (args)); AUTO_STRING (args0, format); args[0] = args0; - for (ptrdiff_t i = 1; i <= nargs; i++) + for (ptrdiff_t i = 1; i < nargs; i++) args[i] = va_arg (ap, Lisp_Object); Lisp_Object msg = Qnil; msg = Fformat_message (nargs, args); @@ -12616,7 +12833,7 @@ display_echo_area (struct window *w) reset the echo_area_buffer in question to nil at the end because with_echo_area_buffer will set it to an empty buffer. */ bool i = display_last_displayed_message_p; - /* According to the C99, C11 and C++11 standards, the integral value + /* According to the C standard, the integral value of a "bool" is always 0 or 1, so this array access is safe here, if oddly typed. */ no_message_p = NILP (echo_area_buffer[i]); @@ -12731,7 +12948,7 @@ resize_mini_window (struct window *w, bool exact_p) displaying changes from under them. Such a resizing can happen, for instance, when which-func prints a long message while we are running fontification-functions. We're running these - functions with safe_call which binds inhibit-redisplay to t. */ + functions with dsafe_call which binds inhibit-redisplay to t. */ if (!NILP (Vinhibit_redisplay)) return false; @@ -12750,7 +12967,7 @@ resize_mini_window (struct window *w, bool exact_p) if (FRAME_MINIBUF_ONLY_P (f)) { if (!NILP (resize_mini_frames)) - safe_call1 (Qwindow__resize_mini_frame, WINDOW_FRAME (w)); + dsafe_call1 (Qwindow__resize_mini_frame, WINDOW_FRAME (w)); } else { @@ -12997,7 +13214,7 @@ set_message (Lisp_Object string) { specpdl_ref count = SPECPDL_INDEX (); specbind (Qinhibit_quit, Qt); - message = safe_call1 (Vset_message_function, string); + message = dsafe_call1 (Vset_message_function, string); unbind_to (count, Qnil); if (STRINGP (message)) @@ -13076,7 +13293,7 @@ clear_message (bool current_p, bool last_displayed_p) { specpdl_ref count = SPECPDL_INDEX (); specbind (Qinhibit_quit, Qt); - preserve = safe_call (1, Vclear_message_function); + preserve = dsafe_calln (false, Vclear_message_function); unbind_to (count, Qnil); } @@ -13114,7 +13331,7 @@ clear_garbaged_frames (void) { struct frame *f = XFRAME (frame); - if (FRAME_VISIBLE_P (f) && FRAME_GARBAGED_P (f)) + if (FRAME_REDISPLAY_P (f) && FRAME_GARBAGED_P (f)) { if (f->resized_p /* It makes no sense to redraw a non-selected TTY @@ -13163,7 +13380,7 @@ echo_area_display (bool update_frame_p) f = XFRAME (WINDOW_FRAME (w)); /* Don't display if frame is invisible or not yet initialized. */ - if (!FRAME_VISIBLE_P (f) || !f->glyphs_initialized_p) + if (!FRAME_REDISPLAY_P (f) || !f->glyphs_initialized_p) return; #ifdef HAVE_WINDOW_SYSTEM @@ -13687,7 +13904,7 @@ prepare_menu_bars (void) windows = Fcons (this, windows); } } - safe__call1 (true, Vpre_redisplay_function, windows); + dsafe_calln (true, Vpre_redisplay_function, windows); } /* Update all frame titles based on their buffer names, etc. We do @@ -13720,7 +13937,7 @@ prepare_menu_bars (void) TTY frames to be completely redrawn, when there are more than one of them, even though nothing should be changed on display. */ - || (FRAME_VISIBLE_P (f) == 2 && FRAME_WINDOW_P (f)))) + || (FRAME_REDISPLAY_P (f) && FRAME_WINDOW_P (f)))) gui_consider_frame_title (frame); } } @@ -14332,7 +14549,7 @@ display_tab_bar_line (struct it *it, int height) row->truncated_on_left_p = false; row->truncated_on_right_p = false; - it->current_x = it->hpos = 0; + it->current_x = it->hpos = it->wrap_prefix_width = 0; it->current_y += row->height; ++it->vpos; ++it->glyph_row; @@ -14611,21 +14828,32 @@ tab_bar_item_info (struct frame *f, struct glyph *glyph, Qmenu_item, f->current_tab_bar_string); if (! FIXNUMP (prop)) return false; + *prop_idx = XFIXNUM (prop); - *close_p = !NILP (Fget_text_property (make_fixnum (charpos), - Qclose_tab, - f->current_tab_bar_string)); + if (close_p) + *close_p = !NILP (Fget_text_property (make_fixnum (charpos), + Qclose_tab, + f->current_tab_bar_string)); return true; } -/* Get information about the tab-bar item at position X/Y on frame F. - Return in *GLYPH a pointer to the glyph of the tab-bar item in - the current matrix of the tab-bar window of F, or NULL if not - on a tab-bar item. Return in *PROP_IDX the index of the tab-bar - item in F->tab_bar_items. Value is +/* Get information about the tab-bar item at position X/Y on frame F's + tab bar window. + + Set *GLYPH to a pointer to the glyph of the tab-bar item in the + current matrix of the tab-bar window of F, or NULL if not on a + tab-bar item. Return in *PROP_IDX the index of the tab-bar item in + F->tab_bar_items. + + Place the window-relative vpos of Y in *VPOS, and the + window-relative hpos of X in *HPOS. If CLOSE_P, set it to whether + or not the tab bar item represents a button that should close a + tab. + + Value is -1 if X/Y is not on a tab-bar item 0 if X/Y is on the same item that was highlighted before. @@ -14633,7 +14861,7 @@ tab_bar_item_info (struct frame *f, struct glyph *glyph, static int get_tab_bar_item (struct frame *f, int x, int y, struct glyph **glyph, - int *hpos, int *vpos, int *prop_idx, bool *close_p) + int *hpos, int *vpos, int *prop_idx, bool *close_p) { struct window *w = XWINDOW (f->tab_bar_window); int area; @@ -14651,6 +14879,38 @@ get_tab_bar_item (struct frame *f, int x, int y, struct glyph **glyph, return *prop_idx == f->last_tab_bar_item ? 0 : 1; } +/* EXPORT: + + Like `get_tab_bar_item'. However, don't return anything for GLYPH, + HPOS, or VPOS, and treat X and Y as relative to F itself, as + opposed to its tab bar window. */ + +int +get_tab_bar_item_kbd (struct frame *f, int x, int y, int *prop_idx, + bool *close_p) +{ + struct window *w; + int area, vpos, hpos; + struct glyph *glyph; + + w = XWINDOW (f->tab_bar_window); + + /* Convert X and Y to window coordinates. */ + frame_to_window_pixel_xy (w, &x, &y); + + /* Find the glyph under X/Y. */ + glyph = x_y_to_hpos_vpos (w, x, y, &hpos, &vpos, 0, + 0, &area); + if (glyph == NULL) + return -1; + + /* Get the start of this tab-bar item's properties in + f->tab_bar_items. */ + if (!tab_bar_item_info (f, glyph, prop_idx, close_p)) + return -1; + + return *prop_idx == f->last_tab_bar_item ? 0 : 1; +} /* EXPORT: Handle mouse button event on the tab-bar of frame F, at @@ -14983,7 +15243,10 @@ update_tool_bar (struct frame *f, bool save_match_data) /* Set F->desired_tool_bar_string to a Lisp string representing frame F's desired tool-bar contents. F->tool_bar_items must have - been set up previously by calling prepare_menu_bars. */ + been set up previously by calling prepare_menu_bars. + + Also set F->tool_bar_wraps_p to whether or not the tool bar + contains explicit line breaking items. */ static void build_desired_tool_bar_string (struct frame *f) @@ -15005,9 +15268,11 @@ build_desired_tool_bar_string (struct frame *f) size_needed = f->n_tool_bar_items; /* Reuse f->desired_tool_bar_string, if possible. */ + if (size < size_needed || NILP (f->desired_tool_bar_string)) - fset_desired_tool_bar_string - (f, Fmake_string (make_fixnum (size_needed), make_fixnum (' '), Qnil)); + /* Don't initialize the contents of this string yet, as they will + be set within the loop below. */ + fset_desired_tool_bar_string (f, make_uninit_string (size_needed)); else { AUTO_LIST4 (props, Qdisplay, Qnil, Qmenu_item, Qnil); @@ -15015,6 +15280,8 @@ build_desired_tool_bar_string (struct frame *f) props, f->desired_tool_bar_string); } + f->tool_bar_wraps_p = false; + /* Put a `display' property on the string for the images to display, put a `menu_item' property on tool-bar items with a value that is the index of the item in F's tool-bar item vector. */ @@ -15027,6 +15294,21 @@ build_desired_tool_bar_string (struct frame *f) bool selected_p = !NILP (PROP (TOOL_BAR_ITEM_SELECTED_P)); int hmargin, vmargin, relief, idx, end; + if (!NILP (PROP (TOOL_BAR_ITEM_WRAP))) + { + /* This is a line wrap. Instead of building a tool bar + item, display a new line character instead. */ + SSET (f->desired_tool_bar_string, i, '\n'); + + /* Set F->tool_bar_wraps_p. This tells redisplay_tool_bar + to allow individual rows to be different heights. */ + f->tool_bar_wraps_p = true; + continue; + } + + /* Replace this with a space character. */ + SSET (f->desired_tool_bar_string, i, ' '); + /* If image is a vector, choose the image according to the button state. */ image = PROP (TOOL_BAR_ITEM_IMAGES); @@ -15138,6 +15420,16 @@ build_desired_tool_bar_string (struct frame *f) props, f->desired_tool_bar_string); #undef PROP } + + /* Now replace each character between i and the end of the tool bar + string with spaces, to prevent stray newlines from accumulating + when the number of tool bar items decreases. `size' is 0 if the + tool bar string is new, but in that case the string will have + been completely initialized anyway. */ + + for (; i < size; ++i) + /* Replace this with a space character. */ + SSET (f->desired_tool_bar_string, i, ' '); } @@ -15151,7 +15443,10 @@ build_desired_tool_bar_string (struct frame *f) 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. -*/ + + HEIGHT may also be -1 if there is an explicit line wrapping item + inside the tool bar; in that case, allow individual rows of the + tool bar to differ in height. */ static void display_tool_bar_line (struct it *it, int height) @@ -15215,8 +15510,18 @@ display_tool_bar_line (struct it *it, int height) ++i; } - /* Stop at line end. */ + /* Stop at the end of the iterator, and move to the next line + upon a '\n' appearing in the tool bar string. Tool bar + strings may contain multiple new line characters when + explicit wrap items are encountered. */ + if (ITERATOR_AT_END_OF_LINE_P (it)) + { + reseat_at_next_visible_line_start (it, false); + break; + } + + if (ITERATOR_AT_END_P (it)) break; set_iterator_to_next (it, true); @@ -15243,7 +15548,8 @@ display_tool_bar_line (struct it *it, int height) last->left_box_line_p = true; /* Make line the desired height and center it vertically. */ - if ((height -= it->max_ascent + it->max_descent) > 0) + if (height != -1 + && (height -= it->max_ascent + it->max_descent) > 0) { /* Don't add more than one line height. */ height %= FRAME_LINE_HEIGHT (it->f); @@ -15267,7 +15573,7 @@ display_tool_bar_line (struct it *it, int height) row->truncated_on_left_p = false; row->truncated_on_right_p = false; - it->current_x = it->hpos = 0; + it->current_x = it->hpos = it->wrap_prefix_width = 0; it->current_y += row->height; ++it->vpos; ++it->glyph_row; @@ -15277,6 +15583,7 @@ display_tool_bar_line (struct it *it, int height) /* Value is the number of pixels needed to make all tool-bar items of frame F visible. The actual number of glyph rows needed is returned in *N_ROWS if non-NULL. */ + static int tool_bar_height (struct frame *f, int *n_rows, bool pixelwise) { @@ -15354,7 +15661,9 @@ redisplay_tool_bar (struct frame *f) struct window *w; struct it it; struct glyph_row *row; + bool change_height_p; + change_height_p = false; f->tool_bar_redisplayed = true; /* If frame hasn't a tool-bar window or if it is zero-height, don't @@ -15407,6 +15716,15 @@ redisplay_tool_bar (struct frame *f) /* Always do that now. */ clear_glyph_matrix (w->desired_matrix); f->fonts_changed = true; + + /* Kludge (this applies to the X Windows version as well as + Android): when the tool bar size changes, + adjust_window_size (presumably called by + change_tool_bar_height_hook) does not call through to + resize_frame_windows. Pending further investigation, + just call it here as well. */ + resize_frame_windows (f, FRAME_INNER_HEIGHT (f), false); + return true; } } @@ -15429,18 +15747,39 @@ redisplay_tool_bar (struct frame *f) 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) + if (f->tool_bar_wraps_p) { - int h = 0; - if (extra > 0 && rows-- > 0) + /* If the tool bar contains explicit line wrapping items, + don't force each row to have a fixed height. */ + + while (!ITERATOR_AT_END_P (&it)) + display_tool_bar_line (&it, -1); + + /* Because changes to individual tool bar items may now + change the height of the tool bar, adjust the height of + the tool bar window if it is different from the tool bar + height in any way. */ + + if (it.current_y != it.last_visible_y) + change_height_p = true; + } + else + { + 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) { - h = (extra + rows - 1) / rows; - extra -= h; + int h = 0; + if (extra > 0 && rows-- > 0) + { + h = (extra + rows - 1) / rows; + extra -= h; + } + + display_tool_bar_line (&it, height + h); } - display_tool_bar_line (&it, height + h); } } else @@ -15456,8 +15795,6 @@ redisplay_tool_bar (struct frame *f) if (!NILP (Vauto_resize_tool_bars)) { - bool change_height_p = false; - /* If we couldn't display everything, change the tool-bar's height if there is room for more. */ if (IT_STRING_CHARPOS (it) < it.end_charpos) @@ -16516,8 +16853,9 @@ redisplay_internal (void) enum {MAX_GARBAGED_FRAME_RETRIES = 2 }; int garbaged_frame_retries = 0; - /* True means redisplay has to consider all windows on all - frames. False, only selected_window is considered. */ + /* False means that only the selected_window needs to be updated. + True means that other windows may need to be updated as well, + so we need to consult `needs_no_update` for all windows. */ bool consider_all_windows_p; /* True means redisplay has to redisplay the miniwindow. */ @@ -16594,7 +16932,7 @@ redisplay_internal (void) display area, displaying a different frame means redisplay the whole thing. */ SET_FRAME_GARBAGED (sf); -#ifndef DOS_NT +#if !defined DOS_NT && !defined HAVE_ANDROID set_tty_color_mode (FRAME_TTY (sf), sf); #endif FRAME_TTY (sf)->previous_frame = sf; @@ -16609,7 +16947,7 @@ redisplay_internal (void) { struct frame *f = XFRAME (frame); - if (FRAME_VISIBLE_P (f)) + if (FRAME_REDISPLAY_P (f)) { ++number_of_visible_frames; /* Adjust matrices for visible frames only. */ @@ -16751,7 +17089,7 @@ redisplay_internal (void) && !w->update_mode_line && !current_buffer->clip_changed && !current_buffer->prevent_redisplay_optimizations_p - && FRAME_VISIBLE_P (XFRAME (w->frame)) + && FRAME_REDISPLAY_P (XFRAME (w->frame)) && !FRAME_OBSCURED_P (XFRAME (w->frame)) && !XFRAME (w->frame)->cursor_type_changed && !XFRAME (w->frame)->face_change @@ -16935,6 +17273,7 @@ redisplay_internal (void) NULL, DEFAULT_FACE_ID); it.current_x = this_line_start_x; it.current_y = this_line_y; + it.wrap_prefix_width = 0; it.vpos = this_line_vpos; if (current_buffer->long_line_optimizations_p @@ -17029,7 +17368,7 @@ redisplay_internal (void) if (gcscrollbars && FRAME_TERMINAL (f)->condemn_scroll_bars_hook) FRAME_TERMINAL (f)->condemn_scroll_bars_hook (f); - if (FRAME_VISIBLE_P (f) && !FRAME_OBSCURED_P (f)) + if (FRAME_REDISPLAY_P (f) && !FRAME_OBSCURED_P (f)) { /* Don't allow freeing images and faces for this frame as long as the frame's update wasn't @@ -17055,7 +17394,7 @@ redisplay_internal (void) if (gcscrollbars && FRAME_TERMINAL (f)->judge_scroll_bars_hook) FRAME_TERMINAL (f)->judge_scroll_bars_hook (f); - if (FRAME_VISIBLE_P (f) && !FRAME_OBSCURED_P (f)) + if (FRAME_REDISPLAY_P (f) && !FRAME_OBSCURED_P (f)) { /* If fonts changed on visible frame, display again. */ if (f->fonts_changed) @@ -17161,7 +17500,7 @@ redisplay_internal (void) } } } - else if (FRAME_VISIBLE_P (sf) && !FRAME_OBSCURED_P (sf)) + else if (FRAME_REDISPLAY_P (sf) && !FRAME_OBSCURED_P (sf)) { sf->inhibit_clear_image_cache = true; displayed_buffer = XBUFFER (XWINDOW (selected_window)->contents); @@ -17212,7 +17551,7 @@ redisplay_internal (void) unrequest_sigio (); STOP_POLLING; - if (FRAME_VISIBLE_P (sf) && !FRAME_OBSCURED_P (sf)) + if (FRAME_REDISPLAY_P (sf) && !FRAME_OBSCURED_P (sf)) { if (hscroll_retries <= MAX_HSCROLL_RETRIES && hscroll_windows (selected_window)) @@ -17311,7 +17650,7 @@ redisplay_internal (void) FOR_EACH_FRAME (tail, frame) { - if (XFRAME (frame)->visible) + if (FRAME_REDISPLAY_P (XFRAME (frame))) new_count++; } @@ -17435,6 +17774,9 @@ static void mark_window_display_accurate_1 (struct window *w, bool accurate_p) { struct buffer *b = XBUFFER (w->contents); +#ifdef HAVE_TEXT_CONVERSION + ptrdiff_t prev_point, prev_mark; +#endif /* HAVE_TEXT_CONVERSION */ w->last_modified = accurate_p ? BUF_MODIFF (b) : 0; w->last_overlay_modified = accurate_p ? BUF_OVERLAY_MODIFF (b) : 0; @@ -17464,12 +17806,59 @@ mark_window_display_accurate_1 (struct window *w, bool accurate_p) w->last_cursor_vpos = w->cursor.vpos; w->last_cursor_off_p = w->cursor_off_p; +#ifdef HAVE_TEXT_CONVERSION + prev_point = w->last_point; + prev_mark = w->last_mark; +#endif /* HAVE_TEXT_CONVERSION */ + if (w == XWINDOW (selected_window)) w->last_point = BUF_PT (b); else w->last_point = marker_position (w->pointm); - w->window_end_valid = true; + /* w->last_mark is recorded for text conversion purposes. + Input methods aren't interested in the value of the mark + if it is inactive, so set it to -1 if it's not. */ + + if (XMARKER (BVAR (b, mark))->buffer == b + && !NILP (BVAR (b, mark_active))) + w->last_mark = marker_position (BVAR (b, mark)); + else + w->last_mark = -1; + +#ifdef HAVE_TEXT_CONVERSION + /* See the description of this field in struct window. */ + w->ephemeral_last_point = w->last_point; + + /* Point motion is only propagated to the input method for use + in text conversion during a redisplay. While this can lead + to inconsistencies when point has moved but the change has + not yet been displayed, it leads to better results most of + the time, as point often changes within calls to + `save-excursion', and the only way to detect such calls is to + observe that the next redisplay never ends with those changes + applied. + + Changes to buffer text are immediately propagated to the + input method, and the position of point is also updated + during such a change, so the consequences are not that + severe. */ + + if ((prev_point != w->last_point + || prev_mark != w->last_mark) + && FRAME_WINDOW_P (WINDOW_XFRAME (w)) + && w == XWINDOW (WINDOW_XFRAME (w)->selected_window)) + report_point_change (WINDOW_XFRAME (w), w, b); +#endif /* HAVE_TEXT_CONVERSION */ + + struct glyph_row *row; + /* These conditions should be consistent with CHECK_WINDOW_END. */ + if (w->window_end_vpos < w->current_matrix->nrows + && ((row = MATRIX_ROW (w->current_matrix, w->window_end_vpos), + !row->enabled_p + || MATRIX_ROW_DISPLAYS_TEXT_P (row) + || MATRIX_ROW_VPOS (row, w->current_matrix) == 0))) + w->window_end_valid = true; w->update_mode_line = false; w->preserve_vscroll_p = false; } @@ -18350,11 +18739,8 @@ run_window_scroll_functions (Lisp_Object window, struct text_pos startp) if (!NILP (Vwindow_scroll_functions)) { - specpdl_ref count = SPECPDL_INDEX (); - specbind (Qinhibit_quit, Qt); safe_run_hooks_2 (Qwindow_scroll_functions, window, make_fixnum (CHARPOS (startp))); - unbind_to (count, Qnil); SET_TEXT_POS_FROM_MARKER (startp, w->start); /* In case the hook functions switch buffers. */ set_buffer_internal (XBUFFER (w->contents)); @@ -18406,7 +18792,7 @@ cursor_row_fully_visible_p (struct window *w, bool force_p, XSETWINDOW (window, w); /* Implementation note: if the function we call here signals an error, we will NOT scroll when the cursor is partially-visible. */ - Lisp_Object val = safe_call1 (mclfv_p, window); + Lisp_Object val = dsafe_call1 (mclfv_p, window); if (NILP (val)) return true; else if (just_test_user_preference_p) @@ -18473,6 +18859,14 @@ enum `scroll-conservatively' and the Emacs manual. */ #define SCROLL_LIMIT 100 +/* The freshness of the w->base_line_number cache is only ensured at every + redisplay cycle, so the cache can be used only if there's been + no relevant changes to the buffer since the last redisplay. */ +#define BASE_LINE_NUMBER_VALID_P(w) \ + (eassert (current_buffer == XBUFFER ((w)->contents)), \ + !current_buffer->clip_changed \ + && BEG_UNCHANGED >= (w)->base_line_pos) + static int try_scrolling (Lisp_Object window, bool just_this_one_p, intmax_t arg_scroll_conservatively, intmax_t scroll_step, @@ -18773,9 +19167,10 @@ try_scrolling (Lisp_Object window, bool just_this_one_p, else { /* Maybe forget recorded base line for line number display. */ - if (!just_this_one_p - || current_buffer->clip_changed - || BEG_UNCHANGED < CHARPOS (startp)) + /* FIXME: Why do we need this? `try_scrolling` can only be called from + `redisplay_window` which should have flushed this cache already when + eeded. */ + if (!BASE_LINE_NUMBER_VALID_P (w)) w->base_line_number = 0; /* If cursor ends up on a partially visible line, @@ -18966,7 +19361,7 @@ try_cursor_movement (Lisp_Object window, struct text_pos startp, && !f->cursor_type_changed && NILP (Vshow_trailing_whitespace) /* When display-line-numbers is in relative mode, moving point - requires to redraw the entire window. */ + requires redrawing the entire window. */ && !EQ (Vdisplay_line_numbers, Qrelative) && !EQ (Vdisplay_line_numbers, Qvisual) /* When the current line number should be displayed in a @@ -19545,9 +19940,6 @@ redisplay_window (Lisp_Object window, bool just_this_one_p) /* Record it now because it's overwritten. */ bool current_matrix_up_to_date_p = false; bool used_current_matrix_p = false; - /* This is less strict than current_matrix_up_to_date_p. - It indicates that the buffer contents and narrowing are unchanged. */ - bool buffer_unchanged_p = false; bool temp_scroll_step = false; specpdl_ref count = SPECPDL_INDEX (); int rc; @@ -19653,11 +20045,6 @@ redisplay_window (Lisp_Object window, bool just_this_one_p) specbind (Qinhibit_point_motion_hooks, Qt); - buffer_unchanged_p - = (w->window_end_valid - && !current_buffer->clip_changed - && !window_outdated (w)); - /* When windows_or_buffers_changed is non-zero, we can't rely on the window end being valid, so set it to zero there. */ if (windows_or_buffers_changed) @@ -19797,6 +20184,10 @@ redisplay_window (Lisp_Object window, bool just_this_one_p) } } + if (!BASE_LINE_NUMBER_VALID_P (w)) + /* Forget any recorded base line for line number display. */ + w->base_line_number = 0; + force_start: /* Handle case where place to start displaying has been specified, @@ -19817,10 +20208,6 @@ redisplay_window (Lisp_Object window, bool just_this_one_p) w->preserve_vscroll_p = false; w->window_end_valid = false; - /* Forget any recorded base line for line number display. */ - if (!buffer_unchanged_p) - w->base_line_number = 0; - /* Redisplay the mode line. Select the buffer properly for that. Also, run the hook window-scroll-functions because we have scrolled. */ @@ -19974,7 +20361,7 @@ redisplay_window (Lisp_Object window, bool just_this_one_p) propagated its info to `w' anyway. */ w->redisplay = false; XBUFFER (w->contents)->text->redisplay = false; - safe__call1 (true, Vpre_redisplay_function, Fcons (window, Qnil)); + dsafe_calln (true, Vpre_redisplay_function, Fcons (window, Qnil)); if (w->redisplay || XBUFFER (w->contents)->text->redisplay || ((EQ (Vdisplay_line_numbers, Qrelative) @@ -20149,12 +20536,6 @@ redisplay_window (Lisp_Object window, bool just_this_one_p) if (w->cursor.vpos >= 0) { - if (!just_this_one_p - || current_buffer->clip_changed - || BEG_UNCHANGED < CHARPOS (startp)) - /* Forget any recorded base line for line number display. */ - w->base_line_number = 0; - if (!cursor_row_fully_visible_p (w, true, false, false)) { clear_glyph_matrix (w->desired_matrix); @@ -20225,10 +20606,6 @@ redisplay_window (Lisp_Object window, bool just_this_one_p) debug_method_add (w, "recenter"); #endif - /* Forget any previously recorded base line for line number display. */ - if (!buffer_unchanged_p) - w->base_line_number = 0; - /* Determine the window start relative to point. */ init_iterator (&it, w, PT, PT_BYTE, NULL, DEFAULT_FACE_ID); it.current_y = it.last_visible_y; @@ -20334,7 +20711,7 @@ redisplay_window (Lisp_Object window, bool just_this_one_p) it.current_y = 0; } - it.current_x = it.hpos = 0; + it.current_x = it.wrap_prefix_width = it.hpos = 0; /* Set the window start position here explicitly, to avoid an infinite loop in case the functions in window-scroll-functions @@ -22302,7 +22679,7 @@ try_window_id (struct window *w) /* We may start in a continuation line. If so, we have to get the right continuation_lines_width and current_x. */ it.continuation_lines_width = last_row->continuation_lines_width; - it.hpos = it.current_x = 0; + it.hpos = it.current_x = it.wrap_prefix_width = 0; /* Display the rest of the lines at the window end. */ it.glyph_row = MATRIX_ROW (desired_matrix, it.vpos); @@ -22907,6 +23284,7 @@ insert_left_trunc_glyphs (struct it *it) /* Get the truncation glyphs. */ truncate_it = *it; truncate_it.current_x = 0; + truncate_it.wrap_prefix_width = 0; truncate_it.face_id = DEFAULT_FACE_ID; truncate_it.glyph_row = &scratch_glyph_row; truncate_it.area = TEXT_AREA; @@ -23669,6 +24047,10 @@ extend_face_to_end_of_line (struct it *it) for (it->current_x = 0; g < e; g++) it->current_x += g->pixel_width; + if (it->continuation_lines_width + && it->string_from_prefix_prop_p) + it->wrap_prefix_width = it->current_x; + it->area = LEFT_MARGIN_AREA; it->face_id = default_face->id; while (it->glyph_row->used[LEFT_MARGIN_AREA] @@ -24390,6 +24772,13 @@ maybe_produce_line_number (struct it *it) if (!last_line) { /* If possible, reuse data cached by line-number-mode. */ + /* NOTE: We use `base_line_number` without checking + BASE_LINE_NUMBER_VALID_P because we assume that `redisplay_window` + has already flushed this cache for us when needed. + NOTE2: Checking BASE_LINE_NUMBER_VALID_P here would be + overly pessimistic because it might say that the cache + was invalid before entering `redisplay_window` yet the + value has just been refreshed. */ if (it->w->base_line_number > 0 && it->w->base_line_pos > 0 && it->w->base_line_pos <= IT_CHARPOS (*it) @@ -24439,7 +24828,7 @@ maybe_produce_line_number (struct it *it) /* Produce the glyphs for the line number. */ struct it tem_it; char lnum_buf[INT_STRLEN_BOUND (ptrdiff_t) + 1]; - bool beyond_zv = IT_BYTEPOS (*it) >= ZV_BYTE ? true : false; + bool beyond_zv = IT_BYTEPOS (*it) >= ZV_BYTE; ptrdiff_t lnum_offset = -1; /* to produce 1-based line numbers */ int lnum_face_id = merge_faces (it->w, Qline_number, 0, DEFAULT_FACE_ID); int current_lnum_face_id @@ -24669,7 +25058,7 @@ should_produce_line_number (struct it *it) because get-char-property always returns nil for ZV, except if the property is in 'default-text-properties'. */ if (NILP (val) && IT_CHARPOS (*it) >= ZV) - val = disable_line_numbers_overlay_at_eob (); + return !disable_line_numbers_overlay_at_eob (); return NILP (val) ? true : false; } @@ -24734,6 +25123,7 @@ display_line (struct it *it, int cursor_vpos) int first_visible_x = it->first_visible_x; int last_visible_x = it->last_visible_x; int x_incr = 0; + int this_line_subject_to_line_prefix = 0; /* We always start displaying at hpos zero even if hscrolled. */ eassert (it->hpos == 0 && it->current_x == 0); @@ -24810,7 +25200,10 @@ display_line (struct it *it, int cursor_vpos) if (it->current_x < it->first_visible_x && (move_result == MOVE_NEWLINE_OR_CR || move_result == MOVE_POS_MATCH_OR_ZV)) - it->current_x = it->first_visible_x; + { + it->current_x = it->first_visible_x; + it->wrap_prefix_width = 0; + } /* In case move_it_in_display_line_to above "produced" the line number. */ @@ -24839,6 +25232,7 @@ display_line (struct it *it, int cursor_vpos) /* We only do this when not calling move_it_in_display_line_to above, because that function calls itself handle_line_prefix. */ handle_line_prefix (it); + this_line_subject_to_line_prefix = it->string_from_prefix_prop_p; } else { @@ -25005,12 +25399,15 @@ display_line (struct it *it, int cursor_vpos) process the prefix now. */ if (it->area == TEXT_AREA && pending_handle_line_prefix) { - /* Line numbers should precede the line-prefix or wrap-prefix. */ + /* Line numbers should precede the line-prefix or + wrap-prefix. */ if (line_number_needed) maybe_produce_line_number (it); pending_handle_line_prefix = false; handle_line_prefix (it); + this_line_subject_to_line_prefix + = it->string_from_prefix_prop_p; } continue; } @@ -25031,7 +25428,16 @@ display_line (struct it *it, int cursor_vpos) if (/* Not a newline. */ nglyphs > 0 /* Glyphs produced fit entirely in the line. */ - && it->current_x < it->last_visible_x) + && (it->current_x < it->last_visible_x + /* Or a line or wrap prefix is in effect, and not + truncating the glyph produced immediately after it + would cause an infinite cycle. */ + || (it->line_wrap != TRUNCATE + /* This code is not valid if multiple glyphs were + produced, as some of these glyphs might remain + within this line. */ + && nglyphs == 1 + && this_line_subject_to_line_prefix))) { it->hpos += nglyphs; row->ascent = max (row->ascent, it->max_ascent); @@ -25082,7 +25488,20 @@ display_line (struct it *it, int cursor_vpos) && FRAME_WINDOW_P (it->f) && (row->reversed_p ? WINDOW_LEFT_FRINGE_WIDTH (it->w) - : WINDOW_RIGHT_FRINGE_WIDTH (it->w))))) + : WINDOW_RIGHT_FRINGE_WIDTH (it->w)))) + /* There is no line prefix, next to which the + iterator _must_ produce a minimum of one actual + glyph. */ + && (!this_line_subject_to_line_prefix + /* Or this is the second glyph to be produced + beyond the confines of the line. */ + || (i != 0 + && (x > it->last_visible_x + || (x == it->last_visible_x + && FRAME_WINDOW_P (it->f) + && (row->reversed_p + ? WINDOW_LEFT_FRINGE_WIDTH (it->w) + : WINDOW_RIGHT_FRINGE_WIDTH (it->w))))))) { /* End of a continued line. */ @@ -25379,24 +25798,23 @@ display_line (struct it *it, int cursor_vpos) break; } - /* Detect overly-wide wrap-prefixes made of (space ...) display - properties. When such a wrap prefix reaches past the right - margin of the window, we need to avoid the call to - set_iterator_to_next below, so that it->line_wrap is left at - its TRUNCATE value wisely set by handle_line_prefix. - Otherwise, set_iterator_to_next will pop the iterator stack, - restore it->line_wrap, and redisplay might infloop. */ - bool overwide_wrap_prefix = - CONSP (it->object) && EQ (XCAR (it->object), Qspace) - && it->sp > 0 && it->method == GET_FROM_STRETCH - && it->current_x >= it->last_visible_x - && it->continuation_lines_width > 0 - && it->line_wrap == TRUNCATE && it->stack[0].line_wrap != TRUNCATE; - /* Proceed with next display element. Note that this skips over lines invisible because of selective display. */ - if (!overwide_wrap_prefix) - set_iterator_to_next (it, true); + set_iterator_to_next (it, true); + + /* If IT has just finished producing glyphs for the wrap prefix + and is proceeding to the next method, there might not be + sufficient space remaining in this line to accommodate its + glyphs, and one real glyph must be produced to prevent an + infinite loop. Next, clear this flag if such a glyph has + already been produced. */ + + if (this_line_subject_to_line_prefix == 1 + && !it->string_from_prefix_prop_p) + this_line_subject_to_line_prefix = 2; + else if (this_line_subject_to_line_prefix == 2 + && !it->string_from_prefix_prop_p) + this_line_subject_to_line_prefix = 0; /* If we truncate lines, we are done when the last displayed glyphs reach past the right margin of the window. */ @@ -25642,7 +26060,7 @@ display_line (struct it *it, int cursor_vpos) HPOS) = (0 0). Vertical positions are incremented. As a convenience for the caller, IT->glyph_row is set to the next row to be used. */ - it->current_x = it->hpos = 0; + it->wrap_prefix_width = it->current_x = it->hpos = 0; it->current_y += row->height; /* Restore the first and last visible X if we adjusted them for current-line hscrolling. */ @@ -26121,7 +26539,7 @@ Value is the new character position of point. */) { struct text_pos pt; struct it it; - int pt_x, target_x, pixel_width, pt_vpos; + int pt_x, pt_wrap_prefix_x, target_x, pixel_width, pt_vpos; bool at_eol_p; bool overshoot_expected = false; bool target_is_eol_p = false; @@ -26153,6 +26571,7 @@ Value is the new character position of point. */) reseat: reseat_at_previous_visible_line_start (&it); it.current_x = it.hpos = it.current_y = it.vpos = 0; + it.wrap_prefix_width = 0; if (IT_CHARPOS (it) != PT) { move_it_to (&it, overshoot_expected ? PT - 1 : PT, @@ -26171,6 +26590,7 @@ Value is the new character position of point. */) move_it_in_display_line (&it, PT, -1, MOVE_TO_POS); } pt_x = it.current_x; + pt_wrap_prefix_x = it.wrap_prefix_width; pt_vpos = it.vpos; if (dir > 0 || overshoot_expected) { @@ -26185,10 +26605,11 @@ Value is the new character position of point. */) it.glyph_row = NULL; PRODUCE_GLYPHS (&it); /* compute it.pixel_width */ it.glyph_row = row; - /* PRODUCE_GLYPHS advances it.current_x, so we must restore - it, lest it will become out of sync with it's buffer + /* PRODUCE_GLYPHS advances it.current_x, so it must be + restored, lest it become out of sync with its buffer position. */ it.current_x = pt_x; + it.wrap_prefix_width = pt_wrap_prefix_x; } else at_eol_p = ITERATOR_AT_END_OF_LINE_P (&it); @@ -26233,6 +26654,7 @@ Value is the new character position of point. */) it.last_visible_x = DISP_INFINITY; reseat_at_previous_visible_line_start (&it); it.current_x = it.current_y = it.hpos = 0; + it.wrap_prefix_width = 0; if (pt_vpos != 0) move_it_by_lines (&it, pt_vpos); } @@ -26523,17 +26945,18 @@ display_menu_bar (struct window *w) init_iterator (&it, w, -1, -1, f->desired_matrix->rows, MENU_FACE_ID); it.first_visible_x = 0; it.last_visible_x = FRAME_PIXEL_WIDTH (f); -#elif defined (HAVE_X_WINDOWS) /* X without toolkit. */ +#elif defined (HAVE_X_WINDOWS) || defined (HAVE_ANDROID) + struct window *menu_window = NULL; + struct face *face = FACE_FROM_ID (f, MENU_FACE_ID); + if (FRAME_WINDOW_P (f)) { /* Menu bar lines are displayed in the desired matrix of the dummy window menu_bar_window. */ - struct window *menu_w; - menu_w = XWINDOW (f->menu_bar_window); - init_iterator (&it, menu_w, -1, -1, menu_w->desired_matrix->rows, + menu_window = XWINDOW (f->menu_bar_window); + init_iterator (&it, menu_window, -1, -1, + menu_window->desired_matrix->rows, MENU_FACE_ID); - it.first_visible_x = 0; - it.last_visible_x = FRAME_PIXEL_WIDTH (f); } else #endif /* not USE_X_TOOLKIT and not USE_GTK */ @@ -26587,8 +27010,61 @@ display_menu_bar (struct window *w) /* Compute the total height of the lines. */ compute_line_metrics (&it); + it.glyph_row->full_width_p = true; + it.glyph_row->continued_p = false; + it.glyph_row->truncated_on_left_p = false; + it.glyph_row->truncated_on_right_p = false; + + /* This will break the moment someone tries to add another window + system that uses the no toolkit menu bar. Oh well. At least + there will be an error, meaning he will correct the ifdef inside + which `face' is defined. */ +#if defined HAVE_WINDOW_SYSTEM && !defined HAVE_EXT_MENU_BAR + /* Make a 3D menu bar have a shadow at its right end. */ + extend_face_to_end_of_line (&it); + if (face->box != FACE_NO_BOX) + { + struct glyph *last = (it.glyph_row->glyphs[TEXT_AREA] + + it.glyph_row->used[TEXT_AREA] - 1); + int box_thickness = face->box_vertical_line_width; + last->right_box_line_p = true; + /* Add back the space for the right box line we subtracted in + init_iterator, since the right_box_line_p flag will make the + glyph wider. We actually add only as much space as is + available for the last glyph of the menu bar and whatever + space is left beyond it, since that glyph could be only + partially visible. */ + if (box_thickness > 0) + last->pixel_width += max (0, (box_thickness + - (it.current_x - it.last_visible_x))); + } + + /* With the non-toolkit version, modify the menu bar window height + accordingly. */ + if (FRAME_WINDOW_P (it.f) && menu_window) + { + struct glyph_row *row; + int delta_height; + + row = it.glyph_row; + delta_height + = ((row->y + row->height) + - WINDOW_BOX_HEIGHT_NO_MODE_LINE (menu_window)); + + if (delta_height != 0) + { + FRAME_MENU_BAR_HEIGHT (it.f) += delta_height; + adjust_frame_size (it.f, -1, -1, 3, false, Qmenu_bar_lines); + } + } +#endif } +/* This code is never used on Android where there are only GUI and + initial frames. */ + +#ifndef HAVE_ANDROID + /* Deep copy of a glyph row, including the glyphs. */ static void deep_copy_glyph_row (struct glyph_row *to, struct glyph_row *from) @@ -26709,6 +27185,9 @@ display_tty_menu_item (const char *item_text, int width, int face_id, row->full_width_p = saved_width; row->reversed_p = saved_reversed; } + +#endif + /*********************************************************************** Mode Line @@ -26794,7 +27273,7 @@ display_mode_lines (struct window *w) can reasonably tell whether a mouse click will select w. */ XSETWINDOW (window, w); if (FUNCTIONP (default_help)) - wset_mode_line_help_echo (w, safe_call1 (default_help, window)); + wset_mode_line_help_echo (w, dsafe_call1 (default_help, window)); else if (STRINGP (default_help)) wset_mode_line_help_echo (w, default_help); else @@ -27133,6 +27612,7 @@ display_mode_element (struct it *it, int depth, int field_width, int precision, /* PROPS might cause set-text-properties to signal an error, so we call it via internal_condition_case_n, to avoid an infloop in redisplay due to the error. */ + /* FIXME: Use 'SAFE_CALLMANY'? */ internal_condition_case_n (safe_set_text_properties, 4, ((Lisp_Object []) @@ -27140,7 +27620,7 @@ display_mode_element (struct it *it, int depth, int field_width, int precision, Flength (elt), props, elt}), - Qt, safe_eval_handler); + Qt, dsafe_eval_handler); /* Add this item to mode_line_proptrans_alist. */ mode_line_proptrans_alist = Fcons (Fcons (elt, props), @@ -27393,7 +27873,7 @@ display_mode_element (struct it *it, int depth, int field_width, int precision, if (CONSP (XCDR (elt))) { Lisp_Object spec; - spec = safe__eval (true, XCAR (XCDR (elt))); + spec = dsafe_eval (XCAR (XCDR (elt))); /* The :eval form could delete the frame stored in the iterator, which will cause a crash if we try to access faces and other fields (e.g., FRAME_KBOARD) @@ -27691,6 +28171,11 @@ are the selected window and the WINDOW's buffer). */) init_iterator (&it, w, -1, -1, NULL, face_id); + /* Make sure `base_line_number` is fresh in case we encounter a `%l`. */ + if (current_buffer == XBUFFER ((w)->contents) + && !BASE_LINE_NUMBER_VALID_P (w)) + w->base_line_number = 0; + if (no_props) { mode_line_target = MODE_LINE_NOPROP; @@ -27770,7 +28255,9 @@ static const char power_letter[] = 'P', /* peta */ 'E', /* exa */ 'Z', /* zetta */ - 'Y' /* yotta */ + 'Y', /* yotta */ + 'R', /* ronna */ + 'Q' /* quetta */ }; static void @@ -28141,30 +28628,29 @@ decode_mode_spec (struct window *w, register int c, int field_width, when the buffer's restriction was changed, but the window wasn't yet redisplayed after that. If that happens, we need to determine a new base line. */ - if (!(BUF_BEGV_BYTE (b) <= startpos_byte + if (current_buffer != XBUFFER (w->contents) + || !(BUF_BEGV_BYTE (b) <= startpos_byte && startpos_byte <= BUF_ZV_BYTE (b))) { startpos = BUF_BEGV (b); startpos_byte = BUF_BEGV_BYTE (b); - w->base_line_pos = 0; - w->base_line_number = 0; } /* If we decided that this buffer isn't suitable for line numbers, - don't forget that too fast. */ + don't forget that too fast. + FIXME: What if `current_buffer != w->contents`? */ if (w->base_line_pos == -1) goto no_value; /* If the buffer is very big, don't waste time. */ if (FIXNUMP (Vline_number_display_limit) && BUF_ZV (b) - BUF_BEGV (b) > XFIXNUM (Vline_number_display_limit)) - { - w->base_line_pos = 0; - w->base_line_number = 0; - goto no_value; - } + goto no_value; - if (w->base_line_number > 0 + /* Callers of `display_mode_element` are in charge of flushing + any stale `base_line_number` cache. */ + if (current_buffer == XBUFFER ((w)->contents) + && w->base_line_number > 0 && w->base_line_pos > 0 && w->base_line_pos <= startpos) { @@ -28190,7 +28676,9 @@ decode_mode_spec (struct window *w, register int c, int field_width, or too far away, or if we did not have one. "Too close" means it's plausible a scroll-down would go back past it. */ - if (startpos == BUF_BEGV (b)) + if (current_buffer != XBUFFER (w->contents)) + ; /* The base line is for another buffer, don't touch it! */ + else if (startpos == BUF_BEGV (b)) { w->base_line_number = topline; w->base_line_pos = BUF_BEGV (b); @@ -28203,9 +28691,8 @@ decode_mode_spec (struct window *w, register int c, int field_width, ptrdiff_t position; ptrdiff_t distance = (line_number_display_limit_width < 0 ? 0 - : INT_MULTIPLY_WRAPV (line_number_display_limit_width, - height * 2 + 30, - &distance) + : ckd_mul (&distance, line_number_display_limit_width, + height * 2 + 30) ? PTRDIFF_MAX : distance); if (startpos - distance > limit) @@ -28228,6 +28715,12 @@ decode_mode_spec (struct window *w, register int c, int field_width, goto no_value; } + /* NOTE: if `clip_changed` is set or if `BEG_UNCHANGED` is + before `position`, this new cached value may get flushed + soon needlessly, because we can't reset `BEG_UNCHANGED` or + `clip_changed` from here (since they reflect the changes + since the last redisplay so they can only be reset from + `mark_window_display_accurate_1`). :-( */ w->base_line_number = topline - nlines; w->base_line_pos = BYTE_TO_CHAR (position); } @@ -28364,7 +28857,7 @@ decode_mode_spec (struct window *w, register int c, int field_width, Lisp_Object val = Qnil; if (STRINGP (curdir)) - val = safe_call1 (intern ("file-remote-p"), curdir); + val = dsafe_call1 (intern ("file-remote-p"), curdir); val = unbind_to (count, val); @@ -28756,7 +29249,11 @@ display_string (const char *string, Lisp_Object lisp_string, Lisp_Object face_st { /* Add truncation mark, but don't do it if the line is truncated at a padding space. */ - if (it_charpos < it->string_nchars) + /* Need to do the below for the last string character as + well, since it could be a double-width character, in + which case the previous character ends before + last_visible_x. Thus, comparison with <=, not <. */ + if (it_charpos <= it->string_nchars) { if (!FRAME_WINDOW_P (it->f)) { @@ -28764,6 +29261,18 @@ display_string (const char *string, Lisp_Object lisp_string, Lisp_Object face_st if (it->current_x > it->last_visible_x) { + /* This flag is true if we are displaying mode + line, false for header-line or tab-line. */ + bool mode_line_p = false; + + /* ROW->mode_line_p is true if we display mode + line or header-line or tab-line. */ + if (row->mode_line_p) + { + struct window *w = it->w; + if (row == MATRIX_MODE_LINE_ROW (w->desired_matrix)) + mode_line_p = true; + } if (!row->reversed_p) { for (ii = row->used[TEXT_AREA] - 1; ii > 0; --ii) @@ -28781,7 +29290,10 @@ display_string (const char *string, Lisp_Object lisp_string, Lisp_Object face_st for (n = row->used[TEXT_AREA]; ii < n; ++ii) { row->used[TEXT_AREA] = ii; - produce_special_glyphs (it, IT_TRUNCATION); + if (row->mode_line_p) + pad_mode_line (it, mode_line_p); + else + produce_special_glyphs (it, IT_TRUNCATION); } } produce_special_glyphs (it, IT_TRUNCATION); @@ -29016,7 +29528,9 @@ calc_pixel_width_or_height (double *res, struct it *it, Lisp_Object prop, /* 'width': the width of FONT. */ if (EQ (prop, Qwidth)) return OK_PIXELS (font - ? FONT_WIDTH (font) + ? (font->average_width + ? font->average_width + : font->space_width) : FRAME_COLUMN_WIDTH (it->f)); #else if (EQ (prop, Qheight) || EQ (prop, Qwidth)) @@ -29234,9 +29748,9 @@ dump_glyph_string (struct glyph_string *s) # define ALLOCATE_HDC(hdc, f) \ Lisp_Object prev_quit = Vinhibit_quit; \ Vinhibit_quit = Qt; \ - HDC hdc = get_frame_dc ((f)) + HDC hdc = get_frame_dc (f) # define RELEASE_HDC(hdc, f) \ - release_frame_dc ((f), (hdc)); \ + release_frame_dc (f, hdc); \ Vinhibit_quit = prev_quit #else # define ALLOCATE_HDC(hdc, f) @@ -29355,9 +29869,9 @@ get_char_face_and_encoding (struct frame *f, int c, int face_id, } -/* Get face and two-byte form of character glyph GLYPH on frame F. - The encoding of GLYPH->u.ch is returned in *CHAR2B. Value is - a pointer to a realized face that is ready for display. */ +/* Get face glyph GLYPH on frame F, and if a character glyph, its + multi-byte character form in *CHAR2B. Value is a pointer to a + realized face that is ready for display. */ static struct face * get_glyph_face_and_encoding (struct frame *f, struct glyph *glyph, @@ -29366,25 +29880,28 @@ get_glyph_face_and_encoding (struct frame *f, struct glyph *glyph, struct face *face; unsigned code = 0; - eassert (glyph->type == CHAR_GLYPH); face = FACE_FROM_ID (f, glyph->face_id); /* Make sure X resources of the face are allocated. */ prepare_face_for_display (f, face); - if (face->font) + if (glyph->type == CHAR_GLYPH) { - if (CHAR_BYTE8_P (glyph->u.ch)) - code = CHAR_TO_BYTE8 (glyph->u.ch); - else - code = face->font->driver->encode_char (face->font, glyph->u.ch); + if (face->font) + { + if (CHAR_BYTE8_P (glyph->u.ch)) + code = CHAR_TO_BYTE8 (glyph->u.ch); + else + code = face->font->driver->encode_char (face->font, glyph->u.ch); - if (code == FONT_INVALID_CODE) - code = 0; + if (code == FONT_INVALID_CODE) + code = 0; + } + + /* Ensure that the code is only 2 bytes wide. */ + *char2b = code & 0xFFFF; } - /* Ensure that the code is only 2 bytes wide. */ - *char2b = code & 0xFFFF; return face; } @@ -29884,17 +30401,28 @@ normal_char_height (struct font *font, int c) void gui_get_glyph_overhangs (struct glyph *glyph, struct frame *f, int *left, int *right) { + unsigned char2b; + struct face *face; + *left = *right = 0; + face = get_glyph_face_and_encoding (f, glyph, &char2b); if (glyph->type == CHAR_GLYPH) { - unsigned char2b; - struct face *face = get_glyph_face_and_encoding (f, glyph, &char2b); if (face->font) { - struct font_metrics *pcm = get_per_char_metric (face->font, &char2b); + struct font_metrics *pcm + = get_per_char_metric (face->font, &char2b); + if (pcm) { + /* Overstruck text is displayed twice, the second time + one pixel to the right. Increase the right-side + bearing to match. */ + + if (face->overstrike) + pcm->rbearing++; + if (pcm->rbearing > pcm->width) *right = pcm->rbearing - pcm->width; if (pcm->lbearing < 0) @@ -29907,8 +30435,18 @@ gui_get_glyph_overhangs (struct glyph *glyph, struct frame *f, int *left, int *r if (! glyph->u.cmp.automatic) { struct composition *cmp = composition_table[glyph->u.cmp.id]; + int rbearing; + + rbearing = cmp->rbearing; + + /* Overstruck text is displayed twice, the second time one + pixel to the right. Increase the right-side bearing to + match. */ + + if (face->overstrike) + rbearing++; - if (cmp->rbearing > cmp->pixel_width) + if (rbearing > cmp->pixel_width) *right = cmp->rbearing - cmp->pixel_width; if (cmp->lbearing < 0) *left = - cmp->lbearing; @@ -29920,6 +30458,14 @@ gui_get_glyph_overhangs (struct glyph *glyph, struct frame *f, int *left, int *r composition_gstring_width (gstring, glyph->slice.cmp.from, glyph->slice.cmp.to + 1, &metrics); + + /* Overstruck text is displayed twice, the second time one + pixel to the right. Increase the right-side bearing to + match. */ + + if (face->overstrike) + metrics.rbearing++; + if (metrics.rbearing > metrics.width) *right = metrics.rbearing - metrics.width; if (metrics.lbearing < 0) @@ -30633,6 +31179,26 @@ draw_glyphs (struct window *w, int x, struct glyph_row *row, } } +#ifdef HAVE_RSVG + /* Update SVG image glyphs with mouse face features. FIXME: it + should be possible to have this behavior with transparent + background PNG. */ + if (hl == DRAW_MOUSE_FACE) + { + Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f); + for (s = head; s; s = s->next) + if (s->first_glyph->type == IMAGE_GLYPH) + if (s->img + && (EQ (image_spec_value (s->img->spec, QCtype, NULL), Qsvg))) + { + ptrdiff_t id; + id = lookup_image (f, s->img->spec, hlinfo->mouse_face_face_id); + s->img = IMAGE_FROM_ID (f, id); + prepare_image_for_display (f, s->img); + } + } +#endif + /* Draw all strings. */ for (s = head; s; s = s->next) FRAME_RIF (f)->draw_glyph_string (s); @@ -31008,9 +31574,16 @@ produce_image_glyph (struct it *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) + /* Automatically crop wide image glyphs at right edge so we can draw + the cursor on same display row. But don't do that under + word-wrap, unless the image starts at column zero, because + wrapping correctly needs the real pixel width of the image. */ + if ((it->line_wrap != WORD_WRAP + || it->hpos == 0 + /* Always crop images larger than the window-width, minus 1 space. */ + || it->pixel_width > it->last_visible_x - FRAME_COLUMN_WIDTH (it->f)) + && (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; @@ -31607,6 +32180,38 @@ produce_special_glyphs (struct it *it, enum display_element_type what) it->nglyphs = temp_it.nglyphs; } +/* Produce padding glyphs for mode/header/tab-line whose text needs to + be truncated. This is used when the last visible character leaves + one or more columns till the window edge, but the next character is + wider than that number of columns, and therefore cannot fit on the + line. We then replace these columns with the appropriate padding + character: '-' for the mode line and SPC for the other two. That's + because these lines should not show the usual truncation glyphs + there. This function is only used on TTY frames. */ +static void +pad_mode_line (struct it *it, bool mode_line_p) +{ + struct it temp_it; + GLYPH glyph; + + eassert (!FRAME_WINDOW_P (it->f)); + temp_it = *it; + temp_it.object = Qnil; + memset (&temp_it.current, 0, sizeof temp_it.current); + + SET_GLYPH (glyph, mode_line_p ? '-' : ' ', it->base_face_id); + + temp_it.dp = NULL; + temp_it.what = IT_CHARACTER; + temp_it.c = temp_it.char_to_display = GLYPH_CHAR (glyph); + temp_it.face_id = GLYPH_FACE (glyph); + temp_it.len = CHAR_BYTES (temp_it.c); + + PRODUCE_GLYPHS (&temp_it); + it->pixel_width = temp_it.pixel_width; + it->nglyphs = temp_it.nglyphs; +} + #ifdef HAVE_WINDOW_SYSTEM /* Calculate line-height and line-spacing properties. @@ -31996,6 +32601,14 @@ gui_produce_glyphs (struct it *it) if (get_char_glyph_code (it->char_to_display, font, &char2b)) { pcm = get_per_char_metric (font, &char2b); + + /* Overstruck text is displayed twice, the second time + one pixel to the right. Increase the right-side + bearing to match. */ + + if (pcm && face->overstrike) + pcm->rbearing++; + if (pcm->width == 0 && pcm->rbearing == 0 && pcm->lbearing == 0) pcm = NULL; @@ -32201,7 +32814,19 @@ gui_produce_glyphs (struct it *it) if (font->space_width > 0) { int tab_width = it->tab_width * font->space_width; - int x = it->current_x + it->continuation_lines_width; + /* wrap-prefix strings are prepended to continuation + lines, so the width of tab characters inside should + be computed from the start of this screen line rather + than as a product of the total width of the physical + line being wrapped. */ + int x = it->current_x + (it->string_from_prefix_prop_p + /* Subtract the width of the + prefix from it->current_x if + it exists. */ + ? 0 : (it->continuation_lines_width + ? (it->continuation_lines_width + - it->wrap_prefix_width) + : 0)); int x0 = x; /* Adjust for line numbers, if needed. */ if (!NILP (Vdisplay_line_numbers) && it->line_number_produced_p) @@ -32388,6 +33013,13 @@ gui_produce_glyphs (struct it *it) /* Initialize the bounding box. */ if (pcm) { + /* Overstruck text is displayed twice, the second time + one pixel to the right. Increase the right-side + bearing to match. */ + + if (face->overstrike) + pcm->rbearing++; + width = cmp->glyph_len > 0 ? pcm->width : 0; ascent = pcm->ascent; descent = pcm->descent; @@ -32449,6 +33081,13 @@ gui_produce_glyphs (struct it *it) cmp->offsets[i * 2] = cmp->offsets[i * 2 + 1] = 0; else { + /* Overstruck text is displayed twice, the second + time one pixel to the right. Increase the + right-side bearing to match. */ + + if (face->overstrike) + pcm->rbearing++; + width = pcm->width; ascent = pcm->ascent; descent = pcm->descent; @@ -32658,7 +33297,13 @@ gui_produce_glyphs (struct it *it) because this isn't true for images with `:ascent 100'. */ eassert (it->ascent >= 0 && it->descent >= 0); if (it->area == TEXT_AREA) - it->current_x += it->pixel_width; + { + it->current_x += it->pixel_width; + + if (it->continuation_lines_width + && it->string_from_prefix_prop_p) + it->wrap_prefix_width = it->current_x; + } if (extra_line_spacing > 0) { @@ -33177,13 +33822,18 @@ notice_overwritten_cursor (struct window *w, enum glyph_row_area area, void gui_fix_overlapping_area (struct window *w, struct glyph_row *row, - enum glyph_row_area area, int overlaps) + enum glyph_row_area area, int overlaps) { int i, x; block_input (); - x = 0; + /* row->x might be smaller than zero when produced from an iterator + under horizontal scrolling. Offset all measurements by this + basic value, lest hscrolled text with overlaps be displayed with + its overlapping portions misaligned. */ + x = row->x; + for (i = 0; i < row->used[area];) { if (row->glyphs[area][i].overlaps_vertically_p) @@ -33418,7 +34068,7 @@ display_and_set_cursor (struct window *w, bool on, windows and frames; in the latter case, the frame or window may be in the midst of changing its size, and x and y may be off the window. */ - if (! FRAME_VISIBLE_P (f) + if (! FRAME_REDISPLAY_P (f) || vpos >= w->current_matrix->nrows || hpos >= w->current_matrix->matrix_w) return; @@ -33487,6 +34137,7 @@ display_and_set_cursor (struct window *w, bool on, completely erased, to avoid the extra work of erasing the cursor twice. In other words, phys_cursor_on_p can be true and the cursor still not be visible, or it has only been partly erased. */ + if (on) { w->phys_cursor_ascent = glyph_row->ascent; @@ -33500,9 +34151,15 @@ display_and_set_cursor (struct window *w, bool on, w->phys_cursor.vpos = vpos; } - FRAME_RIF (f)->draw_window_cursor (w, glyph_row, x, y, - new_cursor_type, new_cursor_width, - on, active_cursor); + /* If make_cursor_line_fully_visible is nil and the row is in fact + vscrolled out of the window, then glyph_row->y + + glyph_row->height will be less than or equal to 0. Eschew + displaying the cursor in that case. */ + + if (MATRIX_ROW_BOTTOM_Y (glyph_row) > 0) + FRAME_RIF (f)->draw_window_cursor (w, glyph_row, x, y, + new_cursor_type, new_cursor_width, + on, active_cursor); } @@ -33579,7 +34236,7 @@ gui_update_cursor (struct frame *f, bool on_p) void gui_clear_cursor (struct window *w) { - if (FRAME_VISIBLE_P (XFRAME (w->frame)) && w->phys_cursor_on_p) + if (FRAME_REDISPLAY_P (XFRAME (w->frame)) && w->phys_cursor_on_p) update_window_cursor (w, false); } @@ -33600,7 +34257,9 @@ draw_row_with_mouse_face (struct window *w, int start_x, struct glyph_row *row, } #endif +#ifndef HAVE_ANDROID tty_draw_row_with_mouse_face (w, row, start_hpos, end_hpos, draw); +#endif } /* Display the active region described by mouse_face_* according to DRAW. */ @@ -35091,7 +35750,8 @@ note_mouse_highlight (struct frame *f, int x, int y) struct buffer *b; /* When a menu is active, don't highlight because this looks odd. */ -#if defined (HAVE_X_WINDOWS) || defined (HAVE_NS) || defined (MSDOS) +#if defined (HAVE_X_WINDOWS) || defined (HAVE_NS) || defined (MSDOS) \ + || defined (HAVE_ANDROID) if (popup_activated ()) return; #endif @@ -35113,7 +35773,7 @@ note_mouse_highlight (struct frame *f, int x, int y) return; /* Which window is that in? */ - window = window_from_coordinates (f, x, y, &part, true, true); + window = window_from_coordinates (f, x, y, &part, true, true, true); /* If displaying active text in another window, clear that. */ if (! EQ (window, hlinfo->mouse_face_window) @@ -35212,6 +35872,16 @@ note_mouse_highlight (struct frame *f, int x, int y) w = XWINDOW (window); frame_to_window_pixel_xy (w, &x, &y); +#if defined (HAVE_WINDOW_SYSTEM) && ! defined (HAVE_EXT_MENU_BAR) + /* Handle menu-bar window differently since it doesn't display a + buffer. */ + if (EQ (window, f->menu_bar_window)) + { + cursor = FRAME_OUTPUT_DATA (f)->nontext_cursor; + goto set_cursor; + } +#endif + #if defined (HAVE_WINDOW_SYSTEM) /* Handle tab-bar window differently since it doesn't display a buffer. */ @@ -35219,12 +35889,10 @@ note_mouse_highlight (struct frame *f, int x, int y) { note_tab_bar_highlight (f, x, y); if (tab_bar__dragging_in_progress) - { cursor = FRAME_OUTPUT_DATA (f)->hand_cursor; - goto set_cursor; - } else - return; + cursor = FRAME_OUTPUT_DATA (f)->nontext_cursor; + goto set_cursor; } else { @@ -35242,7 +35910,8 @@ note_mouse_highlight (struct frame *f, int x, int y) if (EQ (window, f->tool_bar_window)) { note_tool_bar_highlight (f, x, y); - return; + cursor = FRAME_OUTPUT_DATA (f)->nontext_cursor; + goto set_cursor; } #endif @@ -35793,7 +36462,7 @@ expose_area (struct window *w, struct glyph_row *row, const Emacs_Rectangle *r, /* Use a signed int intermediate value to avoid catastrophic failures due to comparison between signed and unsigned, when x is negative (can happen for wide images that are hscrolled). */ - int r_end = r->x + r->width; + int r_end = r->x + (int) r->width; while (last < end && x < r_end) { x += last->pixel_width; @@ -36092,7 +36761,7 @@ expose_window (struct window *w, const Emacs_Rectangle *fr) /* Use a signed int intermediate value to avoid catastrophic failures due to comparison between signed and unsigned, when y0 or y1 is negative (can happen for tall images). */ - int r_bottom = r.y + r.height; + int r_bottom = r.y + (int) r.height; /* We must temporarily switch to the window's buffer, in case the fringe face has been remapped in that buffer's @@ -36139,7 +36808,7 @@ expose_window (struct window *w, const Emacs_Rectangle *fr) /* We must redraw a row overlapping the exposed area. */ if (y0 < r.y ? y0 + row->phys_height > r.y - : y0 + row->ascent - row->phys_ascent < r.y +r.height) + : y0 + row->ascent - row->phys_ascent < r.y + (int) r.height) { if (first_overlapping_row == NULL) first_overlapping_row = row; @@ -36272,14 +36941,10 @@ expose_frame (struct frame *f, int x, int y, int w, int h) |= expose_window (XWINDOW (f->tool_bar_window), &r); #endif -#ifdef HAVE_X_WINDOWS -#ifndef MSDOS -#if ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK) +#if defined HAVE_WINDOW_SYSTEM && !defined HAVE_EXT_MENU_BAR if (WINDOWP (f->menu_bar_window)) mouse_face_overwritten_p |= expose_window (XWINDOW (f->menu_bar_window), &r); -#endif /* not USE_X_TOOLKIT and not USE_GTK */ -#endif #endif /* Some window managers support a focus-follows-mouse style with @@ -36322,7 +36987,7 @@ gui_intersect_rectangles (const Emacs_Rectangle *r1, const Emacs_Rectangle *r2, const Emacs_Rectangle *upper, *lower; bool intersection_p = false; - /* Rearrange so that R1 is the left-most rectangle. */ + /* Rearrange so that left is the left-most rectangle. */ if (r1->x < r2->x) left = r1, right = r2; else @@ -36330,13 +36995,14 @@ gui_intersect_rectangles (const Emacs_Rectangle *r1, const Emacs_Rectangle *r2, /* X0 of the intersection is right.x0, if this is inside R1, otherwise there is no intersection. */ - if (right->x <= left->x + left->width) + if (right->x <= left->x + (int) left->width) { result->x = right->x; /* The right end of the intersection is the minimum of the right ends of left and right. */ - result->width = (min (left->x + left->width, right->x + right->width) + result->width = (min (left->x + (int) left->width, + right->x + (int) right->width) - result->x); /* Same game for Y. */ @@ -36347,14 +37013,14 @@ gui_intersect_rectangles (const Emacs_Rectangle *r1, const Emacs_Rectangle *r2, /* The upper end of the intersection is lower.y0, if this is inside of upper. Otherwise, there is no intersection. */ - if (lower->y <= upper->y + upper->height) + if (lower->y <= upper->y + (int) upper->height) { result->y = lower->y; /* The lower end of the intersection is the minimum of the lower ends of upper and lower. */ - result->height = (min (lower->y + lower->height, - upper->y + upper->height) + result->height = (min (lower->y + (int) lower->height, + upper->y + (int) upper->height) - result->y); intersection_p = true; } @@ -36363,6 +37029,55 @@ gui_intersect_rectangles (const Emacs_Rectangle *r1, const Emacs_Rectangle *r2, return intersection_p; } +/* EXPORT: + Determine the union of the rectangles A and B. Return the smallest + rectangle encompassing both the bounds of A and B in *RESULT. It + is safe for all three arguments to point to each other. */ + +void +gui_union_rectangles (const Emacs_Rectangle *a, const Emacs_Rectangle *b, + Emacs_Rectangle *result) +{ + struct gui_box a_box, b_box, result_box; + + /* Handle special cases where one of the rectangles is empty. */ + + if (!a->width || !a->height) + { + *result = *b; + return; + } + else if (!b->width || !b->height) + { + *result = *a; + return; + } + + /* Convert A and B to boxes. */ + a_box.x1 = a->x; + a_box.y1 = a->y; + a_box.x2 = a->x + a->width; + a_box.y2 = a->y + a->height; + + b_box.x1 = b->x; + b_box.y1 = b->y; + b_box.x2 = b->x + b->width; + b_box.y2 = b->y + b->height; + + /* Compute the union of the boxes. */ + result_box.x1 = min (a_box.x1, b_box.x1); + result_box.y1 = min (a_box.y1, b_box.y1); + result_box.x2 = max (a_box.x2, b_box.x2); + result_box.y2 = max (a_box.y2, b_box.y2); + + /* Convert result_box to an XRectangle and put the result in + RESULT. */ + result->x = result_box.x1; + result->y = result_box.y1; + result->width = result_box.x2 - result_box.x1; + result->height = result_box.y2 - result_box.y1; +} + #endif /* HAVE_WINDOW_SYSTEM */ @@ -37296,6 +38011,8 @@ cursor shapes. */); DEFSYM (Qthin_space, "thin-space"); DEFSYM (Qzero_width, "zero-width"); + DEFSYM (Qdebug_early__muted, "debug-early--muted"); + DEFVAR_LISP ("pre-redisplay-function", Vpre_redisplay_function, doc: /* Function run just before redisplay. It is called with one argument, which is the set of windows that are to @@ -37394,9 +38111,12 @@ may be more familiar to users. */); display_raw_bytes_as_hex = false; DEFVAR_BOOL ("mouse-fine-grained-tracking", mouse_fine_grained_tracking, - doc: /* Non-nil for pixel-wise mouse-movement. + doc: /* Non-nil for pixelwise mouse-movement. When nil, mouse-movement events will not be generated as long as the -mouse stays within the extent of a single glyph (except for images). */); +mouse stays within the extent of a single glyph (except for images). +When nil and `mouse-prefer-closest-glyph' is non-nil, mouse-movement +events will instead not be generated as long as the mouse stays within +the extent of a single left/right half glyph (except for images). */); mouse_fine_grained_tracking = false; DEFVAR_BOOL ("tab-bar--dragging-in-progress", tab_bar__dragging_in_progress, @@ -37441,13 +38161,13 @@ composed on display. */); DEFVAR_INT ("max-redisplay-ticks", max_redisplay_ticks, doc: /* Maximum number of redisplay ticks before aborting redisplay of a window. -This allows to abort the display of a window if the amount of low-level -redisplay operations exceeds the value of this variable. When display of -a window is aborted due to this reason, the buffer shown in that window -will not have its windows redisplayed until the buffer is modified or until -you type \\[recenter-top-bottom] with one of its windows selected. -You can also decide to kill the buffer and visit it in some -other way, like under `so-long-mode' or literally. +This enables aborting the display of a window if the amount of +low-level redisplay operations exceeds the value of this variable. +When display of a window is aborted due to this reason, the buffer +shown in that window will not have its windows redisplayed until the +buffer is modified or until you type \\[recenter-top-bottom] with one +of its windows selected. You can also decide to kill the buffer and +visit it in some other way, like under `so-long-mode' or literally. The default value is zero, which disables this feature. The recommended non-zero value is between 100000 and 1000000, @@ -37478,7 +38198,7 @@ init_xdisp (void) r->pixel_top = r->top_line * FRAME_LINE_HEIGHT (f); r->total_cols = FRAME_COLS (f); r->pixel_width = r->total_cols * FRAME_COLUMN_WIDTH (f); - r->total_lines = FRAME_TOTAL_LINES (f) - 1 - FRAME_TOP_MARGIN (f); + r->total_lines = FRAME_TOTAL_LINES (f) - 1 - FRAME_MARGINS (f); r->pixel_height = r->total_lines * FRAME_LINE_HEIGHT (f); m->top_line = FRAME_TOTAL_LINES (f) - 1; |