diff src/w32term.c @ 40137:5f0d7d58283b

(remember_mouse_glyph): New function. (w32_mouse_position): Use it. (note_mouse_movement): If the mouse moved off the glyph, remember its new position. Sync with xterm.c: (notice_overwritten_cursor): Renamed from note_overwritten_text_cursor. Rewritten to take glyph widths into account. (x_y_to_hpos_vpos): Add parameter BUFFER_ONLY_P. (fast_find_string_pos): New function. (fast_find_position): Return the correct vpos. Add parameter STOP. In the final row, stop before glyphs having STOP as object. Don't consider glyphs that are not from a buffer. (fast_find_position) [0]: Add a presumably more correct version for after 21.1. (expose_window_tree, expose_frame): Don't compute intersections here. (expose_window): Do it here instead. (expose_window_tree, expose_window, expose_line): Return 1 when overwriting mouse-face. (expose_window): If W is the window currently being updated, mark the frame garbaged. (expose_frame): If mouse-face was overwritten, redo it. (x_use_underline_position_properties): New variable. (syms_of_xterm): DEFVAR_BOOL it. (x_draw_glyph_string): Add comment to use it in future. (x_draw_glyph_string): Restore clipping after drawing box. Fix a computation of the underline position. (w32_get_glyph_string_clip_rect): Minor cleanup. (x_fill_stretch_glyph_string): Remove an assertion. (x_produce_glyphs): Don't convert multibyte characters to unibyte characters in unibyte buffers. (cursor_in_mouse_face_p): New function. (x_draw_stretch_glyph_string): Use it to choose a different GC when drawing a cursor within highlighted text. Don't draw background again if it has already been drawn. (x_draw_glyph_string_box): Don't draw a full-width box just because the glyph row's full_width_p flag is set. (x_draw_glyphs): Fix computation of rightmost x for full-width rows. (x_dump_glyph_string): Put in #if GLYPH_DEBUG. (w32_draw_relief_rect): Extend left shadow to the bottom and left; change bottom shadow accordingly. Some cleanup. (x_update_window_end): Handle overwritten mouse face also for tool bar windows. (show_mouse_face): Set the glyph row's mouse_face_p flag also when DRAW is DRAW_IMAGE_RAISED. (clear_mouse_face): Return 1 if text with mouse face was actually redrawn. Make the function static. Reset dpyinfo->mouse_face_overlay otherwise note_mouse_highlight might optimize away highlighting if we pass over that same overlay again. (note_mouse_highlight): Call mouse_face_overlay_overlaps to detect a case where we have to highlight a different region despite not having left the currently highlighted region. Set mouse_face_overlay in the x_display_info. Avoid changing the mouse pointer shape when show_mouse_face has already done it, or there is no need. Handle mouse-face and help-echo in strings. (glyph_rect): New function. (w32_mouse_position): Use it to raise the threshold for mouse movement event generation. (w32_initialize_display_info): Initialize the x_display_info's mouse_face_overlay. (w32_set_vertical_scroll_bar): Don't clear a zero height or width area. (w32_set_vertical_scroll_bar, x_scroll_bar_create): Don't configure a widget to zero height.
author Jason Rumney <jasonr@gnu.org>
date Sun, 21 Oct 2001 15:20:03 +0000
parents 11e29c86babb
children ccd2ee0384ff
line wrap: on
line diff
--- a/src/w32term.c	Sun Oct 21 14:44:58 2001 +0000
+++ b/src/w32term.c	Sun Oct 21 15:20:03 2001 +0000
@@ -168,6 +168,10 @@
 
 int x_stretch_cursor_p;
 
+/* Non-zero means make use of UNDERLINE_POSITION font properties.  */
+
+int x_use_underline_position_properties;
+
 extern unsigned int msh_mousewheel;
 
 extern void free_frame_menubar ();
@@ -331,10 +335,12 @@
 static void frame_to_window_pixel_xy P_ ((struct window *, int *, int *));
 void w32_delete_display P_ ((struct w32_display_info *));
 static int fast_find_position P_ ((struct window *, int, int *, int *,
-				   int *, int *));
+				   int *, int *, Lisp_Object));
+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));
@@ -342,7 +348,8 @@
                                           struct input_event *));
 static void show_mouse_face P_ ((struct w32_display_info *,
 				 enum draw_glyphs_face));
-void clear_mouse_face P_ ((struct w32_display_info *));
+static int cursor_in_mouse_face_p P_ ((struct window *));
+static int clear_mouse_face P_ ((struct w32_display_info *));
 
 void x_lower_frame P_ ((struct frame *));
 void x_scroll_bar_clear P_ ((struct frame *));
@@ -375,12 +382,12 @@
 static void x_draw_hollow_cursor P_ ((struct window *, struct glyph_row *));
 static void x_draw_bar_cursor P_ ((struct window *, struct glyph_row *, int));
 static void expose_frame P_ ((struct frame *, int, int, int, int));
-static void expose_window_tree P_ ((struct window *, RECT *));
-static void expose_window P_ ((struct window *, RECT *));
+static int expose_window_tree P_ ((struct window *, RECT *));
+static int expose_window P_ ((struct window *, RECT *));
 static void expose_area P_ ((struct window *, struct glyph_row *,
 			     RECT *, enum glyph_row_area));
-static void expose_line P_ ((struct window *, struct glyph_row *,
-			     RECT *));
+static int expose_line P_ ((struct window *, struct glyph_row *,
+			    RECT *));
 void x_update_cursor P_ ((struct frame *, int));
 static void x_update_cursor_in_window_tree P_ ((struct window *, int));
 static void x_update_window_cursor P_ ((struct window *, int));
@@ -634,7 +641,8 @@
       RECT r;
       HDC hdc;
 
-      window_box_edges (w, -1, &r.left, &r.top, &r.right, &r.bottom);
+      window_box_edges (w, -1, (int *) &r.left, (int *) &r.top,
+			(int *) &r.right, (int *) &r.bottom);
       r.left = r.right + FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f);
       r.right = r.left + 1;
       r.bottom -= 1;
@@ -664,22 +672,13 @@
      struct window *w;
      int cursor_on_p, mouse_face_overwritten_p;
 {
+  struct w32_display_info *dpyinfo
+    = FRAME_W32_DISPLAY_INFO (XFRAME (w->frame));
+
   if (!w->pseudo_window_p)
     {
-      struct w32_display_info *dpyinfo
-        = FRAME_W32_DISPLAY_INFO (XFRAME (w->frame));
-
       BLOCK_INPUT;
 
-      /* If a row with mouse-face was overwritten, arrange for
-	 XTframe_up_to_date to redisplay the mouse highlight.  */
-      if (mouse_face_overwritten_p)
-	{
-	  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;
-	}
-
       if (cursor_on_p)
 	x_display_and_set_cursor (w, 1, output_cursor.hpos,
 				  output_cursor.vpos,
@@ -688,7 +687,16 @@
       x_draw_vertical_border (w);
       UNBLOCK_INPUT;
     }
-  
+
+  /* If a row with mouse-face was overwritten, arrange for
+     XTframe_up_to_date to redisplay the mouse highlight.  */
+  if (mouse_face_overwritten_p)
+    {
+      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;
+    }
+
   updated_window = NULL;
 }
 
@@ -1981,8 +1989,7 @@
 	  else if (!SINGLE_BYTE_CHAR_P (it->c)
 		   && !it->multibyte_p)
 	    {
-	      it->char_to_display = multibyte_char_to_unibyte (it->c, Qnil);
-              it->multibyte_p = 0;
+              it->multibyte_p = 1;
 	      it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display);
 	      face = FACE_FROM_ID (it->f, it->face_id);
 	    }
@@ -2680,7 +2687,7 @@
                 nchars * charset_dim, NULL);
 }
 
-#if 0
+#if GLYPH_DEBUG
 
 static void
 x_dump_glyph_string (s)
@@ -3030,20 +3037,6 @@
       r_height = s->row->visible_height;
     }
 
