(Ffset): Save autoload of the function being set.
[bpt/emacs.git] / src / w32term.c
index 796a341..510f238 100644 (file)
@@ -1,12 +1,13 @@
 /* Implementation of GUI terminal on the Microsoft W32 API.
-   Copyright (C) 1989, 93, 94, 95, 96, 1997, 1998, 1999, 2000, 2001
-   Free Software Foundation, Inc.
+   Copyright (C) 1989, 1993, 1994, 1995, 1996, 1997, 1998,
+                 1999, 2000, 2001, 2002, 2003, 2004, 2005,
+                 2006, 2007 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
 GNU Emacs is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
+the Free Software Foundation; either version 3, or (at your option)
 any later version.
 
 GNU Emacs is distributed in the hope that it will be useful,
@@ -91,6 +92,10 @@ static Lisp_Object last_window;
    (Not yet supported, see TODO in x_draw_glyph_string.)  */
 int x_use_underline_position_properties;
 
+/* Non-zero means to draw the underline at the same place as the descent line.  */
+
+int x_underline_at_descent_line;
+
 extern unsigned int msh_mousewheel;
 
 extern void free_frame_menubar ();
@@ -146,32 +151,6 @@ HANDLE hWindowsThread = NULL;
 DWORD dwMainThreadId = 0;
 HANDLE hMainThread = NULL;
 
-#ifndef SIF_ALL
-/* These definitions are new with Windows 95. */
-#define SIF_RANGE           0x0001
-#define SIF_PAGE            0x0002
-#define SIF_POS             0x0004
-#define SIF_DISABLENOSCROLL 0x0008
-#define SIF_TRACKPOS        0x0010
-#define SIF_ALL             (SIF_RANGE | SIF_PAGE | SIF_POS | SIF_TRACKPOS)
-
-typedef struct tagSCROLLINFO
-{
-    UINT    cbSize;
-    UINT    fMask;
-    int     nMin;
-    int     nMax;
-    UINT    nPage;
-    int     nPos;
-    int     nTrackPos;
-}   SCROLLINFO, FAR *LPSCROLLINFO;
-typedef SCROLLINFO CONST FAR *LPCSCROLLINFO;
-#endif /* SIF_ALL */
-
-/* Dynamic linking to new proportional scroll bar functions. */
-int (PASCAL *pfnSetScrollInfo) (HWND hwnd, int fnBar, LPSCROLLINFO lpsi, BOOL fRedraw);
-BOOL (PASCAL *pfnGetScrollInfo) (HWND hwnd, int fnBar, LPSCROLLINFO lpsi);
-
 int vertical_scroll_bar_min_handle;
 int vertical_scroll_bar_top_border;
 int vertical_scroll_bar_bottom_border;
@@ -183,6 +162,7 @@ int last_scroll_bar_drag_pos;
 /* Where the mouse was last time we reported a mouse event.  */
 
 static RECT last_mouse_glyph;
+static FRAME_PTR last_mouse_glyph_frame;
 static Lisp_Object last_mouse_press_frame;
 
 int w32_num_mouse_buttons;
@@ -1567,7 +1547,7 @@ x_draw_glyph_string_foreground (s)
   else
     x = s->x;
 
-  if (s->for_overlaps_p || (s->background_filled_p && s->hl != DRAW_CURSOR))
+  if (s->for_overlaps || (s->background_filled_p && s->hl != DRAW_CURSOR))
     SetBkMode (s->hdc, TRANSPARENT);
   else
     SetBkMode (s->hdc, OPAQUE);
@@ -1612,7 +1592,10 @@ x_draw_glyph_string_foreground (s)
        {
          /* For overstriking (to simulate bold-face), draw the
             characters again shifted to the right by one pixel.  */
+         int old_BkMode = SetBkMode (s->hdc, TRANSPARENT);
          w32_text_out (s, x + 1, s->ybase - boff, s->char2b, s->nchars);
+         if (old_BkMode && old_BkMode != TRANSPARENT)
+           SetBkMode (s->hdc, old_BkMode);
        }
     }
   if (s->font && s->font->hfont)
@@ -2388,20 +2371,29 @@ x_draw_stretch_glyph_string (s)
     {
       /* If `x-stretch-block-cursor' is nil, don't draw a block cursor
         as wide as the stretch glyph.  */
-      int width = min (FRAME_COLUMN_WIDTH (s->f), s->background_width);
+      int width, background_width = s->background_width;
+      int x = s->x, left_x = window_box_left_offset (s->w, TEXT_AREA);
+
+      if (x < left_x)
+       {
+         background_width -= left_x - x;
+         x = left_x;
+       }
+      width = min (FRAME_COLUMN_WIDTH (s->f), background_width);
 
       /* Draw cursor.  */
-      x_draw_glyph_string_bg_rect (s, s->x, s->y, width, s->height);
+      x_draw_glyph_string_bg_rect (s, x, s->y, width, s->height);
 
       /* Clear rest using the GC of the original non-cursor face.  */
-      if (width < s->background_width)
+      if (width < background_width)
        {
          XGCValues *gc = s->face->gc;
-         int x = s->x + width, y = s->y;
-         int w = s->background_width - width, h = s->height;
+         int y = s->y;
+         int w = background_width - width, h = s->height;
          RECT r;
           HDC hdc = s->hdc;
 
+         x += width;
          if (s->row->mouse_face_p
              && cursor_in_mouse_face_p (s->w))
            {
@@ -2430,8 +2422,20 @@ x_draw_stretch_glyph_string (s)
         }
     }
   else if (!s->background_filled_p)
-    x_draw_glyph_string_bg_rect (s, s->x, s->y, s->background_width,
-                                s->height);
+    {
+      int background_width = s->background_width;
+      int x = s->x, left_x = window_box_left_offset (s->w, TEXT_AREA);
+
+      /* Don't draw into left margin, fringe or scrollbar area
+         except for header line and mode line.  */
+      if (x < left_x && !s->row->mode_line_p)
+       {
+         background_width -= left_x - x;
+         x = left_x;
+       }
+      if (background_width > 0)
+       x_draw_glyph_string_bg_rect (s, x, s->y, background_width, s->height);
+    }
 
   s->background_filled_p = 1;
 }
