]> git.eshelyaron.com Git - emacs.git/commitdiff
(note_mouse_highlight): Handle mouse-face and
authorGerd Moellmann <gerd@gnu.org>
Thu, 8 Mar 2001 20:54:18 +0000 (20:54 +0000)
committerGerd Moellmann <gerd@gnu.org>
Thu, 8 Mar 2001 20:54:18 +0000 (20:54 +0000)
help-echo in strings.
(x_y_to_hpos_vpos): Add parameter BUFFER_ONLY_P.
(fast_find_string_pos): New function.

src/xterm.c

index ae786d5058b2d25162343dc935624912f540c1fd..592c60ff2bc0f37df69eef740bb053c5edf85d0f 100644 (file)
@@ -405,9 +405,11 @@ static unsigned int x_x_to_emacs_modifiers P_ ((struct x_display_info *,
                                                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 @@ note_mouse_movement (frame, event)
    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 @@ x_y_to_hpos_vpos (w, x, y, hpos, vpos, area)
        {
          if (w->pseudo_window_p)
            break;
-         else if (BUFFERP (glyph->object))
+         else if (!buffer_only_p || BUFFERP (glyph->object))
            break;
        }
       
@@ -6710,9 +6713,10 @@ note_mouse_highlight (f, x, y)
     {
       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 @@ note_mouse_highlight (f, x, y)
        }
 
       pos = glyph->charpos;
-      xassert (w->pseudo_window_p || BUFFERP (glyph->object));
+      object = glyph->object;
+      if (!STRINGP (object) && !BUFFERP (object))
+       return;
 
-      /* Check for mouse-face and help-echo.  */
       {
-       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 @@ note_mouse_highlight (f, x, y)
        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 @@ note_mouse_highlight (f, x, y)
            /* 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);
+             mouse_face = Fget_text_property (position, Qmouse_face, object);
 
-           dpyinfo->mouse_face_overlay = overlay;
-           
            /* Handle the overlay case.  */
            if (!NILP (overlay))
              {
@@ -6835,7 +6842,7 @@ note_mouse_highlight (f, x, y)
                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 @@ note_mouse_highlight (f, x, y)
                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 @@ note_mouse_highlight (f, x, y)
                                         &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 @@ x_tool_bar_item (f, x, y, glyph, hpos, vpos, prop_idx)
   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 @@ fast_find_position (w, pos, hpos, vpos, x, y)
   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 @@ fast_find_position (w, pos, hpos, vpos, x, y)
 }
 
 
+/* 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.  */