-  /* Don't use S->y for clipping because it doesn't take partially
-     visible lines into account.  For example, it can be negative for
-     partially visible lines at the top of a window.  */
-  if (!s->row->full_width_p
-      && MATRIX_ROW_PARTIALLY_VISIBLE_AT_TOP_P (s->w, s->row))
-    r->top = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (s->w);
-  else
-    r->top = max (0, s->row->y);
-
-  /* If drawing a tool-bar window, draw it over the internal border
-     at the top of the window.  */
-  if (s->w == XWINDOW (s->f->tool_bar_window))
-    r->top -= s->f->output_data.w32->internal_border_width;
-
   /* If S draws overlapping rows, it's sufficient to use the top and
      bottom of the window for clipping because this glyph string
      intentionally draws over other lines.  */
@@ -3052,7 +3045,23 @@
       r->top = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (s->w);
       r_height = window_text_bottom_y (s->w) - r->top;
     }
-      
+  else
+    {
+      /* Don't use S->y for clipping because it doesn't take partially
+	 visible lines into account.  For example, it can be negative for
+	 partially visible lines at the top of a window.  */
+      if (!s->row->full_width_p
+	  && MATRIX_ROW_PARTIALLY_VISIBLE_AT_TOP_P (s->w, s->row))
+	r->top = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (s->w);
+      else
+	r->top = max (0, s->row->y);
+
+      /* If drawing a tool-bar window, draw it over the internal border
+	 at the top of the window.  */
+      if (s->w == XWINDOW (s->f->tool_bar_window))
+	r->top -= s->f->output_data.w32->internal_border_width;
+    }
+
   r->top = WINDOW_TO_FRAME_PIXEL_Y (s->w, r->top);
 
   r->bottom = r->top + r_height;
@@ -3646,47 +3655,34 @@
 
   /* Top.  */
   for (i = 0; i < width; ++i)
-    {
-      w32_fill_area (f, hdc, gc.foreground,
-                     left_x + i * left_p, top_y + i,
-                     (right_x + 1 - i * right_p) - (left_x + i * left_p), 1);
-    }
+    w32_fill_area (f, hdc, gc.foreground,
+		   left_x + i * left_p, top_y + i,
+		   (right_x + 1 - i * right_p) - (left_x + i * left_p), 1);
 
   /* Left.  */
   if (left_p)
     for (i = 0; i < width; ++i)
-      {
-        w32_fill_area (f, hdc, gc.foreground,
-                       left_x + i, top_y + i, 1,
-                       (bottom_y - i) - (top_y + i));
-      }
-
-  w32_set_clip_rectangle (hdc, NULL);
+      w32_fill_area (f, hdc, gc.foreground,
+		     left_x + i, top_y + i, 1,
+		     (bottom_y - i + 1) - (top_y + i));
 
   if (raised_p)
     gc.foreground = f->output_data.w32->black_relief.gc->foreground;
   else
     gc.foreground = f->output_data.w32->white_relief.gc->foreground;
-
-
-  w32_set_clip_rectangle (hdc, clip_rect);
   
   /* Bottom.  */
   for (i = 0; i < width; ++i)
-    {
-      w32_fill_area (f, hdc, gc.foreground, 
-                     left_x + i * left_p, bottom_y - i,
-                     (right_x + 1 - i * right_p) - left_x + i * left_p, 1);
-    }
+    w32_fill_area (f, hdc, gc.foreground, 
+		   left_x + i * left_p, bottom_y - i,
+		   (right_x + 2 - i * right_p) - (left_x + i * left_p), 1);
 
   /* Right.  */
   if (right_p)
     for (i = 0; i < width; ++i)
-      {
-        w32_fill_area (f, hdc, gc.foreground,
-                       right_x - i, top_y + i + 1, 1,
-                       (bottom_y - i) - (top_y + i + 1));
-      }
+      w32_fill_area (f, hdc, gc.foreground,
+		     right_x - i, top_y + i + 1, 1,
+		     (bottom_y - i) - (top_y + i + 1));
 
   w32_set_clip_rectangle (hdc, NULL);
   
@@ -3764,7 +3760,7 @@
   width = abs (s->face->box_line_width);
   raised_p = s->face->box == FACE_RAISED_BOX;
   left_x = s->x;
-  right_x = ((s->row->full_width_p
+  right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p
 	      ? last_x - 1
 	      : min (last_x, s->x + s->background_width) - 1));
   top_y = s->y;
@@ -4213,6 +4209,16 @@
 	  int w = s->background_width - width, h = s->height;
 	  RECT r;
           HDC hdc = s->hdc;
+
+	  if (s->row->mouse_face_p
+	      && cursor_in_mouse_face_p (s->w))
+	    {
+	      x_set_mouse_face_gc (s);
+	      gc = s->gc;
+	    }
+	  else
+	    gc = s->face->gc;
+  
 	  w32_get_glyph_string_clip_rect (s, &r);
 	  w32_set_clip_rectangle (hdc, &r);
 
@@ -4231,7 +4237,7 @@
             }
         }
     }
-  else
+  else if (!s->background_filled_p)
     x_draw_glyph_string_bg_rect (s, s->x, s->y, s->background_width,
 				 s->height);
   
@@ -4260,7 +4266,6 @@
 
   /* Set up S->gc, set clipping and draw S.  */
   x_set_glyph_string_gc (s);
-  x_set_glyph_string_clipping (s);
 
   /* Draw relief (if any) in advance for char/composition so that the
      glyph string can be drawn over it.  */
@@ -4270,10 +4275,14 @@
 	  || s->first_glyph->type == COMPOSITE_GLYPH))
 
     {
+      x_set_glyph_string_clipping (s);
       x_draw_glyph_string_background (s, 1);
       x_draw_glyph_string_box (s);
+      x_set_glyph_string_clipping (s);
       relief_drawn_p = 1;
     }