@@ -2448,7 +2452,7 @@ x_draw_glyph_string (s)
   /* If S draws into the background of its successor, draw the
      background of the successor first so that S can draw into it.
      This makes S->next use XDrawString instead of XDrawImageString.  */
-  if (s->next && s->right_overhang && !s->for_overlaps_p)
+  if (s->next && s->right_overhang && !s->for_overlaps)
     {
       xassert (s->next->img == NULL);
       x_set_glyph_string_gc (s->next);
@@ -2461,7 +2465,7 @@ x_draw_glyph_string (s)
 
   /* Draw relief (if any) in advance for char/composition so that the
      glyph string can be drawn over it.  */
-  if (!s->for_overlaps_p
+  if (!s->for_overlaps
       && s->face->box != FACE_NO_BOX
       && (s->first_glyph->type == CHAR_GLYPH
          || s->first_glyph->type == COMPOSITE_GLYPH))
@@ -2487,7 +2491,7 @@ x_draw_glyph_string (s)
       break;
 
     case CHAR_GLYPH:
-      if (s->for_overlaps_p)
+      if (s->for_overlaps)
        s->background_filled_p = 1;
       else
         x_draw_glyph_string_background (s, 0);
@@ -2495,7 +2499,7 @@ x_draw_glyph_string (s)
       break;
 
     case COMPOSITE_GLYPH:
-      if (s->for_overlaps_p || s->gidx > 0)
+      if (s->for_overlaps || s->gidx > 0)
        s->background_filled_p = 1;
       else
        x_draw_glyph_string_background (s, 1);
@@ -2506,28 +2510,34 @@ x_draw_glyph_string (s)
       abort ();
     }
 
-  if (!s->for_overlaps_p)
+  if (!s->for_overlaps)
     {
       /* Draw underline.  */
       if (s->face->underline_p
           && (s->font->bdf || !s->font->tm.tmUnderlined))
         {
           unsigned long h = 1;
-          unsigned long dy = s->height - h;
+          unsigned long dy = 0;
 
-         /* TODO: Use font information for positioning and thickness
-            of underline.  See OUTLINETEXTMETRIC, and xterm.c.
-            Note: If you make this work, don't forget to change the
-            doc string of x-use-underline-position-properties below.  */
+          if (x_underline_at_descent_line)
+            dy = s->height - h;
+          else
+            {
+              /* TODO: Use font information for positioning and thickness of
+                 underline.  See OUTLINETEXTMETRIC, and xterm.c.  Note: If
+                 you make this work, don't forget to change the doc string of
+                 x-use-underline-position-properties below.  */
+              dy = s->height - h;
+            }
           if (s->face->underline_defaulted_p)
             {
               w32_fill_area (s->f, s->hdc, s->gc->foreground, s->x,
-                             s->y + dy, s->width, 1);
+                             s->y + dy, s->background_width, 1);
             }
           else
             {
               w32_fill_area (s->f, s->hdc, s->face->underline_color, s->x,
-                             s->y + dy, s->width, 1);
+                             s->y + dy, s->background_width, 1);
             }
         }
 
@@ -2537,14 +2547,14 @@ x_draw_glyph_string (s)
           unsigned long dy = 0, h = 1;
 
           if (s->face->overline_color_defaulted_p)
-        {
-          w32_fill_area (s->f, s->hdc, s->gc->foreground, s->x,
-                         s->y + dy, s->width, h);
-        }
+           {
+             w32_fill_area (s->f, s->hdc, s->gc->foreground, s->x,
+                            s->y + dy, s->background_width, h);
+           }
           else
             {
               w32_fill_area (s->f, s->hdc, s->face->overline_color, s->x,
-                             s->y + dy, s->width, h);
+                             s->y + dy, s->background_width, h);
             }
         }
 
@@ -2562,7 +2572,7 @@ x_draw_glyph_string (s)
             }
           else
             {
-              w32_fill_area (s->f, s->hdc, s->face->underline_color, s->x,
+              w32_fill_area (s->f, s->hdc, s->face->strike_through_color, s->x,
                              s->y + dy, s->width, h);
             }
         }
@@ -3130,8 +3140,10 @@ construct_mouse_wheel (result, msg, f)
   result->modifiers = (msg->dwModifiers
                        | ((delta < 0 ) ? down_modifier : up_modifier));
 
