summaryrefslogtreecommitdiff
path: root/src/xdisp.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/xdisp.c')
-rw-r--r--src/xdisp.c1488
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;