+  else
+    x_set_glyph_string_clipping (s);
 
   switch (s->first_glyph->type)
     {
@@ -4314,6 +4323,8 @@
           unsigned long h = 1;
           unsigned long dy = s->height - h;
 
+	  /* TODO: Use font information for positioning and thickness
+	     of underline.  See OUTLINETEXTMETRIC, and xterm.c.  */
           if (s->face->underline_defaulted_p)
             {
               w32_fill_area (s->f, s->hdc, s->gc->foreground, s->x,
@@ -4563,7 +4574,7 @@
   /* Adjust base line for subscript/superscript text.  */
   s->ybase += voffset;
 
-  xassert (s->face && s->face->gc);
+  xassert (s->face);
   return glyph - s->row->glyphs[s->area];
 }
 
@@ -5440,6 +5451,7 @@
      int x, y, w, h;
 {
   RECT r;
+  int mouse_face_overwritten_p = 0;
 
   TRACE ((stderr, "expose_frame "));
 
@@ -5475,23 +5487,35 @@
     }
 
   TRACE ((stderr, "(%d, %d, %d, %d)\n", r.left, r.top, r.right, r.bottom));
-  expose_window_tree (XWINDOW (f->root_window), &r);
+  mouse_face_overwritten_p = expose_window_tree (XWINDOW (f->root_window), &r);
 
   if (WINDOWP (f->tool_bar_window))
-    {
-      struct window *w = XWINDOW (f->tool_bar_window);
-      RECT window_rect;
-      RECT intersection_rect;
-      int window_x, window_y, window_width, window_height;
-
-      window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
-      window_rect.left = window_x;
-      window_rect.top = window_y;
-      window_rect.right = window_x + window_width;
-      window_rect.bottom = window_y + window_height;
-
-      if (IntersectRect (&intersection_rect, &r, &window_rect))
-	expose_window (w, &intersection_rect);
+    mouse_face_overwritten_p
+      |= expose_window (XWINDOW (f->tool_bar_window), &r);
+
+  /* Some window managers support a focus-follows-mouse style with
+     delayed raising of frames.  Imagine a partially obscured frame,
+     and moving the mouse into partially obscured mouse-face on that
+     frame.  The visible part of the mouse-face will be highlighted,
+     then the WM raises the obscured frame.  With at least one WM, KDE
+     2.1, Emacs is not getting any event for the raising of the frame
+     (even tried with SubstructureRedirectMask), only Expose events.
+     These expose events will draw text normally, i.e. not
+     highlighted.  Which means we must redo the highlight here.
+     Subsume it under ``we love X''.  --gerd 2001-08-15  */
+  /* Included in Windows version because Windows most likely does not
+     do the right thing if any third party tool offers
+     focus-follows-mouse with delayed raise.  --jason 2001-10-12  */
+  if (mouse_face_overwritten_p && !FRAME_GARBAGED_P (f))
+    {
+      struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
+      if (f == dpyinfo->mouse_face_mouse_frame)
+	{
+	  int x = dpyinfo->mouse_face_mouse_x;
+	  int y = dpyinfo->mouse_face_mouse_y;
+	  clear_mouse_face (dpyinfo);
+	  note_mouse_highlight (f, x, y);
+	}
     }
 }
 
@@ -5499,45 +5523,29 @@
 /* Redraw (parts) of all windows in the window tree rooted at W that
    intersect R.  R contains frame pixel coordinates.  */
 
-static void
+static int
 expose_window_tree (w, r)
      struct window *w;
      RECT *r;
 {
-  while (w)
+  struct frame *f = XFRAME (w->frame);
+  int mouse_face_overwritten_p = 0;
+
+  while (w && !FRAME_GARBAGED_P (f))
     {
       if (!NILP (w->hchild))
-	expose_window_tree (XWINDOW (w->hchild), r);
+	mouse_face_overwritten_p
+	  |= expose_window_tree (XWINDOW (w->hchild), r);
       else if (!NILP (w->vchild))
-	expose_window_tree (XWINDOW (w->vchild), r);
+	mouse_face_overwritten_p
+	  |= expose_window_tree (XWINDOW (w->vchild), r);
       else
-	{
-	  RECT window_rect;
-	  RECT intersection_rect;
-	  struct frame *f = XFRAME (w->frame);
-	  int window_x, window_y, window_width, window_height;
-
-	  /* Frame-relative pixel rectangle of W.  */
-	  window_box (w, -1, &window_x, &window_y, &window_width,
-		      &window_height);
-	  window_rect.left
-	    = (window_x
-	       - FRAME_X_LEFT_FLAGS_AREA_WIDTH (f)
-	       - FRAME_LEFT_SCROLL_BAR_WIDTH (f) * CANON_Y_UNIT (f));
-	  window_rect.top = window_y;
-	  window_rect.right = window_rect.left
-	    + (window_width
-	       + FRAME_X_FLAGS_AREA_WIDTH (f)
-	       + FRAME_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f));
-	  window_rect.bottom = window_rect.top
-	    + window_height + CURRENT_MODE_LINE_HEIGHT (w);
-
-	  if (IntersectRect (&intersection_rect, r, &window_rect))
-	    expose_window (w, &intersection_rect);
-	}
-
-      w = NILP (w->next) ? 0 : XWINDOW (w->next);
-    }
+	mouse_face_overwritten_p |= expose_window (w, r);
+
+      w = NILP (w->next) ? NULL : XWINDOW (w->next);
+    }
+
+  return mouse_face_overwritten_p;
 }
 
 
@@ -5606,9 +5614,10 @@
 
 
 /* Redraw the parts of the glyph row ROW on window W intersecting
-   rectangle R.  R is in window-relative coordinates.  */
-
-static void
+   rectangle R.  R is in window-relative coordinates.  Value is
+   non-zero if mouse face was overwritten.  */
+
+static int
 expose_line (w, row, r)
      struct window *w;
      struct glyph_row *row;
@@ -5629,6 +5638,8 @@
 	expose_area (w, row, r, RIGHT_MARGIN_AREA);
       x_draw_row_bitmaps (w, row);
     }
+
+  return row->mouse_face_p;
 }
 
 
@@ -5656,82 +5667,110 @@
 }
 
 
-/* Redraw a rectangle of window W.  R is a rectangle in window
-   relative coordinates.  Call this function with input blocked.  */
-
-static void
-expose_window (w, r)
+/* Redraw the part of window W intersection rectagle FR.  Pixel
+   coordinates in FR are frame relative.  Call this function with
+   input blocked.  Value is non-zero if the exposure overwrites
+   mouse-face.  */
+
+static int
+expose_window (w, fr)
      struct window *w;