-  p.x = LOWORD (msg->msg.lParam);
-  p.y = HIWORD (msg->msg.lParam);
+  /* With multiple monitors, we can legitimately get negative
+     coordinates, so cast to short to interpret them correctly.  */
+  p.x = (short) LOWORD (msg->msg.lParam);
+  p.y = (short) HIWORD (msg->msg.lParam);
   ScreenToClient (msg->msg.hwnd, &p);
   XSETINT (result->x, p.x);
   XSETINT (result->y, p.y);
@@ -3187,8 +3199,8 @@ construct_drag_n_drop (result, msg, f)
   DragFinish (hdrop);
 
   XSETFRAME (frame, f);
-  result->frame_or_window = Fcons (frame, files);
-  result->arg = Qnil;
+  result->frame_or_window = frame;
+  result->arg = files;
   return Qnil;
 }
 
@@ -3204,9 +3216,7 @@ 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
+static int
 note_mouse_movement (frame, msg)
      FRAME_PTR frame;
      MSG *msg;
@@ -3223,13 +3233,16 @@ note_mouse_movement (frame, msg)
       frame->mouse_moved = 1;
       last_mouse_scroll_bar = Qnil;
       note_mouse_highlight (frame, -1, -1);
+      last_mouse_glyph_frame = 0;
+      return 1;
     }
 
   /* Has the mouse moved off the glyph it was on at the last sighting?  */
-  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)
+  if (frame != last_mouse_glyph_frame
+      || 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;
@@ -3238,8 +3251,12 @@ note_mouse_movement (frame, msg)
         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);
+      remember_mouse_glyph (frame, mouse_x, mouse_y, &last_mouse_glyph);
+      last_mouse_glyph_frame = frame;
+      return 1;
     }
+
+  return 0;
 }
 
 \f
@@ -3250,8 +3267,6 @@ note_mouse_movement (frame, msg)
 static struct scroll_bar *x_window_to_scroll_bar ();
 static void x_scroll_bar_report_motion ();
 static void x_check_fullscreen P_ ((struct frame *));
-static int glyph_rect P_ ((struct frame *f, int, int, RECT *));
-
 
 static void
 redo_mouse_highlight ()
@@ -3270,108 +3285,6 @@ w32_define_cursor (window, cursor)
 {
   PostMessage (window, WM_EMACS_SETCURSOR, (WPARAM) cursor, 0);
 }
-
-/* 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;
-
-  window = window_from_coordinates (f, x, y, 0, &x, &y, 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;
-
-      for (; r < end && r->enabled_p; ++r)
-       if (r->y <= y && r->y + r->height > y)
-         {
-           /* Found the row at y.  */
-           struct glyph *g = r->glyphs[TEXT_AREA];
-           struct glyph *end = g + r->used[TEXT_AREA];
-           int gx;
-
-           rect->top = WINDOW_TO_FRAME_PIXEL_Y (w, r->y);
-           rect->bottom = rect->top + r->height;
-
-           if (x < r->x)
-             {
-               /* x is to the left of the first glyph in the row.  */
-               /* Shouldn't this be a pixel value?
-                  WINDOW_LEFT_EDGE_X (w) seems to be the right value.
-                  ++KFS */
-               rect->left = WINDOW_LEFT_EDGE_COL (w);
-               rect->right = WINDOW_TO_FRAME_PIXEL_X (w, r->x);
-               return 1;
-             }
-
-           for (gx = r->x; g < end; gx += g->pixel_width, ++g)
-             if (gx <= x && gx + g->pixel_width > x)
-               {
-                 /* x is on a glyph.  */
-                 rect->left = WINDOW_TO_FRAME_PIXEL_X (w, gx);
-                 rect->right = rect->left + g->pixel_width;
-                 return 1;
-               }
-
-           /* x is to the right of the last glyph in the row.  */
-           rect->left = WINDOW_TO_FRAME_PIXEL_X (w, gx);
-           /* Shouldn't this be a pixel value?
-              WINDOW_RIGHT_EDGE_X (w) seems to be the right value.
-              ++KFS */
-           rect->right = WINDOW_RIGHT_EDGE_COL (w);
-           return 1;
-         }
-    }
-
-  /* The y is not on any row.  */
-  return 0;
-}
-
-/* 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 FRAME_PIXEL_X_TO_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.
 
@@ -3463,19 +3376,9 @@ w32_mouse_position (fp, insist, bar_window, part, x, y, time)
               on it, i.e. into the same rectangles that matrices on
               the frame are divided into.  */
 
-#if OLD_REDISPLAY_CODE
-           int ignore1, ignore2;
-
            ScreenToClient (FRAME_W32_WINDOW (f1), &pt);
-
-           pixel_to_glyph_coords (f1, pt.x, pt.y, &ignore1, &ignore2,
-                                  &last_mouse_glyph,
-                                  FRAME_W32_DISPLAY_INFO (f1)->grabbed
-                                  || insist);
-#else
-           ScreenToClient (FRAME_W32_WINDOW (f1), &pt);
-           remember_mouse_glyph (f1, pt.x, pt.y);
-#endif
+           remember_mouse_glyph (f1, pt.x, pt.y, &last_mouse_glyph);
+           last_mouse_glyph_frame = f1;
 
            *bar_window = Qnil;
            *part = 0;
