# HG changeset patch # User Eli Zaretskii # Date 1287233574 -7200 # Node ID 560acc231de37e1a25ae5c1da0145d08e6183b5f # Parent 73d72d472c021e2e2d745b3694b7f87192c140f6 Support bidi-reordered text in mouse-highlighted mode- and header-lines. Note: Not tested with actually bidi-reordered strings. xdisp.c (note_mode_line_or_margin_highlight): Support bidi-reordered strings and R2L glyph rows. Fix more comments. diff -r 73d72d472c02 -r 560acc231de3 src/ChangeLog --- a/src/ChangeLog Sat Oct 16 12:04:03 2010 +0200 +++ b/src/ChangeLog Sat Oct 16 14:52:54 2010 +0200 @@ -1,3 +1,8 @@ +2010-10-16 Eli Zaretskii + + * xdisp.c (note_mode_line_or_margin_highlight): Support + bidi-reordered strings and R2L glyph rows. Fix more comments. + 2010-10-16 Eli Zaretskii * xdisp.c (rows_from_pos_range, mouse_face_from_buffer_pos) diff -r 73d72d472c02 -r 560acc231de3 src/xdisp.c --- a/src/xdisp.c Sat Oct 16 12:04:03 2010 +0200 +++ b/src/xdisp.c Sat Oct 16 14:52:54 2010 +0200 @@ -24602,6 +24602,8 @@ int x0; struct glyph *end; + /* Kludge alert: mode_line_string takes X/Y in pixels, but + returns them in row/column units! */ string = mode_line_string (w, area, &x, &y, &charpos, &object, &dx, &dy, &width, &height); @@ -24627,6 +24629,8 @@ else { x -= WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (w); + /* Kludge alert: marginal_area_string takes X/Y in pixels, but + returns them in row/column units! */ string = marginal_area_string (w, area, &x, &y, &charpos, &object, &dx, &dy, &width, &height); } @@ -24715,21 +24719,26 @@ int gpos; int gseq_length; int total_pixel_width; - EMACS_INT ignore; + EMACS_INT begpos, endpos, ignore; int vpos, hpos; b = Fprevious_single_property_change (make_number (charpos + 1), Qmouse_face, string, Qnil); if (NILP (b)) - b = make_number (0); + begpos = 0; + else + begpos = XINT (b); e = Fnext_single_property_change (pos, Qmouse_face, string, Qnil); if (NILP (e)) - e = make_number (SCHARS (string)); + endpos = SCHARS (string); + else + endpos = XINT (e); /* Calculate the glyph position GPOS of GLYPH in the - displayed string. + displayed string, relative to the beginning of the + highlighted part of the string. Note: GPOS is different from CHARPOS. CHARPOS is the position of GLYPH in the internal string object. A mode @@ -24737,71 +24746,89 @@ a flattened string by the Emacs Lisp interpreter. The internal string is an element of those structures. The displayed string is the flattened string. */ - gpos = 0; - if (glyph > row_start_glyph) - { - tmp_glyph = glyph - 1; - while (tmp_glyph >= row_start_glyph - && tmp_glyph->charpos >= XINT (b) - && EQ (tmp_glyph->object, glyph->object)) - { - tmp_glyph--; - gpos++; - } - } - - /* Calculate the glyph sequence length GSEQ_LENGTH of the - displayed string to which GLYPH belongs. Note: - GSEQ_LENGTH is different from SCHARS (STRING), because - the latter returns the length of the internal string. */ - for (tmp_glyph = glyph, gseq_length = gpos; - tmp_glyph->charpos < XINT (e); - tmp_glyph++, gseq_length++) - { - if (!EQ (tmp_glyph->object, glyph->object)) - break; - } - + tmp_glyph = row_start_glyph; + while (tmp_glyph < glyph + && (!(EQ (tmp_glyph->object, glyph->object) + && begpos <= tmp_glyph->charpos + && tmp_glyph->charpos < endpos))) + tmp_glyph++; + gpos = glyph - tmp_glyph; + + /* Calculate the length GSEQ_LENGTH of the glyph sequence of + the highlighted part of the displayed string to which + GLYPH belongs. Note: GSEQ_LENGTH is different from + SCHARS (STRING), because the latter returns the length of + the internal string. */ + for (tmp_glyph = row->glyphs[TEXT_AREA] + row->used[TEXT_AREA] - 1; + tmp_glyph > glyph + && (!(EQ (tmp_glyph->object, glyph->object) + && begpos <= tmp_glyph->charpos + && tmp_glyph->charpos < endpos)); + tmp_glyph--) + ; + gseq_length = gpos + (tmp_glyph - glyph) + 1; + + /* Calculate the total pixel width of all the glyphs between + the beginning of the highlighted area and GLYPH. */ total_pixel_width = 0; for (tmp_glyph = glyph - gpos; tmp_glyph != glyph; tmp_glyph++) total_pixel_width += tmp_glyph->pixel_width; - /* Pre calculation of re-rendering position. */ + /* Pre calculation of re-rendering position. Note: X is in + column units here, after the call to mode_line_string or + marginal_area_string. */ hpos = x - gpos; vpos = (area == ON_MODE_LINE ? (w->current_matrix)->nrows - 1 : 0); - /* If the re-rendering position is included in the last - re-rendering area, we should do nothing. */ + /* If GLYPH's position is included in the region that is + already drawn in mouse face, we have nothing to do. */ if ( EQ (window, dpyinfo->mouse_face_window) - && dpyinfo->mouse_face_beg_col <= hpos - && hpos < dpyinfo->mouse_face_end_col + && (!row->reversed_p + ? (dpyinfo->mouse_face_beg_col <= hpos + && hpos < dpyinfo->mouse_face_end_col) + /* In R2L rows we swap BEG and END, see below. */ + : (dpyinfo->mouse_face_end_col <= hpos + && hpos < dpyinfo->mouse_face_beg_col)) && dpyinfo->mouse_face_beg_row == vpos ) return; if (clear_mouse_face (dpyinfo)) cursor = No_Cursor; - dpyinfo->mouse_face_beg_col = hpos; - dpyinfo->mouse_face_beg_row = vpos; - - dpyinfo->mouse_face_beg_x = original_x_pixel - (total_pixel_width + dx); - dpyinfo->mouse_face_beg_y = 0; - - dpyinfo->mouse_face_end_col = hpos + gseq_length; - dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_beg_row; - - dpyinfo->mouse_face_end_x = 0; - dpyinfo->mouse_face_end_y = 0; - + if (!row->reversed_p) + { + dpyinfo->mouse_face_beg_col = hpos; + dpyinfo->mouse_face_beg_x = original_x_pixel + - (total_pixel_width + dx); + dpyinfo->mouse_face_end_col = hpos + gseq_length; + dpyinfo->mouse_face_end_x = 0; + } + else + { + /* In R2L rows, show_mouse_face expects BEG and END + coordinates to be swapped. */ + dpyinfo->mouse_face_end_col = hpos; + dpyinfo->mouse_face_end_x = original_x_pixel + - (total_pixel_width + dx); + dpyinfo->mouse_face_beg_col = hpos + gseq_length; + dpyinfo->mouse_face_beg_x = 0; + } + + dpyinfo->mouse_face_beg_row = vpos; + dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_beg_row; + dpyinfo->mouse_face_beg_y = 0; + dpyinfo->mouse_face_end_y = 0; dpyinfo->mouse_face_past_end = 0; - dpyinfo->mouse_face_window = window; + dpyinfo->mouse_face_window = window; dpyinfo->mouse_face_face_id = face_at_string_position (w, string, charpos, - 0, 0, 0, &ignore, - glyph->face_id, 1); + 0, 0, 0, + &ignore, + glyph->face_id, + 1); show_mouse_face (dpyinfo, DRAW_MOUSE_FACE); if (NILP (pointer))