-     RECT *r;
-{
-  struct glyph_row *row;
-  int y;
-  int yb = window_text_bottom_y (w);
-  int cursor_cleared_p;
+     RECT *fr;
+{
+  struct frame *f = XFRAME (w->frame);
+  RECT wr, r;
+  int mouse_face_overwritten_p = 0;
 
   /* If window is not yet fully initialized, do nothing.  This can
      happen when toolkit scroll bars are used and a window is split.
      Reconfiguring the scroll bar will generate an expose for a newly
      created window.  */
-  if (w->current_matrix == NULL || w == updated_window)
-    return;
-
-  TRACE ((stderr, "expose_window (%d, %d, %d, %d)\n",
-	  r->left, r->top, r->right, r->bottom));
-
-  /* Convert to window coordinates.  */
-  r->left = FRAME_TO_WINDOW_PIXEL_X (w, r->left);
-  r->top = FRAME_TO_WINDOW_PIXEL_Y (w, r->top);
-  r->right = FRAME_TO_WINDOW_PIXEL_X (w, r->right);
-  r->bottom = FRAME_TO_WINDOW_PIXEL_Y (w, r->bottom);
-
-  /* Turn off the cursor.  */
-  if (!w->pseudo_window_p
-      && x_phys_cursor_in_rect_p (w, r))
-    {
-      x_clear_cursor (w);
-      cursor_cleared_p = 1;
-    }
-  else
-    cursor_cleared_p = 0;
-
-  /* Find the first row intersecting the rectangle R.  */
-  row = w->current_matrix->rows;
-  y = 0;
-  while (row->enabled_p
-	 && y < yb
-	 && y + row->height < r->top)
-    {
-      y += row->height;
-      ++row;
-    }
-	
-  /* Display the text in the rectangle, one text line at a time.  */
-  while (row->enabled_p
-	 && y < yb
-	 && y < r->bottom)
-    {
-      expose_line (w, row, r);
-      y += row->height;
-      ++row;
-    }
-
-  /* Display the mode line if there is one.  */
-  if (WINDOW_WANTS_MODELINE_P (w)
-      && (row = MATRIX_MODE_LINE_ROW (w->current_matrix),
-	  row->enabled_p)
-      && row->y < r->bottom)
-    expose_line (w, row, r);
-
-  if (!w->pseudo_window_p)
-    {
-      /* Draw border between windows.  */
-      x_draw_vertical_border (w);
-      
-      /* Turn the cursor on again.  */
-      if (cursor_cleared_p)
-	x_update_window_cursor (w, 1);
-    }
+  if (w->current_matrix == NULL)
+    return 0;
+
+  /* When we're currently updating the window, display and current
+     matrix usually don't agree.  Arrange for a thorough display
+     later.  */
+  if (w == updated_window)
+    {
+      SET_FRAME_GARBAGED (f);
+      return 0;
+    }
+
+  /* Frame-relative pixel rectangle of W.  */
+  wr.left = XFASTINT (w->left) * CANON_X_UNIT (f);
+  wr.top = XFASTINT (w->top) * CANON_Y_UNIT (f);
+  wr.right = wr.left + XFASTINT (w->width) * CANON_X_UNIT (f);
+  wr.bottom = wr.top + XFASTINT (w->height) * CANON_Y_UNIT (f);
+
+  if (IntersectRect(&r, fr, &wr))
+    {
+      int yb = window_text_bottom_y (w);
+      struct glyph_row *row;
+      int cursor_cleared_p;
+
+      TRACE ((stderr, "expose_window (%d, %d, %d, %d)\n",
+	      r.left, r.top, r.right, r.bottom));
+
+      /* Convert to window coordinates.  */
+      r.left = FRAME_TO_WINDOW_PIXEL_X (w, r.left);
+      r.right = FRAME_TO_WINDOW_PIXEL_X (w, r.right);
+      r.top = FRAME_TO_WINDOW_PIXEL_Y (w, r.top);
+      r.bottom = FRAME_TO_WINDOW_PIXEL_Y (w, r.bottom);
+
+      /* Turn off the cursor.  */
+      if (!w->pseudo_window_p
+	  && x_phys_cursor_in_rect_p (w, &r))
+	{
+	  x_clear_cursor (w);
+	  cursor_cleared_p = 1;
+	}
+      else
+	cursor_cleared_p = 0;
+
+      /* Find the first row intersecting the rectangle R.  */
+      for (row = w->current_matrix->rows;
+	   row->enabled_p;
+	   ++row)
+	{
+	  int y0 = row->y;
+	  int y1 = MATRIX_ROW_BOTTOM_Y (row);
+
+	  if ((y0 >= r.top && y0 < r.bottom)
+	      || (y1 > r.top && y1 < r.bottom)
+	      || (r.top >= y0 && r.top < y1)
+	      || (r.bottom > y0 && r.bottom < y1))
+	    {
+	      if (expose_line (w, row, &r))
+		mouse_face_overwritten_p = 1;
+	    }
+
+	  if (y1 >= yb)
+	    break;
+	}
+
+      /* Display the mode line if there is one.  */
+      if (WINDOW_WANTS_MODELINE_P (w)
+	  && (row = MATRIX_MODE_LINE_ROW (w->current_matrix),
+	      row->enabled_p)
+	  && row->y < r.bottom)
+	{
+	  if (expose_line (w, row, &r))
+	    mouse_face_overwritten_p = 1;
+	}
+
+      if (!w->pseudo_window_p)
+	{
+	  /* Draw border between windows.  */
+	  x_draw_vertical_border (w);
+
+	  /* Turn the cursor on again.  */
+	  if (cursor_cleared_p)
+	    x_update_window_cursor (w, 1);
+	}
+    }
+
+  return mouse_face_overwritten_p;
 }
 
 
@@ -6134,11 +6173,16 @@
 static MSG last_mouse_motion_event;
 static Lisp_Object last_mouse_motion_frame;
 
+static void remember_mouse_glyph P_ ((struct frame *, int, int));
+
 static void
 note_mouse_movement (frame, msg)
      FRAME_PTR frame;
      MSG *msg;
 {
+  int mouse_x = LOWORD (msg->lParam);
+  int mouse_y = HIWORD (msg->lParam);
+
   last_mouse_movement_time = msg->time;
   memcpy (&last_mouse_motion_event, msg, sizeof (last_mouse_motion_event));
   XSETFRAME (last_mouse_motion_frame, frame);
@@ -6151,14 +6195,19 @@
     }
 
   /* Has the mouse moved off the glyph it was on at the last sighting?  */
-  else if (LOWORD (msg->lParam) < last_mouse_glyph.left
-	   || LOWORD (msg->lParam) > last_mouse_glyph.right
-	   || HIWORD (msg->lParam) < last_mouse_glyph.top
-	   || HIWORD (msg->lParam) > last_mouse_glyph.bottom)
+  else if (mouse_x < last_mouse_glyph.left
+	   || mouse_x > last_mouse_glyph.right
+	   || mouse_y < last_mouse_glyph.top
+	   || mouse_y > last_mouse_glyph.bottom)
     {
       frame->mouse_moved = 1;
       last_mouse_scroll_bar = Qnil;
-      note_mouse_highlight (frame, LOWORD (msg->lParam), HIWORD (msg->lParam));
+      note_mouse_highlight (frame, mouse_x, mouse_y);
+      /* Remember the mouse position here, as w32_mouse_position only
+	 gets called when mouse tracking is enabled but we also need
+	 to keep track of the mouse for help_echo and highlighting at
+	 other times.  */
+      remember_mouse_glyph (frame, mouse_x, mouse_y);
     }
 }
 
@@ -6181,10 +6230,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;
@@ -6242,7 +6292,7 @@
 	{
 	  if (w->pseudo_window_p)
 	    break;
-	  else if (BUFFERP (glyph->object))
+	  else if (!buffer_only_p || BUFFERP (glyph->object))
 	    break;
 	}
       
@@ -6376,6 +6426,7 @@
   int portion;
   Lisp_Object window;
   struct window *w;
+  struct buffer *b;
 
   /* When a menu is active, don't highlight because this looks odd. */
   if (popup_activated ())
@@ -6421,35 +6472,38 @@
       return;
     }
 
+  /* Mouse is on the mode or header line?  */
   if (portion == 1 || portion == 3)
     {
-      /* Mouse is on the mode or top line.  */
       note_mode_line_highlight (w, x, portion == 1);
       return;
     }
 #if 0 /* TODO: mouse cursor */
-  else if (portion == 2)
-    XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
-		   f->output_data.x->horizontal_drag_cursor);
+  if (portion == 2)
+    cursor = f->output_data.x->horizontal_drag_cursor;
   else
-    XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
-		   f->output_data.x->text_cursor);
+    cursor = f->output_data.x->text_cursor;
 #endif
-
   /* Are we in a window whose display is up to date?
      And verify the buffer's text has not changed.  */
+  b = XBUFFER (w->buffer);
   if (/* Within text portion of the window.  */
       portion == 0
       && EQ (w->window_end_valid, w->buffer)
-      && XFASTINT (w->last_modified) == BUF_MODIFF (XBUFFER (w->buffer))
-      && (XFASTINT (w->last_overlay_modified)
-	  == BUF_OVERLAY_MODIFF (XBUFFER (w->buffer))))
+      && XFASTINT (w->last_modified) == BUF_MODIFF (b)
+      && XFASTINT (w->last_overlay_modified) == BUF_OVERLAY_MODIFF (b))
     {
       int hpos, vpos, pos, i, area;
       struct glyph *glyph;
+      Lisp_Object object;
+      Lisp_Object mouse_face = Qnil, overlay = Qnil, position;
+      Lisp_Object *overlay_vec = NULL;
+      int len, noverlays;
+      struct buffer *obuf;
+      int obegv, ozv, same_region;
 
       /* 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
@@ -6457,197 +6511,333 @@
 	  || !MATRIX_ROW (w->current_matrix, vpos)->displays_text_p)
 	{
 	  clear_mouse_face (dpyinfo);
-	  return;
+	  /* TODO: mouse cursor */
+	  goto set_cursor;
 	}
 
       pos = glyph->charpos;
