Commit 8a668709 authored by Chong Yidong's avatar Chong Yidong
Browse files

* xdisp.c (Qbefore_string, Qafter_string): Add externs.

(load_overlay_strings): Remove externs.
(fast_find_position): Function deleted.
(mouse_face_from_buffer_pos): New function, based on
fast_find_position.  Correctly handle before-strings,
display-strings, and after-strings (Bug#1220).
(note_mouse_highlight): Use mouse_face_from_buffer_pos.
parent 70243478
2009-06-22 Chong Yidong <cyd@stupidchicken.com>
* xdisp.c (Qbefore_string, Qafter_string): Add externs.
(load_overlay_strings): Remove externs.
(fast_find_position): Function deleted.
(mouse_face_from_buffer_pos): New function, based on
fast_find_position. Correctly handle before-strings,
display-strings, and after-strings (Bug#1220).
(note_mouse_highlight): Use mouse_face_from_buffer_pos.
2009-06-21 Chong Yidong <cyd@stupidchicken.com> 2009-06-21 Chong Yidong <cyd@stupidchicken.com>
   
* xdisp.c (IT_DISPLAYING_WHITESPACE): Define for * xdisp.c (IT_DISPLAYING_WHITESPACE): Define for
......
...@@ -235,6 +235,7 @@ extern Lisp_Object Voverriding_local_map_menu_flag; ...@@ -235,6 +235,7 @@ extern Lisp_Object Voverriding_local_map_menu_flag;
extern Lisp_Object Qmenu_item; extern Lisp_Object Qmenu_item;
extern Lisp_Object Qwhen; extern Lisp_Object Qwhen;
extern Lisp_Object Qhelp_echo; extern Lisp_Object Qhelp_echo;
extern Lisp_Object Qbefore_string, Qafter_string;
   
Lisp_Object Qoverriding_local_map, Qoverriding_terminal_local_map; Lisp_Object Qoverriding_local_map, Qoverriding_terminal_local_map;
Lisp_Object Qwindow_scroll_functions, Vwindow_scroll_functions; Lisp_Object Qwindow_scroll_functions, Vwindow_scroll_functions;
...@@ -4870,7 +4871,7 @@ load_overlay_strings (it, charpos) ...@@ -4870,7 +4871,7 @@ load_overlay_strings (it, charpos)
struct it *it; struct it *it;
int charpos; int charpos;
{ {
extern Lisp_Object Qafter_string, Qbefore_string, Qwindow, Qpriority; extern Lisp_Object Qwindow, Qpriority;
Lisp_Object overlay, window, str, invisible; Lisp_Object overlay, window, str, invisible;
struct Lisp_Overlay *ov; struct Lisp_Overlay *ov;
int start, end; int start, end;
...@@ -22918,206 +22919,181 @@ cursor_in_mouse_face_p (w) ...@@ -22918,206 +22919,181 @@ cursor_in_mouse_face_p (w)
   
   
/* Find the glyph matrix position of buffer position CHARPOS in window /* This function sets the mouse_face_* elements of DPYINFO, assuming
*W. HPOS, *VPOS, *X, and *Y are set to the positions found. W's the mouse cursor is on a glyph with buffer charpos MOUSE_CHARPOS in
current glyphs must be up to date. If CHARPOS is above window window WINDOW. START_CHARPOS and END_CHARPOS are buffer positions
start return (0, 0, 0, 0). If CHARPOS is after end of W, return end for the overlay or run of text properties specifying the mouse
of last line in W. In the row containing CHARPOS, stop before glyphs face. BEFORE_STRING and AFTER_STRING, if non-nil, are a
having STOP as object. */ before-string and after-string that must also be highlighted.
DISPLAY_STRING, if non-nil, is a display string that may cover some
#if 1 /* This is a version of fast_find_position that's more correct or all of the highlighted text. */
in the presence of hscrolling, for example. I didn't install
it right away because the problem fixed is minor, it failed
in 20.x as well, and I think it's too risky to install
so near the release of 21.1. 2001-09-25 gerd. */
   
static static void
int mouse_face_from_buffer_pos (Lisp_Object window,
fast_find_position (w, charpos, hpos, vpos, x, y, stop) Display_Info *dpyinfo,
struct window *w; EMACS_INT mouse_charpos,
EMACS_INT charpos; EMACS_INT start_charpos,
int *hpos, *vpos, *x, *y; EMACS_INT end_charpos,
Lisp_Object stop; Lisp_Object before_string,
Lisp_Object after_string,
Lisp_Object display_string)
{ {
struct glyph_row *row, *first; struct window *w = XWINDOW (window);
struct glyph_row *first = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
struct glyph_row *row;
struct glyph *glyph, *end; struct glyph *glyph, *end;
int past_end = 0; EMACS_INT ignore;
int x;
   
first = MATRIX_FIRST_TEXT_ROW (w->current_matrix); xassert (NILP (display_string) || STRINGP (display_string));
if (charpos < MATRIX_ROW_START_CHARPOS (first)) xassert (NILP (before_string) || STRINGP (before_string));
{ xassert (NILP (after_string) || STRINGP (after_string));
*x = first->x;
*y = first->y;
*hpos = 0;
*vpos = MATRIX_ROW_VPOS (first, w->current_matrix);
return 1;
}
   
row = row_containing_pos (w, charpos, first, NULL, 0); /* Find the first highlighted glyph. */
if (row == NULL) if (start_charpos < MATRIX_ROW_START_CHARPOS (first))
{ {
row = MATRIX_ROW (w->current_matrix, XFASTINT (w->window_end_vpos)); dpyinfo->mouse_face_beg_col = 0;
past_end = 1; dpyinfo->mouse_face_beg_row = MATRIX_ROW_VPOS (first, w->current_matrix);
dpyinfo->mouse_face_beg_x = first->x;
dpyinfo->mouse_face_beg_y = first->y;
} }
else
/* If whole rows or last part of a row came from a display overlay,
row_containing_pos will skip over such rows because their end pos
equals the start pos of the overlay or interval.
Move back if we have a STOP object and previous row's
end glyph came from STOP. */
if (!NILP (stop))
{ {
struct glyph_row *prev; row = row_containing_pos (w, start_charpos, first, NULL, 0);
while ((prev = row - 1, prev >= first) if (row == NULL)
&& MATRIX_ROW_END_CHARPOS (prev) == charpos row = MATRIX_ROW (w->current_matrix, XFASTINT (w->window_end_vpos));
&& prev->used[TEXT_AREA] > 0)
/* If the before-string or display-string contains newlines,
row_containing_pos skips to its last row. Move back. */
if (!NILP (before_string) || !NILP (display_string))
{ {
struct glyph *beg = prev->glyphs[TEXT_AREA]; struct glyph_row *prev;
glyph = beg + prev->used[TEXT_AREA]; while ((prev = row - 1, prev >= first)
while (--glyph >= beg && MATRIX_ROW_END_CHARPOS (prev) == start_charpos
&& INTEGERP (glyph->object)); && prev->used[TEXT_AREA] > 0)
if (glyph < beg {
|| !EQ (stop, glyph->object)) struct glyph *beg = prev->glyphs[TEXT_AREA];
break; glyph = beg + prev->used[TEXT_AREA];
row = prev; while (--glyph >= beg && INTEGERP (glyph->object));
if (glyph < beg
|| !(EQ (glyph->object, before_string)
|| EQ (glyph->object, display_string)))
break;
row = prev;
}
} }
}
   
*x = row->x; glyph = row->glyphs[TEXT_AREA];
*y = row->y; end = glyph + row->used[TEXT_AREA];
*vpos = MATRIX_ROW_VPOS (row, w->current_matrix); x = row->x;
dpyinfo->mouse_face_beg_y = row->y;
dpyinfo->mouse_face_beg_row = MATRIX_ROW_VPOS (row, w->current_matrix);
   
glyph = row->glyphs[TEXT_AREA]; /* Skip truncation glyphs at the start of the glyph row. */
end = glyph + row->used[TEXT_AREA]; if (row->displays_text_p)
for (; glyph < end && INTEGERP (glyph->object); ++glyph)
x += glyph->pixel_width;
   
/* Skip over glyphs not having an object at the start of the row. /* Scan the glyph row, stopping before BEFORE_STRING or
These are special glyphs like truncation marks on terminal DISPLAY_STRING or START_CHARPOS. */
frames. */ for (; glyph < end
if (row->displays_text_p) && !INTEGERP (glyph->object)
while (glyph < end && !EQ (glyph->object, before_string)
&& INTEGERP (glyph->object) && !EQ (glyph->object, display_string)
&& !EQ (stop, glyph->object) && !(BUFFERP (glyph->object)
&& glyph->charpos < 0) && glyph->charpos >= start_charpos);
{ ++glyph)
*x += glyph->pixel_width; x += glyph->pixel_width;
++glyph;
}
   
while (glyph < end dpyinfo->mouse_face_beg_x = x;
&& !INTEGERP (glyph->object) dpyinfo->mouse_face_beg_col = glyph - row->glyphs[TEXT_AREA];
&& !EQ (stop, glyph->object) }
&& (!BUFFERP (glyph->object)
|| glyph->charpos < charpos)) /* Find the last highlighted glyph. */
row = row_containing_pos (w, end_charpos, first, NULL, 0);
if (row == NULL)
{ {
*x += glyph->pixel_width; row = MATRIX_ROW (w->current_matrix, XFASTINT (w->window_end_vpos));
++glyph; dpyinfo->mouse_face_past_end = 1;
} }
else if (!NILP (after_string))
{
/* If the after-string has newlines, advance to its last row. */
struct glyph_row *next;
struct glyph_row *last
= MATRIX_ROW (w->current_matrix, XFASTINT (w->window_end_vpos));
   
*hpos = glyph - row->glyphs[TEXT_AREA]; for (next = row + 1;
return !past_end; next <= last
} && next->used[TEXT_AREA] > 0
&& EQ (next->glyphs[TEXT_AREA]->object, after_string);
++next)
row = next;
}
   
#else /* not 1 */ glyph = row->glyphs[TEXT_AREA];
end = glyph + row->used[TEXT_AREA];
x = row->x;
dpyinfo->mouse_face_end_y = row->y;
dpyinfo->mouse_face_end_row = MATRIX_ROW_VPOS (row, w->current_matrix);
   
static int /* Skip truncation glyphs at the start of the row. */
fast_find_position (w, pos, hpos, vpos, x, y, stop) if (row->displays_text_p)
struct window *w; for (; glyph < end && INTEGERP (glyph->object); ++glyph)
EMACS_INT pos; x += glyph->pixel_width;
int *hpos, *vpos, *x, *y;
Lisp_Object stop;
{
int i;
int lastcol;
int maybe_next_line_p = 0;
int line_start_position;
int yb = window_text_bottom_y (w);
struct glyph_row *row, *best_row;
int row_vpos, best_row_vpos;
int current_x;
   
row = best_row = MATRIX_FIRST_TEXT_ROW (w->current_matrix); /* Scan the glyph row, stopping at END_CHARPOS or when we encounter
row_vpos = best_row_vpos = MATRIX_ROW_VPOS (row, w->current_matrix); AFTER_STRING. */
for (; glyph < end
&& !INTEGERP (glyph->object)
&& !EQ (glyph->object, after_string)
&& !(BUFFERP (glyph->object) && glyph->charpos >= end_charpos);
++glyph)
x += glyph->pixel_width;
   
while (row->y < yb) /* If we found AFTER_STRING, consume it and stop. */
if (EQ (glyph->object, after_string))
{ {
if (row->used[TEXT_AREA]) for (; EQ (glyph->object, after_string) && glyph < end; ++glyph)
line_start_position = row->glyphs[TEXT_AREA]->charpos; x += glyph->pixel_width;
else
line_start_position = 0;
if (line_start_position > pos)
break;
/* If the position sought is the end of the buffer,
don't include the blank lines at the bottom of the window. */
else if (line_start_position == pos
&& pos == BUF_ZV (XBUFFER (w->buffer)))
{
maybe_next_line_p = 1;
break;
}
else if (line_start_position > 0)
{
best_row = row;
best_row_vpos = row_vpos;
}
if (row->y + row->height >= yb)
break;
++row;
++row_vpos;
} }
else
/* Find the right column within BEST_ROW. */
lastcol = 0;
current_x = best_row->x;
for (i = 0; i < best_row->used[TEXT_AREA]; i++)
{ {
struct glyph *glyph = best_row->glyphs[TEXT_AREA] + i; /* If there's no after-string, we must check if we overshot,
int charpos = glyph->charpos; which might be the case if we stopped after a string glyph.
That glyph may belong to a before-string or display-string
associated with the end position, which must not be
highlighted. */
Lisp_Object prev_object;
int pos;
   
if (BUFFERP (glyph->object)) while (glyph > row->glyphs[TEXT_AREA])
{ {
if (charpos == pos) prev_object = (glyph - 1)->object;
{ if (!STRINGP (prev_object) || EQ (prev_object, display_string))
*hpos = i;
*vpos = best_row_vpos;
*x = current_x;
*y = best_row->y;
return 1;
}
else if (charpos > pos)
break; break;
}
else if (EQ (glyph->object, stop))
break;
   
if (charpos > 0) pos = string_buffer_position (w, prev_object, end_charpos);
lastcol = i; if (pos && pos < end_charpos)
current_x += glyph->pixel_width; break;
}
   
/* If we're looking for the end of the buffer, for (; glyph > row->glyphs[TEXT_AREA]
and we didn't find it in the line we scanned, && EQ ((glyph - 1)->object, prev_object);
use the start of the following line. */ --glyph)
if (maybe_next_line_p) x -= (glyph - 1)->pixel_width;
{ }
++best_row;
++best_row_vpos;
lastcol = 0;
current_x = best_row->x;
} }
   
*vpos = best_row_vpos; dpyinfo->mouse_face_end_x = x;
*hpos = lastcol + 1; dpyinfo->mouse_face_end_col = glyph - row->glyphs[TEXT_AREA];
*x = current_x; dpyinfo->mouse_face_window = window;
*y = best_row->y; dpyinfo->mouse_face_face_id
return 0; = face_at_buffer_position (w, mouse_charpos, 0, 0, &ignore,
mouse_charpos + 1,
!dpyinfo->mouse_face_hidden, -1);
show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
} }
   
#endif /* not 1 */
   
/* Find the position of the glyph for position POS in OBJECT in /* Find the position of the glyph for position POS in OBJECT in
window W's current matrix, and return in *X, *Y the pixel window W's current matrix, and return in *X, *Y the pixel
...@@ -23844,8 +23820,7 @@ note_mouse_highlight (f, x, y) ...@@ -23844,8 +23820,7 @@ note_mouse_highlight (f, x, y)
|| (OVERLAYP (dpyinfo->mouse_face_overlay) || (OVERLAYP (dpyinfo->mouse_face_overlay)
&& mouse_face_overlay_overlaps (dpyinfo->mouse_face_overlay))) && mouse_face_overlay_overlaps (dpyinfo->mouse_face_overlay)))
{ {
/* Find the highest priority overlay that has a mouse-face /* Find the highest priority overlay with a mouse-face. */
property. */
overlay = Qnil; overlay = Qnil;
for (i = noverlays - 1; i >= 0 && NILP (overlay); --i) for (i = noverlays - 1; i >= 0 && NILP (overlay); --i)
{ {
...@@ -23854,12 +23829,10 @@ note_mouse_highlight (f, x, y) ...@@ -23854,12 +23829,10 @@ note_mouse_highlight (f, x, y)
overlay = overlay_vec[i]; overlay = overlay_vec[i];
} }
   
/* If we're actually highlighting the same overlay as /* If we're highlighting the same overlay as before, there's
before, there's no need to do that again. */ no need to do that again. */
if (!NILP (overlay) if (!NILP (overlay) && EQ (overlay, dpyinfo->mouse_face_overlay))
&& EQ (overlay, dpyinfo->mouse_face_overlay))
goto check_help_echo; goto check_help_echo;
dpyinfo->mouse_face_overlay = overlay; dpyinfo->mouse_face_overlay = overlay;
   
/* Clear the display of the old active region, if any. */ /* Clear the display of the old active region, if any. */
...@@ -23870,95 +23843,19 @@ note_mouse_highlight (f, x, y) ...@@ -23870,95 +23843,19 @@ note_mouse_highlight (f, x, y)
if (NILP (overlay)) if (NILP (overlay))
mouse_face = Fget_text_property (position, Qmouse_face, object); mouse_face = Fget_text_property (position, Qmouse_face, object);
   
/* Handle the overlay case. */ /* Next, compute the bounds of the mouse highlighting and
if (!NILP (overlay)) display it. */
{ if (!NILP (mouse_face) && STRINGP (object))
/* Find the range of text around this char that
should be active. */
Lisp_Object before, after;
EMACS_INT ignore;
before = Foverlay_start (overlay);
after = Foverlay_end (overlay);
/* Record this as the current active region. */
fast_find_position (w, XFASTINT (before),
&dpyinfo->mouse_face_beg_col,
&dpyinfo->mouse_face_beg_row,
&dpyinfo->mouse_face_beg_x,
&dpyinfo->mouse_face_beg_y, Qnil);
dpyinfo->mouse_face_past_end
= !fast_find_position (w, XFASTINT (after),
&dpyinfo->mouse_face_end_col,
&dpyinfo->mouse_face_end_row,
&dpyinfo->mouse_face_end_x,
&dpyinfo->mouse_face_end_y, Qnil);
dpyinfo->mouse_face_window = window;
dpyinfo->mouse_face_face_id
= face_at_buffer_position (w, pos, 0, 0,
&ignore, pos + 1,
!dpyinfo->mouse_face_hidden,
-1);
/* Display it as active. */
show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
cursor = No_Cursor;
}
/* Handle the text property case. */
else if (!NILP (mouse_face) && BUFFERP (object))
{
/* Find the range of text around this char that
should be active. */
Lisp_Object before, after, beginning, end;
EMACS_INT ignore;
beginning = Fmarker_position (w->start);
end = make_number (BUF_Z (XBUFFER (object))
- XFASTINT (w->window_end_pos));
before
= Fprevious_single_property_change (make_number (pos + 1),
Qmouse_face,
object, beginning);
after
= Fnext_single_property_change (position, Qmouse_face,
object, end);
/* Record this as the current active region. */
fast_find_position (w, XFASTINT (before),
&dpyinfo->mouse_face_beg_col,
&dpyinfo->mouse_face_beg_row,
&dpyinfo->mouse_face_beg_x,
&dpyinfo->mouse_face_beg_y, Qnil);
dpyinfo->mouse_face_past_end
= !fast_find_position (w, XFASTINT (after),
&dpyinfo->mouse_face_end_col,
&dpyinfo->mouse_face_end_row,
&dpyinfo->mouse_face_end_x,
&dpyinfo->mouse_face_end_y, Qnil);
dpyinfo->mouse_face_window = window;
if (BUFFERP (object))
dpyinfo->mouse_face_face_id
= face_at_buffer_position (w, pos, 0, 0,
&ignore, pos + 1,
!dpyinfo->mouse_face_hidden,
-1);
/* Display it as active. */
show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
cursor = No_Cursor;
}
else if (!NILP (mouse_face) && STRINGP (object))
{ {
/* The mouse-highlighting comes from a display string
with a mouse-face. */
Lisp_Object b, e; Lisp_Object b, e;
EMACS_INT ignore; EMACS_INT ignore;
   
b = Fprevious_single_property_change (make_number (pos + 1), b = Fprevious_single_property_change
Qmouse_face, (make_number (pos + 1), Qmouse_face, object, Qnil);
object, Qnil); e = Fnext_single_property_change
e = Fnext_single_property_change (position, Qmouse_face, (position, Qmouse_face, object, Qnil);
object, Qnil);
if (NILP (b)) if (NILP (b))
b = make_number (0); b = make_number (0);
if (NILP (e)) if (NILP (e))
...@@ -23982,53 +23879,67 @@ note_mouse_highlight (f, x, y) ...@@ -23982,53 +23879,67 @@ note_mouse_highlight (f, x, y)
show_mouse_face (dpyinfo, DRAW_MOUSE_FACE); show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
cursor = No_Cursor; cursor = No_Cursor;
} }
else if (STRINGP (object) && NILP (mouse_face)) else
{ {
/* A string which doesn't have mouse-face, but /* The mouse-highlighting, if any, comes from an overlay
the text ``under'' it might have. */ or text property in the buffer. */
struct glyph_row *r = MATRIX_ROW (w->current_matrix, vpos); Lisp_Object buffer, display_string;
int start = MATRIX_ROW_START_CHARPOS (r);
if (STRINGP (object))
pos = string_buffer_position (w, object, start);
if (pos > 0)
mouse_face = get_char_property_and_overlay (make_number (pos),
Qmouse_face,
w->buffer,
&overlay);
if (!NILP (mouse_face) && !NILP (overlay))
{ {
Lisp_Object before = Foverlay_start (overlay); /* If we are on a display string with no mouse-face,
Lisp_Object after = Foverlay_end (overlay); check if the text under it has one. */
EMACS_INT ignore; struct glyph_row *r = MATRIX_ROW (w->current_matrix, vpos);
int start = MATRIX_ROW_START_CHARPOS (r);
pos = string_buffer_position (w, object, start);
if (pos > 0)
{
mouse_face = get_char_property_and_overlay
(make_number (pos), Qmouse_face, w->buffer, &overlay);
buffer = w->buffer;
display_string = object;
}
}
else
{
buffer = object;
display_string = Qnil;
}
if (!NILP (mouse_face))
{
Lisp_Object before, after;
Lisp_Object before_string, after_string;
if (NILP (overlay))
{
/* Handle the text property case. */
before = Fprevious_single_property_change
(make_number (pos + 1), Qmouse_face, buffer,
Fmarker_position (w->start));
after = Fnext_single_property_change
(make_number (pos), Qmouse_face, buffer,
make_number (BUF_Z (XBUFFER (buffer))
- XFASTINT (w->window_end_pos)));
before_string = after_string = Qnil;
}
else
{
/* Handle the overlay case. */
before = Foverlay_start (overlay);
after = Foverlay_end (overlay);
before_string = Foverlay_get (overlay, Qbefore_string);
after_string = Foverlay_get (overlay, Qafter_string);
if (!STRINGP (before_string)) before_string = Qnil;
if (!STRINGP (after_string)) after_string = Qnil;
}
   
/* Note that we might not be able to find position mouse_face_from_buffer_pos (window, dpyinfo, pos,
BEFORE in the glyph matrix if the overlay is XFASTINT (before),
entirely covered by a `display' property. In XFASTINT (after),
this case, we overshoot. So let's stop in before_string, after_string,
the glyph matrix before glyphs for OBJECT. */ display_string);
fast_find_position (w, XFASTINT (before),
&dpyinfo->mouse_face_beg_col,
&dpyinfo->mouse_face_beg_row,
&dpyinfo->mouse_face_beg_x,
&dpyinfo->mouse_face_beg_y,
object);
dpyinfo->mouse_face_past_end
= !fast_find_position (w, XFASTINT (after),
&dpyinfo->mouse_face_end_col,
&dpyinfo->mouse_face_end_row,
&dpyinfo->mouse_face_end_x,
&dpyinfo->mouse_face_end_y,
Qnil);
dpyinfo->mouse_face_window = window;
dpyinfo->mouse_face_face_id
= face_at_buffer_position (w, pos, 0, 0,
&ignore, pos + 1,
!dpyinfo->mouse_face_hidden,
-1);
/* Display it as active. */
show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
cursor = No_Cursor; cursor = No_Cursor;
} }
} }
......
Markdown is supported
0% or .