diff options
author | Stefan Monnier <monnier@iro.umontreal.ca> | 2010-12-10 19:13:08 -0500 |
---|---|---|
committer | Stefan Monnier <monnier@iro.umontreal.ca> | 2010-12-10 19:13:08 -0500 |
commit | 8e3217e7bc7672eeba8ed042e730f0da1e261cd0 (patch) | |
tree | b28874c54ab71597a7dddd3d0fab0e1d10de2713 /src/xdisp.c | |
parent | 54467310f586089f2b3f9e4fa46eaadb2ce08fd6 (diff) | |
parent | 6be816dee8c9720dc39ff235b7b31d4190e06d57 (diff) | |
download | emacs-8e3217e7bc7672eeba8ed042e730f0da1e261cd0.tar.gz |
Merge from trunk
Diffstat (limited to 'src/xdisp.c')
-rw-r--r-- | src/xdisp.c | 1850 |
1 files changed, 1424 insertions, 426 deletions
diff --git a/src/xdisp.c b/src/xdisp.c index 4c007e572ce..77e9db2e5eb 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -1,8 +1,8 @@ /* Display generation from window structure and buffer text. - Copyright (C) 1985, 1986, 1987, 1988, 1993, 1994, 1995, - 1997, 1998, 1999, 2000, 2001, 2002, 2003, - 2004, 2005, 2006, 2007, 2008, 2009, 2010 - Free Software Foundation, Inc. + +Copyright (C) 1985, 1986, 1987, 1988, 1993, 1994, 1995, 1997, 1998, + 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, + 2010 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -214,11 +214,41 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ leftmost character with special glyphs, which will display as, well, empty. On text terminals, these special glyphs are simply blank characters. On graphics terminals, there's a single stretch - glyph with suitably computed width. Both the blanks and the + glyph of a suitably computed width. Both the blanks and the stretch glyph are given the face of the background of the line. This way, the terminal-specific back-end can still draw the glyphs left to right, even for R2L lines. + Bidirectional display and character compositions + + Some scripts cannot be displayed by drawing each character + individually, because adjacent characters change each other's shape + on display. For example, Arabic and Indic scripts belong to this + category. + + Emacs display supports this by providing "character compositions", + most of which is implemented in composite.c. During the buffer + scan that delivers characters to PRODUCE_GLYPHS, if the next + character to be delivered is a composed character, the iteration + calls composition_reseat_it and next_element_from_composition. If + they succeed to compose the character with one or more of the + following characters, the whole sequence of characters that where + composed is recorded in the `struct composition_it' object that is + part of the buffer iterator. The composed sequence could produce + one or more font glyphs (called "grapheme clusters") on the screen. + Each of these grapheme clusters is then delivered to PRODUCE_GLYPHS + in the direction corresponding to the current bidi scan direction + (recorded in the scan_dir member of the `struct bidi_it' object + that is part of the buffer iterator). In particular, if the bidi + iterator currently scans the buffer backwards, the grapheme + clusters are delivered back to front. This reorders the grapheme + clusters as appropriate for the current bidi context. Note that + this means that the grapheme clusters are always stored in the + LGSTRING object (see composite.c) in the logical order. + + Moving an iterator in bidirectional text + without producing glyphs + Note one important detail mentioned above: that the bidi reordering engine, driven by the iterator, produces characters in R2L rows starting at the character that will be the rightmost on display. @@ -888,6 +918,9 @@ static int clear_face_cache_count; #ifdef HAVE_WINDOW_SYSTEM #define CLEAR_IMAGE_CACHE_COUNT 101 static int clear_image_cache_count; + +/* Null glyph slice */ +static struct glyph_slice null_glyph_slice = { 0, 0, 0, 0 }; #endif /* Non-zero while redisplay_internal is in progress. */ @@ -913,10 +946,6 @@ EMACS_INT help_echo_pos; Lisp_Object previous_help_echo_string; -/* Null glyph slice */ - -static struct glyph_slice null_glyph_slice = { 0, 0, 0, 0 }; - /* Platform-independent portion of hourglass implementation. */ /* Non-zero means we're allowed to display a hourglass pointer. */ @@ -932,6 +961,21 @@ struct atimer *hourglass_atimer; /* Number of seconds to wait before displaying an hourglass cursor. */ Lisp_Object Vhourglass_delay; +/* Name of the face used to display glyphless characters. */ +Lisp_Object Qglyphless_char; + +/* Char-table to control the display of glyphless characters. */ +Lisp_Object Vglyphless_char_display; + +/* Symbol for the purpose of Vglyphless_char_display. */ +Lisp_Object Qglyphless_char_display; + +/* Method symbols for Vglyphless_char_display. */ +static Lisp_Object Qhex_code, Qempty_box, Qthin_space, Qzero_width; + +/* Default pixel width of `thin-space' display method. */ +#define THIN_SPACE_WIDTH 1 + /* Default number of seconds to wait before displaying an hourglass cursor. */ #define DEFAULT_HOURGLASS_DELAY 1 @@ -960,10 +1004,8 @@ static int text_outside_line_unchanged_p (struct window *, EMACS_INT, EMACS_INT); static void store_mode_line_noprop_char (char); static int store_mode_line_noprop (const unsigned char *, int, int); -static void x_consider_frame_title (Lisp_Object); static void handle_stop (struct it *); static void handle_stop_backwards (struct it *, EMACS_INT); -static int tool_bar_lines_needed (struct frame *, int *); static int single_display_spec_intangible_p (Lisp_Object); static void ensure_echo_area_buffers (void); static Lisp_Object unwind_with_echo_area_buffer (Lisp_Object); @@ -1076,6 +1118,8 @@ static int in_ellipses_for_invisible_text_p (struct display_pos *, #ifdef HAVE_WINDOW_SYSTEM +static void x_consider_frame_title (Lisp_Object); +static int tool_bar_lines_needed (struct frame *, int *); static void update_tool_bar (struct frame *, int); static void build_desired_tool_bar_string (struct frame *f); static int redisplay_tool_bar (struct frame *); @@ -1087,9 +1131,11 @@ static void append_stretch_glyph (struct it *, Lisp_Object, int, int, int); - #endif /* HAVE_WINDOW_SYSTEM */ +static int coords_in_mouse_face_p (struct window *, int, int); + + /*********************************************************************** Window display dimensions @@ -1781,8 +1827,6 @@ glyph_to_pixel_coords (struct window *w, int hpos, int vpos, } -#ifdef HAVE_WINDOW_SYSTEM - /* Find the glyph under window-relative coordinates X/Y in window W. Consider only glyphs from buffer text, i.e. no glyphs from overlay strings. Return in *HPOS and *VPOS the row and column number of @@ -1865,7 +1909,6 @@ x_y_to_hpos_vpos (struct window *w, int x, int y, int *hpos, int *vpos, return glyph; } - /* EXPORT: Convert frame-relative x/y to coordinates relative to window W. Takes pseudo-windows into account. */ @@ -1888,6 +1931,8 @@ frame_to_window_pixel_xy (struct window *w, int *x, int *y) } } +#ifdef HAVE_WINDOW_SYSTEM + /* EXPORT: Return in RECTS[] at most N clipping rectangles for glyph string S. Return the number of stored rectangles. */ @@ -2173,7 +2218,7 @@ remember_mouse_glyph (struct frame *f, int gx, int gy, NativeRectangle *rect) frame pixel coordinates X/Y on frame F. */ if (!f->glyphs_initialized_p - || (window = window_from_coordinates (f, gx, gy, &part, &x, &y, 0), + || (window = window_from_coordinates (f, gx, gy, &part, 0), NILP (window))) { width = FRAME_SMALLEST_CHAR_WIDTH (f); @@ -2185,6 +2230,9 @@ remember_mouse_glyph (struct frame *f, int gx, int gy, NativeRectangle *rect) width = WINDOW_FRAME_COLUMN_WIDTH (w); height = WINDOW_FRAME_LINE_HEIGHT (w); + x = window_relative_x_coord (w, part, gx); + y = gy - WINDOW_TOP_EDGE_Y (w); + r = MATRIX_FIRST_TEXT_ROW (w->current_matrix); end_row = MATRIX_BOTTOM_TEXT_ROW (w->current_matrix, w); @@ -5731,6 +5779,57 @@ static int (* get_next_element[NUM_IT_METHODS]) (struct it *it) = (IT)->string))) +/* Lookup the char-table Vglyphless_char_display for character C (-1 + if we want information for no-font case), and return the display + method symbol. By side-effect, update it->what and + it->glyphless_method. This function is called from + get_next_display_element for each character element, and from + x_produce_glyphs when no suitable font was found. */ + +Lisp_Object +lookup_glyphless_char_display (int c, struct it *it) +{ + Lisp_Object glyphless_method = Qnil; + + if (CHAR_TABLE_P (Vglyphless_char_display) + && CHAR_TABLE_EXTRA_SLOTS (XCHAR_TABLE (Vglyphless_char_display)) >= 1) + glyphless_method = (c >= 0 + ? CHAR_TABLE_REF (Vglyphless_char_display, c) + : XCHAR_TABLE (Vglyphless_char_display)->extras[0]); + retry: + if (NILP (glyphless_method)) + { + if (c >= 0) + /* The default is to display the character by a proper font. */ + return Qnil; + /* The default for the no-font case is to display an empty box. */ + glyphless_method = Qempty_box; + } + if (EQ (glyphless_method, Qzero_width)) + { + if (c >= 0) + return glyphless_method; + /* This method can't be used for the no-font case. */ + glyphless_method = Qempty_box; + } + if (EQ (glyphless_method, Qthin_space)) + it->glyphless_method = GLYPHLESS_DISPLAY_THIN_SPACE; + else if (EQ (glyphless_method, Qempty_box)) + it->glyphless_method = GLYPHLESS_DISPLAY_EMPTY_BOX; + else if (EQ (glyphless_method, Qhex_code)) + it->glyphless_method = GLYPHLESS_DISPLAY_HEX_CODE; + else if (STRINGP (glyphless_method)) + it->glyphless_method = GLYPHLESS_DISPLAY_ACRONYM; + else + { + /* Invalid value. We use the default method. */ + glyphless_method = Qnil; + goto retry; + } + it->what = IT_GLYPHLESS; + return glyphless_method; +} + /* Load IT's display element fields with information about the next display element from the current position of IT. Value is zero if end of buffer (or C string) is reached. */ @@ -5739,6 +5838,10 @@ static struct frame *last_escape_glyph_frame = NULL; static unsigned last_escape_glyph_face_id = (1 << FACE_ID_BITS); static int last_escape_glyph_merged_face_id = 0; +struct frame *last_glyphless_glyph_frame = NULL; +unsigned last_glyphless_glyph_face_id = (1 << FACE_ID_BITS); +int last_glyphless_glyph_merged_face_id = 0; + int get_next_display_element (struct it *it) { @@ -5817,6 +5920,15 @@ get_next_display_element (struct it *it) goto get_next; } + if (! NILP (lookup_glyphless_char_display (c, it))) + { + if (it->what == IT_GLYPHLESS) + goto done; + /* Don't display this character. */ + set_iterator_to_next (it, 0); + goto get_next; + } + if (! ASCII_CHAR_P (c) && ! NILP (Vnobreak_char_display)) nbsp_or_shy = (c == 0xA0 ? char_is_nbsp : c == 0xAD ? char_is_soft_hyphen @@ -6031,6 +6143,7 @@ get_next_display_element (struct it *it) } #endif + done: /* Is this character the last one of a run of characters with box? If yes, set IT->end_of_box_run_p to 1. */ if (it->face_box_p @@ -9271,6 +9384,8 @@ set_message_1 (EMACS_INT a1, Lisp_Object a2, EMACS_INT nbytes, EMACS_INT multiby Fset_buffer_multibyte (message_enable_multibyte ? Qt : Qnil); current_buffer->truncate_lines = message_truncate_lines ? Qt : Qnil; + if (!NILP (current_buffer->bidi_display_reordering)) + current_buffer->bidi_paragraph_direction = Qleft_to_right; /* Insert new message at BEG. */ TEMP_SET_PT_BOTH (BEG, BEG_BYTE); @@ -10737,7 +10852,7 @@ static int get_tool_bar_item (struct frame *f, int x, int y, struct glyph **glyph, int *hpos, int *vpos, int *prop_idx) { - Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f); + Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f); struct window *w = XWINDOW (f->tool_bar_window); int area; @@ -10752,14 +10867,14 @@ get_tool_bar_item (struct frame *f, int x, int y, struct glyph **glyph, return -1; /* Is mouse on the highlighted item? */ - if (EQ (f->tool_bar_window, dpyinfo->mouse_face_window) - && *vpos >= dpyinfo->mouse_face_beg_row - && *vpos <= dpyinfo->mouse_face_end_row - && (*vpos > dpyinfo->mouse_face_beg_row - || *hpos >= dpyinfo->mouse_face_beg_col) - && (*vpos < dpyinfo->mouse_face_end_row - || *hpos < dpyinfo->mouse_face_end_col - || dpyinfo->mouse_face_past_end)) + if (EQ (f->tool_bar_window, hlinfo->mouse_face_window) + && *vpos >= hlinfo->mouse_face_beg_row + && *vpos <= hlinfo->mouse_face_end_row + && (*vpos > hlinfo->mouse_face_beg_row + || *hpos >= hlinfo->mouse_face_beg_col) + && (*vpos < hlinfo->mouse_face_end_row + || *hpos < hlinfo->mouse_face_end_col + || hlinfo->mouse_face_past_end)) return 0; return 1; @@ -10776,7 +10891,7 @@ void handle_tool_bar_click (struct frame *f, int x, int y, int down_p, unsigned int modifiers) { - Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f); + Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f); struct window *w = XWINDOW (f->tool_bar_window); int hpos, vpos, prop_idx; struct glyph *glyph; @@ -10795,8 +10910,8 @@ handle_tool_bar_click (struct frame *f, int x, int y, int down_p, if (down_p) { /* Show item in pressed state. */ - show_mouse_face (dpyinfo, DRAW_IMAGE_SUNKEN); - dpyinfo->mouse_face_image_state = DRAW_IMAGE_SUNKEN; + show_mouse_face (hlinfo, DRAW_IMAGE_SUNKEN); + hlinfo->mouse_face_image_state = DRAW_IMAGE_SUNKEN; last_tool_bar_item = prop_idx; } else @@ -10806,8 +10921,8 @@ handle_tool_bar_click (struct frame *f, int x, int y, int down_p, EVENT_INIT (event); /* Show item in released state. */ - show_mouse_face (dpyinfo, DRAW_IMAGE_RAISED); - dpyinfo->mouse_face_image_state = DRAW_IMAGE_RAISED; + show_mouse_face (hlinfo, DRAW_IMAGE_RAISED); + hlinfo->mouse_face_image_state = DRAW_IMAGE_RAISED; key = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_KEY); @@ -10837,6 +10952,7 @@ note_tool_bar_highlight (struct frame *f, int x, int y) Lisp_Object window = f->tool_bar_window; struct window *w = XWINDOW (window); Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f); + Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f); int hpos, vpos; struct glyph *glyph; struct glyph_row *row; @@ -10850,7 +10966,7 @@ note_tool_bar_highlight (struct frame *f, int x, int y) values when mouse moves outside of the frame. */ if (x <= 0 || y <= 0) { - clear_mouse_face (dpyinfo); + clear_mouse_face (hlinfo); return; } @@ -10858,14 +10974,14 @@ note_tool_bar_highlight (struct frame *f, int x, int y) if (rc < 0) { /* Not on tool-bar item. */ - clear_mouse_face (dpyinfo); + clear_mouse_face (hlinfo); return; } else if (rc == 0) /* On same tool-bar item as before. */ goto set_help_echo; - clear_mouse_face (dpyinfo); + clear_mouse_face (hlinfo); /* Mouse is down, but on different tool-bar item? */ mouse_down_p = (dpyinfo->grabbed @@ -10875,7 +10991,7 @@ note_tool_bar_highlight (struct frame *f, int x, int y) && last_tool_bar_item != prop_idx) return; - dpyinfo->mouse_face_image_state = DRAW_NORMAL_TEXT; + hlinfo->mouse_face_image_state = DRAW_NORMAL_TEXT; draw = mouse_down_p ? DRAW_IMAGE_SUNKEN : DRAW_IMAGE_RAISED; /* If tool-bar item is not enabled, don't highlight it. */ @@ -10889,22 +11005,22 @@ note_tool_bar_highlight (struct frame *f, int x, int y) x += row->glyphs[TEXT_AREA][i].pixel_width; /* Record this as the current active region. */ - dpyinfo->mouse_face_beg_col = hpos; - dpyinfo->mouse_face_beg_row = vpos; - dpyinfo->mouse_face_beg_x = x; - dpyinfo->mouse_face_beg_y = row->y; - dpyinfo->mouse_face_past_end = 0; - - dpyinfo->mouse_face_end_col = hpos + 1; - dpyinfo->mouse_face_end_row = vpos; - dpyinfo->mouse_face_end_x = x + glyph->pixel_width; - dpyinfo->mouse_face_end_y = row->y; - dpyinfo->mouse_face_window = window; - dpyinfo->mouse_face_face_id = TOOL_BAR_FACE_ID; + hlinfo->mouse_face_beg_col = hpos; + hlinfo->mouse_face_beg_row = vpos; + hlinfo->mouse_face_beg_x = x; + hlinfo->mouse_face_beg_y = row->y; + hlinfo->mouse_face_past_end = 0; + + hlinfo->mouse_face_end_col = hpos + 1; + hlinfo->mouse_face_end_row = vpos; + hlinfo->mouse_face_end_x = x + glyph->pixel_width; + hlinfo->mouse_face_end_y = row->y; + hlinfo->mouse_face_window = window; + hlinfo->mouse_face_face_id = TOOL_BAR_FACE_ID; /* Display it as active. */ - show_mouse_face (dpyinfo, draw); - dpyinfo->mouse_face_image_state = draw; + show_mouse_face (hlinfo, draw); + hlinfo->mouse_face_image_state = draw; } set_help_echo: @@ -11578,6 +11694,8 @@ redisplay_internal (int preserve_echo_area) reconsider_clip_changes (w, current_buffer); last_escape_glyph_frame = NULL; last_escape_glyph_face_id = (1 << FACE_ID_BITS); + last_glyphless_glyph_frame = NULL; + last_glyphless_glyph_face_id = (1 << FACE_ID_BITS); /* If new fonts have been loaded that make a glyph matrix adjustment necessary, do it. */ @@ -12723,6 +12841,15 @@ set_cursor_from_row (struct window *w, struct glyph_row *row, && BUFFERP (glyph->object) && glyph->charpos == pt_old) && bpos_covered < pt_old) { + /* An empty line has a single glyph whose OBJECT is zero and + whose CHARPOS is the position of a newline on that line. + Note that on a TTY, there are more glyphs after that, which + were produced by extend_face_to_end_of_line, but their + CHARPOS is zero or negative. */ + int empty_line_p = + (row->reversed_p ? glyph > glyphs_end : glyph < glyphs_end) + && INTEGERP (glyph->object) && glyph->charpos > 0; + if (row->ends_in_ellipsis_p && pos_after == last_pos) { EMACS_INT ellipsis_pos; @@ -12758,10 +12885,11 @@ set_cursor_from_row (struct window *w, struct glyph_row *row, || (row->truncated_on_left_p && pt_old < bpos_min) || (row->truncated_on_right_p && pt_old > bpos_max) /* Zero-width characters produce no glyphs. */ - || ((row->reversed_p - ? glyph_after > glyphs_end - : glyph_after < glyphs_end) - && eabs (glyph_after - glyph_before) == 1)) + || (!string_seen + && !empty_line_p + && (row->reversed_p + ? glyph_after > glyphs_end + : glyph_after < glyphs_end))) { cursor = glyph_after; x = -1; @@ -12815,8 +12943,9 @@ set_cursor_from_row (struct window *w, struct glyph_row *row, cursor on that character's glyph. */ EMACS_INT strpos = glyph->charpos; - cursor = glyph; - for (glyph += incr; + if (tem) + cursor = glyph; + for ( ; (row->reversed_p ? glyph > stop : glyph < stop) && EQ (glyph->object, str); glyph += incr) @@ -12832,7 +12961,7 @@ set_cursor_from_row (struct window *w, struct glyph_row *row, cursor = glyph; break; } - if (glyph->charpos < strpos) + if (tem && glyph->charpos < strpos) { strpos = glyph->charpos; cursor = glyph; @@ -12847,10 +12976,9 @@ set_cursor_from_row (struct window *w, struct glyph_row *row, } /* This string is not what we want; skip all of the glyphs that came from it. */ - do - glyph += incr; while ((row->reversed_p ? glyph > stop : glyph < stop) - && EQ (glyph->object, str)); + && EQ (glyph->object, str)) + glyph += incr; } else glyph += incr; @@ -15333,10 +15461,12 @@ row_containing_pos (struct window *w, EMACS_INT charpos, { struct glyph *g; - if (NILP (XBUFFER (w->buffer)->bidi_display_reordering)) + if (NILP (XBUFFER (w->buffer)->bidi_display_reordering) + || (!best_row && !row->continued_p)) return row; /* In bidi-reordered rows, there could be several rows - occluding point. We need to find the one which fits + occluding point, all of them belonging to the same + continued line. We need to find the row which fits CHARPOS the best. */ for (g = row->glyphs[TEXT_AREA]; g < row->glyphs[TEXT_AREA] + row->used[TEXT_AREA]; @@ -15348,11 +15478,14 @@ row_containing_pos (struct window *w, EMACS_INT charpos, { mindif = eabs (g->charpos - charpos); best_row = row; + /* Exact match always wins. */ + if (mindif == 0) + return best_row; } } } } - else if (best_row) + else if (best_row && !row->continued_p) return best_row; ++row; } @@ -15897,6 +16030,9 @@ try_window_id (struct window *w) + (WINDOW_WANTS_HEADER_LINE_P (w) ? 1 : 0) + window_internal_height (w)); +#if defined (HAVE_GPM) || defined (MSDOS) + x_clear_window_mouse_face (w); +#endif /* Perform the operation on the screen. */ if (dvpos > 0) { @@ -20651,6 +20787,42 @@ fill_gstring_glyph_string (struct glyph_string *s, int face_id, } +/* Fill glyph string S from a sequence glyphs for glyphless characters. + See the comment of fill_glyph_string for arguments. + Value is the index of the first glyph not in S. */ + + +static int +fill_glyphless_glyph_string (struct glyph_string *s, int face_id, + int start, int end, int overlaps) +{ + struct glyph *glyph, *last; + int voffset; + + xassert (s->first_glyph->type == GLYPHLESS_GLYPH); + s->for_overlaps = overlaps; + glyph = s->row->glyphs[s->area] + start; + last = s->row->glyphs[s->area] + end; + voffset = glyph->voffset; + s->face = FACE_FROM_ID (s->f, face_id); + s->font = s->face->font; + s->nchars = 1; + s->width = glyph->pixel_width; + glyph++; + while (glyph < last + && glyph->type == GLYPHLESS_GLYPH + && glyph->voffset == voffset + && glyph->face_id == face_id) + { + s->nchars++; + s->width += glyph->pixel_width; + glyph++; + } + s->ybase += voffset; + return glyph - s->row->glyphs[s->area]; +} + + /* Fill glyph string S from a sequence of character glyphs. FACE_ID is the face id of the string. START is the index of the @@ -21161,6 +21333,28 @@ compute_overhangs_and_x (struct glyph_string *s, int x, int backward_p) } while (0) +/* Add a glyph string for a sequence of glyphless character's glyphs + to the list of strings between HEAD and TAIL. The meanings of + arguments are the same as those of BUILD_CHAR_GLYPH_STRINGS. */ + +#define BUILD_GLYPHLESS_GLYPH_STRING(START, END, HEAD, TAIL, HL, X, LAST_X) \ + do \ + { \ + int face_id; \ + XChar2b *char2b; \ + \ + face_id = (row)->glyphs[area][START].face_id; \ + \ + s = (struct glyph_string *) alloca (sizeof *s); \ + INIT_GLYPH_STRING (s, NULL, w, row, area, START, HL); \ + append_glyph_string (&HEAD, &TAIL, s); \ + s->x = (X); \ + START = fill_glyphless_glyph_string (s, face_id, START, END, \ + overlaps); \ + } \ + while (0) + + /* Build a list of glyph strings between HEAD and TAIL for the glyphs of AREA of glyph row ROW on window W between indices START and END. HL overrides the face for drawing glyph strings, e.g. it is @@ -21184,7 +21378,7 @@ compute_overhangs_and_x (struct glyph_string *s, int x, int backward_p) BUILD_CHAR_GLYPH_STRINGS (START, END, HEAD, TAIL, \ HL, X, LAST_X); \ break; \ - \ + \ case COMPOSITE_GLYPH: \ if (first_glyph->u.cmp.automatic) \ BUILD_GSTRING_GLYPH_STRING (START, END, HEAD, TAIL, \ @@ -21193,21 +21387,26 @@ compute_overhangs_and_x (struct glyph_string *s, int x, int backward_p) BUILD_COMPOSITE_GLYPH_STRING (START, END, HEAD, TAIL, \ HL, X, LAST_X); \ break; \ - \ + \ case STRETCH_GLYPH: \ BUILD_STRETCH_GLYPH_STRING (START, END, HEAD, TAIL, \ HL, X, LAST_X); \ break; \ - \ + \ case IMAGE_GLYPH: \ BUILD_IMAGE_GLYPH_STRING (START, END, HEAD, TAIL, \ HL, X, LAST_X); \ break; \ - \ + \ + case GLYPHLESS_GLYPH: \ + BUILD_GLYPHLESS_GLYPH_STRING (START, END, HEAD, TAIL, \ + HL, X, LAST_X); \ + break; \ + \ default: \ abort (); \ } \ - \ + \ if (s) \ { \ set_glyph_string_background_width (s, START, LAST_X); \ @@ -21291,7 +21490,7 @@ draw_glyphs (struct window *w, int x, struct glyph_row *row, if (head && !overlaps && row->contains_overlapping_glyphs_p) { struct glyph_string *h, *t; - Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f); + Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f); int mouse_beg_col, mouse_end_col, check_mouse_face = 0; int dummy_x = 0; @@ -21301,16 +21500,16 @@ draw_glyphs (struct window *w, int x, struct glyph_row *row, { struct glyph_row *mouse_beg_row, *mouse_end_row; - mouse_beg_row = MATRIX_ROW (w->current_matrix, dpyinfo->mouse_face_beg_row); - mouse_end_row = MATRIX_ROW (w->current_matrix, dpyinfo->mouse_face_end_row); + mouse_beg_row = MATRIX_ROW (w->current_matrix, hlinfo->mouse_face_beg_row); + mouse_end_row = MATRIX_ROW (w->current_matrix, hlinfo->mouse_face_end_row); if (row >= mouse_beg_row && row <= mouse_end_row) { check_mouse_face = 1; mouse_beg_col = (row == mouse_beg_row) - ? dpyinfo->mouse_face_beg_col : 0; + ? hlinfo->mouse_face_beg_col : 0; mouse_end_col = (row == mouse_end_row) - ? dpyinfo->mouse_face_end_col + ? hlinfo->mouse_face_end_col : row->used[TEXT_AREA]; } } @@ -22103,6 +22302,229 @@ calc_line_height_property (struct it *it, Lisp_Object val, struct font *font, } +/* Append a glyph for a glyphless character to IT->glyph_row. FACE_ID + is a face ID to be used for the glyph. FOR_NO_FONT is nonzero if + and only if this is for a character for which no font was found. + + If the display method (it->glyphless_method) is + GLYPHLESS_DISPLAY_ACRONYM or GLYPHLESS_DISPLAY_HEX_CODE, LEN is a + length of the acronym or the hexadecimal string, UPPER_XOFF and + UPPER_YOFF are pixel offsets for the upper part of the string, + LOWER_XOFF and LOWER_YOFF are for the lower part. + + For the other display methods, LEN through LOWER_YOFF are zero. */ + +static void +append_glyphless_glyph (struct it *it, int face_id, int for_no_font, int len, + short upper_xoff, short upper_yoff, + short lower_xoff, short lower_yoff) +{ + struct glyph *glyph; + enum glyph_row_area area = it->area; + + glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area]; + if (glyph < it->glyph_row->glyphs[area + 1]) + { + /* If the glyph row is reversed, we need to prepend the glyph + rather than append it. */ + if (it->glyph_row->reversed_p && area == TEXT_AREA) + { + struct glyph *g; + + /* Make room for the additional glyph. */ + for (g = glyph - 1; g >= it->glyph_row->glyphs[area]; g--) + g[1] = *g; + glyph = it->glyph_row->glyphs[area]; + } + glyph->charpos = CHARPOS (it->position); + glyph->object = it->object; + glyph->pixel_width = it->pixel_width; + glyph->ascent = it->ascent; + glyph->descent = it->descent; + glyph->voffset = it->voffset; + glyph->type = GLYPHLESS_GLYPH; + glyph->u.glyphless.method = it->glyphless_method; + glyph->u.glyphless.for_no_font = for_no_font; + glyph->u.glyphless.len = len; + glyph->u.glyphless.ch = it->c; + glyph->slice.glyphless.upper_xoff = upper_xoff; + glyph->slice.glyphless.upper_yoff = upper_yoff; + glyph->slice.glyphless.lower_xoff = lower_xoff; + glyph->slice.glyphless.lower_yoff = lower_yoff; + glyph->avoid_cursor_p = it->avoid_cursor_p; + glyph->multibyte_p = it->multibyte_p; + glyph->left_box_line_p = it->start_of_box_run_p; + glyph->right_box_line_p = it->end_of_box_run_p; + glyph->overlaps_vertically_p = (it->phys_ascent > it->ascent + || it->phys_descent > it->descent); + glyph->padding_p = 0; + glyph->glyph_not_available_p = 0; + glyph->face_id = face_id; + glyph->font_type = FONT_TYPE_UNKNOWN; + if (it->bidi_p) + { + glyph->resolved_level = it->bidi_it.resolved_level; + if ((it->bidi_it.type & 7) != it->bidi_it.type) + abort (); + glyph->bidi_type = it->bidi_it.type; + } + ++it->glyph_row->used[area]; + } + else + IT_EXPAND_MATRIX_WIDTH (it, area); +} + + +/* Produce a glyph for a glyphless character for iterator IT. + IT->glyphless_method specifies which method to use for displaying + the character. See the description of enum + glyphless_display_method in dispextern.h for the detail. + + FOR_NO_FONT is nonzero if and only if this is for a character for + which no font was found. ACRONYM, if non-nil, is an acronym string + for the character. */ + +static void +produce_glyphless_glyph (struct it *it, int for_no_font, Lisp_Object acronym) +{ + int face_id; + struct face *face; + struct font *font; + int base_width, base_height, width, height; + short upper_xoff, upper_yoff, lower_xoff, lower_yoff; + int len; + + /* Get the metrics of the base font. We always refer to the current + ASCII face. */ + face = FACE_FROM_ID (it->f, it->face_id)->ascii_face; + font = face->font ? face->font : FRAME_FONT (it->f); + it->ascent = FONT_BASE (font) + font->baseline_offset; + it->descent = FONT_DESCENT (font) - font->baseline_offset; + base_height = it->ascent + it->descent; + base_width = font->average_width; + + /* Get a face ID for the glyph by utilizing a cache (the same way as + doen for `escape-glyph' in get_next_display_element). */ + if (it->f == last_glyphless_glyph_frame + && it->face_id == last_glyphless_glyph_face_id) + { + face_id = last_glyphless_glyph_merged_face_id; + } + else + { + /* Merge the `glyphless-char' face into the current face. */ + face_id = merge_faces (it->f, Qglyphless_char, 0, it->face_id); + last_glyphless_glyph_frame = it->f; + last_glyphless_glyph_face_id = it->face_id; + last_glyphless_glyph_merged_face_id = face_id; + } + + if (it->glyphless_method == GLYPHLESS_DISPLAY_THIN_SPACE) + { + it->pixel_width = THIN_SPACE_WIDTH; + len = 0; + upper_xoff = upper_yoff = lower_xoff = lower_yoff = 0; + } + else if (it->glyphless_method == GLYPHLESS_DISPLAY_EMPTY_BOX) + { + width = CHAR_WIDTH (it->c); + if (width == 0) + width = 1; + else if (width > 4) + width = 4; + it->pixel_width = base_width * width; + len = 0; + upper_xoff = upper_yoff = lower_xoff = lower_yoff = 0; + } + else + { + char buf[7], *str; + unsigned int code[6]; + int upper_len; + int ascent, descent; + struct font_metrics metrics_upper, metrics_lower; + + face = FACE_FROM_ID (it->f, face_id); + font = face->font ? face->font : FRAME_FONT (it->f); + PREPARE_FACE_FOR_DISPLAY (it->f, face); + + if (it->glyphless_method == GLYPHLESS_DISPLAY_ACRONYM) + { + if (! STRINGP (acronym) && CHAR_TABLE_P (Vglyphless_char_display)) + acronym = CHAR_TABLE_REF (Vglyphless_char_display, it->c); + str = STRINGP (acronym) ? (char *) SDATA (acronym) : ""; + } + else + { + xassert (it->glyphless_method == GLYPHLESS_DISPLAY_HEX_CODE); + sprintf (buf, "%0*X", it->c < 0x10000 ? 4 : 6, it->c); + str = buf; + } + for (len = 0; str[len] && ASCII_BYTE_P (str[len]); len++) + code[len] = font->driver->encode_char (font, str[len]); + upper_len = (len + 1) / 2; + font->driver->text_extents (font, code, upper_len, + &metrics_upper); + font->driver->text_extents (font, code + upper_len, len - upper_len, + &metrics_lower); + + + + /* +4 is for vertical bars of a box plus 1-pixel spaces at both side. */ + width = max (metrics_upper.width, metrics_lower.width) + 4; + upper_xoff = upper_yoff = 2; /* the typical case */ + if (base_width >= width) + { + /* Align the upper to the left, the lower to the right. */ + it->pixel_width = base_width; + lower_xoff = base_width - 2 - metrics_lower.width; + } + else + { + /* Center the shorter one. */ + it->pixel_width = width; + if (metrics_upper.width >= metrics_lower.width) + lower_xoff = (width - metrics_lower.width) / 2; + else + upper_xoff = (width - metrics_upper.width) / 2; + } + + /* +5 is for horizontal bars of a box plus 1-pixel spaces at + top, bottom, and between upper and lower strings. */ + height = (metrics_upper.ascent + metrics_upper.descent + + metrics_lower.ascent + metrics_lower.descent) + 5; + /* Center vertically. + H:base_height, D:base_descent + h:height, ld:lower_descent, la:lower_ascent, ud:upper_descent + + ascent = - (D - H/2 - h/2 + 1); "+ 1" for rounding up + descent = D - H/2 + h/2; + lower_yoff = descent - 2 - ld; + upper_yoff = lower_yoff - la - 1 - ud; */ + ascent = - (it->descent - (base_height + height + 1) / 2); + descent = it->descent - (base_height - height) / 2; + lower_yoff = descent - 2 - metrics_lower.descent; + upper_yoff = (lower_yoff - metrics_lower.ascent - 1 + - metrics_upper.descent); + /* Don't make the height shorter than the base height. */ + if (height > base_height) + { + it->ascent = ascent; + it->descent = descent; + } + } + + it->phys_ascent = it->ascent; + it->phys_descent = it->descent; + if (it->glyph_row) + append_glyphless_glyph (it, face_id, for_no_font, len, + upper_xoff, upper_yoff, + lower_xoff, lower_yoff); + it->nglyphs = 1; + take_vertical_position_into_account (it); +} + + /* RIF: Produce glyphs/get display metrics for the display element IT is loaded with. See the description of struct it in dispextern.h @@ -22120,29 +22542,25 @@ x_produce_glyphs (struct it *it) XChar2b char2b; struct face *face = FACE_FROM_ID (it->f, it->face_id); struct font *font = face->font; - int font_not_found_p = font == NULL; struct font_metrics *pcm = NULL; int boff; /* baseline offset */ - if (font_not_found_p) - { - /* When no suitable font found, display an empty box based - on the metrics of the font of the default face (or what - remapped). */ - struct face *no_font_face - = FACE_FROM_ID (it->f, - NILP (Vface_remapping_alist) ? DEFAULT_FACE_ID - : lookup_basic_face (it->f, DEFAULT_FACE_ID)); - font = no_font_face->font; - boff = font->baseline_offset; - } - else + if (font == NULL) { - boff = font->baseline_offset; - if (font->vertical_centering) - boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff; + /* When no suitable font is found, display this character by + the method specified in the first extra slot of + Vglyphless_char_display. */ + Lisp_Object acronym = lookup_glyphless_char_display (-1, it); + + xassert (it->what == IT_GLYPHLESS); + produce_glyphless_glyph (it, 1, STRINGP (acronym) ? acronym : Qnil); + goto done; } + boff = font->baseline_offset; + if (font->vertical_centering) + boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff; + if (it->char_to_display != '\n' && it->char_to_display != '\t') { int stretched_p; @@ -22161,8 +22579,7 @@ x_produce_glyphs (struct it *it) it->descent = FONT_DESCENT (font) - boff; } - if (! font_not_found_p - && get_char_glyph_code (it->char_to_display, font, &char2b)) + if (get_char_glyph_code (it->char_to_display, font, &char2b)) { pcm = get_per_char_metric (it->f, font, &char2b); if (pcm->width == 0 @@ -22752,11 +23169,14 @@ x_produce_glyphs (struct it *it) if (it->glyph_row) append_composite_glyph (it); } + else if (it->what == IT_GLYPHLESS) + produce_glyphless_glyph (it, 0, Qnil); else if (it->what == IT_IMAGE) produce_image_glyph (it); else if (it->what == IT_STRETCH) produce_stretch_glyph (it); + done: /* Accumulate dimensions. Note: can't assume that it->descent > 0 because this isn't true for images with `:ascent 100'. */ xassert (it->ascent >= 0 && it->descent >= 0); @@ -23028,6 +23448,8 @@ set_frame_cursor_types (struct frame *f, Lisp_Object arg) } +#ifdef HAVE_WINDOW_SYSTEM + /* Return the cursor we want to be displayed in window W. Return width of bar/hbar cursor through WIDTH arg. Return with ACTIVE_CURSOR arg set to 1 if cursor in window W is `active' @@ -23073,10 +23495,7 @@ get_window_cursor_type (struct window *w, struct glyph *glyph, int *width, /* Detect a nonselected window or nonselected frame. */ else if (w != XWINDOW (f->selected_window) -#ifdef HAVE_WINDOW_SYSTEM - || f != FRAME_X_DISPLAY_INFO (f)->x_highlight_frame -#endif - ) + || f != FRAME_X_DISPLAY_INFO (f)->x_highlight_frame) { *active_cursor = 0; @@ -23117,7 +23536,6 @@ get_window_cursor_type (struct window *w, struct glyph *glyph, int *width, /* Use normal cursor if not blinked off. */ if (!w->cursor_off_p) { -#ifdef HAVE_WINDOW_SYSTEM if (glyph != NULL && glyph->type == IMAGE_GLYPH) { if (cursor_type == FILLED_BOX_CURSOR) @@ -23145,7 +23563,6 @@ get_window_cursor_type (struct window *w, struct glyph *glyph, int *width, cursor_type = HOLLOW_BOX_CURSOR; } } -#endif return cursor_type; } @@ -23187,8 +23604,6 @@ get_window_cursor_type (struct window *w, struct glyph *glyph, int *width, } -#ifdef HAVE_WINDOW_SYSTEM - /* Notice when the text cursor of window W has been completely overwritten by a drawing operation that outputs glyphs in AREA starting at X0 and ending at X1 in the line starting at Y0 and @@ -23354,7 +23769,7 @@ void erase_phys_cursor (struct window *w) { struct frame *f = XFRAME (w->frame); - Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f); + Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f); int hpos = w->phys_cursor.hpos; int vpos = w->phys_cursor.vpos; int mouse_face_here_p = 0; @@ -23410,14 +23825,8 @@ erase_phys_cursor (struct window *w) /* If the cursor is in the mouse face area, redisplay that when we clear the cursor. */ - if (! NILP (dpyinfo->mouse_face_window) - && w == XWINDOW (dpyinfo->mouse_face_window) - && (vpos > dpyinfo->mouse_face_beg_row - || (vpos == dpyinfo->mouse_face_beg_row - && hpos >= dpyinfo->mouse_face_beg_col)) - && (vpos < dpyinfo->mouse_face_end_row - || (vpos == dpyinfo->mouse_face_end_row - && hpos < dpyinfo->mouse_face_end_col)) + if (! NILP (hlinfo->mouse_face_window) + && coords_in_mouse_face_p (w, hpos, vpos) /* Don't redraw the cursor's spot in mouse face if it is at the end of a line (on a newline). The cursor appears there, but mouse highlighting does not. */ @@ -23608,30 +24017,50 @@ x_clear_cursor (struct window *w) update_window_cursor (w, 0); } +#endif /* HAVE_WINDOW_SYSTEM */ + +/* Implementation of draw_row_with_mouse_face for GUI sessions, GPM, + and MSDOS. */ +void +draw_row_with_mouse_face (struct window *w, int start_x, struct glyph_row *row, + int start_hpos, int end_hpos, + enum draw_glyphs_face draw) +{ +#ifdef HAVE_WINDOW_SYSTEM + if (FRAME_WINDOW_P (XFRAME (w->frame))) + { + draw_glyphs (w, start_x, row, TEXT_AREA, start_hpos, end_hpos, draw, 0); + return; + } +#endif +#if defined (HAVE_GPM) || defined (MSDOS) + tty_draw_row_with_mouse_face (w, row, start_hpos, end_hpos, draw); +#endif +} /* EXPORT: Display the active region described by mouse_face_* according to DRAW. */ void -show_mouse_face (Display_Info *dpyinfo, enum draw_glyphs_face draw) +show_mouse_face (Mouse_HLInfo *hlinfo, enum draw_glyphs_face draw) { - struct window *w = XWINDOW (dpyinfo->mouse_face_window); + struct window *w = XWINDOW (hlinfo->mouse_face_window); struct frame *f = XFRAME (WINDOW_FRAME (w)); if (/* If window is in the process of being destroyed, don't bother to do anything. */ w->current_matrix != NULL /* Don't update mouse highlight if hidden */ - && (draw != DRAW_MOUSE_FACE || !dpyinfo->mouse_face_hidden) + && (draw != DRAW_MOUSE_FACE || !hlinfo->mouse_face_hidden) /* Recognize when we are called to operate on rows that don't exist anymore. This can happen when a window is split. */ - && dpyinfo->mouse_face_end_row < w->current_matrix->nrows) + && hlinfo->mouse_face_end_row < w->current_matrix->nrows) { int phys_cursor_on_p = w->phys_cursor_on_p; struct glyph_row *row, *first, *last; - first = MATRIX_ROW (w->current_matrix, dpyinfo->mouse_face_beg_row); - last = MATRIX_ROW (w->current_matrix, dpyinfo->mouse_face_end_row); + first = MATRIX_ROW (w->current_matrix, hlinfo->mouse_face_beg_row); + last = MATRIX_ROW (w->current_matrix, hlinfo->mouse_face_end_row); for (row = first; row <= last && row->enabled_p; ++row) { @@ -23640,8 +24069,30 @@ show_mouse_face (Display_Info *dpyinfo, enum draw_glyphs_face draw) /* For all but the first row, the highlight starts at column 0. */ if (row == first) { - start_hpos = dpyinfo->mouse_face_beg_col; - start_x = dpyinfo->mouse_face_beg_x; + /* R2L rows have BEG and END in reversed order, but the + screen drawing geometry is always left to right. So + we need to mirror the beginning and end of the + highlighted area in R2L rows. */ + if (!row->reversed_p) + { + start_hpos = hlinfo->mouse_face_beg_col; + start_x = hlinfo->mouse_face_beg_x; + } + else if (row == last) + { + start_hpos = hlinfo->mouse_face_end_col; + start_x = hlinfo->mouse_face_end_x; + } + else + { + start_hpos = 0; + start_x = 0; + } + } + else if (row->reversed_p && row == last) + { + start_hpos = hlinfo->mouse_face_end_col; + start_x = hlinfo->mouse_face_end_x; } else { @@ -23650,7 +24101,20 @@ show_mouse_face (Display_Info *dpyinfo, enum draw_glyphs_face draw) } if (row == last) - end_hpos = dpyinfo->mouse_face_end_col; + { + if (!row->reversed_p) + end_hpos = hlinfo->mouse_face_end_col; + else if (row == first) + end_hpos = hlinfo->mouse_face_beg_col; + else + { + end_hpos = row->used[TEXT_AREA]; + if (draw == DRAW_NORMAL_TEXT) + row->fill_line_p = 1; /* Clear to end of line */ + } + } + else if (row->reversed_p && row == first) + end_hpos = hlinfo->mouse_face_beg_col; else { end_hpos = row->used[TEXT_AREA]; @@ -23660,18 +24124,19 @@ show_mouse_face (Display_Info *dpyinfo, enum draw_glyphs_face draw) if (end_hpos > start_hpos) { - draw_glyphs (w, start_x, row, TEXT_AREA, - start_hpos, end_hpos, - draw, 0); + draw_row_with_mouse_face (w, start_x, row, + start_hpos, end_hpos, draw); row->mouse_face_p = draw == DRAW_MOUSE_FACE || draw == DRAW_IMAGE_RAISED; } } +#ifdef HAVE_WINDOW_SYSTEM /* When we've written over the cursor, arrange for it to be displayed again. */ - if (phys_cursor_on_p && !w->phys_cursor_on_p) + if (FRAME_WINDOW_P (f) + && phys_cursor_on_p && !w->phys_cursor_on_p) { BLOCK_INPUT; display_and_set_cursor (w, 1, @@ -23679,15 +24144,22 @@ show_mouse_face (Display_Info *dpyinfo, enum draw_glyphs_face draw) w->phys_cursor.x, w->phys_cursor.y); UNBLOCK_INPUT; } +#endif /* HAVE_WINDOW_SYSTEM */ } +#ifdef HAVE_WINDOW_SYSTEM /* Change the mouse cursor. */ - if (draw == DRAW_NORMAL_TEXT && !EQ (dpyinfo->mouse_face_window, f->tool_bar_window)) - FRAME_RIF (f)->define_frame_cursor (f, FRAME_X_OUTPUT (f)->text_cursor); - else if (draw == DRAW_MOUSE_FACE) - FRAME_RIF (f)->define_frame_cursor (f, FRAME_X_OUTPUT (f)->hand_cursor); - else - FRAME_RIF (f)->define_frame_cursor (f, FRAME_X_OUTPUT (f)->nontext_cursor); + if (FRAME_WINDOW_P (f)) + { + if (draw == DRAW_NORMAL_TEXT + && !EQ (hlinfo->mouse_face_window, f->tool_bar_window)) + FRAME_RIF (f)->define_frame_cursor (f, FRAME_X_OUTPUT (f)->text_cursor); + else if (draw == DRAW_MOUSE_FACE) + FRAME_RIF (f)->define_frame_cursor (f, FRAME_X_OUTPUT (f)->hand_cursor); + else + FRAME_RIF (f)->define_frame_cursor (f, FRAME_X_OUTPUT (f)->nontext_cursor); + } +#endif /* HAVE_WINDOW_SYSTEM */ } /* EXPORT: @@ -23696,23 +24168,70 @@ show_mouse_face (Display_Info *dpyinfo, enum draw_glyphs_face draw) face was actually drawn unhighlighted. */ int -clear_mouse_face (Display_Info *dpyinfo) +clear_mouse_face (Mouse_HLInfo *hlinfo) { int cleared = 0; - if (!dpyinfo->mouse_face_hidden && !NILP (dpyinfo->mouse_face_window)) + if (!hlinfo->mouse_face_hidden && !NILP (hlinfo->mouse_face_window)) { - show_mouse_face (dpyinfo, DRAW_NORMAL_TEXT); + show_mouse_face (hlinfo, DRAW_NORMAL_TEXT); cleared = 1; } - dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1; - dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1; - dpyinfo->mouse_face_window = Qnil; - dpyinfo->mouse_face_overlay = Qnil; + hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1; + hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1; + hlinfo->mouse_face_window = Qnil; + hlinfo->mouse_face_overlay = Qnil; return cleared; } +/* Return non-zero if the coordinates HPOS and VPOS on windows W are + within the mouse face on that window. */ +static int +coords_in_mouse_face_p (struct window *w, int hpos, int vpos) +{ + Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (XFRAME (w->frame)); + + /* Quickly resolve the easy cases. */ + if (!(WINDOWP (hlinfo->mouse_face_window) + && XWINDOW (hlinfo->mouse_face_window) == w)) + return 0; + if (vpos < hlinfo->mouse_face_beg_row + || vpos > hlinfo->mouse_face_end_row) + return 0; + if (vpos > hlinfo->mouse_face_beg_row + && vpos < hlinfo->mouse_face_end_row) + return 1; + + if (!MATRIX_ROW (w->current_matrix, vpos)->reversed_p) + { + if (hlinfo->mouse_face_beg_row == hlinfo->mouse_face_end_row) + { + if (hlinfo->mouse_face_beg_col <= hpos && hpos < hlinfo->mouse_face_end_col) + return 1; + } + else if ((vpos == hlinfo->mouse_face_beg_row + && hpos >= hlinfo->mouse_face_beg_col) + || (vpos == hlinfo->mouse_face_end_row + && hpos < hlinfo->mouse_face_end_col)) + return 1; + } + else + { + if (hlinfo->mouse_face_beg_row == hlinfo->mouse_face_end_row) + { + if (hlinfo->mouse_face_end_col < hpos && hpos <= hlinfo->mouse_face_beg_col) + return 1; + } + else if ((vpos == hlinfo->mouse_face_beg_row + && hpos <= hlinfo->mouse_face_beg_col) + || (vpos == hlinfo->mouse_face_end_row + && hpos > hlinfo->mouse_face_end_col)) + return 1; + } + return 0; +} + /* EXPORT: Non-zero if physical cursor of window W is within mouse face. */ @@ -23720,32 +24239,135 @@ clear_mouse_face (Display_Info *dpyinfo) int cursor_in_mouse_face_p (struct window *w) { - Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (XFRAME (w->frame)); - int in_mouse_face = 0; + return coords_in_mouse_face_p (w, w->phys_cursor.hpos, w->phys_cursor.vpos); +} - if (WINDOWP (dpyinfo->mouse_face_window) - && XWINDOW (dpyinfo->mouse_face_window) == w) - { - int hpos = w->phys_cursor.hpos; - int vpos = w->phys_cursor.vpos; - if (vpos >= dpyinfo->mouse_face_beg_row - && vpos <= dpyinfo->mouse_face_end_row - && (vpos > dpyinfo->mouse_face_beg_row - || hpos >= dpyinfo->mouse_face_beg_col) - && (vpos < dpyinfo->mouse_face_end_row - || hpos < dpyinfo->mouse_face_end_col - || dpyinfo->mouse_face_past_end)) - in_mouse_face = 1; - } + +/* Find the glyph rows START_ROW and END_ROW of window W that display + characters between buffer positions START_CHARPOS and END_CHARPOS + (excluding END_CHARPOS). This is similar to row_containing_pos, + but is more accurate when bidi reordering makes buffer positions + change non-linearly with glyph rows. */ +static void +rows_from_pos_range (struct window *w, + EMACS_INT start_charpos, EMACS_INT end_charpos, + struct glyph_row **start, struct glyph_row **end) +{ + struct glyph_row *first = MATRIX_FIRST_TEXT_ROW (w->current_matrix); + int last_y = window_text_bottom_y (w); + struct glyph_row *row; - return in_mouse_face; -} + *start = NULL; + *end = NULL; + + while (!first->enabled_p + && first < MATRIX_BOTTOM_TEXT_ROW (w->current_matrix, w)) + first++; + + /* Find the START row. */ + for (row = first; + row->enabled_p && MATRIX_ROW_BOTTOM_Y (row) <= last_y; + row++) + { + /* A row can potentially be the START row if the range of the + characters it displays intersects the range + [START_CHARPOS..END_CHARPOS). */ + if (! ((start_charpos < MATRIX_ROW_START_CHARPOS (row) + && end_charpos < MATRIX_ROW_START_CHARPOS (row)) + /* See the commentary in row_containing_pos, for the + explanation of the complicated way to check whether + some position is beyond the end of the characters + displayed by a row. */ + || ((start_charpos > MATRIX_ROW_END_CHARPOS (row) + || (start_charpos == MATRIX_ROW_END_CHARPOS (row) + && !row->ends_at_zv_p + && !MATRIX_ROW_ENDS_IN_MIDDLE_OF_CHAR_P (row))) + && (end_charpos > MATRIX_ROW_END_CHARPOS (row) + || (end_charpos == MATRIX_ROW_END_CHARPOS (row) + && !row->ends_at_zv_p + && !MATRIX_ROW_ENDS_IN_MIDDLE_OF_CHAR_P (row)))))) + { + /* Found a candidate row. Now make sure at least one of the + glyphs it displays has a charpos from the range + [START_CHARPOS..END_CHARPOS). + + This is not obvious because bidi reordering could make + buffer positions of a row be 1,2,3,102,101,100, and if we + want to highlight characters in [50..60), we don't want + this row, even though [50..60) does intersect [1..103), + the range of character positions given by the row's start + and end positions. */ + struct glyph *g = row->glyphs[TEXT_AREA]; + struct glyph *e = g + row->used[TEXT_AREA]; + + while (g < e) + { + if (BUFFERP (g->object) + && start_charpos <= g->charpos && g->charpos < end_charpos) + *start = row; + g++; + } + if (*start) + break; + } + } + /* Find the END row. */ + if (!*start + /* If the last row is partially visible, start looking for END + from that row, instead of starting from FIRST. */ + && !(row->enabled_p + && row->y < last_y && MATRIX_ROW_BOTTOM_Y (row) > last_y)) + row = first; + for ( ; row->enabled_p && MATRIX_ROW_BOTTOM_Y (row) <= last_y; row++) + { + struct glyph_row *next = row + 1; + + if (!next->enabled_p + || next >= MATRIX_BOTTOM_TEXT_ROW (w->current_matrix, w) + /* The first row >= START whose range of displayed characters + does NOT intersect the range [START_CHARPOS..END_CHARPOS] + is the row END + 1. */ + || (start_charpos < MATRIX_ROW_START_CHARPOS (next) + && end_charpos < MATRIX_ROW_START_CHARPOS (next)) + || ((start_charpos > MATRIX_ROW_END_CHARPOS (next) + || (start_charpos == MATRIX_ROW_END_CHARPOS (next) + && !next->ends_at_zv_p + && !MATRIX_ROW_ENDS_IN_MIDDLE_OF_CHAR_P (next))) + && (end_charpos > MATRIX_ROW_END_CHARPOS (next) + || (end_charpos == MATRIX_ROW_END_CHARPOS (next) + && !next->ends_at_zv_p + && !MATRIX_ROW_ENDS_IN_MIDDLE_OF_CHAR_P (next))))) + { + *end = row; + break; + } + else + { + /* If the next row's edges intersect [START_CHARPOS..END_CHARPOS], + but none of the characters it displays are in the range, it is + also END + 1. */ + struct glyph *g = next->glyphs[TEXT_AREA]; + struct glyph *e = g + next->used[TEXT_AREA]; + while (g < e) + { + if (BUFFERP (g->object) + && start_charpos <= g->charpos && g->charpos < end_charpos) + break; + g++; + } + if (g == e) + { + *end = row; + break; + } + } + } +} - -/* This function sets the mouse_face_* elements of DPYINFO, assuming +/* This function sets the mouse_face_* elements of HLINFO, assuming the mouse cursor is on a glyph with buffer charpos MOUSE_CHARPOS in window WINDOW. START_CHARPOS and END_CHARPOS are buffer positions for the overlay or run of text properties specifying the mouse @@ -23756,7 +24378,7 @@ cursor_in_mouse_face_p (struct window *w) static void mouse_face_from_buffer_pos (Lisp_Object window, - Display_Info *dpyinfo, + Mouse_HLInfo *hlinfo, EMACS_INT mouse_charpos, EMACS_INT start_charpos, EMACS_INT end_charpos, @@ -23766,166 +24388,313 @@ mouse_face_from_buffer_pos (Lisp_Object window, { struct window *w = XWINDOW (window); struct glyph_row *first = MATRIX_FIRST_TEXT_ROW (w->current_matrix); - struct glyph_row *row; + struct glyph_row *r1, *r2; struct glyph *glyph, *end; - EMACS_INT ignore; + EMACS_INT ignore, pos; int x; xassert (NILP (display_string) || STRINGP (display_string)); xassert (NILP (before_string) || STRINGP (before_string)); xassert (NILP (after_string) || STRINGP (after_string)); - /* Find the first highlighted glyph. */ - if (start_charpos < MATRIX_ROW_START_CHARPOS (first)) + /* Find the rows corresponding to START_CHARPOS and END_CHARPOS. */ + rows_from_pos_range (w, start_charpos, end_charpos, &r1, &r2); + if (r1 == NULL) + r1 = MATRIX_ROW (w->current_matrix, XFASTINT (w->window_end_vpos)); + /* If the before-string or display-string contains newlines, + rows_from_pos_range skips to its last row. Move back. */ + if (!NILP (before_string) || !NILP (display_string)) + { + struct glyph_row *prev; + while ((prev = r1 - 1, prev >= first) + && MATRIX_ROW_END_CHARPOS (prev) == start_charpos + && prev->used[TEXT_AREA] > 0) + { + struct glyph *beg = prev->glyphs[TEXT_AREA]; + glyph = beg + prev->used[TEXT_AREA]; + while (--glyph >= beg && INTEGERP (glyph->object)); + if (glyph < beg + || !(EQ (glyph->object, before_string) + || EQ (glyph->object, display_string))) + break; + r1 = prev; + } + } + if (r2 == NULL) { - dpyinfo->mouse_face_beg_col = 0; - 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; + r2 = MATRIX_ROW (w->current_matrix, XFASTINT (w->window_end_vpos)); + hlinfo->mouse_face_past_end = 1; } - else + else if (!NILP (after_string)) { - row = row_containing_pos (w, start_charpos, first, NULL, 0); - if (row == NULL) - row = MATRIX_ROW (w->current_matrix, XFASTINT (w->window_end_vpos)); - - /* 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_row *prev; - while ((prev = row - 1, prev >= first) - && MATRIX_ROW_END_CHARPOS (prev) == start_charpos - && prev->used[TEXT_AREA] > 0) - { - struct glyph *beg = prev->glyphs[TEXT_AREA]; - glyph = beg + prev->used[TEXT_AREA]; - while (--glyph >= beg && INTEGERP (glyph->object)); - if (glyph < beg - || !(EQ (glyph->object, before_string) - || EQ (glyph->object, display_string))) - break; - row = prev; - } - } + /* 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)); - glyph = row->glyphs[TEXT_AREA]; - end = glyph + row->used[TEXT_AREA]; - x = row->x; - dpyinfo->mouse_face_beg_y = row->y; - dpyinfo->mouse_face_beg_row = MATRIX_ROW_VPOS (row, w->current_matrix); + for (next = r2 + 1; + next <= last + && next->used[TEXT_AREA] > 0 + && EQ (next->glyphs[TEXT_AREA]->object, after_string); + ++next) + r2 = next; + } + /* The rest of the display engine assumes that mouse_face_beg_row is + either above below mouse_face_end_row or identical to it. But + with bidi-reordered continued lines, the row for START_CHARPOS + could be below the row for END_CHARPOS. If so, swap the rows and + store them in correct order. */ + if (r1->y > r2->y) + { + struct glyph_row *tem = r2; + + r2 = r1; + r1 = tem; + } + + hlinfo->mouse_face_beg_y = r1->y; + hlinfo->mouse_face_beg_row = MATRIX_ROW_VPOS (r1, w->current_matrix); + hlinfo->mouse_face_end_y = r2->y; + hlinfo->mouse_face_end_row = MATRIX_ROW_VPOS (r2, w->current_matrix); + + /* For a bidi-reordered row, the positions of BEFORE_STRING, + AFTER_STRING, DISPLAY_STRING, START_CHARPOS, and END_CHARPOS + could be anywhere in the row and in any order. The strategy + below is to find the leftmost and the rightmost glyph that + belongs to either of these 3 strings, or whose position is + between START_CHARPOS and END_CHARPOS, and highlight all the + glyphs between those two. This may cover more than just the text + between START_CHARPOS and END_CHARPOS if the range of characters + strides the bidi level boundary, e.g. if the beginning is in R2L + text while the end is in L2R text or vice versa. */ + if (!r1->reversed_p) + { + /* This row is in a left to right paragraph. Scan it left to + right. */ + glyph = r1->glyphs[TEXT_AREA]; + end = glyph + r1->used[TEXT_AREA]; + x = r1->x; /* Skip truncation glyphs at the start of the glyph row. */ - if (row->displays_text_p) + if (r1->displays_text_p) for (; glyph < end && INTEGERP (glyph->object) && glyph->charpos < 0; ++glyph) x += glyph->pixel_width; - /* Scan the glyph row, stopping before BEFORE_STRING or - DISPLAY_STRING or START_CHARPOS. */ + /* Scan the glyph row, looking for BEFORE_STRING, AFTER_STRING, + or DISPLAY_STRING, and the first glyph from buffer whose + position is between START_CHARPOS and END_CHARPOS. */ for (; glyph < end && !INTEGERP (glyph->object) - && !EQ (glyph->object, before_string) && !EQ (glyph->object, display_string) && !(BUFFERP (glyph->object) - && glyph->charpos >= start_charpos); + && (glyph->charpos >= start_charpos + && glyph->charpos < end_charpos)); ++glyph) - x += glyph->pixel_width; - - dpyinfo->mouse_face_beg_x = x; - dpyinfo->mouse_face_beg_col = glyph - row->glyphs[TEXT_AREA]; - } - - /* Find the last highlighted glyph. */ - row = row_containing_pos (w, end_charpos, first, NULL, 0); - if (row == NULL) - { - row = MATRIX_ROW (w->current_matrix, XFASTINT (w->window_end_vpos)); - dpyinfo->mouse_face_past_end = 1; + { + /* BEFORE_STRING or AFTER_STRING are only relevant if they + are present at buffer positions between START_CHARPOS and + END_CHARPOS, or if they come from an overlay. */ + if (EQ (glyph->object, before_string)) + { + pos = string_buffer_position (w, before_string, + start_charpos); + /* If pos == 0, it means before_string came from an + overlay, not from a buffer position. */ + if (!pos || (pos >= start_charpos && pos < end_charpos)) + break; + } + else if (EQ (glyph->object, after_string)) + { + pos = string_buffer_position (w, after_string, end_charpos); + if (!pos || (pos >= start_charpos && pos < end_charpos)) + break; + } + x += glyph->pixel_width; + } + hlinfo->mouse_face_beg_x = x; + hlinfo->mouse_face_beg_col = glyph - r1->glyphs[TEXT_AREA]; } - else if (!NILP (after_string)) + else { - /* 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)); + /* This row is in a right to left paragraph. Scan it right to + left. */ + struct glyph *g; - for (next = row + 1; - next <= last - && next->used[TEXT_AREA] > 0 - && EQ (next->glyphs[TEXT_AREA]->object, after_string); - ++next) - row = next; - } + end = r1->glyphs[TEXT_AREA] - 1; + glyph = end + r1->used[TEXT_AREA]; - 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); + /* Skip truncation glyphs at the start of the glyph row. */ + if (r1->displays_text_p) + for (; glyph > end + && INTEGERP (glyph->object) + && glyph->charpos < 0; + --glyph) + ; - /* Skip truncation glyphs at the start of the row. */ - if (row->displays_text_p) - for (; glyph < end - && INTEGERP (glyph->object) - && glyph->charpos < 0; - ++glyph) - x += glyph->pixel_width; - - /* Scan the glyph row, stopping at END_CHARPOS or when we encounter - 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; + /* Scan the glyph row, looking for BEFORE_STRING, AFTER_STRING, + or DISPLAY_STRING, and the first glyph from buffer whose + position is between START_CHARPOS and END_CHARPOS. */ + for (; glyph > end + && !INTEGERP (glyph->object) + && !EQ (glyph->object, display_string) + && !(BUFFERP (glyph->object) + && (glyph->charpos >= start_charpos + && glyph->charpos < end_charpos)); + --glyph) + { + /* BEFORE_STRING or AFTER_STRING are only relevant if they + are present at buffer positions between START_CHARPOS and + END_CHARPOS, or if they come from an overlay. */ + if (EQ (glyph->object, before_string)) + { + pos = string_buffer_position (w, before_string, start_charpos); + /* If pos == 0, it means before_string came from an + overlay, not from a buffer position. */ + if (!pos || (pos >= start_charpos && pos < end_charpos)) + break; + } + else if (EQ (glyph->object, after_string)) + { + pos = string_buffer_position (w, after_string, end_charpos); + if (!pos || (pos >= start_charpos && pos < end_charpos)) + break; + } + } + + glyph++; /* first glyph to the right of the highlighted area */ + for (g = r1->glyphs[TEXT_AREA], x = r1->x; g < glyph; g++) + x += g->pixel_width; + hlinfo->mouse_face_beg_x = x; + hlinfo->mouse_face_beg_col = glyph - r1->glyphs[TEXT_AREA]; + } - /* If we found AFTER_STRING, consume it and stop. */ - if (EQ (glyph->object, after_string)) + /* If the highlight ends in a different row, compute GLYPH and END + for the end row. Otherwise, reuse the values computed above for + the row where the highlight begins. */ + if (r2 != r1) { - for (; EQ (glyph->object, after_string) && glyph < end; ++glyph) + if (!r2->reversed_p) + { + glyph = r2->glyphs[TEXT_AREA]; + end = glyph + r2->used[TEXT_AREA]; + x = r2->x; + } + else + { + end = r2->glyphs[TEXT_AREA] - 1; + glyph = end + r2->used[TEXT_AREA]; + } + } + + if (!r2->reversed_p) + { + /* Skip truncation and continuation glyphs near the end of the + row, and also blanks and stretch glyphs inserted by + extend_face_to_end_of_line. */ + while (end > glyph + && INTEGERP ((end - 1)->object) + && (end - 1)->charpos <= 0) + --end; + /* Scan the rest of the glyph row from the end, looking for the + first glyph that comes from BEFORE_STRING, AFTER_STRING, or + DISPLAY_STRING, or whose position is between START_CHARPOS + and END_CHARPOS */ + for (--end; + end > glyph + && !INTEGERP (end->object) + && !EQ (end->object, display_string) + && !(BUFFERP (end->object) + && (end->charpos >= start_charpos + && end->charpos < end_charpos)); + --end) + { + /* BEFORE_STRING or AFTER_STRING are only relevant if they + are present at buffer positions between START_CHARPOS and + END_CHARPOS, or if they come from an overlay. */ + if (EQ (end->object, before_string)) + { + pos = string_buffer_position (w, before_string, start_charpos); + if (!pos || (pos >= start_charpos && pos < end_charpos)) + break; + } + else if (EQ (end->object, after_string)) + { + pos = string_buffer_position (w, after_string, end_charpos); + if (!pos || (pos >= start_charpos && pos < end_charpos)) + break; + } + } + /* Find the X coordinate of the last glyph to be highlighted. */ + for (; glyph <= end; ++glyph) x += glyph->pixel_width; + + hlinfo->mouse_face_end_x = x; + hlinfo->mouse_face_end_col = glyph - r2->glyphs[TEXT_AREA]; } else { - /* If there's no after-string, we must check if we overshot, - 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; - EMACS_INT pos; - - while (glyph > row->glyphs[TEXT_AREA]) - { - prev_object = (glyph - 1)->object; - if (!STRINGP (prev_object) || EQ (prev_object, display_string)) - break; - - pos = string_buffer_position (w, prev_object, end_charpos); - if (pos && pos < end_charpos) - break; - - for (; glyph > row->glyphs[TEXT_AREA] - && EQ ((glyph - 1)->object, prev_object); - --glyph) - x -= (glyph - 1)->pixel_width; + /* Skip truncation and continuation glyphs near the end of the + row, and also blanks and stretch glyphs inserted by + extend_face_to_end_of_line. */ + x = r2->x; + end++; + while (end < glyph + && INTEGERP (end->object) + && end->charpos <= 0) + { + x += end->pixel_width; + ++end; + } + /* Scan the rest of the glyph row from the end, looking for the + first glyph that comes from BEFORE_STRING, AFTER_STRING, or + DISPLAY_STRING, or whose position is between START_CHARPOS + and END_CHARPOS */ + for ( ; + end < glyph + && !INTEGERP (end->object) + && !EQ (end->object, display_string) + && !(BUFFERP (end->object) + && (end->charpos >= start_charpos + && end->charpos < end_charpos)); + ++end) + { + /* BEFORE_STRING or AFTER_STRING are only relevant if they + are present at buffer positions between START_CHARPOS and + END_CHARPOS, or if they come from an overlay. */ + if (EQ (end->object, before_string)) + { + pos = string_buffer_position (w, before_string, start_charpos); + if (!pos || (pos >= start_charpos && pos < end_charpos)) + break; + } + else if (EQ (end->object, after_string)) + { + pos = string_buffer_position (w, after_string, end_charpos); + if (!pos || (pos >= start_charpos && pos < end_charpos)) + break; + } + x += end->pixel_width; } + hlinfo->mouse_face_end_x = x; + hlinfo->mouse_face_end_col = end - r2->glyphs[TEXT_AREA]; } - dpyinfo->mouse_face_end_x = x; - dpyinfo->mouse_face_end_col = glyph - row->glyphs[TEXT_AREA]; - dpyinfo->mouse_face_window = window; - dpyinfo->mouse_face_face_id + hlinfo->mouse_face_window = window; + hlinfo->mouse_face_face_id = 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); + !hlinfo->mouse_face_hidden, -1); + show_mouse_face (hlinfo, DRAW_MOUSE_FACE); } +/* The following function is not used anymore (replaced with + mouse_face_from_string_pos), but I leave it here for the time + being, in case someone would. */ + +#if 0 /* not used */ /* Find the position of the glyph for position POS in OBJECT in window W's current matrix, and return in *X, *Y the pixel @@ -24003,7 +24772,132 @@ fast_find_string_pos (struct window *w, EMACS_INT pos, Lisp_Object object, return best_glyph != NULL; } +#endif /* not used */ +/* Find the positions of the first and the last glyphs in window W's + current matrix that occlude positions [STARTPOS..ENDPOS] in OBJECT + (assumed to be a string), and return in HLINFO's mouse_face_* + members the pixel and column/row coordinates of those glyphs. */ + +static void +mouse_face_from_string_pos (struct window *w, Mouse_HLInfo *hlinfo, + Lisp_Object object, + EMACS_INT startpos, EMACS_INT endpos) +{ + int yb = window_text_bottom_y (w); + struct glyph_row *r; + struct glyph *g, *e; + int gx; + int found = 0; + + /* Find the glyph row with at least one position in the range + [STARTPOS..ENDPOS], and the first glyph in that row whose + position belongs to that range. */ + for (r = MATRIX_FIRST_TEXT_ROW (w->current_matrix); + r->enabled_p && r->y < yb; + ++r) + { + if (!r->reversed_p) + { + g = r->glyphs[TEXT_AREA]; + e = g + r->used[TEXT_AREA]; + for (gx = r->x; g < e; gx += g->pixel_width, ++g) + if (EQ (g->object, object) + && startpos <= g->charpos && g->charpos <= endpos) + { + hlinfo->mouse_face_beg_row = r - w->current_matrix->rows; + hlinfo->mouse_face_beg_y = r->y; + hlinfo->mouse_face_beg_col = g - r->glyphs[TEXT_AREA]; + hlinfo->mouse_face_beg_x = gx; + found = 1; + break; + } + } + else + { + struct glyph *g1; + + e = r->glyphs[TEXT_AREA]; + g = e + r->used[TEXT_AREA]; + for ( ; g > e; --g) + if (EQ ((g-1)->object, object) + && startpos <= (g-1)->charpos && (g-1)->charpos <= endpos) + { + hlinfo->mouse_face_beg_row = r - w->current_matrix->rows; + hlinfo->mouse_face_beg_y = r->y; + hlinfo->mouse_face_beg_col = g - r->glyphs[TEXT_AREA]; + for (gx = r->x, g1 = r->glyphs[TEXT_AREA]; g1 < g; ++g1) + gx += g1->pixel_width; + hlinfo->mouse_face_beg_x = gx; + found = 1; + break; + } + } + if (found) + break; + } + + if (!found) + return; + + /* Starting with the next row, look for the first row which does NOT + include any glyphs whose positions are in the range. */ + for (++r; r->enabled_p && r->y < yb; ++r) + { + g = r->glyphs[TEXT_AREA]; + e = g + r->used[TEXT_AREA]; + found = 0; + for ( ; g < e; ++g) + if (EQ (g->object, object) + && startpos <= g->charpos && g->charpos <= endpos) + { + found = 1; + break; + } + if (!found) + break; + } + + /* The highlighted region ends on the previous row. */ + r--; + + /* Set the end row and its vertical pixel coordinate. */ + hlinfo->mouse_face_end_row = r - w->current_matrix->rows; + hlinfo->mouse_face_end_y = r->y; + + /* Compute and set the end column and the end column's horizontal + pixel coordinate. */ + if (!r->reversed_p) + { + g = r->glyphs[TEXT_AREA]; + e = g + r->used[TEXT_AREA]; + for ( ; e > g; --e) + if (EQ ((e-1)->object, object) + && startpos <= (e-1)->charpos && (e-1)->charpos <= endpos) + break; + hlinfo->mouse_face_end_col = e - g; + + for (gx = r->x; g < e; ++g) + gx += g->pixel_width; + hlinfo->mouse_face_end_x = gx; + } + else + { + e = r->glyphs[TEXT_AREA]; + g = e + r->used[TEXT_AREA]; + for (gx = r->x ; e < g; ++e) + { + if (EQ (e->object, object) + && startpos <= e->charpos && e->charpos <= endpos) + break; + gx += e->pixel_width; + } + hlinfo->mouse_face_end_col = e - r->glyphs[TEXT_AREA]; + hlinfo->mouse_face_end_x = gx; + } +} + +#ifdef HAVE_WINDOW_SYSTEM /* See if position X, Y is within a hot-spot of an image. */ @@ -24175,6 +25069,8 @@ define_frame_cursor1 (struct frame *f, Cursor cursor, Lisp_Object pointer) FRAME_RIF (f)->define_frame_cursor (f, cursor); } +#endif /* HAVE_WINDOW_SYSTEM */ + /* Take proper action when mouse has moved to the mode or header line or marginal area AREA of window W, x-position X and y-position Y. X is relative to the start of the text display area of W, so the @@ -24187,8 +25083,11 @@ note_mode_line_or_margin_highlight (Lisp_Object window, int x, int y, { struct window *w = XWINDOW (window); struct frame *f = XFRAME (w->frame); - Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f); - Cursor cursor = FRAME_X_OUTPUT (f)->nontext_cursor; + Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f); +#ifdef HAVE_WINDOW_SYSTEM + Display_Info *dpyinfo; +#endif + Cursor cursor = No_Cursor; Lisp_Object pointer = Qnil; int dx, dy, width, height; EMACS_INT charpos; @@ -24205,6 +25104,8 @@ note_mode_line_or_margin_highlight (Lisp_Object window, int x, int y, 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); @@ -24212,7 +25113,7 @@ note_mode_line_or_margin_highlight (Lisp_Object window, int x, int y, ? MATRIX_MODE_LINE_ROW (w->current_matrix) : MATRIX_HEADER_LINE_ROW (w->current_matrix)); - /* Find glyph */ + /* Find the glyph under the mouse pointer. */ if (row->mode_line_p && row->enabled_p) { glyph = row_start_glyph = row->glyphs[TEXT_AREA]; @@ -24230,12 +25131,15 @@ note_mode_line_or_margin_highlight (Lisp_Object window, int x, int y, 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); } help = Qnil; +#ifdef HAVE_WINDOW_SYSTEM if (IMAGEP (object)) { Lisp_Object image_map, hotspot; @@ -24272,6 +25176,7 @@ note_mode_line_or_margin_highlight (Lisp_Object window, int x, int y, if (NILP (pointer)) pointer = Fplist_get (XCDR (object), QCpointer); } +#endif /* HAVE_WINDOW_SYSTEM */ if (STRINGP (string)) { @@ -24291,19 +25196,27 @@ note_mode_line_or_margin_highlight (Lisp_Object window, int x, int y, } } - if (NILP (pointer)) - pointer = Fget_text_property (pos, Qpointer, string); - - /* Change the mouse pointer according to what is under X/Y. */ - if (NILP (pointer) && ((area == ON_MODE_LINE) || (area == ON_HEADER_LINE))) +#ifdef HAVE_WINDOW_SYSTEM + if (FRAME_WINDOW_P (f)) { - Lisp_Object map; - map = Fget_text_property (pos, Qlocal_map, string); - if (!KEYMAPP (map)) - map = Fget_text_property (pos, Qkeymap, string); - if (!KEYMAPP (map)) - cursor = dpyinfo->vertical_scroll_bar_cursor; + dpyinfo = FRAME_X_DISPLAY_INFO (f); + cursor = FRAME_X_OUTPUT (f)->nontext_cursor; + if (NILP (pointer)) + pointer = Fget_text_property (pos, Qpointer, string); + + /* Change the mouse pointer according to what is under X/Y. */ + if (NILP (pointer) + && ((area == ON_MODE_LINE) || (area == ON_HEADER_LINE))) + { + Lisp_Object map; + map = Fget_text_property (pos, Qlocal_map, string); + if (!KEYMAPP (map)) + map = Fget_text_property (pos, Qkeymap, string); + if (!KEYMAPP (map)) + cursor = dpyinfo->vertical_scroll_bar_cursor; + } } +#endif /* Change the mouse face according to what is under X/Y. */ mouse_face = Fget_text_property (pos, Qmouse_face, string); @@ -24318,102 +25231,128 @@ note_mode_line_or_margin_highlight (Lisp_Object window, int x, int y, 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)); - - /* Calculate the position(glyph position: GPOS) of GLYPH in - displayed string. GPOS is different from CHARPOS. - - CHARPOS is the position of glyph in internal string - object. A mode line string format has structures which - is converted to a flatten by emacs lisp interpreter. - The internal string is an element of the structures. - The displayed string is the flatten 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 lenght(glyph sequence length: GSEQ_LENGTH) of - displayed string holding GLYPH. - - GSEQ_LENGTH is different from SCHARS (STRING). - SCHARS (STRING) 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; - } + endpos = SCHARS (string); + else + endpos = XINT (e); + + /* Calculate the glyph position GPOS of GLYPH in the + 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 + line string format has structures which are converted to + a flattened string by the Emacs Lisp interpreter. The + internal string is an element of those structures. The + displayed string is the flattened string. */ + 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 */ - vpos = (x - gpos); - hpos = (area == ON_MODE_LINE + /* 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 ( EQ (window, dpyinfo->mouse_face_window) - && dpyinfo->mouse_face_beg_col <= vpos - && vpos < dpyinfo->mouse_face_end_col - && dpyinfo->mouse_face_beg_row == hpos ) + /* If GLYPH's position is included in the region that is + already drawn in mouse face, we have nothing to do. */ + if ( EQ (window, hlinfo->mouse_face_window) + && (!row->reversed_p + ? (hlinfo->mouse_face_beg_col <= hpos + && hpos < hlinfo->mouse_face_end_col) + /* In R2L rows we swap BEG and END, see below. */ + : (hlinfo->mouse_face_end_col <= hpos + && hpos < hlinfo->mouse_face_beg_col)) + && hlinfo->mouse_face_beg_row == vpos ) return; - if (clear_mouse_face (dpyinfo)) + if (clear_mouse_face (hlinfo)) cursor = No_Cursor; - dpyinfo->mouse_face_beg_col = vpos; - dpyinfo->mouse_face_beg_row = hpos; - - dpyinfo->mouse_face_beg_x = original_x_pixel - (total_pixel_width + dx); - dpyinfo->mouse_face_beg_y = 0; - - dpyinfo->mouse_face_end_col = vpos + gseq_length; - dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_beg_row; - - dpyinfo->mouse_face_end_x = 0; - dpyinfo->mouse_face_end_y = 0; - - dpyinfo->mouse_face_past_end = 0; - dpyinfo->mouse_face_window = window; + if (!row->reversed_p) + { + hlinfo->mouse_face_beg_col = hpos; + hlinfo->mouse_face_beg_x = original_x_pixel + - (total_pixel_width + dx); + hlinfo->mouse_face_end_col = hpos + gseq_length; + hlinfo->mouse_face_end_x = 0; + } + else + { + /* In R2L rows, show_mouse_face expects BEG and END + coordinates to be swapped. */ + hlinfo->mouse_face_end_col = hpos; + hlinfo->mouse_face_end_x = original_x_pixel + - (total_pixel_width + dx); + hlinfo->mouse_face_beg_col = hpos + gseq_length; + hlinfo->mouse_face_beg_x = 0; + } - dpyinfo->mouse_face_face_id = face_at_string_position (w, string, - charpos, - 0, 0, 0, &ignore, - glyph->face_id, 1); - show_mouse_face (dpyinfo, DRAW_MOUSE_FACE); + hlinfo->mouse_face_beg_row = vpos; + hlinfo->mouse_face_end_row = hlinfo->mouse_face_beg_row; + hlinfo->mouse_face_beg_y = 0; + hlinfo->mouse_face_end_y = 0; + hlinfo->mouse_face_past_end = 0; + hlinfo->mouse_face_window = window; + + hlinfo->mouse_face_face_id = face_at_string_position (w, string, + charpos, + 0, 0, 0, + &ignore, + glyph->face_id, + 1); + show_mouse_face (hlinfo, DRAW_MOUSE_FACE); if (NILP (pointer)) pointer = Qhand; } else if ((area == ON_MODE_LINE) || (area == ON_HEADER_LINE)) - clear_mouse_face (dpyinfo); + clear_mouse_face (hlinfo); } - define_frame_cursor1 (f, cursor, pointer); +#ifdef HAVE_WINDOW_SYSTEM + if (FRAME_WINDOW_P (f)) + define_frame_cursor1 (f, cursor, pointer); +#endif } @@ -24426,7 +25365,7 @@ note_mode_line_or_margin_highlight (Lisp_Object window, int x, int y, void note_mouse_highlight (struct frame *f, int x, int y) { - Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f); + Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f); enum window_part part; Lisp_Object window; struct window *w; @@ -24435,7 +25374,7 @@ 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 (USE_X_TOOLKIT) || defined (USE_GTK) || defined (HAVE_NS) +#if defined (USE_X_TOOLKIT) || defined (USE_GTK) || defined (HAVE_NS) || defined (MSDOS) if (popup_activated ()) return; #endif @@ -24445,28 +25384,28 @@ note_mouse_highlight (struct frame *f, int x, int y) || f->pointer_invisible) return; - dpyinfo->mouse_face_mouse_x = x; - dpyinfo->mouse_face_mouse_y = y; - dpyinfo->mouse_face_mouse_frame = f; + hlinfo->mouse_face_mouse_x = x; + hlinfo->mouse_face_mouse_y = y; + hlinfo->mouse_face_mouse_frame = f; - if (dpyinfo->mouse_face_defer) + if (hlinfo->mouse_face_defer) return; if (gc_in_progress) { - dpyinfo->mouse_face_deferred_gc = 1; + hlinfo->mouse_face_deferred_gc = 1; return; } /* Which window is that in? */ - window = window_from_coordinates (f, x, y, &part, 0, 0, 1); + window = window_from_coordinates (f, x, y, &part, 1); /* If we were displaying active text in another window, clear that. Also clear if we move out of text area in same window. */ - if (! EQ (window, dpyinfo->mouse_face_window) + if (! EQ (window, hlinfo->mouse_face_window) || (part != ON_TEXT && part != ON_MODE_LINE && part != ON_HEADER_LINE - && !NILP (dpyinfo->mouse_face_window))) - clear_mouse_face (dpyinfo); + && !NILP (hlinfo->mouse_face_window))) + clear_mouse_face (hlinfo); /* Not on a window -> return. */ if (!WINDOWP (window)) @@ -24479,6 +25418,7 @@ note_mouse_highlight (struct frame *f, int x, int y) w = XWINDOW (window); frame_to_window_pixel_xy (w, &x, &y); +#ifdef HAVE_WINDOW_SYSTEM /* Handle tool-bar window differently since it doesn't display a buffer. */ if (EQ (window, f->tool_bar_window)) @@ -24486,6 +25426,7 @@ note_mouse_highlight (struct frame *f, int x, int y) note_tool_bar_highlight (f, x, y); return; } +#endif /* Mouse is on the mode, header line or margin? */ if (part == ON_MODE_LINE || part == ON_HEADER_LINE @@ -24495,6 +25436,7 @@ note_mouse_highlight (struct frame *f, int x, int y) return; } +#ifdef HAVE_WINDOW_SYSTEM if (part == ON_VERTICAL_BORDER) { cursor = FRAME_X_OUTPUT (f)->horizontal_drag_cursor; @@ -24505,6 +25447,7 @@ note_mouse_highlight (struct frame *f, int x, int y) cursor = FRAME_X_OUTPUT (f)->nontext_cursor; else cursor = FRAME_X_OUTPUT (f)->text_cursor; +#endif /* Are we in a window whose display is up to date? And verify the buffer's text has not changed. */ @@ -24528,6 +25471,7 @@ note_mouse_highlight (struct frame *f, int x, int y) /* Find the glyph under X/Y. */ glyph = x_y_to_hpos_vpos (w, x, y, &hpos, &vpos, &dx, &dy, &area); +#ifdef HAVE_WINDOW_SYSTEM /* Look for :pointer property on image. */ if (glyph != NULL && glyph->type == IMAGE_GLYPH) { @@ -24569,21 +25513,38 @@ note_mouse_highlight (struct frame *f, int x, int y) pointer = Fplist_get (XCDR (img->spec), QCpointer); } } +#endif /* HAVE_WINDOW_SYSTEM */ /* Clear mouse face if X/Y not over text. */ if (glyph == NULL || area != TEXT_AREA - || !MATRIX_ROW (w->current_matrix, vpos)->displays_text_p) - { - if (clear_mouse_face (dpyinfo)) + || !MATRIX_ROW (w->current_matrix, vpos)->displays_text_p + /* Glyph's OBJECT is an integer for glyphs inserted by the + display engine for its internal purposes, like truncation + and continuation glyphs and blanks beyond the end of + line's text on text terminals. If we are over such a + glyph, we are not over any text. */ + || INTEGERP (glyph->object) + /* R2L rows have a stretch glyph at their front, which + stands for no text, whereas L2R rows have no glyphs at + all beyond the end of text. Treat such stretch glyphs + like we do with NULL glyphs in L2R rows. */ + || (MATRIX_ROW (w->current_matrix, vpos)->reversed_p + && glyph == MATRIX_ROW (w->current_matrix, vpos)->glyphs[TEXT_AREA] + && glyph->type == STRETCH_GLYPH + && glyph->avoid_cursor_p)) + { + if (clear_mouse_face (hlinfo)) cursor = No_Cursor; - if (NILP (pointer)) +#ifdef HAVE_WINDOW_SYSTEM + if (FRAME_WINDOW_P (f) && NILP (pointer)) { if (area != TEXT_AREA) cursor = FRAME_X_OUTPUT (f)->nontext_cursor; else pointer = Vvoid_text_area_pointer; } +#endif goto set_cursor; } @@ -24618,14 +25579,7 @@ note_mouse_highlight (struct frame *f, int x, int y) else noverlays = 0; - same_region = (EQ (window, dpyinfo->mouse_face_window) - && vpos >= dpyinfo->mouse_face_beg_row - && vpos <= dpyinfo->mouse_face_end_row - && (vpos > dpyinfo->mouse_face_beg_row - || hpos >= dpyinfo->mouse_face_beg_col) - && (vpos < dpyinfo->mouse_face_end_row - || hpos < dpyinfo->mouse_face_end_col - || dpyinfo->mouse_face_past_end)); + same_region = coords_in_mouse_face_p (w, hpos, vpos); if (same_region) cursor = No_Cursor; @@ -24636,8 +25590,8 @@ note_mouse_highlight (struct frame *f, int x, int y) the one we are currently highlighting, we have to check if we enter the overlapping overlay, and then highlight only that. */ - || (OVERLAYP (dpyinfo->mouse_face_overlay) - && mouse_face_overlay_overlaps (dpyinfo->mouse_face_overlay))) + || (OVERLAYP (hlinfo->mouse_face_overlay) + && mouse_face_overlay_overlaps (hlinfo->mouse_face_overlay))) { /* Find the highest priority overlay with a mouse-face. */ overlay = Qnil; @@ -24650,12 +25604,12 @@ note_mouse_highlight (struct frame *f, int x, int y) /* If we're highlighting the same overlay as before, there's no need to do that again. */ - if (!NILP (overlay) && EQ (overlay, dpyinfo->mouse_face_overlay)) + if (!NILP (overlay) && EQ (overlay, hlinfo->mouse_face_overlay)) goto check_help_echo; - dpyinfo->mouse_face_overlay = overlay; + hlinfo->mouse_face_overlay = overlay; /* Clear the display of the old active region, if any. */ - if (clear_mouse_face (dpyinfo)) + if (clear_mouse_face (hlinfo)) cursor = No_Cursor; /* If no overlay applies, get a text property. */ @@ -24679,23 +25633,14 @@ note_mouse_highlight (struct frame *f, int x, int y) b = make_number (0); if (NILP (e)) e = make_number (SCHARS (object) - 1); - - fast_find_string_pos (w, XINT (b), object, - &dpyinfo->mouse_face_beg_col, - &dpyinfo->mouse_face_beg_row, - &dpyinfo->mouse_face_beg_x, - &dpyinfo->mouse_face_beg_y, 0); - fast_find_string_pos (w, XINT (e), object, - &dpyinfo->mouse_face_end_col, - &dpyinfo->mouse_face_end_row, - &dpyinfo->mouse_face_end_x, - &dpyinfo->mouse_face_end_y, 1); - dpyinfo->mouse_face_past_end = 0; - dpyinfo->mouse_face_window = window; - dpyinfo->mouse_face_face_id + mouse_face_from_string_pos (w, hlinfo, object, + XINT (b), XINT (e)); + hlinfo->mouse_face_past_end = 0; + hlinfo->mouse_face_window = window; + hlinfo->mouse_face_face_id = face_at_string_position (w, object, pos, 0, 0, 0, &ignore, glyph->face_id, 1); - show_mouse_face (dpyinfo, DRAW_MOUSE_FACE); + show_mouse_face (hlinfo, DRAW_MOUSE_FACE); cursor = No_Cursor; } else @@ -24729,17 +25674,33 @@ note_mouse_highlight (struct frame *f, int x, int y) { Lisp_Object before, after; Lisp_Object before_string, after_string; + /* To correctly find the limits of mouse highlight + in a bidi-reordered buffer, we must not use the + optimization of limiting the search in + previous-single-property-change and + next-single-property-change, because + rows_from_pos_range needs the real start and end + positions to DTRT in this case. That's because + the first row visible in a window does not + necessarily display the character whose position + is the smallest. */ + Lisp_Object lim1 = + NILP (XBUFFER (buffer)->bidi_display_reordering) + ? Fmarker_position (w->start) + : Qnil; + Lisp_Object lim2 = + NILP (XBUFFER (buffer)->bidi_display_reordering) + ? make_number (BUF_Z (XBUFFER (buffer)) + - XFASTINT (w->window_end_pos)) + : Qnil; if (NILP (overlay)) { /* Handle the text property case. */ before = Fprevious_single_property_change - (make_number (pos + 1), Qmouse_face, buffer, - Fmarker_position (w->start)); + (make_number (pos + 1), Qmouse_face, buffer, lim1); after = Fnext_single_property_change - (make_number (pos), Qmouse_face, buffer, - make_number (BUF_Z (XBUFFER (buffer)) - - XFASTINT (w->window_end_pos))); + (make_number (pos), Qmouse_face, buffer, lim2); before_string = after_string = Qnil; } else @@ -24754,7 +25715,7 @@ note_mouse_highlight (struct frame *f, int x, int y) if (!STRINGP (after_string)) after_string = Qnil; } - mouse_face_from_buffer_pos (window, dpyinfo, pos, + mouse_face_from_buffer_pos (window, hlinfo, pos, XFASTINT (before), XFASTINT (after), before_string, after_string, @@ -24833,8 +25794,9 @@ note_mouse_highlight (struct frame *f, int x, int y) } } +#ifdef HAVE_WINDOW_SYSTEM /* Look for a `pointer' property. */ - if (NILP (pointer)) + if (FRAME_WINDOW_P (f) && NILP (pointer)) { /* Check overlays first. */ for (i = noverlays - 1; i >= 0 && NILP (pointer); --i) @@ -24873,6 +25835,7 @@ note_mouse_highlight (struct frame *f, int x, int y) Qpointer, object); } } +#endif /* HAVE_WINDOW_SYSTEM */ BEGV = obegv; ZV = ozv; @@ -24881,7 +25844,14 @@ note_mouse_highlight (struct frame *f, int x, int y) set_cursor: - define_frame_cursor1 (f, cursor, pointer); +#ifdef HAVE_WINDOW_SYSTEM + if (FRAME_WINDOW_P (f)) + define_frame_cursor1 (f, cursor, pointer); +#else + /* This is here to prevent a compiler error, about "label at end of + compound statement". */ + return; +#endif } @@ -24893,13 +25863,13 @@ note_mouse_highlight (struct frame *f, int x, int y) void x_clear_window_mouse_face (struct window *w) { - Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (XFRAME (w->frame)); + Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (XFRAME (w->frame)); Lisp_Object window; BLOCK_INPUT; XSETWINDOW (window, w); - if (EQ (window, dpyinfo->mouse_face_window)) - clear_mouse_face (dpyinfo); + if (EQ (window, hlinfo->mouse_face_window)) + clear_mouse_face (hlinfo); UNBLOCK_INPUT; } @@ -24912,20 +25882,18 @@ void cancel_mouse_face (struct frame *f) { Lisp_Object window; - Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f); + Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f); - window = dpyinfo->mouse_face_window; + window = hlinfo->mouse_face_window; if (! NILP (window) && XFRAME (XWINDOW (window)->frame) == f) { - dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1; - dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1; - dpyinfo->mouse_face_window = Qnil; + hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1; + hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1; + hlinfo->mouse_face_window = Qnil; } } -#endif /* HAVE_WINDOW_SYSTEM */ - /*********************************************************************** Exposure Events @@ -25382,12 +26350,12 @@ expose_frame (struct frame *f, int x, int y, int w, int h) focus-follows-mouse with delayed raise. --jason 2001-10-12 */ if (mouse_face_overwritten_p && !FRAME_GARBAGED_P (f)) { - Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f); - if (f == dpyinfo->mouse_face_mouse_frame) + Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f); + if (f == hlinfo->mouse_face_mouse_frame) { - int x = dpyinfo->mouse_face_mouse_x; - int y = dpyinfo->mouse_face_mouse_y; - clear_mouse_face (dpyinfo); + int x = hlinfo->mouse_face_mouse_x; + int y = hlinfo->mouse_face_mouse_y; + clear_mouse_face (hlinfo); note_mouse_highlight (f, x, y); } } @@ -25974,7 +26942,9 @@ the frame's other specifications determine how to blink the cursor off. */); Vblink_cursor_alist = Qnil; DEFVAR_BOOL ("auto-hscroll-mode", &automatic_hscrolling_p, - doc: /* *Non-nil means scroll the display automatically to make point visible. */); + doc: /* Allow or disallow automatic horizontal scrolling of windows. +If non-nil, windows are automatically scrolled horizontally to make +point visible. */); automatic_hscrolling_p = 1; Qauto_hscroll_mode = intern_c_string ("auto-hscroll-mode"); staticpro (&Qauto_hscroll_mode); @@ -26089,16 +27059,46 @@ baseline. The default value is 1. */); underline_minimum_offset = 1; DEFVAR_BOOL ("display-hourglass", &display_hourglass_p, - doc: /* Non-zero means Emacs displays an hourglass pointer on window systems. */); + doc: /* Non-nil means show an hourglass pointer, when Emacs is busy. +This feature only works when on a window system that can change +cursor shapes. */); display_hourglass_p = 1; DEFVAR_LISP ("hourglass-delay", &Vhourglass_delay, - doc: /* *Seconds to wait before displaying an hourglass pointer. -Value must be an integer or float. */); + doc: /* *Seconds to wait before displaying an hourglass pointer when Emacs is busy. */); Vhourglass_delay = make_number (DEFAULT_HOURGLASS_DELAY); hourglass_atimer = NULL; hourglass_shown_p = 0; + + DEFSYM (Qglyphless_char, "glyphless-char"); + DEFSYM (Qhex_code, "hex-code"); + DEFSYM (Qempty_box, "empty-box"); + DEFSYM (Qthin_space, "thin-space"); + DEFSYM (Qzero_width, "zero-width"); + + DEFSYM (Qglyphless_char_display, "glyphless-char-display"); + /* Intern this now in case it isn't already done. + Setting this variable twice is harmless. + But don't staticpro it here--that is done in alloc.c. */ + Qchar_table_extra_slots = intern_c_string ("char-table-extra-slots"); + Fput (Qglyphless_char_display, Qchar_table_extra_slots, make_number (1)); + + DEFVAR_LISP ("glyphless-char-display", &Vglyphless_char_display, + doc: /* Char-table to control displaying of glyphless characters. +Each element, if non-nil, is an ASCII acronym string (displayed in a box) +or one of these symbols: + hex-code: display the hexadecimal code of a character in a box + empty-box: display as an empty box + thin-space: display as 1-pixel width space + zero-width: don't display + +It has one extra slot to control the display of a character for which +no font is found. The value of the slot is `hex-code' or `empty-box'. +The default is `empty-box'. */); + Vglyphless_char_display = Fmake_char_table (Qglyphless_char_display, Qnil); + Fset_char_table_extra_slot (Vglyphless_char_display, make_number (0), + Qempty_box); } @@ -26216,5 +27216,3 @@ cancel_hourglass (void) } #endif /* ! WINDOWSNT */ -/* arch-tag: eacc864d-bb6a-4b74-894a-1a4399a1358b - (do not change this comment) */ |