-      xassert (w->pseudo_window_p || BUFFERP (glyph->object));
-
-      /* Check for mouse-face and help-echo.  */
-      {
-        Lisp_Object mouse_face, overlay, position;
-        Lisp_Object *overlay_vec;
-        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)))
-          return;
-
-        /* Make the window's buffer temporarily current for
-           overlays_at and compute_char_face.  */
-        obuf = current_buffer;
-        current_buffer = XBUFFER (w->buffer);
-        obegv = BEGV;
-        ozv = ZV;
-        BEGV = BEG;
-        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)
-	  {
-	    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);
-
-	/* Check mouse-face highlighting.  */
-	if (! (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)))
-	  {
-	    /* 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.  */
-            overlay = Qnil;
-            for (i = noverlays - 1; i >= 0; --i)
-              {
-                mouse_face = Foverlay_get (overlay_vec[i], Qmouse_face);
-                if (!NILP (mouse_face))
-                  {
-                    overlay = overlay_vec[i];
-                    break;
-                  }
-              }
-
-            /* If no overlay applies, get a text property.  */
-            if (NILP (overlay))
-              mouse_face = Fget_text_property (position, Qmouse_face, w->buffer);
-
-            /* Handle the overlay case.  */
-            if (! NILP (overlay))
-              {
-                /* Find the range of text around this char that
-                   should be active.  */
-                Lisp_Object before, after;
-                int ignore;
-
-                before = Foverlay_start (overlay);
-                after = Foverlay_end (overlay);
-                /* Record this as the current active region.  */
-                fast_find_position (w, XFASTINT (before),
-                                    &dpyinfo->mouse_face_beg_col,
-                                    &dpyinfo->mouse_face_beg_row,
+      object = glyph->object;
+      if (!STRINGP (object) && !BUFFERP (object))
+	goto set_cursor;
+
+      /* If we get an out-of-range value, return now; avoid an error.  */
+      if (BUFFERP (object) && pos > BUF_Z (b))
+	goto set_cursor;
+
+      /* Make the window's buffer temporarily current for
+	 overlays_at and compute_char_face.  */
+      obuf = current_buffer;
+      current_buffer = b;
+      obegv = BEGV;
+      ozv = ZV;
+      BEGV = BEG;
+      ZV = Z;
+
+      /* Is this char mouse-active or does it have help-echo?  */
+      position = make_number (pos);
+
+      if (BUFFERP (object))
+	{
+	  /* 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)
+	    {
+	      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);
+	}
+      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));
+
+      /* TODO: if (same_region)
+	 mouse cursor */
+
+      /* Check mouse-face highlighting.  */
+      if (! same_region
+	  /* If there exists an overlay with mouse-face overlapping
+	     the one we are currently highlighting, we have to
+	     check if we enter the overlapping overlay, and then
+	     highlight that.  */
+	  || (OVERLAYP (dpyinfo->mouse_face_overlay)
+	      && mouse_face_overlay_overlaps (dpyinfo->mouse_face_overlay)))
+	{
+	  /* Find the highest priority overlay that has a mouse-face
+	     property.  */
+	  overlay = Qnil;
+	  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];
+	    }
+
+	  /* If we're actually highlighting the same overlay as
+	     before, there's no need to do that again.  */
+	  if (!NILP (overlay)
+	      && EQ (overlay, dpyinfo->mouse_face_overlay))
+	    goto check_help_echo;
+
+	  dpyinfo->mouse_face_overlay = overlay;
+
+	  /* Clear the display of the old active region, if any.  */
+	  clear_mouse_face (dpyinfo);
+	  /* TODO: mouse cursor changes.  */
+
+	  /* If no overlay applies, get a text property.  */
+	  if (NILP (overlay))
+	    mouse_face = Fget_text_property (position, Qmouse_face, object);
+
+	  /* Handle the overlay case.  */
+	  if (!NILP (overlay))
+	    {
+	      /* Find the range of text around this char that
+		 should be active.  */
+	      Lisp_Object before, after;
+	      int ignore;
+
+	      before = Foverlay_start (overlay);
+	      after = Foverlay_end (overlay);
+	      /* Record this as the current active region.  */
+	      fast_find_position (w, XFASTINT (before),
+				  &dpyinfo->mouse_face_beg_col,
+				  &dpyinfo->mouse_face_beg_row,
+				  &dpyinfo->mouse_face_beg_x,
+				  &dpyinfo->mouse_face_beg_y, Qnil);
+
+	      dpyinfo->mouse_face_past_end
+		= !fast_find_position (w, XFASTINT (after),
+				       &dpyinfo->mouse_face_end_col,
+				       &dpyinfo->mouse_face_end_row,
+				       &dpyinfo->mouse_face_end_x,
+				       &dpyinfo->mouse_face_end_y, Qnil);
+	      dpyinfo->mouse_face_window = window;
+
+	      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);
+	      /* TODO: mouse cursor changes.  */
+	    }
+	  /* Handle the text property case.  */
+	  else if (! NILP (mouse_face) && BUFFERP (object))
+	    {
+	      /* Find the range of text around this char that
+		 should be active.  */
+	      Lisp_Object before, after, beginning, end;
+	      int ignore;
+
+	      beginning = Fmarker_position (w->start);
+	      end = make_number (BUF_Z (XBUFFER (object))
+				 - XFASTINT (w->window_end_pos));
+	      before
+		= Fprevious_single_property_change (make_number (pos + 1),
+						    Qmouse_face,
+						    object, beginning);
+	      after
+		= Fnext_single_property_change (position, Qmouse_face,
+						object, end);
+
+	      /* Record this as the current active region.  */
+	      fast_find_position (w, XFASTINT (before),
+				  &dpyinfo->mouse_face_beg_col,
+				  &dpyinfo->mouse_face_beg_row,
+				  &dpyinfo->mouse_face_beg_x,
+				  &dpyinfo->mouse_face_beg_y, Qnil);
+	      dpyinfo->mouse_face_past_end
+		= !fast_find_position (w, XFASTINT (after),
+				       &dpyinfo->mouse_face_end_col,
+				       &dpyinfo->mouse_face_end_row,
+				       &dpyinfo->mouse_face_end_x,
+				       &dpyinfo->mouse_face_end_y, Qnil);
+	      dpyinfo->mouse_face_window = window;
+
+	      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);
+	      /* TODO: mouse cursor changes.  */
+	    }
+	  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);
-                dpyinfo->mouse_face_past_end
-                  = !fast_find_position (w, XFASTINT (after),
-                                         &dpyinfo->mouse_face_end_col,
-                                         &dpyinfo->mouse_face_end_row,
-                                         &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);
-
-                /* Display it as active.  */
-                show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
-              }
-            /* Handle the text property case.  */
-            else if (! NILP (mouse_face))
-              {
-                /* Find the range of text around this char that
-                   should be active.  */
-                Lisp_Object before, after, beginning, end;
-                int ignore;
-
-                beginning = Fmarker_position (w->start);
-                XSETINT (end, (BUF_Z (XBUFFER (w->buffer))
-                               - XFASTINT (w->window_end_pos)));
-                before
-                  = Fprevious_single_property_change (make_number (pos + 1),
-                                                      Qmouse_face,
-                                                      w->buffer, beginning);
-                after
-                  = Fnext_single_property_change (position, Qmouse_face,
-                                                  w->buffer, end);
-                /* Record this as the current active region.  */
-                fast_find_position (w, XFASTINT (before),
-                                    &dpyinfo->mouse_face_beg_col,
-                                    &dpyinfo->mouse_face_beg_row,
-                                    &dpyinfo->mouse_face_beg_x,
-                                    &dpyinfo->mouse_face_beg_y);
-                dpyinfo->mouse_face_past_end
-                  = !fast_find_position (w, XFASTINT (after),
-                                         &dpyinfo->mouse_face_end_col,
-                                         &dpyinfo->mouse_face_end_row,
-					 &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);
-
-                /* Display it as active.  */
-                show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
-              }
-          }
-
-        /* Look for a `help-echo' property.  */
-        {
-          Lisp_Object help, overlay;
-
-	  /* Check overlays first.  */
-	  help = overlay = Qnil;
-	  for (i = noverlays - 1; i >= 0 && NILP (help); --i)
-            {
-              overlay = overlay_vec[i];
-              help = Foverlay_get (overlay, Qhelp_echo); 
-            }
-
-          if (!NILP (help))
-            {
-              help_echo = help;
-              help_echo_window = window;
-              help_echo_object = overlay;
-              help_echo_pos = pos;
-            }
-          else
-            {
-              /* Try text properties.  */
-              if ((STRINGP (glyph->object)
-		   && glyph->charpos >= 0
-		   && glyph->charpos < XSTRING (glyph->object)->size)
-		  || (BUFFERP (glyph->object)
-		      && glyph->charpos >= BEGV
-		      && glyph->charpos < ZV))
-                help = Fget_text_property (make_number (glyph->charpos),
-                                           Qhelp_echo, glyph->object);
+				    &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);
+	      /* TODO: mouse cursor changes.  */
+	    }
+	  else if (STRINGP (object) && NILP (mouse_face))
+	    {
+	      /* A string which doesn't have mouse-face, but
+		 the text ``under'' it might have.  */
+	      struct glyph_row *r = MATRIX_ROW (w->current_matrix, vpos);
+	      int start = MATRIX_ROW_START_CHARPOS (r);
+	      
+	      pos = string_buffer_position (w, object, start);
+	      if (pos > 0)
+		mouse_face = get_char_property_and_overlay (make_number (pos),
+							    Qmouse_face,
+							    w->buffer,
+							    &overlay);
+	      if (!NILP (mouse_face) && !NILP (overlay))
+		{
+		  Lisp_Object before = Foverlay_start (overlay);
+		  Lisp_Object after = Foverlay_end (overlay);
+		  Lisp_Object ignore;
+
+		  /* Note that we might not be able to find position
+		     BEFORE in the glyph matrix if the overlay is
+		     entirely covered by a `display' property.  In
+		     this case, we overshoot.  So let's stop in
+		     the glyph matrix before glyphs for OBJECT.  */
+		  fast_find_position (w, XFASTINT (before),
+				      &dpyinfo->mouse_face_beg_col,
+				      &dpyinfo->mouse_face_beg_row,
+				      &dpyinfo->mouse_face_beg_x,
+				      &dpyinfo->mouse_face_beg_y,
+				      object);
+		       
+		  dpyinfo->mouse_face_past_end
+		    = !fast_find_position (w, XFASTINT (after),
+					   &dpyinfo->mouse_face_end_col,
+					   &dpyinfo->mouse_face_end_row,
+					   &dpyinfo->mouse_face_end_x,
+					   &dpyinfo->mouse_face_end_y,
+					   Qnil);
+		  dpyinfo->mouse_face_window = window;
+		  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);
+		  /* TODO: mouse cursor changes.  */
+		}
+	    }
+	}
+
+    check_help_echo:
+
+      /* Look for a `help-echo' property.  */
+      {
+	Lisp_Object help, overlay;
+
+	/* Check overlays first.  */
+	help = overlay = Qnil;
+	for (i = noverlays - 1; i >= 0 && NILP (help); --i)
+	  {
+	    overlay = overlay_vec[i];
+	    help = Foverlay_get (overlay, Qhelp_echo); 
+	  }
+
+	if (!NILP (help))
+	  {
+	    help_echo = help;
+	    help_echo_window = window;
+	    help_echo_object = overlay;
+	    help_echo_pos = pos;
+	  }
+	else
+	  {
+	    Lisp_Object object = glyph->object;
+	    int charpos = glyph->charpos;
+
+	    /* Try text properties.  */
+	    if (STRINGP (object)
+		&& charpos >= 0
+		&& charpos < XSTRING (object)->size)
+	      {
+		help = Fget_text_property (make_number (charpos),
+					   Qhelp_echo, object);
+		if (NILP (help))
+		  {
+		    /* If the string itself doesn't specify a help-echo,
+		       see if the buffer text ``under'' it does.  */
+		    struct glyph_row *r
+		      = MATRIX_ROW (w->current_matrix, vpos);
+		    int start = MATRIX_ROW_START_CHARPOS (r);
+		    int pos = string_buffer_position (w, object, start);
+		    if (pos > 0)
+		      {
+			help = Fget_char_property (make_number (pos),
+						   Qhelp_echo, w->buffer);
+			if (!NILP (help))
+			  {
+			    charpos = pos;
+			    object = w->buffer;
+			  }
+		      }
+		  }
+	      }
+	    else if (BUFFERP (object)
+		     && charpos >= BEGV
+		     && charpos < ZV)
+	      help = Fget_text_property (make_number (charpos), Qhelp_echo,
+					 object);
 	    
-              if (!NILP (help))
-                {
-                  help_echo = help;
-                  help_echo_window = window;
-                  help_echo_object = glyph->object;
-                  help_echo_pos = glyph->charpos;
-                }
-            }
-        }
-        
-        BEGV = obegv;
-        ZV = ozv;
-        current_buffer = obuf;
+	    if (!NILP (help))
+	      {
+		help_echo = help;
+		help_echo_window = window;
+		help_echo_object = object;
+		help_echo_pos = charpos;
+	      }
+	  }
       }
