]> git.eshelyaron.com Git - emacs.git/commitdiff
(remember_mouse_glyph): New function.
authorJason Rumney <jasonr@gnu.org>
Sun, 21 Oct 2001 15:20:03 +0000 (15:20 +0000)
committerJason Rumney <jasonr@gnu.org>
Sun, 21 Oct 2001 15:20:03 +0000 (15:20 +0000)
(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.

src/w32term.c

index 09a3295b8f34f2a37ed1940421d001f1f435a604..1fe99c75acc79dcb411a8191d848d2ffea43f040 100644 (file)
@@ -168,6 +168,10 @@ static int any_help_event_p;
 
 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 x_update_window_end P_ ((struct window *, int, int));
 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 @@ static void w32_handle_tool_bar_click P_ ((struct frame *,
                                           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_frame_rehighlight P_ ((struct w32_display_info *));
 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 @@ x_draw_vertical_border (w)
       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 @@ x_update_window_end (w, cursor_on_p, mouse_face_overwritten_p)
      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_update_window_end (w, cursor_on_p, mouse_face_overwritten_p)
       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 @@ x_produce_glyphs (it)
          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 @@ void W32_TEXTOUT (s, x, y,chars,nchars)
                 nchars * charset_dim, NULL);
 }
 
-#if 0
+#if GLYPH_DEBUG
 
 static void
 x_dump_glyph_string (s)
@@ -3030,20 +3037,6 @@ w32_get_glyph_string_clip_rect (s, r)
       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 @@ w32_get_glyph_string_clip_rect (s, r)
       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 @@ w32_draw_relief_rect (f, left_x, top_y, right_x, bottom_y, width,
 
   /* 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 @@ x_draw_glyph_string_box (s)
   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 @@ x_draw_stretch_glyph_string (s)
          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 @@ x_draw_stretch_glyph_string (s)
             }
         }
     }
-  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 @@ x_draw_glyph_string (s)
 
   /* 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 @@ x_draw_glyph_string (s)
          || 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 @@ x_draw_glyph_string (s)
           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 @@ x_fill_stretch_glyph_string (s, row, area, start, end)
   /* 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 @@ expose_frame (f, x, y, w, h)
      int x, y, w, h;
 {
   RECT r;
+  int mouse_face_overwritten_p = 0;
 
   TRACE ((stderr, "expose_frame "));
 
@@ -5475,23 +5487,35 @@ expose_frame (f, x, y, w, h)
     }
 
   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))
+    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 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);
+      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 @@ expose_frame (f, x, y, w, h)
 /* 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);
-       }
+       mouse_face_overwritten_p |= expose_window (w, r);
 
-      w = NILP (w->next) ? 0 : XWINDOW (w->next);
+      w = NILP (w->next) ? NULL : XWINDOW (w->next);
     }
+
+  return mouse_face_overwritten_p;
 }
 
 
@@ -5606,9 +5614,10 @@ expose_area (w, row, r, area)
 
 
 /* Redraw the parts of the glyph row ROW on window W intersecting
-   rectangle R.  R is in window-relative coordinates.  */
+   rectangle R.  R is in window-relative coordinates.  Value is
+   non-zero if mouse face was overwritten.  */
 
-static void
+static int
 expose_line (w, row, r)
      struct window *w;
      struct glyph_row *row;
@@ -5629,6 +5638,8 @@ expose_line (w, row, r)
        expose_area (w, row, r, RIGHT_MARGIN_AREA);
       x_draw_row_bitmaps (w, row);
     }
+
+  return row->mouse_face_p;
 }
 
 
@@ -5656,82 +5667,110 @@ x_phys_cursor_in_rect_p (w, r)
 }
 
 