@@ -3571,24 +3474,51 @@ w32_set_scroll_bar_thumb (bar, portion, position, whole)
      int portion, position, whole;
 {
   Window w = SCROLL_BAR_W32_WINDOW (bar);
-  double range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
+  /* We use the whole scroll-bar height in the calculations below, to
+     avoid strange effects like scrolling backwards when just clicking
+     on the handle (without moving it).  */
+  double range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height))
+                 + VERTICAL_SCROLL_BAR_MIN_HANDLE;
   int sb_page, sb_pos;
   BOOL draggingp = !NILP (bar->dragging) ? TRUE : FALSE;
+  SCROLLINFO si;
+
+  /* We used to change the nPage setting while dragging the handle,
+     but that had very strange effects (such as scrolling backwards
+     while dragging downwards).
+
+     Now, we don't change the nPage setting while dragging unless we
+     get near to the end of the buffer, in which case we often have to
+     resize the handle to "go all the way".  */
+
+  if (draggingp)
+    {
+      int near_bottom_p;
+      BLOCK_INPUT;
+      si.cbSize = sizeof (si);
+      si.fMask = SIF_POS | SIF_PAGE;
+      GetScrollInfo(w, SB_CTL, &si);
+      near_bottom_p = si.nPos + si.nPage >= range;
+      UNBLOCK_INPUT;
+      if (!near_bottom_p)
+       return;
+    }
 
   if (whole)
     {
       /* Position scroll bar at rock bottom if the bottom of the
          buffer is visible. This avoids shinking the thumb away
          to nothing if it is held at the bottom of the buffer.  */
-      if (position + portion >= whole)
-        {
-          sb_page = range * (whole - position) / whole
-            + VERTICAL_SCROLL_BAR_MIN_HANDLE;
-          sb_pos = range;
-        }
-
-      sb_page = portion * range / whole + VERTICAL_SCROLL_BAR_MIN_HANDLE;
-      sb_pos = position * range / whole;
+      if (position + portion >= whole && !draggingp)
+       {
+         sb_page = range * (whole - position) / whole;
+         sb_pos = range;
+       }
+      else
+       {
+         sb_pos = position * range / whole;
+         sb_page = (min (portion, (whole - position)) * range) / whole;
+       }
     }
   else
     {
@@ -3596,26 +3526,16 @@ w32_set_scroll_bar_thumb (bar, portion, position, whole)
       sb_pos = 0;
     }
 
+  sb_page = max (sb_page, VERTICAL_SCROLL_BAR_MIN_HANDLE);
+
   BLOCK_INPUT;
 
-  if (pfnSetScrollInfo)
-    {
-      SCROLLINFO si;
+  si.cbSize = sizeof (si);
+  si.fMask = SIF_PAGE | SIF_POS;
+  si.nPage = sb_page;
+  si.nPos = sb_pos;
 
-      si.cbSize = sizeof (si);
-      /* Only update page size if currently dragging, to reduce
-         flicker effects.  */
-      if (draggingp)
-        si.fMask = SIF_PAGE;
-      else
-        si.fMask = SIF_PAGE | SIF_POS;
-      si.nPage = sb_page;
-      si.nPos = sb_pos;
-
-      pfnSetScrollInfo (w, SB_CTL, &si, !draggingp);
-    }
-  else
-    SetScrollPos (w, SB_CTL, sb_pos, !draggingp);
+  SetScrollInfo (w, SB_CTL, &si, TRUE);
 
   UNBLOCK_INPUT;
 }