-    }
+
+      BEGV = obegv;
+      ZV = ozv;
+      current_buffer = obuf;
+    }
+
+ set_cursor:
+  /* TODO: mouse cursor changes. */
+  ;
 }
 
 static void
@@ -6697,7 +6887,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;
 
@@ -6877,28 +7067,101 @@
 
 
 
-/* Find the glyph matrix position of buffer position POS in window W.
-   *HPOS, *VPOS, *X, and *Y are set to the positions found.  W's
-   current glyphs must be up to date.  If POS is above window start
-   return (0, 0, 0, 0).  If POS is after end of W, return end of
-   last line in W.  */
+/* Find the glyph matrix position of buffer position CHARPOS in window
+   *W.  HPOS, *VPOS, *X, and *Y are set to the positions found.  W's
+   current glyphs must be up to date.  If CHARPOS is above window
+   start return (0, 0, 0, 0).  If CHARPOS is after end of W, return end
+   of last line in W.  In the row containing CHARPOS, stop before glyphs
+   having STOP as object.  */
+
+#if 0 /* This is a version of fast_find_position that's more correct
+	 in the presence of hscrolling, for example.  I didn't install
+	 it right away because the problem fixed is minor, it failed
+	 in 20.x as well, and I think it's too risky to install 
+	 so near the release of 21.1.  2001-09-25 gerd.  */
 
 static int
-fast_find_position (w, pos, hpos, vpos, x, y)
+fast_find_position (w, charpos, hpos, vpos, x, y, stop)
+     struct window *w;
+     int charpos;
+     int *hpos, *vpos, *x, *y;
+     Lisp_Object stop;
+{
+  struct glyph_row *row, *first;
+  struct glyph *glyph, *end;
+  int i, past_end = 0;
+
+  first = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
+  row = row_containing_pos (w, charpos, first, NULL);
+  if (row == NULL)
+    {
+      if (charpos < MATRIX_ROW_START_CHARPOS (first))
+	{
+	  *x = *y = *hpos = *vpos = 0;
+	  return 0;
+	}
+      else
+	{
+	  row = MATRIX_ROW (w->current_matrix, XFASTINT (w->window_end_vpos));
+	  past_end = 1;
+	}
+    }
+
+  *x = row->x;
+  *y = row->y;
+  *vpos = MATRIX_ROW_VPOS (row, w->current_matrix);
+  
+  glyph = row->glyphs[TEXT_AREA];
+  end = glyph + row->used[TEXT_AREA];
+  
+  /* Skip over glyphs not having an object at the start of the row.
+     These are special glyphs like truncation marks on terminal
+     frames.  */
+  if (row->displays_text_p)
+    while (glyph < end
+	   && INTEGERP (glyph->object)
+	   && !EQ (stop, glyph->object)
+	   && glyph->charpos < 0)
+      {
+	*x += glyph->pixel_width;
+	++glyph;
+      }
+
+  while (glyph < end
+	 && !INTEGERP (glyph->object)
+	 && !EQ (stop, glyph->object)
+	 && (!BUFFERP (glyph->object)
+	     || glyph->charpos < charpos))
+    {
+      *x += glyph->pixel_width;
+      ++glyph;
+    }
+
+  *hpos = glyph - row->glyphs[TEXT_AREA];
+  return past_end;
+}
+
+#else /* not 0 */
+
+static int
+fast_find_position (w, pos, hpos, vpos, x, y, stop)
      struct window *w;
      int pos;
      int *hpos, *vpos, *x, *y;