-/* Redraw a rectangle of window W.  R is a rectangle in window
-   relative coordinates.  Call this function with input blocked.  */
+/* 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 void
-expose_window (w, r)
+static int
+expose_window (w, fr)
      struct window *w;
-     RECT *r;
+     RECT *fr;
 {
-  struct glyph_row *row;
-  int y;
-  int yb = window_text_bottom_y (w);
-  int cursor_cleared_p;
+  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);
+  if (w->current_matrix == NULL)
+    return 0;
 
-  /* Turn off the cursor.  */
-  if (!w->pseudo_window_p
-      && x_phys_cursor_in_rect_p (w, r))
+  /* 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)
     {
-      x_clear_cursor (w);
-      cursor_cleared_p = 1;
+      SET_FRAME_GARBAGED (f);
+      return 0;
     }
-  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)
+  /* 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))
     {
-      expose_line (w, row, r);
-      y += row->height;
-      ++row;
-    }
+      int yb = window_text_bottom_y (w);
+      struct glyph_row *row;
+      int cursor_cleared_p;
 
-  /* 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);
+      TRACE ((stderr, "expose_window (%d, %d, %d, %d)\n",
+             r.left, r.top, r.right, r.bottom));
 
-  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);
+      /* 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;
 }
 
 \f
@@ -6134,11 +6173,16 @@ construct_drag_n_drop (result, msg, f)
 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 @@ note_mouse_movement (frame, msg)
     }
 
   /* 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 @@ int disable_mouse_highlight;
    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 @@ 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;
        }
       
@@ -6376,6 +6426,7 @@ note_mouse_highlight (f, x, y)
   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 @@ note_mouse_highlight (f, x, y)
       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 @@ note_mouse_highlight (f, x, y)
          || !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));
+      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];
+           }
 
-      /* Check for mouse-face and help-echo.  */
+         /* 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, 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 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)
+       Lisp_Object help, overlay;
+
+       /* Check overlays first.  */
+       help = overlay = Qnil;
+       for (i = noverlays - 1; i >= 0 && NILP (help); --i)
          {
-           len = noverlays;
-           overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
-           noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL,0);
+           overlay = overlay_vec[i];
+           help = Foverlay_get (overlay, Qhelp_echo); 
          }
 
-       /* 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)))
+       if (!NILP (help))
          {
-           /* 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,
-                                   &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); 
-            }
+           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;
 
-          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);
+           /* 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 @@ 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;
 
@@ -6877,28 +7067,101 @@ note_tool_bar_highlight (f, x, y)
 
 
 \f
-/* 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 @@ fast_find_position (w, pos, hpos, vpos, x, y)
   for (i = 0; i < best_row->used[TEXT_AREA]; i++)
     {
       struct glyph *glyph = best_row->glyphs[TEXT_AREA] + i;
-      int charpos;
+      int charpos = glyph->charpos;
 
-      charpos = glyph->charpos;
-      if (charpos == pos)
+      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)
-       lastcol = i;
 
+      if (charpos > 0)
+       lastcol = i;
       current_x += glyph->pixel_width;
     }
 
@@ -6972,6 +7239,90 @@ fast_find_position (w, pos, hpos, vpos, x, y)
   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 @@ show_mouse_face (dpyinfo, draw)
         {
           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 @@ show_mouse_face (dpyinfo, draw)
 /* 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 @@ cancel_mouse_face (f)
 \f
 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 @@ w32_mouse_position (fp, insist, bar_window, part, x, y, time)
        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 @@ w32_mouse_position (fp, insist, bar_window, part, x, y, time)
                                   || 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 @@ w32_set_vertical_scroll_bar (w, portion, whole, position)
     {
       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 @@ w32_set_vertical_scroll_bar (w, portion, whole, position)
         {
           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 @@ w32_read_socket (sd, bufp, numchars, expected)
       switch (msg.msg.message)
        {
        case WM_PAINT:
-           f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
+         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);
-                 }
-             }
+         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 @@ w32_read_socket (sd, bufp, numchars, expected)
 
        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 @@ w32_read_socket (sd, bufp, numchars, expected)
 
           /* 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 @@ x_erase_phys_cursor (w)
   /* 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 @@ x_erase_phys_cursor (w)
 }
 
 
+/* 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 @@ w32_initialize_display_info (display_name)
   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 @@ For example, if a block cursor is over a tab, it will be drawn as\n\
 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;