diff options
| author | Eli Zaretskii | 2010-10-23 17:30:45 +0200 |
|---|---|---|
| committer | Eli Zaretskii | 2010-10-23 17:30:45 +0200 |
| commit | d1d6801eb4badab97416d0b6294e1920d0f90c3e (patch) | |
| tree | 83cc92ae8e0a28b767e3abe8cc2e2753f1c855c7 /src | |
| parent | a6ac7fc4fddadcf7939f5f8b6ec09fadb4f90fc8 (diff) | |
| parent | a4041a7121ee093ec81ef0cb4b8da62a54587596 (diff) | |
| download | emacs-d1d6801eb4badab97416d0b6294e1920d0f90c3e.tar.gz emacs-d1d6801eb4badab97416d0b6294e1920d0f90c3e.zip | |
Implement mouse highlight for bidi-reordered lines.
xdisp.c (fast_find_string_pos): #ifdef away, not used anymore.
(mouse_face_from_string_pos): New function, replaces
fast_find_string_pos.
(note_mouse_highlight): Call it instead of fast_find_string_pos.
(note_mode_line_or_margin_highlight): Support bidi-reordered
strings and R2L glyph rows. Fix comments.
(note_mouse_highlight): When bidi reordering is turned on in a
buffer, call next-single-property-change and
previous-single-property-change with last argument nil. Clear
mouse highlight when mouse pointer is in a R2L row on the stretch
glyph that stands for no text beyond the line end.
(row_containing_pos): Don't return too early when CHARPOS is in a
bidi-reordered continued line. Return immediately when the first
hit is found in a line that is not continued, or when an exact
match for CHARPOS is found.
(rows_from_pos_range): New function.
(mouse_face_from_buffer_pos): Use it instead of calling
row_containing_pos for START_CHARPOS and END_CHARPOS. Rewrite the
function to support mouse highlight in bidi-reordered lines and
not to assume that START_CHARPOS is always in mouse_face_beg_row.
If necessary, swap mouse_face_beg_row and mouse_face_end_row so
that the former is always above the latter or identical to it.
(show_mouse_face): Support drawing highlighted R2L lines.
(coords_in_mouse_face_p): New function, bidi-aware.
(cursor_in_mouse_face_p, note_mouse_highlight, erase_phys_cursor):
Call it instead of comparing with mouse-face members of dpyinfo.
(note_mode_line_or_margin_highlight): Fix confusingly swapped
usage of hpos and vpos.
Diffstat (limited to 'src')
| -rw-r--r-- | src/ChangeLog | 35 | ||||
| -rw-r--r-- | src/xdisp.c | 950 |
2 files changed, 754 insertions, 231 deletions
diff --git a/src/ChangeLog b/src/ChangeLog index 05a0d442149..e4cd83a6236 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,3 +1,36 @@ | |||
| 1 | 2010-10-23 Eli Zaretskii <eliz@gnu.org> | ||
| 2 | |||
| 3 | Implement mouse highlight for bidi-reordered lines. | ||
| 4 | |||
| 5 | * xdisp.c (fast_find_string_pos): #ifdef away, not used anymore. | ||
| 6 | (mouse_face_from_string_pos): New function, replaces | ||
| 7 | fast_find_string_pos. | ||
| 8 | (note_mouse_highlight): Call it instead of fast_find_string_pos. | ||
| 9 | (note_mode_line_or_margin_highlight): Support bidi-reordered | ||
| 10 | strings and R2L glyph rows. Fix comments. | ||
| 11 | (note_mouse_highlight): When bidi reordering is turned on in a | ||
| 12 | buffer, call next-single-property-change and | ||
| 13 | previous-single-property-change with last argument nil. Clear | ||
| 14 | mouse highlight when mouse pointer is in a R2L row on the stretch | ||
| 15 | glyph that stands for no text beyond the line end. | ||
| 16 | (row_containing_pos): Don't return too early when CHARPOS is in a | ||
| 17 | bidi-reordered continued line. Return immediately when the first | ||
| 18 | hit is found in a line that is not continued, or when an exact | ||
| 19 | match for CHARPOS is found. | ||
| 20 | (rows_from_pos_range): New function. | ||
| 21 | (mouse_face_from_buffer_pos): Use it instead of calling | ||
| 22 | row_containing_pos for START_CHARPOS and END_CHARPOS. Rewrite the | ||
| 23 | function to support mouse highlight in bidi-reordered lines and | ||
| 24 | not to assume that START_CHARPOS is always in mouse_face_beg_row. | ||
| 25 | If necessary, swap mouse_face_beg_row and mouse_face_end_row so | ||
| 26 | that the former is always above the latter or identical to it. | ||
| 27 | (show_mouse_face): Support drawing highlighted R2L lines. | ||
| 28 | (coords_in_mouse_face_p): New function, bidi-aware. | ||
| 29 | (cursor_in_mouse_face_p, note_mouse_highlight, erase_phys_cursor): | ||
| 30 | Call it instead of comparing with mouse-face members of dpyinfo. | ||
| 31 | (note_mode_line_or_margin_highlight): Fix confusingly swapped | ||
| 32 | usage of hpos and vpos. | ||
| 33 | |||
| 1 | 2010-10-22 Jan Djärv <jan.h.d@swipnet.se> | 34 | 2010-10-22 Jan Djärv <jan.h.d@swipnet.se> |
| 2 | 35 | ||
| 3 | * xrdb.c: Include keyboard.h for MOTIF. | 36 | * xrdb.c: Include keyboard.h for MOTIF. |
| @@ -1528,7 +1561,7 @@ | |||
| 1528 | non-MSDOS, non-WINDOWSNT code, it's only defined for such systems | 1561 | non-MSDOS, non-WINDOWSNT code, it's only defined for such systems |
| 1529 | anyway. | 1562 | anyway. |
| 1530 | 1563 | ||
| 1531 | 2010-08-21 Eli Zaretskii <eliz@gnu.org> | 1564 | 2010-08-20 Eli Zaretskii <eliz@gnu.org> |
| 1532 | 1565 | ||
| 1533 | * dispnew.c (buffer_posn_from_coords): Fix off-by-one error in | 1566 | * dispnew.c (buffer_posn_from_coords): Fix off-by-one error in |
| 1534 | mirroring pixel positions. | 1567 | mirroring pixel positions. |
diff --git a/src/xdisp.c b/src/xdisp.c index 4c007e572ce..e2ec1360b49 100644 --- a/src/xdisp.c +++ b/src/xdisp.c | |||
| @@ -1085,6 +1085,7 @@ static void notice_overwritten_cursor (struct window *, | |||
| 1085 | int, int, int, int); | 1085 | int, int, int, int); |
| 1086 | static void append_stretch_glyph (struct it *, Lisp_Object, | 1086 | static void append_stretch_glyph (struct it *, Lisp_Object, |
| 1087 | int, int, int); | 1087 | int, int, int); |
| 1088 | static int coords_in_mouse_face_p (struct window *, int, int); | ||
| 1088 | 1089 | ||
| 1089 | 1090 | ||
| 1090 | 1091 | ||
| @@ -15333,10 +15334,12 @@ row_containing_pos (struct window *w, EMACS_INT charpos, | |||
| 15333 | { | 15334 | { |
| 15334 | struct glyph *g; | 15335 | struct glyph *g; |
| 15335 | 15336 | ||
| 15336 | if (NILP (XBUFFER (w->buffer)->bidi_display_reordering)) | 15337 | if (NILP (XBUFFER (w->buffer)->bidi_display_reordering) |
| 15338 | || (!best_row && !row->continued_p)) | ||
| 15337 | return row; | 15339 | return row; |
| 15338 | /* In bidi-reordered rows, there could be several rows | 15340 | /* In bidi-reordered rows, there could be several rows |
| 15339 | occluding point. We need to find the one which fits | 15341 | occluding point, all of them belonging to the same |
| 15342 | continued line. We need to find the row which fits | ||
| 15340 | CHARPOS the best. */ | 15343 | CHARPOS the best. */ |
| 15341 | for (g = row->glyphs[TEXT_AREA]; | 15344 | for (g = row->glyphs[TEXT_AREA]; |
| 15342 | g < row->glyphs[TEXT_AREA] + row->used[TEXT_AREA]; | 15345 | g < row->glyphs[TEXT_AREA] + row->used[TEXT_AREA]; |
| @@ -15348,11 +15351,14 @@ row_containing_pos (struct window *w, EMACS_INT charpos, | |||
| 15348 | { | 15351 | { |
| 15349 | mindif = eabs (g->charpos - charpos); | 15352 | mindif = eabs (g->charpos - charpos); |
| 15350 | best_row = row; | 15353 | best_row = row; |
| 15354 | /* Exact match always wins. */ | ||
| 15355 | if (mindif == 0) | ||
| 15356 | return best_row; | ||
| 15351 | } | 15357 | } |
| 15352 | } | 15358 | } |
| 15353 | } | 15359 | } |
| 15354 | } | 15360 | } |
| 15355 | else if (best_row) | 15361 | else if (best_row && !row->continued_p) |
| 15356 | return best_row; | 15362 | return best_row; |
| 15357 | ++row; | 15363 | ++row; |
| 15358 | } | 15364 | } |
| @@ -23411,13 +23417,7 @@ erase_phys_cursor (struct window *w) | |||
| 23411 | /* If the cursor is in the mouse face area, redisplay that when | 23417 | /* If the cursor is in the mouse face area, redisplay that when |
| 23412 | we clear the cursor. */ | 23418 | we clear the cursor. */ |
| 23413 | if (! NILP (dpyinfo->mouse_face_window) | 23419 | if (! NILP (dpyinfo->mouse_face_window) |
| 23414 | && w == XWINDOW (dpyinfo->mouse_face_window) | 23420 | && coords_in_mouse_face_p (w, hpos, vpos) |
| 23415 | && (vpos > dpyinfo->mouse_face_beg_row | ||
| 23416 | || (vpos == dpyinfo->mouse_face_beg_row | ||
| 23417 | && hpos >= dpyinfo->mouse_face_beg_col)) | ||
| 23418 | && (vpos < dpyinfo->mouse_face_end_row | ||
| 23419 | || (vpos == dpyinfo->mouse_face_end_row | ||
| 23420 | && hpos < dpyinfo->mouse_face_end_col)) | ||
| 23421 | /* Don't redraw the cursor's spot in mouse face if it is at the | 23421 | /* Don't redraw the cursor's spot in mouse face if it is at the |
| 23422 | end of a line (on a newline). The cursor appears there, but | 23422 | end of a line (on a newline). The cursor appears there, but |
| 23423 | mouse highlighting does not. */ | 23423 | mouse highlighting does not. */ |
| @@ -23640,8 +23640,30 @@ show_mouse_face (Display_Info *dpyinfo, enum draw_glyphs_face draw) | |||
| 23640 | /* For all but the first row, the highlight starts at column 0. */ | 23640 | /* For all but the first row, the highlight starts at column 0. */ |
| 23641 | if (row == first) | 23641 | if (row == first) |
| 23642 | { | 23642 | { |
| 23643 | start_hpos = dpyinfo->mouse_face_beg_col; | 23643 | /* R2L rows have BEG and END in reversed order, but the |
| 23644 | start_x = dpyinfo->mouse_face_beg_x; | 23644 | screen drawing geometry is always left to right. So |
| 23645 | we need to mirror the beginning and end of the | ||
| 23646 | highlighted area in R2L rows. */ | ||
| 23647 | if (!row->reversed_p) | ||
| 23648 | { | ||
| 23649 | start_hpos = dpyinfo->mouse_face_beg_col; | ||
| 23650 | start_x = dpyinfo->mouse_face_beg_x; | ||
| 23651 | } | ||
| 23652 | else if (row == last) | ||
| 23653 | { | ||
| 23654 | start_hpos = dpyinfo->mouse_face_end_col; | ||
| 23655 | start_x = dpyinfo->mouse_face_end_x; | ||
| 23656 | } | ||
| 23657 | else | ||
| 23658 | { | ||
| 23659 | start_hpos = 0; | ||
| 23660 | start_x = 0; | ||
| 23661 | } | ||
| 23662 | } | ||
| 23663 | else if (row->reversed_p && row == last) | ||
| 23664 | { | ||
| 23665 | start_hpos = dpyinfo->mouse_face_end_col; | ||
| 23666 | start_x = dpyinfo->mouse_face_end_x; | ||
| 23645 | } | 23667 | } |
| 23646 | else | 23668 | else |
| 23647 | { | 23669 | { |
| @@ -23650,7 +23672,20 @@ show_mouse_face (Display_Info *dpyinfo, enum draw_glyphs_face draw) | |||
| 23650 | } | 23672 | } |
| 23651 | 23673 | ||
| 23652 | if (row == last) | 23674 | if (row == last) |
| 23653 | end_hpos = dpyinfo->mouse_face_end_col; | 23675 | { |
| 23676 | if (!row->reversed_p) | ||
| 23677 | end_hpos = dpyinfo->mouse_face_end_col; | ||
| 23678 | else if (row == first) | ||
| 23679 | end_hpos = dpyinfo->mouse_face_beg_col; | ||
| 23680 | else | ||
| 23681 | { | ||
| 23682 | end_hpos = row->used[TEXT_AREA]; | ||
| 23683 | if (draw == DRAW_NORMAL_TEXT) | ||
| 23684 | row->fill_line_p = 1; /* Clear to end of line */ | ||
| 23685 | } | ||
| 23686 | } | ||
| 23687 | else if (row->reversed_p && row == first) | ||
| 23688 | end_hpos = dpyinfo->mouse_face_beg_col; | ||
| 23654 | else | 23689 | else |
| 23655 | { | 23690 | { |
| 23656 | end_hpos = row->used[TEXT_AREA]; | 23691 | end_hpos = row->used[TEXT_AREA]; |
| @@ -23713,6 +23748,53 @@ clear_mouse_face (Display_Info *dpyinfo) | |||
| 23713 | return cleared; | 23748 | return cleared; |
| 23714 | } | 23749 | } |
| 23715 | 23750 | ||
| 23751 | /* Return non-zero if the coordinates HPOS and VPOS on windows W are | ||
| 23752 | within the mouse face on that window. */ | ||
| 23753 | static int | ||
| 23754 | coords_in_mouse_face_p (struct window *w, int hpos, int vpos) | ||
| 23755 | { | ||
| 23756 | Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (XFRAME (w->frame)); | ||
| 23757 | |||
| 23758 | /* Quickly resolve the easy cases. */ | ||
| 23759 | if (!(WINDOWP (dpyinfo->mouse_face_window) | ||
| 23760 | && XWINDOW (dpyinfo->mouse_face_window) == w)) | ||
| 23761 | return 0; | ||
| 23762 | if (vpos < dpyinfo->mouse_face_beg_row | ||
| 23763 | || vpos > dpyinfo->mouse_face_end_row) | ||
| 23764 | return 0; | ||
| 23765 | if (vpos > dpyinfo->mouse_face_beg_row | ||
| 23766 | && vpos < dpyinfo->mouse_face_end_row) | ||
| 23767 | return 1; | ||
| 23768 | |||
| 23769 | if (!MATRIX_ROW (w->current_matrix, vpos)->reversed_p) | ||
| 23770 | { | ||
| 23771 | if (dpyinfo->mouse_face_beg_row == dpyinfo->mouse_face_end_row) | ||
| 23772 | { | ||
| 23773 | if (dpyinfo->mouse_face_beg_col <= hpos && hpos < dpyinfo->mouse_face_end_col) | ||
| 23774 | return 1; | ||
| 23775 | } | ||
| 23776 | else if ((vpos == dpyinfo->mouse_face_beg_row | ||
| 23777 | && hpos >= dpyinfo->mouse_face_beg_col) | ||
| 23778 | || (vpos == dpyinfo->mouse_face_end_row | ||
| 23779 | && hpos < dpyinfo->mouse_face_end_col)) | ||
| 23780 | return 1; | ||
| 23781 | } | ||
| 23782 | else | ||
| 23783 | { | ||
| 23784 | if (dpyinfo->mouse_face_beg_row == dpyinfo->mouse_face_end_row) | ||
| 23785 | { | ||
| 23786 | if (dpyinfo->mouse_face_end_col < hpos && hpos <= dpyinfo->mouse_face_beg_col) | ||
| 23787 | return 1; | ||
| 23788 | } | ||
| 23789 | else if ((vpos == dpyinfo->mouse_face_beg_row | ||
| 23790 | && hpos <= dpyinfo->mouse_face_beg_col) | ||
| 23791 | || (vpos == dpyinfo->mouse_face_end_row | ||
| 23792 | && hpos > dpyinfo->mouse_face_end_col)) | ||
| 23793 | return 1; | ||
| 23794 | } | ||
| 23795 | return 0; | ||
| 23796 | } | ||
| 23797 | |||
| 23716 | 23798 | ||
| 23717 | /* EXPORT: | 23799 | /* EXPORT: |
| 23718 | Non-zero if physical cursor of window W is within mouse face. */ | 23800 | Non-zero if physical cursor of window W is within mouse face. */ |
| @@ -23720,31 +23802,134 @@ clear_mouse_face (Display_Info *dpyinfo) | |||
| 23720 | int | 23802 | int |
| 23721 | cursor_in_mouse_face_p (struct window *w) | 23803 | cursor_in_mouse_face_p (struct window *w) |
| 23722 | { | 23804 | { |
| 23723 | Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (XFRAME (w->frame)); | 23805 | return coords_in_mouse_face_p (w, w->phys_cursor.hpos, w->phys_cursor.vpos); |
| 23724 | int in_mouse_face = 0; | 23806 | } |
| 23725 | 23807 | ||
| 23726 | if (WINDOWP (dpyinfo->mouse_face_window) | ||
| 23727 | && XWINDOW (dpyinfo->mouse_face_window) == w) | ||
| 23728 | { | ||
| 23729 | int hpos = w->phys_cursor.hpos; | ||
| 23730 | int vpos = w->phys_cursor.vpos; | ||
| 23731 | 23808 | ||
| 23732 | if (vpos >= dpyinfo->mouse_face_beg_row | 23809 | |
| 23733 | && vpos <= dpyinfo->mouse_face_end_row | 23810 | /* Find the glyph rows START_ROW and END_ROW of window W that display |
| 23734 | && (vpos > dpyinfo->mouse_face_beg_row | 23811 | characters between buffer positions START_CHARPOS and END_CHARPOS |
| 23735 | || hpos >= dpyinfo->mouse_face_beg_col) | 23812 | (excluding END_CHARPOS). This is similar to row_containing_pos, |
| 23736 | && (vpos < dpyinfo->mouse_face_end_row | 23813 | but is more accurate when bidi reordering makes buffer positions |
| 23737 | || hpos < dpyinfo->mouse_face_end_col | 23814 | change non-linearly with glyph rows. */ |
| 23738 | || dpyinfo->mouse_face_past_end)) | 23815 | static void |
| 23739 | in_mouse_face = 1; | 23816 | rows_from_pos_range (struct window *w, |
| 23740 | } | 23817 | EMACS_INT start_charpos, EMACS_INT end_charpos, |
| 23818 | struct glyph_row **start, struct glyph_row **end) | ||
| 23819 | { | ||
| 23820 | struct glyph_row *first = MATRIX_FIRST_TEXT_ROW (w->current_matrix); | ||
| 23821 | int last_y = window_text_bottom_y (w); | ||
| 23822 | struct glyph_row *row; | ||
| 23741 | 23823 | ||
| 23742 | return in_mouse_face; | 23824 | *start = NULL; |
| 23743 | } | 23825 | *end = NULL; |
| 23826 | |||
| 23827 | while (!first->enabled_p | ||
| 23828 | && first < MATRIX_BOTTOM_TEXT_ROW (w->current_matrix, w)) | ||
| 23829 | first++; | ||
| 23830 | |||
| 23831 | /* Find the START row. */ | ||
| 23832 | for (row = first; | ||
| 23833 | row->enabled_p && MATRIX_ROW_BOTTOM_Y (row) <= last_y; | ||
| 23834 | row++) | ||
| 23835 | { | ||
| 23836 | /* A row can potentially be the START row if the range of the | ||
| 23837 | characters it displays intersects the range | ||
| 23838 | [START_CHARPOS..END_CHARPOS). */ | ||
| 23839 | if (! ((start_charpos < MATRIX_ROW_START_CHARPOS (row) | ||
| 23840 | && end_charpos < MATRIX_ROW_START_CHARPOS (row)) | ||
| 23841 | /* See the commentary in row_containing_pos, for the | ||
| 23842 | explanation of the complicated way to check whether | ||
| 23843 | some position is beyond the end of the characters | ||
| 23844 | displayed by a row. */ | ||
| 23845 | || ((start_charpos > MATRIX_ROW_END_CHARPOS (row) | ||
| 23846 | || (start_charpos == MATRIX_ROW_END_CHARPOS (row) | ||
| 23847 | && !row->ends_at_zv_p | ||
| 23848 | && !MATRIX_ROW_ENDS_IN_MIDDLE_OF_CHAR_P (row))) | ||
| 23849 | && (end_charpos > MATRIX_ROW_END_CHARPOS (row) | ||
| 23850 | || (end_charpos == MATRIX_ROW_END_CHARPOS (row) | ||
| 23851 | && !row->ends_at_zv_p | ||
| 23852 | && !MATRIX_ROW_ENDS_IN_MIDDLE_OF_CHAR_P (row)))))) | ||
| 23853 | { | ||
| 23854 | /* Found a candidate row. Now make sure at least one of the | ||
| 23855 | glyphs it displays has a charpos from the range | ||
| 23856 | [START_CHARPOS..END_CHARPOS). | ||
| 23857 | |||
| 23858 | This is not obvious because bidi reordering could make | ||
| 23859 | buffer positions of a row be 1,2,3,102,101,100, and if we | ||
| 23860 | want to highlight characters in [50..60), we don't want | ||
| 23861 | this row, even though [50..60) does intersect [1..103), | ||
| 23862 | the range of character positions given by the row's start | ||
| 23863 | and end positions. */ | ||
| 23864 | struct glyph *g = row->glyphs[TEXT_AREA]; | ||
| 23865 | struct glyph *e = g + row->used[TEXT_AREA]; | ||
| 23866 | |||
| 23867 | while (g < e) | ||
| 23868 | { | ||
| 23869 | if (BUFFERP (g->object) | ||
| 23870 | && start_charpos <= g->charpos && g->charpos < end_charpos) | ||
| 23871 | *start = row; | ||
| 23872 | g++; | ||
| 23873 | } | ||
| 23874 | if (*start) | ||
| 23875 | break; | ||
| 23876 | } | ||
| 23877 | } | ||
| 23744 | 23878 | ||
| 23879 | /* Find the END row. */ | ||
| 23880 | if (!*start | ||
| 23881 | /* If the last row is partially visible, start looking for END | ||
| 23882 | from that row, instead of starting from FIRST. */ | ||
| 23883 | && !(row->enabled_p | ||
| 23884 | && row->y < last_y && MATRIX_ROW_BOTTOM_Y (row) > last_y)) | ||
| 23885 | row = first; | ||
| 23886 | for ( ; row->enabled_p && MATRIX_ROW_BOTTOM_Y (row) <= last_y; row++) | ||
| 23887 | { | ||
| 23888 | struct glyph_row *next = row + 1; | ||
| 23889 | |||
| 23890 | if (!next->enabled_p | ||
| 23891 | || next >= MATRIX_BOTTOM_TEXT_ROW (w->current_matrix, w) | ||
| 23892 | /* The first row >= START whose range of displayed characters | ||
| 23893 | does NOT intersect the range [START_CHARPOS..END_CHARPOS] | ||
| 23894 | is the row END + 1. */ | ||
| 23895 | || (start_charpos < MATRIX_ROW_START_CHARPOS (next) | ||
| 23896 | && end_charpos < MATRIX_ROW_START_CHARPOS (next)) | ||
| 23897 | || ((start_charpos > MATRIX_ROW_END_CHARPOS (next) | ||
| 23898 | || (start_charpos == MATRIX_ROW_END_CHARPOS (next) | ||
| 23899 | && !next->ends_at_zv_p | ||
| 23900 | && !MATRIX_ROW_ENDS_IN_MIDDLE_OF_CHAR_P (next))) | ||
| 23901 | && (end_charpos > MATRIX_ROW_END_CHARPOS (next) | ||
| 23902 | || (end_charpos == MATRIX_ROW_END_CHARPOS (next) | ||
| 23903 | && !next->ends_at_zv_p | ||
| 23904 | && !MATRIX_ROW_ENDS_IN_MIDDLE_OF_CHAR_P (next))))) | ||
| 23905 | { | ||
| 23906 | *end = row; | ||
| 23907 | break; | ||
| 23908 | } | ||
| 23909 | else | ||
| 23910 | { | ||
| 23911 | /* If the next row's edges intersect [START_CHARPOS..END_CHARPOS], | ||
| 23912 | but none of the characters it displays are in the range, it is | ||
| 23913 | also END + 1. */ | ||
| 23914 | struct glyph *g = next->glyphs[TEXT_AREA]; | ||
| 23915 | struct glyph *e = g + next->used[TEXT_AREA]; | ||
| 23745 | 23916 | ||
| 23917 | while (g < e) | ||
| 23918 | { | ||
| 23919 | if (BUFFERP (g->object) | ||
| 23920 | && start_charpos <= g->charpos && g->charpos < end_charpos) | ||
| 23921 | break; | ||
| 23922 | g++; | ||
| 23923 | } | ||
| 23924 | if (g == e) | ||
| 23925 | { | ||
| 23926 | *end = row; | ||
| 23927 | break; | ||
| 23928 | } | ||
| 23929 | } | ||
| 23930 | } | ||
| 23931 | } | ||
| 23746 | 23932 | ||
| 23747 | |||
| 23748 | /* This function sets the mouse_face_* elements of DPYINFO, assuming | 23933 | /* This function sets the mouse_face_* elements of DPYINFO, assuming |
| 23749 | the mouse cursor is on a glyph with buffer charpos MOUSE_CHARPOS in | 23934 | the mouse cursor is on a glyph with buffer charpos MOUSE_CHARPOS in |
| 23750 | window WINDOW. START_CHARPOS and END_CHARPOS are buffer positions | 23935 | window WINDOW. START_CHARPOS and END_CHARPOS are buffer positions |
| @@ -23766,158 +23951,300 @@ mouse_face_from_buffer_pos (Lisp_Object window, | |||
| 23766 | { | 23951 | { |
| 23767 | struct window *w = XWINDOW (window); | 23952 | struct window *w = XWINDOW (window); |
| 23768 | struct glyph_row *first = MATRIX_FIRST_TEXT_ROW (w->current_matrix); | 23953 | struct glyph_row *first = MATRIX_FIRST_TEXT_ROW (w->current_matrix); |
| 23769 | struct glyph_row *row; | 23954 | struct glyph_row *r1, *r2; |
| 23770 | struct glyph *glyph, *end; | 23955 | struct glyph *glyph, *end; |
| 23771 | EMACS_INT ignore; | 23956 | EMACS_INT ignore, pos; |
| 23772 | int x; | 23957 | int x; |
| 23773 | 23958 | ||
| 23774 | xassert (NILP (display_string) || STRINGP (display_string)); | 23959 | xassert (NILP (display_string) || STRINGP (display_string)); |
| 23775 | xassert (NILP (before_string) || STRINGP (before_string)); | 23960 | xassert (NILP (before_string) || STRINGP (before_string)); |
| 23776 | xassert (NILP (after_string) || STRINGP (after_string)); | 23961 | xassert (NILP (after_string) || STRINGP (after_string)); |
| 23777 | 23962 | ||
| 23778 | /* Find the first highlighted glyph. */ | 23963 | /* Find the rows corresponding to START_CHARPOS and END_CHARPOS. */ |
| 23779 | if (start_charpos < MATRIX_ROW_START_CHARPOS (first)) | 23964 | rows_from_pos_range (w, start_charpos, end_charpos, &r1, &r2); |
| 23965 | if (r1 == NULL) | ||
| 23966 | r1 = MATRIX_ROW (w->current_matrix, XFASTINT (w->window_end_vpos)); | ||
| 23967 | /* If the before-string or display-string contains newlines, | ||
| 23968 | rows_from_pos_range skips to its last row. Move back. */ | ||
| 23969 | if (!NILP (before_string) || !NILP (display_string)) | ||
| 23970 | { | ||
| 23971 | struct glyph_row *prev; | ||
| 23972 | while ((prev = r1 - 1, prev >= first) | ||
| 23973 | && MATRIX_ROW_END_CHARPOS (prev) == start_charpos | ||
| 23974 | && prev->used[TEXT_AREA] > 0) | ||
| 23975 | { | ||
| 23976 | struct glyph *beg = prev->glyphs[TEXT_AREA]; | ||
| 23977 | glyph = beg + prev->used[TEXT_AREA]; | ||
| 23978 | while (--glyph >= beg && INTEGERP (glyph->object)); | ||
| 23979 | if (glyph < beg | ||
| 23980 | || !(EQ (glyph->object, before_string) | ||
| 23981 | || EQ (glyph->object, display_string))) | ||
| 23982 | break; | ||
| 23983 | r1 = prev; | ||
| 23984 | } | ||
| 23985 | } | ||
| 23986 | if (r2 == NULL) | ||
| 23780 | { | 23987 | { |
| 23781 | dpyinfo->mouse_face_beg_col = 0; | 23988 | r2 = MATRIX_ROW (w->current_matrix, XFASTINT (w->window_end_vpos)); |
| 23782 | dpyinfo->mouse_face_beg_row = MATRIX_ROW_VPOS (first, w->current_matrix); | 23989 | dpyinfo->mouse_face_past_end = 1; |
| 23783 | dpyinfo->mouse_face_beg_x = first->x; | ||
| 23784 | dpyinfo->mouse_face_beg_y = first->y; | ||
| 23785 | } | 23990 | } |
| 23786 | else | 23991 | else if (!NILP (after_string)) |
| 23787 | { | 23992 | { |
| 23788 | row = row_containing_pos (w, start_charpos, first, NULL, 0); | 23993 | /* If the after-string has newlines, advance to its last row. */ |
| 23789 | if (row == NULL) | 23994 | struct glyph_row *next; |
| 23790 | row = MATRIX_ROW (w->current_matrix, XFASTINT (w->window_end_vpos)); | 23995 | struct glyph_row *last |
| 23791 | 23996 | = MATRIX_ROW (w->current_matrix, XFASTINT (w->window_end_vpos)); | |
| 23792 | /* If the before-string or display-string contains newlines, | ||
| 23793 | row_containing_pos skips to its last row. Move back. */ | ||
| 23794 | if (!NILP (before_string) || !NILP (display_string)) | ||
| 23795 | { | ||
| 23796 | struct glyph_row *prev; | ||
| 23797 | while ((prev = row - 1, prev >= first) | ||
| 23798 | && MATRIX_ROW_END_CHARPOS (prev) == start_charpos | ||
| 23799 | && prev->used[TEXT_AREA] > 0) | ||
| 23800 | { | ||
| 23801 | struct glyph *beg = prev->glyphs[TEXT_AREA]; | ||
| 23802 | glyph = beg + prev->used[TEXT_AREA]; | ||
| 23803 | while (--glyph >= beg && INTEGERP (glyph->object)); | ||
| 23804 | if (glyph < beg | ||
| 23805 | || !(EQ (glyph->object, before_string) | ||
| 23806 | || EQ (glyph->object, display_string))) | ||
| 23807 | break; | ||
| 23808 | row = prev; | ||
| 23809 | } | ||
| 23810 | } | ||
| 23811 | 23997 | ||
| 23812 | glyph = row->glyphs[TEXT_AREA]; | 23998 | for (next = r2 + 1; |
| 23813 | end = glyph + row->used[TEXT_AREA]; | 23999 | next <= last |
| 23814 | x = row->x; | 24000 | && next->used[TEXT_AREA] > 0 |
| 23815 | dpyinfo->mouse_face_beg_y = row->y; | 24001 | && EQ (next->glyphs[TEXT_AREA]->object, after_string); |
| 23816 | dpyinfo->mouse_face_beg_row = MATRIX_ROW_VPOS (row, w->current_matrix); | 24002 | ++next) |
| 24003 | r2 = next; | ||
| 24004 | } | ||
| 24005 | /* The rest of the display engine assumes that mouse_face_beg_row is | ||
| 24006 | either above below mouse_face_end_row or identical to it. But | ||
| 24007 | with bidi-reordered continued lines, the row for START_CHARPOS | ||
| 24008 | could be below the row for END_CHARPOS. If so, swap the rows and | ||
| 24009 | store them in correct order. */ | ||
| 24010 | if (r1->y > r2->y) | ||
| 24011 | { | ||
| 24012 | struct glyph_row *tem = r2; | ||
| 24013 | |||
| 24014 | r2 = r1; | ||
| 24015 | r1 = tem; | ||
| 24016 | } | ||
| 24017 | |||
| 24018 | dpyinfo->mouse_face_beg_y = r1->y; | ||
| 24019 | dpyinfo->mouse_face_beg_row = MATRIX_ROW_VPOS (r1, w->current_matrix); | ||
| 24020 | dpyinfo->mouse_face_end_y = r2->y; | ||
| 24021 | dpyinfo->mouse_face_end_row = MATRIX_ROW_VPOS (r2, w->current_matrix); | ||
| 24022 | |||
| 24023 | /* For a bidi-reordered row, the positions of BEFORE_STRING, | ||
| 24024 | AFTER_STRING, DISPLAY_STRING, START_CHARPOS, and END_CHARPOS | ||
| 24025 | could be anywhere in the row and in any order. The strategy | ||
| 24026 | below is to find the leftmost and the rightmost glyph that | ||
| 24027 | belongs to either of these 3 strings, or whose position is | ||
| 24028 | between START_CHARPOS and END_CHARPOS, and highlight all the | ||
| 24029 | glyphs between those two. This may cover more than just the text | ||
| 24030 | between START_CHARPOS and END_CHARPOS if the range of characters | ||
| 24031 | strides the bidi level boundary, e.g. if the beginning is in R2L | ||
| 24032 | text while the end is in L2R text or vice versa. */ | ||
| 24033 | if (!r1->reversed_p) | ||
| 24034 | { | ||
| 24035 | /* This row is in a left to right paragraph. Scan it left to | ||
| 24036 | right. */ | ||
| 24037 | glyph = r1->glyphs[TEXT_AREA]; | ||
| 24038 | end = glyph + r1->used[TEXT_AREA]; | ||
| 24039 | x = r1->x; | ||
| 23817 | 24040 | ||
| 23818 | /* Skip truncation glyphs at the start of the glyph row. */ | 24041 | /* Skip truncation glyphs at the start of the glyph row. */ |
| 23819 | if (row->displays_text_p) | 24042 | if (r1->displays_text_p) |
| 23820 | for (; glyph < end | 24043 | for (; glyph < end |
| 23821 | && INTEGERP (glyph->object) | 24044 | && INTEGERP (glyph->object) |
| 23822 | && glyph->charpos < 0; | 24045 | && glyph->charpos < 0; |
| 23823 | ++glyph) | 24046 | ++glyph) |
| 23824 | x += glyph->pixel_width; | 24047 | x += glyph->pixel_width; |
| 23825 | 24048 | ||
| 23826 | /* Scan the glyph row, stopping before BEFORE_STRING or | 24049 | /* Scan the glyph row, looking for BEFORE_STRING, AFTER_STRING, |
| 23827 | DISPLAY_STRING or START_CHARPOS. */ | 24050 | or DISPLAY_STRING, and the first glyph from buffer whose |
| 24051 | position is between START_CHARPOS and END_CHARPOS. */ | ||
| 23828 | for (; glyph < end | 24052 | for (; glyph < end |
| 23829 | && !INTEGERP (glyph->object) | 24053 | && !INTEGERP (glyph->object) |
| 23830 | && !EQ (glyph->object, before_string) | ||
| 23831 | && !EQ (glyph->object, display_string) | 24054 | && !EQ (glyph->object, display_string) |
| 23832 | && !(BUFFERP (glyph->object) | 24055 | && !(BUFFERP (glyph->object) |
| 23833 | && glyph->charpos >= start_charpos); | 24056 | && (glyph->charpos >= start_charpos |
| 24057 | && glyph->charpos < end_charpos)); | ||
| 23834 | ++glyph) | 24058 | ++glyph) |
| 23835 | x += glyph->pixel_width; | 24059 | { |
| 23836 | 24060 | /* BEFORE_STRING or AFTER_STRING are only relevant if they | |
| 24061 | are present at buffer positions between START_CHARPOS and | ||
| 24062 | END_CHARPOS, or if they come from an overlay. */ | ||
| 24063 | if (EQ (glyph->object, before_string)) | ||
| 24064 | { | ||
| 24065 | pos = string_buffer_position (w, before_string, | ||
| 24066 | start_charpos); | ||
| 24067 | /* If pos == 0, it means before_string came from an | ||
| 24068 | overlay, not from a buffer position. */ | ||
| 24069 | if (!pos || pos >= start_charpos && pos < end_charpos) | ||
| 24070 | break; | ||
| 24071 | } | ||
| 24072 | else if (EQ (glyph->object, after_string)) | ||
| 24073 | { | ||
| 24074 | pos = string_buffer_position (w, after_string, end_charpos); | ||
| 24075 | if (!pos || pos >= start_charpos && pos < end_charpos) | ||
| 24076 | break; | ||
| 24077 | } | ||
| 24078 | x += glyph->pixel_width; | ||
| 24079 | } | ||
| 23837 | dpyinfo->mouse_face_beg_x = x; | 24080 | dpyinfo->mouse_face_beg_x = x; |
| 23838 | dpyinfo->mouse_face_beg_col = glyph - row->glyphs[TEXT_AREA]; | 24081 | dpyinfo->mouse_face_beg_col = glyph - r1->glyphs[TEXT_AREA]; |
| 23839 | } | 24082 | } |
| 23840 | 24083 | else | |
| 23841 | /* Find the last highlighted glyph. */ | ||
| 23842 | row = row_containing_pos (w, end_charpos, first, NULL, 0); | ||
| 23843 | if (row == NULL) | ||
| 23844 | { | ||
| 23845 | row = MATRIX_ROW (w->current_matrix, XFASTINT (w->window_end_vpos)); | ||
| 23846 | dpyinfo->mouse_face_past_end = 1; | ||
| 23847 | } | ||
| 23848 | else if (!NILP (after_string)) | ||
| 23849 | { | 24084 | { |
| 23850 | /* If the after-string has newlines, advance to its last row. */ | 24085 | /* This row is in a right to left paragraph. Scan it right to |
| 23851 | struct glyph_row *next; | 24086 | left. */ |
| 23852 | struct glyph_row *last | 24087 | struct glyph *g; |
| 23853 | = MATRIX_ROW (w->current_matrix, XFASTINT (w->window_end_vpos)); | ||
| 23854 | 24088 | ||
| 23855 | for (next = row + 1; | 24089 | end = r1->glyphs[TEXT_AREA] - 1; |
| 23856 | next <= last | 24090 | glyph = end + r1->used[TEXT_AREA]; |
| 23857 | && next->used[TEXT_AREA] > 0 | ||
| 23858 | && EQ (next->glyphs[TEXT_AREA]->object, after_string); | ||
| 23859 | ++next) | ||
| 23860 | row = next; | ||
| 23861 | } | ||
| 23862 | 24091 | ||
| 23863 | glyph = row->glyphs[TEXT_AREA]; | 24092 | /* Skip truncation glyphs at the start of the glyph row. */ |
| 23864 | end = glyph + row->used[TEXT_AREA]; | 24093 | if (r1->displays_text_p) |
| 23865 | x = row->x; | 24094 | for (; glyph > end |
| 23866 | dpyinfo->mouse_face_end_y = row->y; | 24095 | && INTEGERP (glyph->object) |
| 23867 | dpyinfo->mouse_face_end_row = MATRIX_ROW_VPOS (row, w->current_matrix); | 24096 | && glyph->charpos < 0; |
| 24097 | --glyph) | ||
| 24098 | ; | ||
| 23868 | 24099 | ||
| 23869 | /* Skip truncation glyphs at the start of the row. */ | 24100 | /* Scan the glyph row, looking for BEFORE_STRING, AFTER_STRING, |
| 23870 | if (row->displays_text_p) | 24101 | or DISPLAY_STRING, and the first glyph from buffer whose |
| 23871 | for (; glyph < end | 24102 | position is between START_CHARPOS and END_CHARPOS. */ |
| 23872 | && INTEGERP (glyph->object) | 24103 | for (; glyph > end |
| 23873 | && glyph->charpos < 0; | 24104 | && !INTEGERP (glyph->object) |
| 23874 | ++glyph) | 24105 | && !EQ (glyph->object, display_string) |
| 23875 | x += glyph->pixel_width; | 24106 | && !(BUFFERP (glyph->object) |
| 23876 | 24107 | && (glyph->charpos >= start_charpos | |
| 23877 | /* Scan the glyph row, stopping at END_CHARPOS or when we encounter | 24108 | && glyph->charpos < end_charpos)); |
| 23878 | AFTER_STRING. */ | 24109 | --glyph) |
| 23879 | for (; glyph < end | 24110 | { |
| 23880 | && !INTEGERP (glyph->object) | 24111 | /* BEFORE_STRING or AFTER_STRING are only relevant if they |
| 23881 | && !EQ (glyph->object, after_string) | 24112 | are present at buffer positions between START_CHARPOS and |
| 23882 | && !(BUFFERP (glyph->object) && glyph->charpos >= end_charpos); | 24113 | END_CHARPOS, or if they come from an overlay. */ |
| 23883 | ++glyph) | 24114 | if (EQ (glyph->object, before_string)) |
| 23884 | x += glyph->pixel_width; | 24115 | { |
| 24116 | pos = string_buffer_position (w, before_string, start_charpos); | ||
| 24117 | /* If pos == 0, it means before_string came from an | ||
| 24118 | overlay, not from a buffer position. */ | ||
| 24119 | if (!pos || pos >= start_charpos && pos < end_charpos) | ||
| 24120 | break; | ||
| 24121 | } | ||
| 24122 | else if (EQ (glyph->object, after_string)) | ||
| 24123 | { | ||
| 24124 | pos = string_buffer_position (w, after_string, end_charpos); | ||
| 24125 | if (!pos || pos >= start_charpos && pos < end_charpos) | ||
| 24126 | break; | ||
| 24127 | } | ||
| 24128 | } | ||
| 24129 | |||
| 24130 | glyph++; /* first glyph to the right of the highlighted area */ | ||
| 24131 | for (g = r1->glyphs[TEXT_AREA], x = r1->x; g < glyph; g++) | ||
| 24132 | x += g->pixel_width; | ||
| 24133 | dpyinfo->mouse_face_beg_x = x; | ||
| 24134 | dpyinfo->mouse_face_beg_col = glyph - r1->glyphs[TEXT_AREA]; | ||
| 24135 | } | ||
| 23885 | 24136 | ||
| 23886 | /* If we found AFTER_STRING, consume it and stop. */ | 24137 | /* If the highlight ends in a different row, compute GLYPH and END |
| 23887 | if (EQ (glyph->object, after_string)) | 24138 | for the end row. Otherwise, reuse the values computed above for |
| 24139 | the row where the highlight begins. */ | ||
| 24140 | if (r2 != r1) | ||
| 23888 | { | 24141 | { |
| 23889 | for (; EQ (glyph->object, after_string) && glyph < end; ++glyph) | 24142 | if (!r2->reversed_p) |
| 24143 | { | ||
| 24144 | glyph = r2->glyphs[TEXT_AREA]; | ||
| 24145 | end = glyph + r2->used[TEXT_AREA]; | ||
| 24146 | x = r2->x; | ||
| 24147 | } | ||
| 24148 | else | ||
| 24149 | { | ||
| 24150 | end = r2->glyphs[TEXT_AREA] - 1; | ||
| 24151 | glyph = end + r2->used[TEXT_AREA]; | ||
| 24152 | } | ||
| 24153 | } | ||
| 24154 | |||
| 24155 | if (!r2->reversed_p) | ||
| 24156 | { | ||
| 24157 | /* Skip truncation and continuation glyphs near the end of the | ||
| 24158 | row, and also blanks and stretch glyphs inserted by | ||
| 24159 | extend_face_to_end_of_line. */ | ||
| 24160 | while (end > glyph | ||
| 24161 | && INTEGERP ((end - 1)->object) | ||
| 24162 | && (end - 1)->charpos <= 0) | ||
| 24163 | --end; | ||
| 24164 | /* Scan the rest of the glyph row from the end, looking for the | ||
| 24165 | first glyph that comes from BEFORE_STRING, AFTER_STRING, or | ||
| 24166 | DISPLAY_STRING, or whose position is between START_CHARPOS | ||
| 24167 | and END_CHARPOS */ | ||
| 24168 | for (--end; | ||
| 24169 | end > glyph | ||
| 24170 | && !INTEGERP (end->object) | ||
| 24171 | && !EQ (end->object, display_string) | ||
| 24172 | && !(BUFFERP (end->object) | ||
| 24173 | && (end->charpos >= start_charpos | ||
| 24174 | && end->charpos < end_charpos)); | ||
| 24175 | --end) | ||
| 24176 | { | ||
| 24177 | /* BEFORE_STRING or AFTER_STRING are only relevant if they | ||
| 24178 | are present at buffer positions between START_CHARPOS and | ||
| 24179 | END_CHARPOS, or if they come from an overlay. */ | ||
| 24180 | if (EQ (end->object, before_string)) | ||
| 24181 | { | ||
| 24182 | pos = string_buffer_position (w, before_string, start_charpos); | ||
| 24183 | if (!pos || pos >= start_charpos && pos < end_charpos) | ||
| 24184 | break; | ||
| 24185 | } | ||
| 24186 | else if (EQ (end->object, after_string)) | ||
| 24187 | { | ||
| 24188 | pos = string_buffer_position (w, after_string, end_charpos); | ||
| 24189 | if (!pos || pos >= start_charpos && pos < end_charpos) | ||
| 24190 | break; | ||
| 24191 | } | ||
| 24192 | } | ||
| 24193 | /* Find the X coordinate of the last glyph to be highlighted. */ | ||
| 24194 | for (; glyph <= end; ++glyph) | ||
| 23890 | x += glyph->pixel_width; | 24195 | x += glyph->pixel_width; |
| 24196 | |||
| 24197 | dpyinfo->mouse_face_end_x = x; | ||
| 24198 | dpyinfo->mouse_face_end_col = glyph - r2->glyphs[TEXT_AREA]; | ||
| 23891 | } | 24199 | } |
| 23892 | else | 24200 | else |
| 23893 | { | 24201 | { |
| 23894 | /* If there's no after-string, we must check if we overshot, | 24202 | /* Skip truncation and continuation glyphs near the end of the |
| 23895 | which might be the case if we stopped after a string glyph. | 24203 | row, and also blanks and stretch glyphs inserted by |
| 23896 | That glyph may belong to a before-string or display-string | 24204 | extend_face_to_end_of_line. */ |
| 23897 | associated with the end position, which must not be | 24205 | x = r2->x; |
| 23898 | highlighted. */ | 24206 | end++; |
| 23899 | Lisp_Object prev_object; | 24207 | while (end < glyph |
| 23900 | EMACS_INT pos; | 24208 | && INTEGERP (end->object) |
| 23901 | 24209 | && end->charpos <= 0) | |
| 23902 | while (glyph > row->glyphs[TEXT_AREA]) | 24210 | { |
| 23903 | { | 24211 | x += end->pixel_width; |
| 23904 | prev_object = (glyph - 1)->object; | 24212 | ++end; |
| 23905 | if (!STRINGP (prev_object) || EQ (prev_object, display_string)) | 24213 | } |
| 23906 | break; | 24214 | /* Scan the rest of the glyph row from the end, looking for the |
| 23907 | 24215 | first glyph that comes from BEFORE_STRING, AFTER_STRING, or | |
| 23908 | pos = string_buffer_position (w, prev_object, end_charpos); | 24216 | DISPLAY_STRING, or whose position is between START_CHARPOS |
| 23909 | if (pos && pos < end_charpos) | 24217 | and END_CHARPOS */ |
| 23910 | break; | 24218 | for ( ; |
| 23911 | 24219 | end < glyph | |
| 23912 | for (; glyph > row->glyphs[TEXT_AREA] | 24220 | && !INTEGERP (end->object) |
| 23913 | && EQ ((glyph - 1)->object, prev_object); | 24221 | && !EQ (end->object, display_string) |
| 23914 | --glyph) | 24222 | && !(BUFFERP (end->object) |
| 23915 | x -= (glyph - 1)->pixel_width; | 24223 | && (end->charpos >= start_charpos |
| 24224 | && end->charpos < end_charpos)); | ||
| 24225 | ++end) | ||
| 24226 | { | ||
| 24227 | /* BEFORE_STRING or AFTER_STRING are only relevant if they | ||
| 24228 | are present at buffer positions between START_CHARPOS and | ||
| 24229 | END_CHARPOS, or if they come from an overlay. */ | ||
| 24230 | if (EQ (end->object, before_string)) | ||
| 24231 | { | ||
| 24232 | pos = string_buffer_position (w, before_string, start_charpos); | ||
| 24233 | if (!pos || pos >= start_charpos && pos < end_charpos) | ||
| 24234 | break; | ||
| 24235 | } | ||
| 24236 | else if (EQ (end->object, after_string)) | ||
| 24237 | { | ||
| 24238 | pos = string_buffer_position (w, after_string, end_charpos); | ||
| 24239 | if (!pos || pos >= start_charpos && pos < end_charpos) | ||
| 24240 | break; | ||
| 24241 | } | ||
| 24242 | x += end->pixel_width; | ||
| 23916 | } | 24243 | } |
| 24244 | dpyinfo->mouse_face_end_x = x; | ||
| 24245 | dpyinfo->mouse_face_end_col = end - r2->glyphs[TEXT_AREA]; | ||
| 23917 | } | 24246 | } |
| 23918 | 24247 | ||
| 23919 | dpyinfo->mouse_face_end_x = x; | ||
| 23920 | dpyinfo->mouse_face_end_col = glyph - row->glyphs[TEXT_AREA]; | ||
| 23921 | dpyinfo->mouse_face_window = window; | 24248 | dpyinfo->mouse_face_window = window; |
| 23922 | dpyinfo->mouse_face_face_id | 24249 | dpyinfo->mouse_face_face_id |
| 23923 | = face_at_buffer_position (w, mouse_charpos, 0, 0, &ignore, | 24250 | = face_at_buffer_position (w, mouse_charpos, 0, 0, &ignore, |
| @@ -23926,6 +24253,11 @@ mouse_face_from_buffer_pos (Lisp_Object window, | |||
| 23926 | show_mouse_face (dpyinfo, DRAW_MOUSE_FACE); | 24253 | show_mouse_face (dpyinfo, DRAW_MOUSE_FACE); |
| 23927 | } | 24254 | } |
| 23928 | 24255 | ||
| 24256 | /* The following function is not used anymore (replaced with | ||
| 24257 | mouse_face_from_string_pos), but I leave it here for the time | ||
| 24258 | being, in case someone would. */ | ||
| 24259 | |||
| 24260 | #if 0 /* not used */ | ||
| 23929 | 24261 | ||
| 23930 | /* Find the position of the glyph for position POS in OBJECT in | 24262 | /* Find the position of the glyph for position POS in OBJECT in |
| 23931 | window W's current matrix, and return in *X, *Y the pixel | 24263 | window W's current matrix, and return in *X, *Y the pixel |
| @@ -24003,7 +24335,130 @@ fast_find_string_pos (struct window *w, EMACS_INT pos, Lisp_Object object, | |||
| 24003 | 24335 | ||
| 24004 | return best_glyph != NULL; | 24336 | return best_glyph != NULL; |
| 24005 | } | 24337 | } |
| 24338 | #endif /* not used */ | ||
| 24339 | |||
| 24340 | /* Find the positions of the first and the last glyphs in window W's | ||
| 24341 | current matrix that occlude positions [STARTPOS..ENDPOS] in OBJECT | ||
| 24342 | (assumed to be a string), and return in DPYINFO's mouse_face | ||
| 24343 | members the pixel and column/row coordinates of those glyphs. */ | ||
| 24344 | |||
| 24345 | static void | ||
| 24346 | mouse_face_from_string_pos (struct window *w, Display_Info *dpyinfo, | ||
| 24347 | Lisp_Object object, | ||
| 24348 | EMACS_INT startpos, EMACS_INT endpos) | ||
| 24349 | { | ||
| 24350 | int yb = window_text_bottom_y (w); | ||
| 24351 | struct glyph_row *r; | ||
| 24352 | struct glyph *g, *e; | ||
| 24353 | int gx; | ||
| 24354 | int found = 0; | ||
| 24355 | |||
| 24356 | /* Find the glyph row with at least one position in the range | ||
| 24357 | [STARTPOS..ENDPOS], and the first glyph in that row whose | ||
| 24358 | position belongs to that range. */ | ||
| 24359 | for (r = MATRIX_FIRST_TEXT_ROW (w->current_matrix); | ||
| 24360 | r->enabled_p && r->y < yb; | ||
| 24361 | ++r) | ||
| 24362 | { | ||
| 24363 | if (!r->reversed_p) | ||
| 24364 | { | ||
| 24365 | g = r->glyphs[TEXT_AREA]; | ||
| 24366 | e = g + r->used[TEXT_AREA]; | ||
| 24367 | for (gx = r->x; g < e; gx += g->pixel_width, ++g) | ||
| 24368 | if (EQ (g->object, object) | ||
| 24369 | && startpos <= g->charpos && g->charpos <= endpos) | ||
| 24370 | { | ||
| 24371 | dpyinfo->mouse_face_beg_row = r - w->current_matrix->rows; | ||
| 24372 | dpyinfo->mouse_face_beg_y = r->y; | ||
| 24373 | dpyinfo->mouse_face_beg_col = g - r->glyphs[TEXT_AREA]; | ||
| 24374 | dpyinfo->mouse_face_beg_x = gx; | ||
| 24375 | found = 1; | ||
| 24376 | break; | ||
| 24377 | } | ||
| 24378 | } | ||
| 24379 | else | ||
| 24380 | { | ||
| 24381 | struct glyph *g1; | ||
| 24382 | |||
| 24383 | e = r->glyphs[TEXT_AREA]; | ||
| 24384 | g = e + r->used[TEXT_AREA]; | ||
| 24385 | for ( ; g > e; --g) | ||
| 24386 | if (EQ ((g-1)->object, object) | ||
| 24387 | && startpos <= (g-1)->charpos && (g-1)->charpos <= endpos) | ||
| 24388 | { | ||
| 24389 | dpyinfo->mouse_face_beg_row = r - w->current_matrix->rows; | ||
| 24390 | dpyinfo->mouse_face_beg_y = r->y; | ||
| 24391 | dpyinfo->mouse_face_beg_col = g - r->glyphs[TEXT_AREA]; | ||
| 24392 | for (gx = r->x, g1 = r->glyphs[TEXT_AREA]; g1 < g; ++g1) | ||
| 24393 | gx += g1->pixel_width; | ||
| 24394 | dpyinfo->mouse_face_beg_x = gx; | ||
| 24395 | found = 1; | ||
| 24396 | break; | ||
| 24397 | } | ||
| 24398 | } | ||
| 24399 | if (found) | ||
| 24400 | break; | ||
| 24401 | } | ||
| 24402 | |||
| 24403 | if (!found) | ||
| 24404 | return; | ||
| 24006 | 24405 | ||
| 24406 | /* Starting with the next row, look for the first row which does NOT | ||
| 24407 | include any glyphs whose positions are in the range. */ | ||
| 24408 | for (++r; r->enabled_p && r->y < yb; ++r) | ||
| 24409 | { | ||
| 24410 | g = r->glyphs[TEXT_AREA]; | ||
| 24411 | e = g + r->used[TEXT_AREA]; | ||
| 24412 | found = 0; | ||
| 24413 | for ( ; g < e; ++g) | ||
| 24414 | if (EQ (g->object, object) | ||
| 24415 | && startpos <= g->charpos && g->charpos <= endpos) | ||
| 24416 | { | ||
| 24417 | found = 1; | ||
| 24418 | break; | ||
| 24419 | } | ||
| 24420 | if (!found) | ||
| 24421 | break; | ||
| 24422 | } | ||
| 24423 | |||
| 24424 | /* The highlighted region ends on the previous row. */ | ||
| 24425 | r--; | ||
| 24426 | |||
| 24427 | /* Set the end row and its vertical pixel coordinate. */ | ||
| 24428 | dpyinfo->mouse_face_end_row = r - w->current_matrix->rows; | ||
| 24429 | dpyinfo->mouse_face_end_y = r->y; | ||
| 24430 | |||
| 24431 | /* Compute and set the end column and the end column's horizontal | ||
| 24432 | pixel coordinate. */ | ||
| 24433 | if (!r->reversed_p) | ||
| 24434 | { | ||
| 24435 | g = r->glyphs[TEXT_AREA]; | ||
| 24436 | e = g + r->used[TEXT_AREA]; | ||
| 24437 | for ( ; e > g; --e) | ||
| 24438 | if (EQ ((e-1)->object, object) | ||
| 24439 | && startpos <= (e-1)->charpos && (e-1)->charpos <= endpos) | ||
| 24440 | break; | ||
| 24441 | dpyinfo->mouse_face_end_col = e - g; | ||
| 24442 | |||
| 24443 | for (gx = r->x; g < e; ++g) | ||
| 24444 | gx += g->pixel_width; | ||
| 24445 | dpyinfo->mouse_face_end_x = gx; | ||
| 24446 | } | ||
| 24447 | else | ||
| 24448 | { | ||
| 24449 | e = r->glyphs[TEXT_AREA]; | ||
| 24450 | g = e + r->used[TEXT_AREA]; | ||
| 24451 | for (gx = r->x ; e < g; ++e) | ||
| 24452 | { | ||
| 24453 | if (EQ (e->object, object) | ||
| 24454 | && startpos <= e->charpos && e->charpos <= endpos) | ||
| 24455 | break; | ||
| 24456 | gx += e->pixel_width; | ||
| 24457 | } | ||
| 24458 | dpyinfo->mouse_face_end_col = e - r->glyphs[TEXT_AREA]; | ||
| 24459 | dpyinfo->mouse_face_end_x = gx; | ||
| 24460 | } | ||
| 24461 | } | ||
| 24007 | 24462 | ||
| 24008 | /* See if position X, Y is within a hot-spot of an image. */ | 24463 | /* See if position X, Y is within a hot-spot of an image. */ |
| 24009 | 24464 | ||
| @@ -24205,6 +24660,8 @@ note_mode_line_or_margin_highlight (Lisp_Object window, int x, int y, | |||
| 24205 | int x0; | 24660 | int x0; |
| 24206 | struct glyph *end; | 24661 | struct glyph *end; |
| 24207 | 24662 | ||
| 24663 | /* Kludge alert: mode_line_string takes X/Y in pixels, but | ||
| 24664 | returns them in row/column units! */ | ||
| 24208 | string = mode_line_string (w, area, &x, &y, &charpos, | 24665 | string = mode_line_string (w, area, &x, &y, &charpos, |
| 24209 | &object, &dx, &dy, &width, &height); | 24666 | &object, &dx, &dy, &width, &height); |
| 24210 | 24667 | ||
| @@ -24212,7 +24669,7 @@ note_mode_line_or_margin_highlight (Lisp_Object window, int x, int y, | |||
| 24212 | ? MATRIX_MODE_LINE_ROW (w->current_matrix) | 24669 | ? MATRIX_MODE_LINE_ROW (w->current_matrix) |
| 24213 | : MATRIX_HEADER_LINE_ROW (w->current_matrix)); | 24670 | : MATRIX_HEADER_LINE_ROW (w->current_matrix)); |
| 24214 | 24671 | ||
| 24215 | /* Find glyph */ | 24672 | /* Find the glyph under the mouse pointer. */ |
| 24216 | if (row->mode_line_p && row->enabled_p) | 24673 | if (row->mode_line_p && row->enabled_p) |
| 24217 | { | 24674 | { |
| 24218 | glyph = row_start_glyph = row->glyphs[TEXT_AREA]; | 24675 | glyph = row_start_glyph = row->glyphs[TEXT_AREA]; |
| @@ -24230,6 +24687,8 @@ note_mode_line_or_margin_highlight (Lisp_Object window, int x, int y, | |||
| 24230 | else | 24687 | else |
| 24231 | { | 24688 | { |
| 24232 | x -= WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (w); | 24689 | x -= WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (w); |
| 24690 | /* Kludge alert: marginal_area_string takes X/Y in pixels, but | ||
| 24691 | returns them in row/column units! */ | ||
| 24233 | string = marginal_area_string (w, area, &x, &y, &charpos, | 24692 | string = marginal_area_string (w, area, &x, &y, &charpos, |
| 24234 | &object, &dx, &dy, &width, &height); | 24693 | &object, &dx, &dy, &width, &height); |
| 24235 | } | 24694 | } |
| @@ -24318,93 +24777,116 @@ note_mode_line_or_margin_highlight (Lisp_Object window, int x, int y, | |||
| 24318 | int gpos; | 24777 | int gpos; |
| 24319 | int gseq_length; | 24778 | int gseq_length; |
| 24320 | int total_pixel_width; | 24779 | int total_pixel_width; |
| 24321 | EMACS_INT ignore; | 24780 | EMACS_INT begpos, endpos, ignore; |
| 24322 | 24781 | ||
| 24323 | int vpos, hpos; | 24782 | int vpos, hpos; |
| 24324 | 24783 | ||
| 24325 | b = Fprevious_single_property_change (make_number (charpos + 1), | 24784 | b = Fprevious_single_property_change (make_number (charpos + 1), |
| 24326 | Qmouse_face, string, Qnil); | 24785 | Qmouse_face, string, Qnil); |
| 24327 | if (NILP (b)) | 24786 | if (NILP (b)) |
| 24328 | b = make_number (0); | 24787 | begpos = 0; |
| 24788 | else | ||
| 24789 | begpos = XINT (b); | ||
| 24329 | 24790 | ||
| 24330 | e = Fnext_single_property_change (pos, Qmouse_face, string, Qnil); | 24791 | e = Fnext_single_property_change (pos, Qmouse_face, string, Qnil); |
| 24331 | if (NILP (e)) | 24792 | if (NILP (e)) |
| 24332 | e = make_number (SCHARS (string)); | 24793 | endpos = SCHARS (string); |
| 24333 | 24794 | else | |
| 24334 | /* Calculate the position(glyph position: GPOS) of GLYPH in | 24795 | endpos = XINT (e); |
| 24335 | displayed string. GPOS is different from CHARPOS. | 24796 | |
| 24336 | 24797 | /* Calculate the glyph position GPOS of GLYPH in the | |
| 24337 | CHARPOS is the position of glyph in internal string | 24798 | displayed string, relative to the beginning of the |
| 24338 | object. A mode line string format has structures which | 24799 | highlighted part of the string. |
| 24339 | is converted to a flatten by emacs lisp interpreter. | 24800 | |
| 24340 | The internal string is an element of the structures. | 24801 | Note: GPOS is different from CHARPOS. CHARPOS is the |
| 24341 | The displayed string is the flatten string. */ | 24802 | position of GLYPH in the internal string object. A mode |
| 24342 | gpos = 0; | 24803 | line string format has structures which are converted to |
| 24343 | if (glyph > row_start_glyph) | 24804 | a flattened string by the Emacs Lisp interpreter. The |
| 24344 | { | 24805 | internal string is an element of those structures. The |
| 24345 | tmp_glyph = glyph - 1; | 24806 | displayed string is the flattened string. */ |
| 24346 | while (tmp_glyph >= row_start_glyph | 24807 | tmp_glyph = row_start_glyph; |
| 24347 | && tmp_glyph->charpos >= XINT (b) | 24808 | while (tmp_glyph < glyph |
| 24348 | && EQ (tmp_glyph->object, glyph->object)) | 24809 | && (!(EQ (tmp_glyph->object, glyph->object) |
| 24349 | { | 24810 | && begpos <= tmp_glyph->charpos |
| 24350 | tmp_glyph--; | 24811 | && tmp_glyph->charpos < endpos))) |
| 24351 | gpos++; | 24812 | tmp_glyph++; |
| 24352 | } | 24813 | gpos = glyph - tmp_glyph; |
| 24353 | } | 24814 | |
| 24354 | 24815 | /* Calculate the length GSEQ_LENGTH of the glyph sequence of | |
| 24355 | /* Calculate the lenght(glyph sequence length: GSEQ_LENGTH) of | 24816 | the highlighted part of the displayed string to which |
| 24356 | displayed string holding GLYPH. | 24817 | GLYPH belongs. Note: GSEQ_LENGTH is different from |
| 24357 | 24818 | SCHARS (STRING), because the latter returns the length of | |
| 24358 | GSEQ_LENGTH is different from SCHARS (STRING). | 24819 | the internal string. */ |
| 24359 | SCHARS (STRING) returns the length of the internal string. */ | 24820 | for (tmp_glyph = row->glyphs[TEXT_AREA] + row->used[TEXT_AREA] - 1; |
| 24360 | for (tmp_glyph = glyph, gseq_length = gpos; | 24821 | tmp_glyph > glyph |
| 24361 | tmp_glyph->charpos < XINT (e); | 24822 | && (!(EQ (tmp_glyph->object, glyph->object) |
| 24362 | tmp_glyph++, gseq_length++) | 24823 | && begpos <= tmp_glyph->charpos |
| 24363 | { | 24824 | && tmp_glyph->charpos < endpos)); |
| 24364 | if (!EQ (tmp_glyph->object, glyph->object)) | 24825 | tmp_glyph--) |
| 24365 | break; | 24826 | ; |
| 24366 | } | 24827 | gseq_length = gpos + (tmp_glyph - glyph) + 1; |
| 24367 | 24828 | ||
| 24829 | /* Calculate the total pixel width of all the glyphs between | ||
| 24830 | the beginning of the highlighted area and GLYPH. */ | ||
| 24368 | total_pixel_width = 0; | 24831 | total_pixel_width = 0; |
| 24369 | for (tmp_glyph = glyph - gpos; tmp_glyph != glyph; tmp_glyph++) | 24832 | for (tmp_glyph = glyph - gpos; tmp_glyph != glyph; tmp_glyph++) |
| 24370 | total_pixel_width += tmp_glyph->pixel_width; | 24833 | total_pixel_width += tmp_glyph->pixel_width; |
| 24371 | 24834 | ||
| 24372 | /* Pre calculation of re-rendering position */ | 24835 | /* Pre calculation of re-rendering position. Note: X is in |
| 24373 | vpos = (x - gpos); | 24836 | column units here, after the call to mode_line_string or |
| 24374 | hpos = (area == ON_MODE_LINE | 24837 | marginal_area_string. */ |
| 24838 | hpos = x - gpos; | ||
| 24839 | vpos = (area == ON_MODE_LINE | ||
| 24375 | ? (w->current_matrix)->nrows - 1 | 24840 | ? (w->current_matrix)->nrows - 1 |
| 24376 | : 0); | 24841 | : 0); |
| 24377 | 24842 | ||
| 24378 | /* If the re-rendering position is included in the last | 24843 | /* If GLYPH's position is included in the region that is |
| 24379 | re-rendering area, we should do nothing. */ | 24844 | already drawn in mouse face, we have nothing to do. */ |
| 24380 | if ( EQ (window, dpyinfo->mouse_face_window) | 24845 | if ( EQ (window, dpyinfo->mouse_face_window) |
| 24381 | && dpyinfo->mouse_face_beg_col <= vpos | 24846 | && (!row->reversed_p |
| 24382 | && vpos < dpyinfo->mouse_face_end_col | 24847 | ? (dpyinfo->mouse_face_beg_col <= hpos |
| 24383 | && dpyinfo->mouse_face_beg_row == hpos ) | 24848 | && hpos < dpyinfo->mouse_face_end_col) |
| 24849 | /* In R2L rows we swap BEG and END, see below. */ | ||
| 24850 | : (dpyinfo->mouse_face_end_col <= hpos | ||
| 24851 | && hpos < dpyinfo->mouse_face_beg_col)) | ||
| 24852 | && dpyinfo->mouse_face_beg_row == vpos ) | ||
| 24384 | return; | 24853 | return; |
| 24385 | 24854 | ||
| 24386 | if (clear_mouse_face (dpyinfo)) | 24855 | if (clear_mouse_face (dpyinfo)) |
| 24387 | cursor = No_Cursor; | 24856 | cursor = No_Cursor; |
| 24388 | 24857 | ||
| 24389 | dpyinfo->mouse_face_beg_col = vpos; | 24858 | if (!row->reversed_p) |
| 24390 | dpyinfo->mouse_face_beg_row = hpos; | 24859 | { |
| 24391 | 24860 | dpyinfo->mouse_face_beg_col = hpos; | |
| 24392 | dpyinfo->mouse_face_beg_x = original_x_pixel - (total_pixel_width + dx); | 24861 | dpyinfo->mouse_face_beg_x = original_x_pixel |
| 24393 | dpyinfo->mouse_face_beg_y = 0; | 24862 | - (total_pixel_width + dx); |
| 24394 | 24863 | dpyinfo->mouse_face_end_col = hpos + gseq_length; | |
| 24395 | dpyinfo->mouse_face_end_col = vpos + gseq_length; | 24864 | dpyinfo->mouse_face_end_x = 0; |
| 24396 | dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_beg_row; | 24865 | } |
| 24397 | 24866 | else | |
| 24398 | dpyinfo->mouse_face_end_x = 0; | 24867 | { |
| 24399 | dpyinfo->mouse_face_end_y = 0; | 24868 | /* In R2L rows, show_mouse_face expects BEG and END |
| 24869 | coordinates to be swapped. */ | ||
| 24870 | dpyinfo->mouse_face_end_col = hpos; | ||
| 24871 | dpyinfo->mouse_face_end_x = original_x_pixel | ||
| 24872 | - (total_pixel_width + dx); | ||
| 24873 | dpyinfo->mouse_face_beg_col = hpos + gseq_length; | ||
| 24874 | dpyinfo->mouse_face_beg_x = 0; | ||
| 24875 | } | ||
| 24400 | 24876 | ||
| 24877 | dpyinfo->mouse_face_beg_row = vpos; | ||
| 24878 | dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_beg_row; | ||
| 24879 | dpyinfo->mouse_face_beg_y = 0; | ||
| 24880 | dpyinfo->mouse_face_end_y = 0; | ||
| 24401 | dpyinfo->mouse_face_past_end = 0; | 24881 | dpyinfo->mouse_face_past_end = 0; |
| 24402 | dpyinfo->mouse_face_window = window; | 24882 | dpyinfo->mouse_face_window = window; |
| 24403 | 24883 | ||
| 24404 | dpyinfo->mouse_face_face_id = face_at_string_position (w, string, | 24884 | dpyinfo->mouse_face_face_id = face_at_string_position (w, string, |
| 24405 | charpos, | 24885 | charpos, |
| 24406 | 0, 0, 0, &ignore, | 24886 | 0, 0, 0, |
| 24407 | glyph->face_id, 1); | 24887 | &ignore, |
| 24888 | glyph->face_id, | ||
| 24889 | 1); | ||
| 24408 | show_mouse_face (dpyinfo, DRAW_MOUSE_FACE); | 24890 | show_mouse_face (dpyinfo, DRAW_MOUSE_FACE); |
| 24409 | 24891 | ||
| 24410 | if (NILP (pointer)) | 24892 | if (NILP (pointer)) |
| @@ -24573,7 +25055,15 @@ note_mouse_highlight (struct frame *f, int x, int y) | |||
| 24573 | /* Clear mouse face if X/Y not over text. */ | 25055 | /* Clear mouse face if X/Y not over text. */ |
| 24574 | if (glyph == NULL | 25056 | if (glyph == NULL |
| 24575 | || area != TEXT_AREA | 25057 | || area != TEXT_AREA |
| 24576 | || !MATRIX_ROW (w->current_matrix, vpos)->displays_text_p) | 25058 | || !MATRIX_ROW (w->current_matrix, vpos)->displays_text_p |
| 25059 | /* R2L rows have a stretch glyph at their front, which | ||
| 25060 | stands for no text, whereas L2R rows have no glyphs at | ||
| 25061 | all beyond the end of text. Treat such stretch glyphs | ||
| 25062 | like we do with NULL glyphs in L2R rows. */ | ||
| 25063 | || (MATRIX_ROW (w->current_matrix, vpos)->reversed_p | ||
| 25064 | && glyph == MATRIX_ROW (w->current_matrix, vpos)->glyphs[TEXT_AREA] | ||
| 25065 | && glyph->type == STRETCH_GLYPH | ||
| 25066 | && glyph->avoid_cursor_p)) | ||
| 24577 | { | 25067 | { |
| 24578 | if (clear_mouse_face (dpyinfo)) | 25068 | if (clear_mouse_face (dpyinfo)) |
| 24579 | cursor = No_Cursor; | 25069 | cursor = No_Cursor; |
| @@ -24618,14 +25108,7 @@ note_mouse_highlight (struct frame *f, int x, int y) | |||
| 24618 | else | 25108 | else |
| 24619 | noverlays = 0; | 25109 | noverlays = 0; |
| 24620 | 25110 | ||
| 24621 | same_region = (EQ (window, dpyinfo->mouse_face_window) | 25111 | same_region = coords_in_mouse_face_p (w, hpos, vpos); |
| 24622 | && vpos >= dpyinfo->mouse_face_beg_row | ||
| 24623 | && vpos <= dpyinfo->mouse_face_end_row | ||
| 24624 | && (vpos > dpyinfo->mouse_face_beg_row | ||
| 24625 | || hpos >= dpyinfo->mouse_face_beg_col) | ||
| 24626 | && (vpos < dpyinfo->mouse_face_end_row | ||
| 24627 | || hpos < dpyinfo->mouse_face_end_col | ||
| 24628 | || dpyinfo->mouse_face_past_end)); | ||
| 24629 | 25112 | ||
| 24630 | if (same_region) | 25113 | if (same_region) |
| 24631 | cursor = No_Cursor; | 25114 | cursor = No_Cursor; |
| @@ -24679,17 +25162,8 @@ note_mouse_highlight (struct frame *f, int x, int y) | |||
| 24679 | b = make_number (0); | 25162 | b = make_number (0); |
| 24680 | if (NILP (e)) | 25163 | if (NILP (e)) |
| 24681 | e = make_number (SCHARS (object) - 1); | 25164 | e = make_number (SCHARS (object) - 1); |
| 24682 | 25165 | mouse_face_from_string_pos (w, dpyinfo, object, | |
| 24683 | fast_find_string_pos (w, XINT (b), object, | 25166 | XINT (b), XINT (e)); |
| 24684 | &dpyinfo->mouse_face_beg_col, | ||
| 24685 | &dpyinfo->mouse_face_beg_row, | ||
| 24686 | &dpyinfo->mouse_face_beg_x, | ||
| 24687 | &dpyinfo->mouse_face_beg_y, 0); | ||
| 24688 | fast_find_string_pos (w, XINT (e), object, | ||
| 24689 | &dpyinfo->mouse_face_end_col, | ||
| 24690 | &dpyinfo->mouse_face_end_row, | ||
| 24691 | &dpyinfo->mouse_face_end_x, | ||
| 24692 | &dpyinfo->mouse_face_end_y, 1); | ||
| 24693 | dpyinfo->mouse_face_past_end = 0; | 25167 | dpyinfo->mouse_face_past_end = 0; |
| 24694 | dpyinfo->mouse_face_window = window; | 25168 | dpyinfo->mouse_face_window = window; |
| 24695 | dpyinfo->mouse_face_face_id | 25169 | dpyinfo->mouse_face_face_id |
| @@ -24729,17 +25203,33 @@ note_mouse_highlight (struct frame *f, int x, int y) | |||
| 24729 | { | 25203 | { |
| 24730 | Lisp_Object before, after; | 25204 | Lisp_Object before, after; |
| 24731 | Lisp_Object before_string, after_string; | 25205 | Lisp_Object before_string, after_string; |
| 25206 | /* To correctly find the limits of mouse highlight | ||
| 25207 | in a bidi-reordered buffer, we must not use the | ||
| 25208 | optimization of limiting the search in | ||
| 25209 | previous-single-property-change and | ||
| 25210 | next-single-property-change, because | ||
| 25211 | rows_from_pos_range needs the real start and end | ||
| 25212 | positions to DTRT in this case. That's because | ||
| 25213 | the first row visible in a window does not | ||
| 25214 | necessarily display the character whose position | ||
| 25215 | is the smallest. */ | ||
| 25216 | Lisp_Object lim1 = | ||
| 25217 | NILP (XBUFFER (buffer)->bidi_display_reordering) | ||
| 25218 | ? Fmarker_position (w->start) | ||
| 25219 | : Qnil; | ||
| 25220 | Lisp_Object lim2 = | ||
| 25221 | NILP (XBUFFER (buffer)->bidi_display_reordering) | ||
| 25222 | ? make_number (BUF_Z (XBUFFER (buffer)) | ||
| 25223 | - XFASTINT (w->window_end_pos)) | ||
| 25224 | : Qnil; | ||
| 24732 | 25225 | ||
| 24733 | if (NILP (overlay)) | 25226 | if (NILP (overlay)) |
| 24734 | { | 25227 | { |
| 24735 | /* Handle the text property case. */ | 25228 | /* Handle the text property case. */ |
| 24736 | before = Fprevious_single_property_change | 25229 | before = Fprevious_single_property_change |
| 24737 | (make_number (pos + 1), Qmouse_face, buffer, | 25230 | (make_number (pos + 1), Qmouse_face, buffer, lim1); |
| 24738 | Fmarker_position (w->start)); | ||
| 24739 | after = Fnext_single_property_change | 25231 | after = Fnext_single_property_change |
| 24740 | (make_number (pos), Qmouse_face, buffer, | 25232 | (make_number (pos), Qmouse_face, buffer, lim2); |
| 24741 | make_number (BUF_Z (XBUFFER (buffer)) | ||
| 24742 | - XFASTINT (w->window_end_pos))); | ||
| 24743 | before_string = after_string = Qnil; | 25233 | before_string = after_string = Qnil; |
| 24744 | } | 25234 | } |
| 24745 | else | 25235 | else |