+     Lisp_Object stop;
 {
   int i;
   int lastcol;
   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 *best_row = row;
-  int row_vpos = 0, best_row_vpos = 0;
+  struct glyph_row *row, *best_row;
+  int row_vpos, best_row_vpos;
   int current_x;
 
+  row = best_row = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
+  row_vpos = best_row_vpos = MATRIX_ROW_VPOS (row, w->current_matrix);
+
   while (row->y < yb)
     {
       if (row->used[TEXT_AREA])
@@ -6935,22 +7198,26 @@
   for (i = 0; i < best_row->used[TEXT_AREA]; i++)
     {
       struct glyph *glyph = best_row->glyphs[TEXT_AREA] + i;
-      int charpos;
-
-      charpos = glyph->charpos;
-      if (charpos == pos)
+      int charpos = glyph->charpos;
+
+      if (BUFFERP (glyph->object))
 	{
-	  *hpos = i;
-	  *vpos = best_row_vpos;
-	  *x = current_x;
-	  *y = best_row->y;
-	  return 1;
+	  if (charpos == pos)
+	    {
+	      *hpos = i;
+	      *vpos = best_row_vpos;
+	      *x = current_x;
+	      *y = best_row->y;
+	      return 1;
+	    }
+	  else if (charpos > pos)
+	    break;
 	}
-      else if (charpos > pos)
+      else if (EQ (glyph->object, stop))
 	break;
-      else if (charpos > 0)
+
+      if (charpos > 0)
 	lastcol = i;
-
       current_x += glyph->pixel_width;
     }
 
@@ -6972,6 +7239,90 @@
   return 0;
 }
 
+#endif /* not 0 */
+
+
+/* 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.  */
@@ -7045,7 +7396,7 @@
         {
           x_draw_glyphs (w, start_x, row, TEXT_AREA,
                          start_hpos, end_hpos, draw, NULL, NULL, 0);
-          row->mouse_face_p = draw == DRAW_MOUSE_FACE;
+          row->mouse_face_p = draw == DRAW_MOUSE_FACE || DRAW_IMAGE_RAISED;
         }
     }
 
@@ -7076,22 +7427,23 @@
 /* Clear out the mouse-highlighted active region.
    Redraw it un-highlighted first.  */
 
