# HG changeset patch # User Gerd Moellmann # Date 984084858 0 # Node ID ba5967636e3300bae2a21a7b37b093792b8584b9 # Parent 824d5e6982a4648eb6979f64f6ebb0e9de5b15ce (note_mouse_highlight): Handle mouse-face and help-echo in strings. (x_y_to_hpos_vpos): Add parameter BUFFER_ONLY_P. (fast_find_string_pos): New function. diff -r 824d5e6982a4 -r ba5967636e33 src/xterm.c --- a/src/xterm.c Thu Mar 08 15:47:58 2001 +0000 +++ b/src/xterm.c Thu Mar 08 20:54:18 2001 +0000 @@ -405,9 +405,11 @@ unsigned)); static int fast_find_position P_ ((struct window *, int, int *, int *, int *, int *)); +static int fast_find_string_pos P_ ((struct window *, int, Lisp_Object, + int *, int *, int *, int *, int)); static void set_output_cursor P_ ((struct cursor_pos *)); static struct glyph *x_y_to_hpos_vpos P_ ((struct window *, int, int, - int *, int *, int *)); + int *, int *, int *, int)); static void note_mode_line_highlight P_ ((struct window *, int, int)); static void note_mouse_highlight P_ ((struct frame *, int, int)); static void note_tool_bar_highlight P_ ((struct frame *f, int, int)); @@ -6446,10 +6448,11 @@ date. */ static struct glyph * -x_y_to_hpos_vpos (w, x, y, hpos, vpos, area) +x_y_to_hpos_vpos (w, x, y, hpos, vpos, area, buffer_only_p) struct window *w; int x, y; int *hpos, *vpos, *area; + int buffer_only_p; { struct glyph *glyph, *end; struct glyph_row *row = NULL; @@ -6507,7 +6510,7 @@ { if (w->pseudo_window_p) break; - else if (BUFFERP (glyph->object)) + else if (!buffer_only_p || BUFFERP (glyph->object)) break; } @@ -6710,9 +6713,10 @@ { int hpos, vpos, pos, i, area; struct glyph *glyph; + Lisp_Object object; /* Find the glyph under X/Y. */ - glyph = x_y_to_hpos_vpos (w, x, y, &hpos, &vpos, &area); + glyph = x_y_to_hpos_vpos (w, x, y, &hpos, &vpos, &area, 0); /* Clear mouse face if X/Y not over text. */ if (glyph == NULL @@ -6724,18 +6728,19 @@ } pos = glyph->charpos; - xassert (w->pseudo_window_p || BUFFERP (glyph->object)); - - /* Check for mouse-face and help-echo. */ + object = glyph->object; + if (!STRINGP (object) && !BUFFERP (object)) + return; + { - Lisp_Object mouse_face = Qnil, overlay, position; - Lisp_Object *overlay_vec; + Lisp_Object mouse_face = Qnil, overlay = Qnil, position; + Lisp_Object *overlay_vec = NULL; int len, noverlays; struct buffer *obuf; int obegv, ozv; /* If we get an out-of-range value, return now; avoid an error. */ - if (pos > BUF_Z (XBUFFER (w->buffer))) + if (BUFFERP (object) && pos > BUF_Z (XBUFFER (w->buffer))) return; /* Make the window's buffer temporarily current for @@ -6748,23 +6753,28 @@ ZV = Z; /* Is this char mouse-active or does it have help-echo? */ - XSETINT (position, pos); - - /* Put all the overlays we want in a vector in overlay_vec. - Store the length in len. If there are more than 10, make - enough space for all, and try again. */ - len = 10; - overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object)); - noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL, 0); - if (noverlays > len) + position = make_number (pos); + + if (BUFFERP (object)) { - len = noverlays; + /* Put all the overlays we want in a vector in overlay_vec. + Store the length in len. If there are more than 10, make + enough space for all, and try again. */ + len = 10; overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object)); - noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL,0); + noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL, 0); + if (noverlays > len) + { + len = noverlays; + overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object)); + noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL,0); + } + + /* Sort overlays into increasing priority order. */ + noverlays = sort_overlays (overlay_vec, noverlays, w); } - - /* Sort overlays into increasing priority order. */ - noverlays = sort_overlays (overlay_vec, noverlays, w); + else + noverlays = 0; /* Check mouse-face highlighting. */ if (! (EQ (window, dpyinfo->mouse_face_window) @@ -6786,24 +6796,21 @@ /* Clear the display of the old active region, if any. */ clear_mouse_face (dpyinfo); - /* Find the highest priority overlay that has a mouse-face prop. */ + /* Find the highest priority overlay that has a mouse-face + property. */ overlay = Qnil; - for (i = noverlays - 1; i >= 0; --i) + for (i = noverlays - 1; i >= 0 && NILP (overlay); --i) { mouse_face = Foverlay_get (overlay_vec[i], Qmouse_face); if (!NILP (mouse_face)) - { - overlay = overlay_vec[i]; - break; - } + overlay = overlay_vec[i]; } - + dpyinfo->mouse_face_overlay = overlay; + /* If no overlay applies, get a text property. */ if (NILP (overlay)) - mouse_face = Fget_text_property (position, Qmouse_face, w->buffer); - - dpyinfo->mouse_face_overlay = overlay; - + mouse_face = Fget_text_property (position, Qmouse_face, object); + /* Handle the overlay case. */ if (!NILP (overlay)) { @@ -6835,7 +6842,7 @@ show_mouse_face (dpyinfo, DRAW_MOUSE_FACE); } /* Handle the text property case. */ - else if (! NILP (mouse_face)) + else if (!NILP (mouse_face) && BUFFERP (object)) { /* Find the range of text around this char that should be active. */ @@ -6843,15 +6850,16 @@ int ignore; beginning = Fmarker_position (w->start); - XSETINT (end, (BUF_Z (XBUFFER (w->buffer)) - - XFASTINT (w->window_end_pos))); + end = make_number (BUF_Z (XBUFFER (object)) + - XFASTINT (w->window_end_pos)); before = Fprevious_single_property_change (make_number (pos + 1), Qmouse_face, - w->buffer, beginning); + object, beginning); after = Fnext_single_property_change (position, Qmouse_face, - w->buffer, end); + object, end); + /* Record this as the current active region. */ fast_find_position (w, XFASTINT (before), &dpyinfo->mouse_face_beg_col, @@ -6865,13 +6873,46 @@ &dpyinfo->mouse_face_end_x, &dpyinfo->mouse_face_end_y); dpyinfo->mouse_face_window = window; - dpyinfo->mouse_face_face_id - = face_at_buffer_position (w, pos, 0, 0, - &ignore, pos + 1, 1); + + if (BUFFERP (object)) + dpyinfo->mouse_face_face_id + = face_at_buffer_position (w, pos, 0, 0, + &ignore, pos + 1, 1); /* Display it as active. */ show_mouse_face (dpyinfo, DRAW_MOUSE_FACE); } + else if (!NILP (mouse_face) && STRINGP (object)) + { + Lisp_Object b, e; + int ignore; + + b = Fprevious_single_property_change (make_number (pos + 1), + Qmouse_face, + object, Qnil); + e = Fnext_single_property_change (position, Qmouse_face, + object, Qnil); + if (NILP (b)) + b = make_number (0); + if (NILP (e)) + e = make_number (XSTRING (object)->size) - 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 + = face_at_string_position (w, object, pos, 0, 0, 0, &ignore, + glyph->face_id, 1); + show_mouse_face (dpyinfo, DRAW_MOUSE_FACE); + } } /* Look for a `help-echo' property. */ @@ -6969,7 +7010,7 @@ int area; /* Find the glyph under X/Y. */ - *glyph = x_y_to_hpos_vpos (w, x, y, hpos, vpos, &area); + *glyph = x_y_to_hpos_vpos (w, x, y, hpos, vpos, &area, 0); if (*glyph == NULL) return -1; @@ -7167,7 +7208,7 @@ int maybe_next_line_p = 0; int line_start_position; int yb = window_text_bottom_y (w); - struct glyph_row *row = MATRIX_ROW (w->current_matrix, 0); + struct glyph_row *row = MATRIX_FIRST_TEXT_ROW (w->current_matrix); struct glyph_row *best_row = row; int row_vpos = 0, best_row_vpos = 0; int current_x; @@ -7246,6 +7287,88 @@ } +/* Find the position of the the glyph for position POS in OBJECT in + window W's current matrix, and return in *X/*Y the pixel + coordinates, and return in *HPOS/*VPOS the column/row of the glyph. + + RIGHT_P non-zero means return the position of the right edge of the + glyph, RIGHT_P zero means return the left edge position. + + If no glyph for POS exists in the matrix, return the position of + the glyph with the next smaller position that is in the matrix, if + RIGHT_P is zero. If RIGHT_P is non-zero, and no glyph for POS + exists in the matrix, return the position of the glyph with the + next larger position in OBJECT. + + Value is non-zero if a glyph was found. */ + +static int +fast_find_string_pos (w, pos, object, hpos, vpos, x, y, right_p) + struct window *w; + int pos; + Lisp_Object object; + int *hpos, *vpos, *x, *y; + int right_p; +{ + int yb = window_text_bottom_y (w); + struct glyph_row *r; + struct glyph *best_glyph = NULL; + struct glyph_row *best_row = NULL; + int best_x = 0; + + for (r = MATRIX_FIRST_TEXT_ROW (w->current_matrix); + r->enabled_p && r->y < yb; + ++r) + { + struct glyph *g = r->glyphs[TEXT_AREA]; + struct glyph *e = g + r->used[TEXT_AREA]; + int gx; + + for (gx = r->x; g < e; gx += g->pixel_width, ++g) + if (EQ (g->object, object)) + { + if (g->charpos == pos) + { + best_glyph = g; + best_x = gx; + best_row = r; + goto found; + } + else if (best_glyph == NULL + || ((abs (g->charpos - pos) + < abs (best_glyph->charpos - pos)) + && (right_p + ? g->charpos < pos + : g->charpos > pos))) + { + best_glyph = g; + best_x = gx; + best_row = r; + } + } + } + + found: + + if (best_glyph) + { + *x = best_x; + *hpos = best_glyph - best_row->glyphs[TEXT_AREA]; + + if (right_p) + { + *x += best_glyph->pixel_width; + ++*hpos; + } + + *y = best_row->y; + *vpos = best_row - w->current_matrix->rows; + } + + return best_glyph != NULL; +} + + /* Display the active region described by mouse_face_* in its mouse-face if HL > 0, in its normal face if HL = 0. */