@@ -3704,6 +3624,7 @@ x_scroll_bar_create (w, top, left, width, height)
 {
   struct frame *f = XFRAME (WINDOW_FRAME (w));
   HWND hwnd;
+  SCROLLINFO si;
   struct scroll_bar *bar
     = XSCROLL_BAR (Fmake_vector (make_number (SCROLL_BAR_VEC_SIZE), Qnil));
 
@@ -3722,26 +3643,15 @@ x_scroll_bar_create (w, top, left, width, height)
 
   hwnd = my_create_scrollbar (f, bar);
 
-  if (pfnSetScrollInfo)
-    {
-      SCROLLINFO si;
+  si.cbSize = sizeof (si);
+  si.fMask = SIF_ALL;
+  si.nMin = 0;
+  si.nMax = VERTICAL_SCROLL_BAR_TOP_RANGE (f, height)
+    + VERTICAL_SCROLL_BAR_MIN_HANDLE;
+  si.nPage = si.nMax;
+  si.nPos = 0;
 
-      si.cbSize = sizeof (si);
-      si.fMask = SIF_ALL;
-      si.nMin = 0;
-      si.nMax = VERTICAL_SCROLL_BAR_TOP_RANGE (f, height)
-       + VERTICAL_SCROLL_BAR_MIN_HANDLE;
-      si.nPage = si.nMax;
-      si.nPos = 0;
-
-      pfnSetScrollInfo (hwnd, SB_CTL, &si, FALSE);
-    }
-  else
-    {
-      SetScrollRange (hwnd, SB_CTL, 0,
-                      VERTICAL_SCROLL_BAR_TOP_RANGE (f, height), FALSE);
-      SetScrollPos (hwnd, SB_CTL, 0, FALSE);
-    }
+  SetScrollInfo (hwnd, SB_CTL, &si, FALSE);
 
   SET_SCROLL_BAR_W32_WINDOW (bar, hwnd);
 
@@ -3850,6 +3760,8 @@ w32_set_vertical_scroll_bar (w, portion, whole, position)
       else
         {
           HDC hdc;
+         SCROLLINFO si;
+
           BLOCK_INPUT;
          if (width && height)
            {
@@ -3869,21 +3781,15 @@ w32_set_vertical_scroll_bar (w, portion, whole, position)
           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;
 
-              si.cbSize = sizeof (si);
-              si.fMask = SIF_RANGE;
-              si.nMin = 0;
-              si.nMax = VERTICAL_SCROLL_BAR_TOP_RANGE (f, height)
-                + VERTICAL_SCROLL_BAR_MIN_HANDLE;
+         si.cbSize = sizeof (si);
+         si.fMask = SIF_RANGE;
+         si.nMin = 0;
+         si.nMax = VERTICAL_SCROLL_BAR_TOP_RANGE (f, height)
+           + VERTICAL_SCROLL_BAR_MIN_HANDLE;
+
+         SetScrollInfo (hwnd, SB_CTL, &si, FALSE);
 
-              pfnSetScrollInfo (hwnd, SB_CTL, &si, FALSE);
-            }
-          else
-            SetScrollRange (hwnd, SB_CTL, 0,
-                            VERTICAL_SCROLL_BAR_TOP_RANGE (f, height), FALSE);
           my_show_window (f, hwnd, SW_NORMAL);
           /* InvalidateRect (w, NULL, FALSE);  */
 
@@ -4035,19 +3941,13 @@ w32_scroll_bar_handle_click (bar, msg, emacs_event)
     int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
     int y;
     int dragging = !NILP (bar->dragging);
+    SCROLLINFO si;
 
-    if (pfnGetScrollInfo)
-      {
-       SCROLLINFO si;
-
-       si.cbSize = sizeof (si);
-       si.fMask = SIF_POS;
+    si.cbSize = sizeof (si);
+    si.fMask = SIF_POS;
 
-       pfnGetScrollInfo ((HWND) msg->msg.lParam, SB_CTL, &si);
-       y = si.nPos;
-      }
-    else
-      y = GetScrollPos ((HWND) msg->msg.lParam, SB_CTL);
+    GetScrollInfo ((HWND) msg->msg.lParam, SB_CTL, &si);
+    y = si.nPos;
 
     bar->dragging = Qnil;
 
@@ -4084,21 +3984,18 @@ w32_scroll_bar_handle_click (bar, msg, emacs_event)
        emacs_event->part = scroll_bar_handle;
 
        /* "Silently" update current position.  */
-       if (pfnSetScrollInfo)
-         {
-           SCROLLINFO si;
+       {
+         SCROLLINFO si;
 
-           si.cbSize = sizeof (si);
-           si.fMask = SIF_POS;
-           si.nPos = y;
-           /* Remember apparent position (we actually lag behind the real
-              position, so don't set that directly.  */
-           last_scroll_bar_drag_pos = y;
+         si.cbSize = sizeof (si);
+         si.fMask = SIF_POS;
+         si.nPos = y;
+         /* Remember apparent position (we actually lag behind the real
+            position, so don't set that directly.  */
+         last_scroll_bar_drag_pos = y;
 
-           pfnSetScrollInfo (SCROLL_BAR_W32_WINDOW (bar), SB_CTL, &si, FALSE);
-         }
-       else
-         SetScrollPos (SCROLL_BAR_W32_WINDOW (bar), SB_CTL, y, FALSE);
+         SetScrollInfo (SCROLL_BAR_W32_WINDOW (bar), SB_CTL, &si, FALSE);
+       }
        break;
       case SB_ENDSCROLL:
        /* If this is the end of a drag sequence, then reset the scroll
@@ -4106,20 +4003,15 @@ w32_scroll_bar_handle_click (bar, msg, emacs_event)
           nothing.  */
        if (dragging)
          {
-           if (pfnSetScrollInfo)
-             {
-               SCROLLINFO si;
-               int start = XINT (bar->start);
-               int end = XINT (bar->end);
-
-               si.cbSize = sizeof (si);
-               si.fMask = SIF_PAGE | SIF_POS;
-                si.nPage = end - start + VERTICAL_SCROLL_BAR_MIN_HANDLE;
-               si.nPos = last_scroll_bar_drag_pos;
-               pfnSetScrollInfo (SCROLL_BAR_W32_WINDOW (bar), SB_CTL, &si, TRUE);
-             }
-           else
-             SetScrollPos (SCROLL_BAR_W32_WINDOW (bar), SB_CTL, y, TRUE);
+           SCROLLINFO si;
+           int start = XINT (bar->start);
+           int end = XINT (bar->end);
+
+           si.cbSize = sizeof (si);
+           si.fMask = SIF_PAGE | SIF_POS;
+           si.nPage = end - start + VERTICAL_SCROLL_BAR_MIN_HANDLE;
+           si.nPos = last_scroll_bar_drag_pos;
+           SetScrollInfo (SCROLL_BAR_W32_WINDOW (bar), SB_CTL, &si, TRUE);
          }
        /* fall through */
       default:
@@ -4150,25 +4042,19 @@ x_scroll_bar_report_motion (fp, bar_window, part, x, y, time)
   FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
   int pos;
   int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
+  SCROLLINFO si;
 
   BLOCK_INPUT;
 
   *fp = f;
   *bar_window = bar->window;
 
-  if (pfnGetScrollInfo)
-    {
-      SCROLLINFO si;
+  si.cbSize = sizeof (si);
+  si.fMask = SIF_POS | SIF_PAGE | SIF_RANGE;
 
-      si.cbSize = sizeof (si);
-      si.fMask = SIF_POS | SIF_PAGE | SIF_RANGE;
-
-      pfnGetScrollInfo (w, SB_CTL, &si);
-      pos = si.nPos;
-      top_range = si.nMax - si.nPage + 1;
-    }
-  else
-    pos = GetScrollPos (w, SB_CTL);
+  GetScrollInfo (w, SB_CTL, &si);
+  pos = si.nPos;
+  top_range = si.nMax - si.nPage + 1;
 
   switch (LOWORD (last_mouse_scroll_bar_pos))
   {
@@ -4368,7 +4254,8 @@ w32_read_socket (sd, expected, hold_quit)
 
          if (f && !f->iconified)
            {
-             if (!dpyinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
+             if (!dpyinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight)
+                 && !EQ (f->tool_bar_window, dpyinfo->mouse_face_window))
                {
                  clear_mouse_face (dpyinfo);
                  dpyinfo->mouse_face_hidden = 1;
@@ -4391,7 +4278,8 @@ w32_read_socket (sd, expected, hold_quit)
 
          if (f && !f->iconified)
            {
-             if (!dpyinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
+             if (!dpyinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight)
+                 && !EQ (f->tool_bar_window, dpyinfo->mouse_face_window))
                {
                  clear_mouse_face (dpyinfo);
                  dpyinfo->mouse_face_hidden = 1;
@@ -4420,6 +4308,7 @@ w32_read_socket (sd, expected, hold_quit)
          }
 
           previous_help_echo_string = help_echo_string;
+         help_echo_string = Qnil;
 
          if (dpyinfo->grabbed && last_mouse_frame
              && FRAME_LIVE_P (last_mouse_frame))
@@ -4436,7 +4325,7 @@ w32_read_socket (sd, expected, hold_quit)
          if (f)
            {
              /* Generate SELECT_WINDOW_EVENTs when needed.  */
-             if (mouse_autoselect_window)
+             if (!NILP (Vmouse_autoselect_window))
                {
                  Lisp_Object window;
                  int x = LOWORD (msg.msg.lParam);
@@ -4447,10 +4336,16 @@ w32_read_socket (sd, expected, hold_quit)
                  /* Window will be selected only when it is not
                     selected now and last mouse movement event was
                     not in it.  Minibuffer window will be selected
-                    iff it is active.  */
+                    only when it is active.  */
                  if (WINDOWP(window)
                      && !EQ (window, last_window)
-                     && !EQ (window, selected_window))
+                     && !EQ (window, selected_window)
+                     /* For click-to-focus window managers
+                        create event iff we don't leave the
+                        selected frame.  */
+                     && (focus_follows_mouse
+                         || (EQ (XWINDOW (window)->frame,
+                                 XWINDOW (selected_window)->frame))))
                    {
                      inev.kind = SELECT_WINDOW_EVENT;
                      inev.frame_or_window = window;
@@ -4458,7 +4353,8 @@ w32_read_socket (sd, expected, hold_quit)
 
                  last_window=window;
                }
-             note_mouse_movement (f, &msg.msg);
+             if (!note_mouse_movement (f, &msg.msg))
+               help_echo_string = previous_help_echo_string;
            }
          else
             {
@@ -4573,7 +4469,7 @@ w32_read_socket (sd, expected, hold_quit)
                /* Ignore any mouse motion that happened before this
                   event; any subsequent mouse-movement Emacs events
                   should reflect only motion after the
-                  ButtonPress.  */
+                  ButtonPress.  */
                f->mouse_moved = 0;
              }
            last_mouse_frame = f;
@@ -5033,7 +4929,7 @@ x_draw_hollow_cursor (w, row)
   struct frame *f = XFRAME (WINDOW_FRAME (w));
   HDC hdc;
   RECT rect;
-  int h;
+  int left, top, h;
   struct glyph *cursor_glyph;
   HBRUSH hb = CreateSolidBrush (f->output_data.w32->cursor_pixel);
 
@@ -5044,8 +4940,9 @@ x_draw_hollow_cursor (w, row)
     return;
 
   /* Compute frame-relative coordinates for phys cursor.  */
-  rect.left = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
-  rect.top = get_phys_cursor_geometry (w, row, cursor_glyph, &h);
+  get_phys_cursor_geometry (w, row, cursor_glyph, &left, &top, &h);
+  rect.left = left;
+  rect.top = top;
   rect.bottom = rect.top + h;
   rect.right = rect.left + w->phys_cursor_width;
 
@@ -5267,16 +5164,25 @@ x_bitmap_icon (f, icon)
      struct frame *f;
      Lisp_Object icon;
 {
-  HANDLE hicon;
+  HANDLE main_icon;
+  HANDLE small_icon = NULL;
 
   if (FRAME_W32_WINDOW (f) == 0)
     return 1;
 
   if (NILP (icon))
-    hicon = LoadIcon (hinst, EMACS_CLASS);
+    main_icon = LoadIcon (hinst, EMACS_CLASS);
   else if (STRINGP (icon))
-    hicon = LoadImage (NULL, (LPCTSTR) SDATA (icon), IMAGE_ICON, 0, 0,
-                      LR_DEFAULTSIZE | LR_LOADFROMFILE);
+    {
+      /* Load the main icon from the named file.  */
+      main_icon = LoadImage (NULL, (LPCTSTR) SDATA (icon), IMAGE_ICON, 0, 0,
+                            LR_DEFAULTSIZE | LR_LOADFROMFILE);
+      /* Try to load a small icon to go with it.  */
+      small_icon = LoadImage (NULL, (LPCSTR) SDATA (icon), IMAGE_ICON,
+                             GetSystemMetrics (SM_CXSMICON),
+                             GetSystemMetrics (SM_CYSMICON),
+                             LR_LOADFROMFILE);
+    }
   else if (SYMBOLP (icon))
     {
       LPCTSTR name;
@@ -5296,16 +5202,21 @@ x_bitmap_icon (f, icon)
       else
        return 1;
 
-      hicon = LoadIcon (NULL, name);
+      main_icon = LoadIcon (NULL, name);
     }
   else
     return 1;
 
-  if (hicon == NULL)
+  if (main_icon == NULL)
     return 1;
 
   PostMessage (FRAME_W32_WINDOW (f), WM_SETICON, (WPARAM) ICON_BIG,
-               (LPARAM) hicon);
+               (LPARAM) main_icon);
+
+  /* If there is a small icon that goes with it, set that too.  */
+  if (small_icon)
+    PostMessage (FRAME_W32_WINDOW (f), WM_SETICON, (WPARAM) ICON_SMALL,
+                (LPARAM) small_icon);
 
   return 0;
 }
@@ -5322,6 +5233,8 @@ x_error_catcher (display, error)
 x_catch_errors (dpy)
 x_catch_errors_unwind (old_val)
 x_check_errors (dpy, format)
+x_fully_uncatch_errors ()
+x_catching_errors ()
 x_had_errors_p (dpy)
 x_clear_errors (dpy)
 x_uncatch_errors (dpy, count)
@@ -5444,20 +5357,52 @@ x_calc_absolute_position (f)
 {
   int flags = f->size_hint_flags;
 
-  /* Treat negative positions as relative to the leftmost bottommost
+  /* The sum of the widths of the frame's left and right borders, and
+     the sum of the heights of the frame's top and bottom borders (in
+     pixels) drawn by Windows.  */
+  unsigned int left_right_borders_width, top_bottom_borders_height;
+
+  /* Try to get the actual values of these two variables.  We compute
+     the border width (height) by subtracting the width (height) of
+     the frame's client area from the width (height) of the frame's
+     entire window.  */
+  WINDOWPLACEMENT wp = { 0 };
+  RECT client_rect = { 0 };
+
+  if (GetWindowPlacement (FRAME_W32_WINDOW (f), &wp)
+      && GetClientRect (FRAME_W32_WINDOW (f), &client_rect))
+    {
+      left_right_borders_width =
+       (wp.rcNormalPosition.right - wp.rcNormalPosition.left) -
+       (client_rect.right - client_rect.left);
+
+      top_bottom_borders_height =
+       (wp.rcNormalPosition.bottom - wp.rcNormalPosition.top) -
+       (client_rect.bottom - client_rect.top);
+    }
+  else
+    {
+      /* Use sensible default values.  */
+      left_right_borders_width = 8;
+      top_bottom_borders_height = 32;
+    }
+
+  /* Treat negative positions as relative to the rightmost bottommost
      position that fits on the screen.  */
   if (flags & XNegative)
     f->left_pos = (FRAME_W32_DISPLAY_INFO (f)->width
                   - FRAME_PIXEL_WIDTH (f)
-                  + f->left_pos);
+                  + f->left_pos
+                  - (left_right_borders_width - 1));
 
   if (flags & YNegative)
     f->top_pos = (FRAME_W32_DISPLAY_INFO (f)->height
                  - FRAME_PIXEL_HEIGHT (f)
-                 + f->top_pos);
-  /* The left_pos and top_pos
-     are now relative to the top and left screen edges,
-     so the flags should correspond.  */
+                 + f->top_pos
+                 - (top_bottom_borders_height - 1));
+
+  /* The left_pos and top_pos are now relative to the top and left
+     screen edges, so the flags should correspond.  */
   f->size_hint_flags &= ~ (XNegative | YNegative);
 }
 
@@ -5576,7 +5521,22 @@ x_set_window_size (f, change_gravity, cols, rows)
                       SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
   }
 
-  /* Now, strictly speaking, we can't be sure that this is accurate,
+#if 0
+  /* The following mirrors what is done in xterm.c. It appears to be
+     for informing lisp of the new size immediately, while the actual
+     resize will happen asynchronously. But on Windows, the menu bar
+     automatically wraps when the frame is too narrow to contain it,
+     and that causes any calculations made here to come out wrong. The
+     end is some nasty buggy behaviour, including the potential loss
+     of the minibuffer.
+
+     Disabling this code is either not sufficient to fix the problems
+     completely, or it causes fresh problems, but at least it removes
+     the most problematic symptom of the minibuffer becoming unusable.
+
+     -----------------------------------------------------------------
+
+     Now, strictly speaking, we can't be sure that this is accurate,
      but the window manager will get around to dealing with the size
      change request eventually, and we'll hear how it went when the
      ConfigureNotify event gets here.
@@ -5607,6 +5567,7 @@ x_set_window_size (f, change_gravity, cols, rows)
      Actually checking whether it is outside is a pain in the neck,
      so don't try--just let the highlighting be done afresh with new size.  */
   cancel_mouse_face (f);
+#endif
 
   UNBLOCK_INPUT;
 }
@@ -5797,7 +5758,22 @@ x_make_frame_visible (f)
         before the window gets really visible.  */
       if (! FRAME_ICONIFIED_P (f)
          && ! f->output_data.w32->asked_for_visible)
-       x_set_offset (f, f->left_pos, f->top_pos, 0);
+       {
+         RECT workarea_rect;
+         RECT window_rect;
+
+         /* Adjust vertical window position in order to avoid being
+            covered by a task bar placed at the bottom of the desktop. */
+         SystemParametersInfo(SPI_GETWORKAREA, 0, &workarea_rect, 0);
+         GetWindowRect(FRAME_W32_WINDOW(f), &window_rect);
+         if (window_rect.bottom > workarea_rect.bottom
+             && window_rect.top > workarea_rect.top)
+           f->top_pos = max (window_rect.top
+                             - window_rect.bottom + workarea_rect.bottom,
+                             workarea_rect.top);
+
+         x_set_offset (f, f->left_pos, f->top_pos, 0);
+       }
 
       f->output_data.w32->asked_for_visible = 1;
 
@@ -6352,7 +6328,7 @@ x_delete_display (dpyinfo)
 \f
 /* Set up use of W32.  */
 
-DWORD w32_msg_worker ();
+DWORD WINAPI w32_msg_worker (void * arg);
 
 void
 x_flush (struct frame * f)
@@ -6457,8 +6433,8 @@ w32_initialize ()
     PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE);
 
     hWindowsThread = CreateThread (NULL, 0,
-                              (LPTHREAD_START_ROUTINE) w32_msg_worker,
-                              0, 0, &dwWindowsThreadId);
+                                   w32_msg_worker,
+                                   0, 0, &dwWindowsThreadId);
 
     GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
   }