-void
+static int
 clear_mouse_face (dpyinfo)
      struct w32_display_info *dpyinfo;
 {
-#if 0 /* This prevents redrawing tool bar items when changing from one
-	 to another while a tooltip is open, so don't do it.  */
-  if (!NILP (tip_frame))
-    return;
-#endif
+  int cleared = 0;
 
   if (! NILP (dpyinfo->mouse_face_window))
-    show_mouse_face (dpyinfo, DRAW_NORMAL_TEXT);
+    {
+      show_mouse_face (dpyinfo, 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;
+  return cleared;
 }
 
 
@@ -7136,6 +7488,88 @@
 
 static struct scroll_bar *x_window_to_scroll_bar ();
 static void x_scroll_bar_report_motion ();
+static int glyph_rect P_ ((struct frame *f, int, int, RECT *));
+
+
+/* Try to determine frame pixel position and size of the glyph under
+   frame pixel coordinates X/Y on frame F .  Return the position and
+   size in *RECT.  Value is non-zero if we could compute these
+   values.  */
+
+static int
+glyph_rect (f, x, y, rect)
+     struct frame *f;
+     int x, y;
+     RECT *rect;
+{
+  Lisp_Object window;
+  int part, found = 0;
+
+  window = window_from_coordinates (f, x, y, &part, 0);
+  if (!NILP (window))
+    {
+      struct window *w = XWINDOW (window);
+      struct glyph_row *r = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
+      struct glyph_row *end = r + w->current_matrix->nrows - 1;
+      int area;
+
+      frame_to_window_pixel_xy (w, &x, &y);
+      
+      for (; !found && r < end && r->enabled_p; ++r)
+	if (r->y + r->height >= y)
+	  {
+	    struct glyph *g = r->glyphs[TEXT_AREA];
+	    struct glyph *end = g + r->used[TEXT_AREA];
+	    int gx;
+	      
+	    for (gx = r->x; !found && g < end; gx += g->pixel_width, ++g)
+	      if (gx + g->pixel_width >= x)
+		{
+		  rect->left = WINDOW_TO_FRAME_PIXEL_X (w, gx);
+		  rect->top = WINDOW_TO_FRAME_PIXEL_Y (w, r->y);
+		  rect->right = rect->left + g->pixel_width;
+		  rect->bottom = rect->top + r->height;
+		  found = 1;
+		}
+	  }
+    }
+
+  return found;
+}
+
+/* Record the position of the mouse in last_mouse_glyph.  */
+static void remember_mouse_glyph (f1, gx, gy)
+     struct frame * f1;
+     int gx, gy;
+{
+  if (!glyph_rect (f1, gx, gy, &last_mouse_glyph))
+    {
+      int width = FRAME_SMALLEST_CHAR_WIDTH (f1);
+      int height = FRAME_SMALLEST_FONT_HEIGHT (f1);
+
+      /* Arrange for the division in PIXEL_TO_CHAR_COL etc. to
+	 round down even for negative values.  */
+      if (gx < 0)
+	gx -= width - 1;
+      if (gy < 0)
+	gy -= height - 1;
+#if 0
+      /* This was the original code from XTmouse_position, but it seems
+	 to give the position of the glyph diagonally next to the one
+	 the mouse is over.  */
+      gx = (gx + width - 1) / width * width;
+      gy = (gy + height - 1) / height * height;
+#else
+      gx = gx / width * width;
+      gy = gy / height * height;
+#endif
+
+      last_mouse_glyph.left = gx;
+      last_mouse_glyph.top = gy;
+      last_mouse_glyph.right  = gx + width;
+      last_mouse_glyph.bottom = gy + height;
+    }
+}
 
 /* Return the current position of the mouse.
    *fp should be a frame which indicates which display to ask about.
@@ -7199,7 +7633,7 @@
 	else
 	  {
 	    /* Is window under mouse one of our frames?  */
-	    f1 = x_window_to_frame (FRAME_W32_DISPLAY_INFO (*fp),
+	    f1 = x_any_window_to_frame (FRAME_W32_DISPLAY_INFO (*fp),
                                     WindowFromPoint (pt));
 	  }
 
@@ -7239,24 +7673,7 @@
 				   || insist);
 #else
 	    ScreenToClient (FRAME_W32_WINDOW (f1), &pt);
-	    {
-	      int width = FRAME_SMALLEST_CHAR_WIDTH (f1);
-	      int height = FRAME_SMALLEST_FONT_HEIGHT (f1);
-	      int x = pt.x;
-	      int y = pt.y;
-	      
-	      /* Arrange for the division in PIXEL_TO_CHAR_COL etc. to
-		 round down even for negative values.  */
-	      if (x < 0)
-		x -= width - 1;
-	      if (y < 0)
-		y -= height - 1;
-	      
-	      last_mouse_glyph.left = (x + width - 1) / width * width;
-	      last_mouse_glyph.top = (y + height - 1) / height * height;
-	      last_mouse_glyph.right  = last_mouse_glyph.left + width;
-	      last_mouse_glyph.bottom = last_mouse_glyph.top + height;
-	    }
+	    remember_mouse_glyph (f1, pt.x, pt.y);
 #endif
 
 	    *bar_window = Qnil;
@@ -7576,9 +7993,12 @@
     {
       HDC hdc;
       BLOCK_INPUT;
-      hdc = get_frame_dc (f);
-      w32_clear_area (f, hdc, left, top, width, height);
-      release_frame_dc (f, hdc);
+      if (width && height)
+	{
+	  hdc = get_frame_dc (f);
+	  w32_clear_area (f, hdc, left, top, width, height);
+	  release_frame_dc (f, hdc);
+	}
       UNBLOCK_INPUT;
 
       bar = x_scroll_bar_create (w, top, sb_left, sb_width, height);
@@ -7605,22 +8025,24 @@
         {
           HDC hdc;
           BLOCK_INPUT;
-
-          hdc = get_frame_dc (f);
-          /* Since Windows scroll bars are smaller than the space reserved
-             for them on the frame, we have to clear "under" them.  */
-          w32_clear_area (f, hdc,
-                          left,
-                          top,
-                          width,
-                          height);
-          release_frame_dc (f, hdc);
-
+	  if (width && height)
+	    {
+	      hdc = get_frame_dc (f);
+	      /* Since Windows scroll bars are smaller than the space reserved
+		 for them on the frame, we have to clear "under" them.  */
+	      w32_clear_area (f, hdc,
+			      left,
+			      top,
+			      width,
+			      height);
+	      release_frame_dc (f, hdc);
+	    }
           /* Make sure scroll bar is "visible" before moving, to ensure the
              area of the parent window now exposed will be refreshed.  */
           my_show_window (f, hwnd, SW_HIDE);
-          MoveWindow (hwnd, sb_left, top,
-                      sb_width, height, TRUE);
+          MoveWindow (hwnd, sb_left + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
+		      top, sb_width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
+		      max (height, 1), TRUE);
           if (pfnSetScrollInfo)
             {
               SCROLLINFO si;
@@ -8057,58 +8479,58 @@
       switch (msg.msg.message)
 	{
 	case WM_PAINT:
-	    f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
-
-	    if (f) 
-	      {
-		if (msg.rect.right == msg.rect.left ||
-		    msg.rect.bottom == msg.rect.top)
-		  {
-		    /* We may get paint messages even though the client
-		       area is clipped - these are not expose events. */
-		    DebPrint (("clipped frame %p (%s) got WM_PAINT - ignored\n", f,
-			       XSTRING (f->name)->data));
-		  }
-		else if (f->async_visible != 1)
-		  {
-		    /* Definitely not obscured, so mark as visible.  */
-		    f->async_visible = 1;
-		    f->async_iconified = 0;
-		    SET_FRAME_GARBAGED (f);
-		    DebPrint (("frame %p (%s) reexposed by WM_PAINT\n", f,
-			       XSTRING (f->name)->data));
-
-		    /* WM_PAINT serves as MapNotify as well, so report
-                       visibility changes properly.  */
-		    if (f->iconified)
-		      {
-			bufp->kind = deiconify_event;
-			XSETFRAME (bufp->frame_or_window, f);
-			bufp->arg = Qnil;
-			bufp++;
-			count++;
-			numchars--;
-		      }
-		    else if (! NILP (Vframe_list)
-			     && ! NILP (XCDR (Vframe_list)))
-		      /* Force a redisplay sooner or later to update the
-			 frame titles in case this is the second frame.  */
-		      record_asynch_buffer_change ();
-		  }
-		else
-		  {
-                    HDC hdc = get_frame_dc (f);
-
-		    /* Erase background again for safety.  */
-		    w32_clear_rect (f, hdc, &msg.rect);
-                    release_frame_dc (f, hdc);
-		    expose_frame (f,
-                                  msg.rect.left,
-                                  msg.rect.top,
-                                  msg.rect.right - msg.rect.left,
-                                  msg.rect.bottom - msg.rect.top);
-		  }
-	      }
+	  f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
+
+	  if (f) 
+	    {
+	      if (msg.rect.right == msg.rect.left ||
+		  msg.rect.bottom == msg.rect.top)
+		{
+		  /* We may get paint messages even though the client
+		     area is clipped - these are not expose events. */
+		  DebPrint (("clipped frame %p (%s) got WM_PAINT - ignored\n", f,
+			     XSTRING (f->name)->data));
+		}
+	      else if (f->async_visible != 1)
+		{
+		  /* Definitely not obscured, so mark as visible.  */
+		  f->async_visible = 1;
+		  f->async_iconified = 0;
+		  SET_FRAME_GARBAGED (f);
+		  DebPrint (("frame %p (%s) reexposed by WM_PAINT\n", f,
+			     XSTRING (f->name)->data));
+
+		  /* WM_PAINT serves as MapNotify as well, so report
+		     visibility changes properly.  */
+		  if (f->iconified)
+		    {
+		      bufp->kind = deiconify_event;
+		      XSETFRAME (bufp->frame_or_window, f);
+		      bufp->arg = Qnil;
+		      bufp++;
+		      count++;
+		      numchars--;
+		    }
+		  else if (! NILP (Vframe_list)
+			   && ! NILP (XCDR (Vframe_list)))
+		    /* Force a redisplay sooner or later to update the
+		       frame titles in case this is the second frame.  */
+		    record_asynch_buffer_change ();
+		}
+	      else
+		{
+		  HDC hdc = get_frame_dc (f);
+
+		  /* Erase background again for safety.  */
+		  w32_clear_rect (f, hdc, &msg.rect);
+		  release_frame_dc (f, hdc);
+		  expose_frame (f,
+				msg.rect.left,
+				msg.rect.top,
+				msg.rect.right - msg.rect.left,
+				msg.rect.bottom - msg.rect.top);
+		}
+	    }
 	  break;
 
 	case WM_INPUTLANGCHANGE:
@@ -8175,7 +8597,7 @@
 
 	case WM_MOUSEMOVE:
           previous_help_echo = help_echo;
-          help_echo = help_echo_object = help_echo_window = Qnil;
+          help_echo_object = help_echo_window = Qnil;
           help_echo_pos = -1;
 
 	  if (dpyinfo->grabbed && last_mouse_frame
@@ -8195,8 +8617,7 @@
 
           /* If the contents of the global variable help_echo
              has changed, generate a HELP_EVENT.  */
-          if (!NILP (help_echo)
-              || !NILP (previous_help_echo))
+          if (help_echo != previous_help_echo)
             {
               Lisp_Object frame;
               int n;
@@ -9005,6 +9426,8 @@
   /* Erase the cursor by redrawing the character underneath it.  */
   if (mouse_face_here_p)
     hl = DRAW_MOUSE_FACE;
+  else if (cursor_row->inverse_p)
+    hl = DRAW_INVERSE_VIDEO;
   else
     hl = DRAW_NORMAL_TEXT;
   x_draw_phys_cursor_glyph (w, cursor_row, hl);
@@ -9015,6 +9438,36 @@
 }
 
 
+/* Non-zero if physical cursor of window W is within mouse face.  */
+
+static int
+cursor_in_mouse_face_p (w)
+     struct window *w;
+{
+  struct w32_display_info *dpyinfo
+    = FRAME_W32_DISPLAY_INFO (XFRAME (w->frame));
+  int in_mouse_face = 0;
+  
+  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;
+    }
+
+  return in_mouse_face;
+}
+
+
 /* Display or clear cursor of window W.  If ON is zero, clear the
    cursor.  If it is non-zero, display the cursor.  If ON is nonzero,
    where to put the cursor is specified by HPOS, VPOS, X and Y.  */
@@ -10126,7 +10579,7 @@
   dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
   dpyinfo->mouse_face_face_id = DEFAULT_FACE_ID;
   dpyinfo->mouse_face_window = Qnil;
-
+  dpyinfo->mouse_face_overlay = Qnil;
   /* TODO: dpyinfo->gray */
 
 }
@@ -10470,6 +10923,16 @@
 wide as that tab on the display.");
   x_stretch_cursor_p = 0;
 
+#if 0 /* TODO: Setting underline position from font properties.  */
+  DEFVAR_BOOL ("x-use-underline-position-properties",
+	       &x_use_underline_position_properties,
+     "*Non-nil means make use of UNDERLINE_POSITION font properties.\n\
+Nil means ignore them.  If you encounter fonts with bogus\n\
+UNDERLINE_POSITION font properties, for example 7x13 on XFree prior\n\
+to 4.1, set this to nil.");
+  x_use_underline_position_properties = 1;
+#endif
+
   DEFVAR_LISP ("x-toolkit-scroll-bars", &Vx_toolkit_scroll_bars,
     "If not nil, Emacs uses toolkit scroll bars.");
   Vx_toolkit_scroll_bars = Qt;