changeset 36670:ba5967636e33

(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.
author Gerd Moellmann <gerd@gnu.org>
date Thu, 08 Mar 2001 20:54:18 +0000
parents 824d5e6982a4
children b5aa229bcb18
files src/xterm.c
diffstat 1 files changed, 168 insertions(+), 45 deletions(-) [+]
line wrap: on
line diff
--- 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.  */