@@ -6475,26 +6451,14 @@ w32_initialize ()
   AttachThreadInput (dwMainThreadId, dwWindowsThreadId, TRUE);
 #endif
 
-  /* Dynamically link to optional system components. */
+  /* Load system settings.  */
   {
-    HANDLE user_lib = LoadLibrary ("user32.dll");
     UINT smoothing_type;
     BOOL smoothing_enabled;
 
-#define LOAD_PROC(fn) pfn##fn = (void *) GetProcAddress (user_lib, #fn)
-
-    /* New proportional scroll bar functions. */
-    LOAD_PROC (SetScrollInfo);
-    LOAD_PROC (GetScrollInfo);
-
-#undef LOAD_PROC
-
-    FreeLibrary (user_lib);
-
     /* If using proportional scroll bars, ensure handle is at least 5 pixels;
        otherwise use the fixed height.  */
-    vertical_scroll_bar_min_handle = (pfnSetScrollInfo != NULL) ? 5 :
-      GetSystemMetrics (SM_CYVTHUMB);
+    vertical_scroll_bar_min_handle = 5;
 
     /* For either kind of scroll bar, take account of the arrows; these
        effectively form the border of the main scroll bar range.  */
@@ -6598,13 +6562,21 @@ the cursor have no effect.  */);
   DEFVAR_BOOL ("x-use-underline-position-properties",
               &x_use_underline_position_properties,
      doc: /* *Non-nil means make use of UNDERLINE_POSITION font properties.
-nil means ignore them.  If you encounter fonts with bogus
+A value of nil means ignore them.  If you encounter fonts with bogus
 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
 to 4.1, set this to nil.
 
 NOTE: Not supported on MS-Windows yet.  */);
   x_use_underline_position_properties = 0;
 
+  DEFVAR_BOOL ("x-underline-at-descent-line",
+              &x_underline_at_descent_line,
+     doc: /* *Non-nil means to draw the underline at the same place as the descent line.
+A value of nil means to draw the underline according to the value of the
+variable `x-use-underline-position-properties', which is usually at the
+baseline level.  The default value is nil.  */);
+  x_underline_at_descent_line = 0;
+
   DEFVAR_LISP ("x-toolkit-scroll-bars", &Vx_toolkit_scroll_bars,
               doc: /* If not nil, Emacs uses toolkit scroll bars.  */);
   Vx_toolkit_scroll_bars = Qt;