(Ffset): Save autoload of the function being set.
[bpt/emacs.git] / src / w32term.c
index 8ee27b8..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,
@@ -16,8 +17,8 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU Emacs; see the file COPYING.  If not, write to
-the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.  */
 
 #include <config.h>
 #include <signal.h>
@@ -62,7 +63,8 @@ Boston, MA 02111-1307, USA.  */
 \f
 /* Fringe bitmaps.  */
 
-static HBITMAP fringe_bmp[MAX_FRINGE_BITMAPS];
+static int max_fringe_bmp = 0;
+static HBITMAP *fringe_bmp = 0;
 
 /* Non-nil means Emacs uses toolkit scroll bars.  */
 
@@ -73,6 +75,11 @@ Lisp_Object Vx_toolkit_scroll_bars;
 static int last_mousemove_x = 0;
 static int last_mousemove_y = 0;
 
+/* Define GET_WHEEL_DELTA_WPARAM macro if system headers don't.  */
+#ifndef GET_WHEEL_DELTA_WPARAM
+#define GET_WHEEL_DELTA_WPARAM(wparam) ((short)HIWORD (wparam))
+#endif
+
 /* Non-zero means that a HELP_EVENT has been generated since Emacs
    start.  */
 
@@ -81,6 +88,14 @@ static int any_help_event_p;
 /* Last window where we saw the mouse.  Used by mouse-autoselect-window.  */
 static Lisp_Object last_window;
 
+/* Non-zero means make use of UNDERLINE_POSITION font properties.
+   (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 ();
@@ -128,37 +143,14 @@ int w32_use_visible_system_caret;
    for Far East languages.  */
 int w32_enable_unicode_output;
 
+/* Flag to enable Cleartype hack for font metrics.  */
+static int cleartype_active;
+
 DWORD dwWindowsThreadId = 0;
 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;
@@ -170,9 +162,10 @@ 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;
 
-Lisp_Object Vw32_num_mouse_buttons;
+int w32_num_mouse_buttons;
 
 Lisp_Object Vw32_swap_mouse_buttons;
 
@@ -216,8 +209,6 @@ static int input_signal_count;
 
 extern Lisp_Object Vcommand_line_args, Vsystem_name;
 
-extern Lisp_Object Qface, Qmouse_face;
-
 #ifndef USE_CRT_DLL
 extern int errno;
 #endif
@@ -251,12 +242,21 @@ static void frame_highlight P_ ((struct frame *));
 static void frame_unhighlight P_ ((struct frame *));
 static void x_new_focus_frame P_ ((struct w32_display_info *,
                                   struct frame *));
+static void x_focus_changed P_ ((int, int, struct w32_display_info *,
+                                 struct frame *, struct input_event *));
+static void w32_detect_focus_change P_ ((struct w32_display_info *,
+                                       W32Msg *, struct input_event *));
 static void w32_frame_rehighlight P_ ((struct frame *));
 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,
                                   enum text_cursor_kinds));
-static void w32_clip_to_row P_ ((struct window *, struct glyph_row *, HDC));
+static void w32_clip_to_row P_ ((struct window *, struct glyph_row *, int, HDC));
+static BOOL my_show_window P_ ((struct frame *, HWND, int));
+static void my_set_window_pos P_ ((HWND, HWND, int, int, int, int, UINT));
+static void my_set_focus P_ ((struct frame *, HWND));
+static void my_set_foreground_window P_ ((HWND));
+static void my_destroy_window P_ ((struct frame *, HWND));
 
 static Lisp_Object Qvendor_specific_keysyms;
 
@@ -495,14 +495,20 @@ w32_draw_vertical_window_border (w, x, y0, y1)
   struct frame *f = XFRAME (WINDOW_FRAME (w));
   RECT r;
   HDC hdc;
-  
+  struct face *face;
+
   r.left = x;
   r.right = x + 1;
   r.top = y0;
   r.bottom = y1;
 
   hdc = get_frame_dc (f);
-  w32_fill_rect (f, hdc, FRAME_FOREGROUND_PIXEL (f), &r);
+  face = FACE_FROM_ID (f, VERTICAL_BORDER_FACE_ID);
+  if (face)
+    w32_fill_rect (f, hdc, face->foreground, &r);
+  else
+    w32_fill_rect (f, hdc, FRAME_FOREGROUND_PIXEL (f), &r);
+
   release_frame_dc (f, hdc);
 }
 
@@ -536,7 +542,9 @@ x_update_window_end (w, cursor_on_p, mouse_face_overwritten_p)
                                output_cursor.vpos,
                                output_cursor.x, output_cursor.y);
 
-      x_draw_vertical_border (w);
+      if (draw_window_fringes (w, 1))
+       x_draw_vertical_border (w);
+
       UNBLOCK_INPUT;
     }
 
@@ -621,11 +629,7 @@ x_after_update_window_line (desired_row)
   xassert (w);
 
   if (!desired_row->mode_line_p && !w->pseudo_window_p)
-    {
-      BLOCK_INPUT;
-      draw_row_fringe_bitmaps (w, desired_row);
-      UNBLOCK_INPUT;
-    }
+    desired_row->redraw_fringe_bitmaps_p = 1;
 
   /* When a window has disappeared, make sure that no rest of
      full-width rows stays visible in the internal border.  Could
@@ -675,34 +679,79 @@ w32_draw_fringe_bitmap (w, row, p)
   struct frame *f = XFRAME (WINDOW_FRAME (w));
   HDC hdc;
   struct face *face = p->face;
+  int rowY;
 
   hdc = get_frame_dc (f);
 
   /* Must clip because of partially visible lines.  */
-  w32_clip_to_row (w, row, hdc);
+  rowY = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
+  if (p->y < rowY)
+    {
+      /* Adjust position of "bottom aligned" bitmap on partially
+        visible last row.  */
+      int oldY = row->y;
+      int oldVH = row->visible_height;
+      row->visible_height = p->h;
+      row->y -= rowY - p->y;
+      w32_clip_to_row (w, row, -1, hdc);
+      row->y = oldY;
+      row->visible_height = oldVH;
+    }
+  else
+    w32_clip_to_row (w, row, -1, hdc);
 
-  if (p->bx >= 0)
+  if (p->bx >= 0 && !p->overlay_p)
     {
       w32_fill_area (f, hdc, face->background,
                     p->bx, p->by, p->nx, p->ny);
     }
 
-  if (p->which != NO_FRINGE_BITMAP)
+  if (p->which && p->which < max_fringe_bmp)
     {
       HBITMAP pixmap = fringe_bmp[p->which];
       HDC compat_hdc;
       HANDLE horig_obj;
 
       compat_hdc = CreateCompatibleDC (hdc);
+
       SaveDC (hdc);
 
       horig_obj = SelectObject (compat_hdc, pixmap);
-      SetTextColor (hdc, face->background);
-      SetBkColor (hdc, face->foreground);
 
-      BitBlt (hdc, p->x, p->y, p->wd, p->h,
-             compat_hdc, 0, p->dh,
-             SRCCOPY);
+      /* Paint overlays transparently.  */
+      if (p->overlay_p)
+       {
+         HBRUSH h_brush, h_orig_brush;
+
+         SetTextColor (hdc, BLACK_PIX_DEFAULT (f));
+         SetBkColor (hdc, WHITE_PIX_DEFAULT (f));
+         h_brush = CreateSolidBrush (face->foreground);
+         h_orig_brush = SelectObject (hdc, h_brush);
+
+         BitBlt (hdc, p->x, p->y, p->wd, p->h,
+                 compat_hdc, 0, p->dh,
+                 DSTINVERT);
+         BitBlt (hdc, p->x, p->y, p->wd, p->h,
+                 compat_hdc, 0, p->dh,
+                 0x2E064A);
+         BitBlt (hdc, p->x, p->y, p->wd, p->h,
+                 compat_hdc, 0, p->dh,
+                 DSTINVERT);
+
+         SelectObject (hdc, h_orig_brush);
+         DeleteObject (h_brush);
+       }
+      else
+       {
+         SetTextColor (hdc, face->background);
+         SetBkColor (hdc, (p->cursor_p
+                           ? f->output_data.w32->cursor_pixel
+                           : face->foreground));
+
+         BitBlt (hdc, p->x, p->y, p->wd, p->h,
+                 compat_hdc, 0, p->dh,
+                 SRCCOPY);
+       }
 
       SelectObject (compat_hdc, horig_obj);
       DeleteDC (compat_hdc);
@@ -714,6 +763,37 @@ w32_draw_fringe_bitmap (w, row, p)
   release_frame_dc (f, hdc);
 }
 
+static void
+w32_define_fringe_bitmap (which, bits, h, wd)
+     int which;
+     unsigned short *bits;
+     int h, wd;
+{
+  if (which >= max_fringe_bmp)
+    {
+      int i = max_fringe_bmp;
+      max_fringe_bmp = which + 20;
+      fringe_bmp = (HBITMAP *) xrealloc (fringe_bmp, max_fringe_bmp * sizeof (HBITMAP));
+      while (i < max_fringe_bmp)
+       fringe_bmp[i++] = 0;
+    }
+
+  fringe_bmp[which] = CreateBitmap (wd, h, 1, 1, bits);
+}
+
+static void
+w32_destroy_fringe_bitmap (which)
+     int which;
+{
+  if (which >= max_fringe_bmp)
+    return;
+
+  if (fringe_bmp[which])
+    DeleteObject (fringe_bmp[which]);
+  fringe_bmp[which] = 0;
+}
+
+
 \f
 /* This is called when starting Emacs and when restarting after
    suspend.  When starting Emacs, no window is mapped.  And nothing
@@ -741,8 +821,7 @@ w32_reset_terminal_modes (void)
 
 /* Function prototypes of this page.  */
 
-static XCharStruct *w32_per_char_metric P_ ((XFontStruct *,
-                                             wchar_t *, int));
+XCharStruct *w32_per_char_metric P_ ((XFontStruct *, wchar_t *, int));
 static int w32_encode_char P_ ((int, wchar_t *, struct font_info *, int *));
 
 
@@ -822,6 +901,16 @@ w32_native_per_char_metric (font, char2b, font_type, pcm)
          int real_width;
          GetCharWidth (hdc, *char2b, *char2b, &real_width);
 #endif
+         if (cleartype_active)
+           {
+             /* Cleartype antialiasing causes characters to overhang
+                by a pixel on each side compared with what GetCharABCWidths
+                reports.  */
+             char_widths.abcA -= 1;
+             char_widths.abcC -= 1;
+             char_widths.abcB += 2;
+           }
+
          pcm->width = char_widths.abcA + char_widths.abcB + char_widths.abcC;
 #if 0
          /* As far as I can tell, this is the best way to determine what
@@ -879,7 +968,7 @@ w32_native_per_char_metric (font, char2b, font_type, pcm)
 }
 
 
-static XCharStruct *
+XCharStruct *
 w32_per_char_metric (font, char2b, font_type)
      XFontStruct *font;
      wchar_t *char2b;
@@ -890,7 +979,17 @@ w32_per_char_metric (font, char2b, font_type)
   BOOL retval;
 
   xassert (font && char2b);
-  xassert (font_type != UNKNOWN_FONT);
+
+  /* TODO: This function is currently called through the RIF, and in
+     some cases font_type is UNKNOWN_FONT. We currently allow the
+     cached metrics to be used, which seems to work, but in cases
+     where font_type is UNKNOWN_FONT, we probably haven't encoded
+     char2b appropriately. All callers need checking to see what they
+     are passing.  This is most likely to affect variable width fonts
+     outside the Latin-1 range, particularly in languages like Thai
+     that rely on rbearing and lbearing to provide composition. I
+     don't think that is working currently anyway, but we don't seem
+     to have anyone testing such languages on Windows.  */
 
   /* Handle the common cases quickly.  */
   if (!font->bdf && font->per_char == NULL)
@@ -899,6 +998,8 @@ w32_per_char_metric (font, char2b, font_type)
   else if (!font->bdf && *char2b < 128)
     return &font->per_char[*char2b];
 
+  xassert (font_type != UNKNOWN_FONT);
+
   pcm = &font->scratch;
 
   if (font_type == BDF_1D_FONT)
@@ -1106,9 +1207,9 @@ w32_text_out (s, x, y,chars,nchars)
      wchar_t * chars;
      int nchars;
 {
-  int charset_dim = w32_font_is_double_byte (s->gc->font) ? 2 : 1;
-  if (s->gc->font->bdf)
-    w32_BDF_TextOut (s->gc->font->bdf, s->hdc,
+  int charset_dim = w32_font_is_double_byte (s->font) ? 2 : 1;
+  if (s->font->bdf)
+    w32_BDF_TextOut (s->font->bdf, s->hdc,
                      x, y, (char *) chars, charset_dim,
                      nchars * charset_dim, 0);
   else if (s->first_glyph->font_type == UNICODE_FONT)
@@ -1119,7 +1220,6 @@ w32_text_out (s, x, y,chars,nchars)
 }
 
 
-
 static void x_set_glyph_string_clipping P_ ((struct glyph_string *));
 static void x_set_glyph_string_gc P_ ((struct glyph_string *));
 static void x_draw_glyph_string_background P_ ((struct glyph_string *,
@@ -1142,7 +1242,8 @@ static void w32_draw_image_foreground_1 P_ ((struct glyph_string *, HBITMAP));
 static void x_clear_glyph_string_rect P_ ((struct glyph_string *, int,
                                           int, int, int));
 static void w32_draw_relief_rect P_ ((struct frame *, int, int, int, int,
-                                   int, int, int, int, RECT *));
+                                     int, int, int, int, int, int,
+                                     RECT *));
 static void w32_draw_box_rect P_ ((struct glyph_string *, int, int, int, int,
                                 int, int, int, RECT *));
 
@@ -1446,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);
@@ -1491,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)
@@ -1723,9 +1827,10 @@ x_setup_relief_colors (s)
 
 static void
 w32_draw_relief_rect (f, left_x, top_y, right_x, bottom_y, width,
-                      raised_p, left_p, right_p, clip_rect)
+                      raised_p, top_p, bot_p, left_p, right_p, clip_rect)
      struct frame *f;
-     int left_x, top_y, right_x, bottom_y, width, left_p, right_p, raised_p;
+     int left_x, top_y, right_x, bottom_y, width;
+     int top_p, bot_p, left_p, right_p, raised_p;
      RECT *clip_rect;
 {
   int i;
@@ -1740,10 +1845,11 @@ w32_draw_relief_rect (f, left_x, top_y, right_x, bottom_y, width,
   w32_set_clip_rectangle (hdc, clip_rect);
 
   /* Top.  */
-  for (i = 0; i < width; ++i)
-    w32_fill_area (f, hdc, gc.foreground,
-                  left_x + i * left_p, top_y + i,
-                  right_x - left_x - i * (left_p + right_p ) + 1, 1);
+  if (top_p)
+    for (i = 0; i < width; ++i)
+      w32_fill_area (f, hdc, gc.foreground,
+                    left_x + i * left_p, top_y + i,
+                    right_x - left_x - i * (left_p + right_p ) + 1, 1);
 
   /* Left.  */
   if (left_p)
@@ -1758,10 +1864,11 @@ w32_draw_relief_rect (f, left_x, top_y, right_x, bottom_y, width,
     gc.foreground = f->output_data.w32->white_relief.gc->foreground;
 
   /* Bottom.  */
-  for (i = 0; i < width; ++i)
-    w32_fill_area (f, hdc, gc.foreground,
-                  left_x + i * left_p, bottom_y - i,
-                  right_x - left_x - i * (left_p + right_p) + 1, 1);
+  if (bot_p)
+    for (i = 0; i < width; ++i)
+      w32_fill_area (f, hdc, gc.foreground,
+                    left_x + i * left_p, bottom_y - i,
+                    right_x - left_x - i * (left_p + right_p) + 1, 1);
 
   /* Right.  */
   if (right_p)
@@ -1829,15 +1936,9 @@ x_draw_glyph_string_box (s)
   struct glyph *last_glyph;
   RECT clip_rect;
 
-  last_x = window_box_right (s->w, s->area);
-  if (s->row->full_width_p
-      && !s->w->pseudo_window_p)
-    {
-      last_x += WINDOW_RIGHT_SCROLL_BAR_AREA_WIDTH (s->w);
-      if (s->area != RIGHT_MARGIN_AREA
-         || WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (s->w))
-       last_x += WINDOW_RIGHT_FRINGE_WIDTH (s->w);
-    }
+  last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
+           ? WINDOW_RIGHT_EDGE_X (s->w)
+           : window_box_right (s->w, s->area));
 
   /* The glyph that may have a right box line.  */
   last_glyph = (s->cmp || s->img
@@ -1871,7 +1972,7 @@ x_draw_glyph_string_box (s)
     {
       x_setup_relief_colors (s);
       w32_draw_relief_rect (s->f, left_x, top_y, right_x, bottom_y,
-                            width, raised_p, left_p, right_p, &clip_rect);
+                            width, raised_p, 1, 1, left_p, right_p, &clip_rect);
     }
 }
 
@@ -1882,21 +1983,22 @@ static void
 x_draw_image_foreground (s)
      struct glyph_string *s;
 {
-  int x;
-  int y = s->ybase - image_ascent (s->img, s->face);
+  int x = s->x;
+  int y = s->ybase - image_ascent (s->img, s->face, &s->slice);
 
   /* If first glyph of S has a left box line, start drawing it to the
      right of that line.  */
   if (s->face->box != FACE_NO_BOX
-      && s->first_glyph->left_box_line_p)
-    x = s->x + abs (s->face->box_line_width);
-  else
-    x = s->x;
+      && s->first_glyph->left_box_line_p
+      && s->slice.x == 0)
+    x += abs (s->face->box_line_width);
 
   /* If there is a margin around the image, adjust x- and y-position
      by that margin.  */
-  x += s->img->hmargin;
-  y += s->img->vmargin;
+  if (s->slice.x == 0)
+    x += s->img->hmargin;
+  if (s->slice.y == 0)
+    y += s->img->vmargin;
 
   SaveDC (s->hdc);
 
@@ -1918,12 +2020,12 @@ x_draw_image_foreground (s)
          SetTextColor (s->hdc, RGB (255, 255, 255));
          SetBkColor (s->hdc, RGB (0, 0, 0));
 
-         BitBlt (s->hdc, x, y, s->img->width, s->img->height,
-                 compat_hdc, 0, 0, SRCINVERT);
-         BitBlt (s->hdc, x, y, s->img->width, s->img->height,
-                 mask_dc, 0, 0, SRCAND);
-         BitBlt (s->hdc, x, y, s->img->width, s->img->height,
-                 compat_hdc, 0, 0, SRCINVERT);
+         BitBlt (s->hdc, x, y, s->slice.width, s->slice.height,
+                 compat_hdc, s->slice.x, s->slice.y, SRCINVERT);
+         BitBlt (s->hdc, x, y, s->slice.width, s->slice.height,
+                 mask_dc, s->slice.x, s->slice.y, SRCAND);
+         BitBlt (s->hdc, x, y, s->slice.width, s->slice.height,
+                 compat_hdc, s->slice.x, s->slice.y, SRCINVERT);
 
          SelectObject (mask_dc, mask_orig_obj);
          DeleteDC (mask_dc);
@@ -1933,8 +2035,8 @@ x_draw_image_foreground (s)
          SetTextColor (s->hdc, s->gc->foreground);
          SetBkColor (s->hdc, s->gc->background);
 
-          BitBlt (s->hdc, x, y, s->img->width, s->img->height,
-                  compat_hdc, 0, 0, SRCCOPY);
+          BitBlt (s->hdc, x, y, s->slice.width, s->slice.height,
+                  compat_hdc, s->slice.x, s->slice.y, SRCCOPY);
 
          /* When the image has a mask, we can expect that at
             least part of a mouse highlight or a block cursor will
@@ -1947,7 +2049,8 @@ x_draw_image_foreground (s)
              int r = s->img->relief;
              if (r < 0) r = -r;
              w32_draw_rectangle (s->hdc, s->gc, x - r, y - r ,
-                                 s->img->width + r*2 - 1, s->img->height + r*2 - 1);
+                                 s->slice.width + r*2 - 1,
+                                 s->slice.height + r*2 - 1);
            }
        }
 
@@ -1958,14 +2061,13 @@ x_draw_image_foreground (s)
       DeleteDC (compat_hdc);
     }
   else
-    w32_draw_rectangle (s->hdc, s->gc, x, y, s->img->width -1,
-                        s->img->height - 1);
+    w32_draw_rectangle (s->hdc, s->gc, x, y,
+                       s->slice.width - 1, s->slice.height - 1);
 
   RestoreDC (s->hdc ,-1);
 }
 
 
-
 /* Draw a relief around the image glyph string S.  */
 
 static void
@@ -1974,21 +2076,22 @@ x_draw_image_relief (s)
 {
   int x0, y0, x1, y1, thick, raised_p;
   RECT r;
-  int x;
-  int y = s->ybase - image_ascent (s->img, s->face);
+  int x = s->x;
+  int y = s->ybase - image_ascent (s->img, s->face, &s->slice);
 
   /* If first glyph of S has a left box line, start drawing it to the
      right of that line.  */
   if (s->face->box != FACE_NO_BOX
-      && s->first_glyph->left_box_line_p)
-    x = s->x + abs (s->face->box_line_width);
-  else
-    x = s->x;
+      && s->first_glyph->left_box_line_p
+      && s->slice.x == 0)
+    x += abs (s->face->box_line_width);
 
   /* If there is a margin around the image, adjust x- and y-position
      by that margin.  */
-  x += s->img->hmargin;
-  y += s->img->vmargin;
+  if (s->slice.x == 0)
+    x += s->img->hmargin;
+  if (s->slice.y == 0)
+    y += s->img->vmargin;
 
   if (s->hl == DRAW_IMAGE_SUNKEN
       || s->hl == DRAW_IMAGE_RAISED)
@@ -2004,12 +2107,17 @@ x_draw_image_relief (s)
 
   x0 = x - thick;
   y0 = y - thick;
-  x1 = x + s->img->width + thick - 1;
-  y1 = y + s->img->height + thick - 1;
+  x1 = x + s->slice.width + thick - 1;
+  y1 = y + s->slice.height + thick - 1;
 
   x_setup_relief_colors (s);
   get_glyph_string_clip_rect (s, &r);
-  w32_draw_relief_rect (s->f, x0, y0, x1, y1, thick, raised_p, 1, 1, &r);
+  w32_draw_relief_rect (s->f, x0, y0, x1, y1, thick, raised_p,
+                       s->slice.y == 0,
+                       s->slice.y + s->slice.height == s->img->height,
+                       s->slice.x == 0,
+                       s->slice.x + s->slice.width == s->img->width,
+                       &r);
 }
 
 
@@ -2022,21 +2130,22 @@ w32_draw_image_foreground_1 (s, pixmap)
 {
   HDC hdc = CreateCompatibleDC (s->hdc);
   HGDIOBJ orig_hdc_obj = SelectObject (hdc, pixmap);
-  int x;
-  int y = s->ybase - s->y - image_ascent (s->img, s->face);
+  int x = 0;
+  int y = s->ybase - s->y - image_ascent (s->img, s->face, &s->slice);
 
   /* If first glyph of S has a left box line, start drawing it to the
      right of that line.  */
   if (s->face->box != FACE_NO_BOX
-      && s->first_glyph->left_box_line_p)
-    x = abs (s->face->box_line_width);
-  else
-    x = 0;
+      && s->first_glyph->left_box_line_p
+      && s->slice.x == 0)
+    x += abs (s->face->box_line_width);
 
   /* If there is a margin around the image, adjust x- and y-position
      by that margin.  */
-  x += s->img->hmargin;
-  y += s->img->vmargin;
+  if (s->slice.x == 0)
+    x += s->img->hmargin;
+  if (s->slice.y == 0)
+    y += s->img->vmargin;
 
   if (s->img->pixmap)
     {
@@ -2052,12 +2161,12 @@ w32_draw_image_foreground_1 (s, pixmap)
 
          SetTextColor (hdc, RGB (0, 0, 0));
          SetBkColor (hdc, RGB (255, 255, 255));
-         BitBlt (hdc, x, y, s->img->width, s->img->height,
-                 compat_hdc, 0, 0, SRCINVERT);
-         BitBlt (hdc, x, y, s->img->width, s->img->height,
-                 mask_dc, 0, 0, SRCAND);
-         BitBlt (hdc, x, y, s->img->width, s->img->height,
-                 compat_hdc, 0, 0, SRCINVERT);
+         BitBlt (hdc, x, y, s->slice.width, s->slice.height,
+                 compat_hdc, s->slice.x, s->slice.y, SRCINVERT);
+         BitBlt (hdc, x, y, s->slice.width, s->slice.height,
+                 mask_dc, s->slice.x, s->slice.y, SRCAND);
+         BitBlt (hdc, x, y, s->slice.width, s->slice.height,
+                 compat_hdc, s->slice.x, s->slice.y, SRCINVERT);
 
          SelectObject (mask_dc, mask_orig_obj);
          DeleteDC (mask_dc);
@@ -2067,8 +2176,8 @@ w32_draw_image_foreground_1 (s, pixmap)
          SetTextColor (hdc, s->gc->foreground);
          SetBkColor (hdc, s->gc->background);
 
-          BitBlt (hdc, x, y, s->img->width, s->img->height,
-                  compat_hdc, 0, 0, SRCCOPY);
+          BitBlt (hdc, x, y, s->slice.width, s->slice.height,
+                  compat_hdc, s->slice.x, s->slice.y, SRCCOPY);
 
          /* When the image has a mask, we can expect that at
             least part of a mouse highlight or a block cursor will
@@ -2080,8 +2189,9 @@ w32_draw_image_foreground_1 (s, pixmap)
            {
              int r = s->img->relief;
              if (r < 0) r = -r;
-             w32_draw_rectangle (hdc, s->gc, x - r, y - r ,
-                                 s->img->width + r*2 - 1, s->img->height + r*2 - 1);
+             w32_draw_rectangle (hdc, s->gc, x - r, y - r,
+                                 s->slice.width + r*2 - 1,
+                                 s->slice.height + r*2 - 1);
            }
        }
 
@@ -2091,8 +2201,8 @@ w32_draw_image_foreground_1 (s, pixmap)
       DeleteDC (compat_hdc);
     }
   else
-    w32_draw_rectangle (hdc, s->gc, x, y, s->img->width - 1,
-                        s->img->height - 1);
+    w32_draw_rectangle (hdc, s->gc, x, y,
+                       s->slice.width - 1, s->slice.height - 1);
 
   SelectObject (hdc, orig_hdc_obj);
   DeleteDC (hdc);
@@ -2151,19 +2261,22 @@ x_draw_image_glyph_string (s)
      taller than image or if image has a clip mask to reduce
      flickering.  */
   s->stippled_p = s->face->stipple != 0;
-  if (height > s->img->height
+  if (height > s->slice.height
       || s->img->hmargin
       || s->img->vmargin
       || s->img->mask
       || s->img->pixmap == 0
       || s->width != s->background_width)
     {
-      if (box_line_hwidth && s->first_glyph->left_box_line_p)
-       x = s->x + box_line_hwidth;
-      else
-       x = s->x;
+      x = s->x;
+      if (s->first_glyph->left_box_line_p
+         && s->slice.x == 0)
+       x += box_line_hwidth;
+
+      y = s->y;
+      if (s->slice.y == 0)
+       y += box_line_vwidth;
 
-      y = s->y + box_line_vwidth;
 #if 0 /* TODO: figure out if we need to do this on Windows.  */
       if (s->img->mask)
        {
@@ -2258,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))
            {
@@ -2300,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;
 }
@@ -2318,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);
@@ -2331,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))
@@ -2357,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);
@@ -2365,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);
@@ -2376,26 +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.  */
+          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);
             }
         }
 
@@ -2405,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->underline_color, s->x,
-                             s->y + dy, s->width, h);
+              w32_fill_area (s->f, s->hdc, s->face->overline_color, s->x,
+                             s->y + dy, s->background_width, h);
             }
         }
 
@@ -2430,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);
             }
         }
@@ -2658,9 +2800,13 @@ x_scroll_run (w, run)
     /* If the dirty region is not what we expected, redraw the entire frame.  */
     if (!EqualRgn (combined, expect_dirty))
       SET_FRAME_GARBAGED (f);
+
+    DeleteObject (dirty);
+    DeleteObject (combined);
   }
 
   UNBLOCK_INPUT;
+  DeleteObject (expect_dirty);
 }
 
 
@@ -2705,23 +2851,90 @@ x_new_focus_frame (dpyinfo, frame)
       if (old_focus && old_focus->auto_lower)
        x_lower_frame (old_focus);
 
+      if (dpyinfo->w32_focus_frame && dpyinfo->w32_focus_frame->auto_raise)
+       pending_autoraise_frame = dpyinfo->w32_focus_frame;
+      else
+       pending_autoraise_frame = 0;
+    }
 
+  x_frame_rehighlight (dpyinfo);
+}
 
 
+/* Handle FocusIn and FocusOut state changes for FRAME.
+   If FRAME has focus and there exists more than one frame, puts
+   a FOCUS_IN_EVENT into *BUFP.  */
 
+static void
+x_focus_changed (type, state, dpyinfo, frame, bufp)
+     int type;
+     int state;
+     struct w32_display_info *dpyinfo;
+     struct frame *frame;
+     struct input_event *bufp;
+{
+  if (type == WM_SETFOCUS)
+    {
+      if (dpyinfo->w32_focus_event_frame != frame)
+        {
+          x_new_focus_frame (dpyinfo, frame);
+          dpyinfo->w32_focus_event_frame = frame;
+
+          /* Don't stop displaying the initial startup message
+             for a switch-frame event we don't need.  */
+          if (GC_NILP (Vterminal_frame)
+              && GC_CONSP (Vframe_list)
+              && !GC_NILP (XCDR (Vframe_list)))
+            {
+              bufp->kind = FOCUS_IN_EVENT;
+              XSETFRAME (bufp->frame_or_window, frame);
+            }
+        }
 
+      frame->output_data.x->focus_state |= state;
 
+      /* TODO: IME focus?  */
+    }
+  else if (type == WM_KILLFOCUS)
+    {
+      frame->output_data.x->focus_state &= ~state;
 
+      if (dpyinfo->w32_focus_event_frame == frame)
+        {
+          dpyinfo->w32_focus_event_frame = 0;
+          x_new_focus_frame (dpyinfo, 0);
+        }
 
-      if (dpyinfo->w32_focus_frame && dpyinfo->w32_focus_frame->auto_raise)
-       pending_autoraise_frame = dpyinfo->w32_focus_frame;
-      else
-       pending_autoraise_frame = 0;
+      /* TODO: IME focus?  */
     }
+}
 
-  x_frame_rehighlight (dpyinfo);
+
+/* The focus may have changed.  Figure out if it is a real focus change,
+   by checking both FocusIn/Out and Enter/LeaveNotify events.
+
+   Returns FOCUS_IN_EVENT event in *BUFP. */
+
+static void
+w32_detect_focus_change (dpyinfo, event, bufp)
+     struct w32_display_info *dpyinfo;
+     W32Msg *event;
+     struct input_event *bufp;
+{
+  struct frame *frame;
+
+  frame = x_any_window_to_frame (dpyinfo, event->msg.hwnd);
+  if (! frame)
+    return;
+
+  /* On w32, this is only called from focus events, so no switch needed.  */
+  x_focus_changed (event->msg.message,
+                  (event->msg.message == WM_KILLFOCUS ?
+                   FOCUS_IMPLICIT : FOCUS_EXPLICIT),
+                  dpyinfo, frame, bufp);
 }
 
+
 /* Handle an event saying the mouse has moved out of an Emacs frame.  */
 
 void
@@ -2911,12 +3124,26 @@ construct_mouse_wheel (result, msg, f)
      struct frame *f;
 {
   POINT p;
-  result->kind = MOUSE_WHEEL_EVENT;
-  result->code = (short) HIWORD (msg->msg.wParam);
+  int delta;
+
+  result->kind = WHEEL_EVENT;
+  result->code = 0;
   result->timestamp = msg->msg.time;
-  result->modifiers = msg->dwModifiers;
-  p.x = LOWORD (msg->msg.lParam);
-  p.y = HIWORD (msg->msg.lParam);
+
+  /* A WHEEL_DELTA positive value indicates that the wheel was rotated
+     forward, away from the user (up); a negative value indicates that
+     the wheel was rotated backward, toward the user (down).  */
+  delta = GET_WHEEL_DELTA_WPARAM (msg->msg.wParam);
+
+  /* The up and down modifiers indicate if the wheel was rotated up or
+     down based on WHEEL_DELTA value.  */
+  result->modifiers = (msg->dwModifiers
+                       | ((delta < 0 ) ? down_modifier : up_modifier));
+
+  /* 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);
@@ -2972,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;
 }
 
@@ -2989,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;
@@ -3008,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;
@@ -3023,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
@@ -3035,9 +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 void x_check_fullscreen_move P_ ((struct frame *));
-static int glyph_rect P_ ((struct frame *f, int, int, RECT *));
-
 
 static void
 redo_mouse_highlight ()
@@ -3056,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.
 
@@ -3249,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;
@@ -3357,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
     {
@@ -3382,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;
 }
@@ -3423,7 +3557,7 @@ my_create_scrollbar (f, bar)
 
 /*#define ATTACH_THREADS*/
 
-BOOL
+static BOOL
 my_show_window (FRAME_PTR f, HWND hwnd, int how)
 {
 #ifndef ATTACH_THREADS
@@ -3434,7 +3568,7 @@ my_show_window (FRAME_PTR f, HWND hwnd, int how)
 #endif
 }
 
-void
+static void
 my_set_window_pos (HWND hwnd, HWND hwndAfter,
                   int x, int y, int cx, int cy, UINT flags)
 {
@@ -3452,7 +3586,7 @@ my_set_window_pos (HWND hwnd, HWND hwndAfter,
 #endif
 }
 
-void
+static void
 my_set_focus (f, hwnd)
      struct frame * f;
      HWND hwnd;
@@ -3461,14 +3595,15 @@ my_set_focus (f, hwnd)
               (WPARAM) hwnd, 0);
 }
 
-void
+static void
 my_set_foreground_window (hwnd)
      HWND hwnd;
 {
   SendMessage (hwnd, WM_EMACS_SETFOREGROUND, (WPARAM) hwnd, 0);
 }
 
-void
+
+static void
 my_destroy_window (f, hwnd)
      struct frame * f;
      HWND hwnd;
@@ -3489,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));
 
@@ -3507,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);
 
@@ -3635,6 +3760,8 @@ w32_set_vertical_scroll_bar (w, portion, whole, position)
       else
         {
           HDC hdc;
+         SCROLLINFO si;
+
           BLOCK_INPUT;
          if (width && height)
            {
@@ -3654,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);  */
 
@@ -3820,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;
 
@@ -3869,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
@@ -3891,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:
@@ -3935,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))
   {
@@ -4033,8 +4134,6 @@ static short temp_buffer[100];
    This routine is called by the SIGIO handler.
    We return as soon as there are no more events to be read.
 
-   Events representing keys are stored in buffer BUFP,
-   which can hold up to NUMCHARS characters.
    We return the number of characters stored into the buffer,
    thus pretending to be `read'.
 
@@ -4050,11 +4149,10 @@ static short temp_buffer[100];
 */
 
 int
-w32_read_socket (sd, bufp, numchars, expected)
+w32_read_socket (sd, expected, hold_quit)
      register int sd;
-     /* register */ struct input_event *bufp;
-     /* register */ int numchars;
      int expected;
+     struct input_event *hold_quit;
 {
   int count = 0;
   int check_visibility = 0;
@@ -4074,13 +4172,16 @@ w32_read_socket (sd, bufp, numchars, expected)
   /* So people can tell when we have read the available input.  */
   input_signal_count++;
 
-  if (numchars <= 0)
-    abort ();                   /* Don't think this happens. */
-
-  /* TODO: tool-bars, ghostscript integration, mouse
-     cursors. */
+  /* TODO: ghostscript integration. */
   while (get_next_msg (&msg, FALSE))
     {
+      struct input_event inev;
+      int do_help = 0;
+
+      EVENT_INIT (inev);
+      inev.kind = NO_EVENT;
+      inev.arg = Qnil;
+
       switch (msg.msg.message)
        {
        case WM_PAINT:
@@ -4109,12 +4210,8 @@ w32_read_socket (sd, bufp, numchars, expected)
                     visibility changes properly.  */
                  if (f->iconified)
                    {
-                     bufp->kind = DEICONIFY_EVENT;
-                     XSETFRAME (bufp->frame_or_window, f);
-                     bufp->arg = Qnil;
-                     bufp++;
-                     count++;
-                     numchars--;
+                     inev.kind = DEICONIFY_EVENT;
+                     XSETFRAME (inev.frame_or_window, f);
                    }
                  else if (! NILP (Vframe_list)
                           && ! NILP (XCDR (Vframe_list)))
@@ -4144,17 +4241,10 @@ w32_read_socket (sd, bufp, numchars, expected)
 
          if (f)
            {
-             if (numchars == 0)
-               abort ();
-
-             bufp->kind = LANGUAGE_CHANGE_EVENT;
-             XSETFRAME (bufp->frame_or_window, f);
-             bufp->arg = Qnil;
-             bufp->code = msg.msg.wParam;
-             bufp->modifiers = msg.msg.lParam & 0xffff;
-             bufp++;
-             count++;
-             numchars--;
+             inev.kind = LANGUAGE_CHANGE_EVENT;
+             XSETFRAME (inev.frame_or_window, f);
+             inev.code = msg.msg.wParam;
+             inev.modifiers = msg.msg.lParam & 0xffff;
            }
          break;
 
@@ -4164,24 +4254,21 @@ w32_read_socket (sd, bufp, numchars, expected)
 
          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))
                {
-                 dpyinfo->mouse_face_hidden = 1;
                  clear_mouse_face (dpyinfo);
+                 dpyinfo->mouse_face_hidden = 1;
                }
 
              if (temp_index == sizeof temp_buffer / sizeof (short))
                temp_index = 0;
              temp_buffer[temp_index++] = msg.msg.wParam;
-             bufp->kind = NON_ASCII_KEYSTROKE_EVENT;
-             bufp->code = msg.msg.wParam;
-             bufp->modifiers = msg.dwModifiers;
-             XSETFRAME (bufp->frame_or_window, f);
-             bufp->arg = Qnil;
-             bufp->timestamp = msg.msg.time;
-             bufp++;
-             numchars--;
-             count++;
+             inev.kind = NON_ASCII_KEYSTROKE_EVENT;
+             inev.code = msg.msg.wParam;
+             inev.modifiers = msg.dwModifiers;
+             XSETFRAME (inev.frame_or_window, f);
+             inev.timestamp = msg.msg.time;
            }
          break;
 
@@ -4191,24 +4278,21 @@ w32_read_socket (sd, bufp, numchars, expected)
 
          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))
                {
-                 dpyinfo->mouse_face_hidden = 1;
                  clear_mouse_face (dpyinfo);
+                 dpyinfo->mouse_face_hidden = 1;
                }
 
              if (temp_index == sizeof temp_buffer / sizeof (short))
                temp_index = 0;
              temp_buffer[temp_index++] = msg.msg.wParam;
-             bufp->kind = ASCII_KEYSTROKE_EVENT;
-             bufp->code = msg.msg.wParam;
-             bufp->modifiers = msg.dwModifiers;
-             XSETFRAME (bufp->frame_or_window, f);
-             bufp->arg = Qnil;
-             bufp->timestamp = msg.msg.time;
-             bufp++;
-             numchars--;
-             count++;
+             inev.kind = ASCII_KEYSTROKE_EVENT;
+             inev.code = msg.msg.wParam;
+             inev.modifiers = msg.dwModifiers;
+             XSETFRAME (inev.frame_or_window, f);
+             inev.timestamp = msg.msg.time;
            }
          break;
 
@@ -4224,6 +4308,7 @@ w32_read_socket (sd, bufp, numchars, expected)
          }
 
           previous_help_echo_string = help_echo_string;
+         help_echo_string = Qnil;
 
          if (dpyinfo->grabbed && last_mouse_frame
              && FRAME_LIVE_P (last_mouse_frame))
@@ -4240,7 +4325,7 @@ w32_read_socket (sd, bufp, numchars, expected)
          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);
@@ -4251,21 +4336,25 @@ w32_read_socket (sd, bufp, numchars, expected)
                  /* 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)
-                     && numchars > 0)
+                     /* 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))))
                    {
-                     bufp->kind = SELECT_WINDOW_EVENT;
-                     bufp->frame_or_window = window;
-                     bufp->arg = Qnil;
-                     ++bufp, ++count, --numchars;
+                     inev.kind = SELECT_WINDOW_EVENT;
+                     inev.frame_or_window = window;
                    }
 
                  last_window=window;
                }
-             note_mouse_movement (f, &msg.msg);
+             if (!note_mouse_movement (f, &msg.msg))
+               help_echo_string = previous_help_echo_string;
            }
          else
             {
@@ -4276,29 +4365,16 @@ w32_read_socket (sd, bufp, numchars, expected)
 
           /* If the contents of the global variable help_echo_string
              has changed, generate a HELP_EVENT.  */
+#if 0 /* The below is an invalid comparison when USE_LISP_UNION_TYPE.
+        But it was originally changed to this to fix a bug, so I have
+        not removed it completely in case the bug is still there.  */
           if (help_echo_string != previous_help_echo_string ||
              (!NILP (help_echo_string) && !STRINGP (help_echo_string) && f->mouse_moved))
-            {
-              Lisp_Object frame;
-              int n;
-
-             if (help_echo_string == Qnil)
-               {
-                 help_echo_object = help_echo_window = Qnil;
-                 help_echo_pos = -1;
-               }
-
-              if (f)
-                XSETFRAME (frame, f);
-              else
-                frame = Qnil;
-
-              any_help_event_p = 1;
-              n = gen_help_event (bufp, numchars, help_echo_string, frame,
-                                 help_echo_window, help_echo_object,
-                                 help_echo_pos);
-              bufp += n, count += n, numchars -= n;
-            }
+#else /* This is what xterm.c does.  */
+           if (!NILP (help_echo_string)
+               || !NILP (previous_help_echo_string))
+           do_help = 1;
+#endif
           break;
 
        case WM_LBUTTONDOWN:
@@ -4312,13 +4388,10 @@ w32_read_socket (sd, bufp, numchars, expected)
          {
             /* If we decide we want to generate an event to be seen
                by the rest of Emacs, we put it here.  */
-            struct input_event emacs_event;
             int tool_bar_p = 0;
            int button;
            int up;
 
-            emacs_event.kind = NO_EVENT;
-
            if (dpyinfo->grabbed && last_mouse_frame
                && FRAME_LIVE_P (last_mouse_frame))
              f = last_mouse_frame;
@@ -4327,35 +4400,29 @@ w32_read_socket (sd, bufp, numchars, expected)
 
            if (f)
              {
-                construct_mouse_click (&emacs_event, &msg, f);
+                construct_mouse_click (&inev, &msg, f);
 
                 /* Is this in the tool-bar?  */
                 if (WINDOWP (f->tool_bar_window)
                     && WINDOW_TOTAL_LINES (XWINDOW (f->tool_bar_window)))
                   {
                     Lisp_Object window;
-                   int x = XFASTINT (emacs_event.x);
-                   int y = XFASTINT (emacs_event.y);
+                   int x = XFASTINT (inev.x);
+                   int y = XFASTINT (inev.y);
 
                     window = window_from_coordinates (f, x, y, 0, 0, 0, 1);
 
                     if (EQ (window, f->tool_bar_window))
                       {
-                        w32_handle_tool_bar_click (f, &emacs_event);
+                        w32_handle_tool_bar_click (f, &inev);
                         tool_bar_p = 1;
                       }
                   }
 
-                if (!tool_bar_p)
-                  if (!dpyinfo->w32_focus_frame
-                      || f == dpyinfo->w32_focus_frame
-                      && (numchars >= 1))
-                    {
-                      construct_mouse_click (bufp, &msg, f);
-                      bufp++;
-                      count++;
-                      numchars--;
-                    }
+                if (tool_bar_p
+                   || (dpyinfo->w32_focus_frame
+                       && f != dpyinfo->w32_focus_frame))
+                 inev.kind = NO_EVENT;
              }
 
            parse_button (msg.msg.message, HIWORD (msg.msg.wParam),
@@ -4382,37 +4449,39 @@ w32_read_socket (sd, bufp, numchars, expected)
            break;
          }
 
-      case WM_MOUSEWHEEL:
-          if (dpyinfo->grabbed && last_mouse_frame
-              && FRAME_LIVE_P (last_mouse_frame))
-            f = last_mouse_frame;
-          else
-            f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
+       case WM_MOUSEWHEEL:
+         {
+           if (dpyinfo->grabbed && last_mouse_frame
+               && FRAME_LIVE_P (last_mouse_frame))
+             f = last_mouse_frame;
+           else
+             f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
 
-          if (f)
-            {
-              if ((!dpyinfo->w32_focus_frame
-                   || f == dpyinfo->w32_focus_frame)
-                  && (numchars >= 1))
-                {
-                  construct_mouse_wheel (bufp, &msg, f);
-                  bufp++;
-                  count++;
-                  numchars--;
-                }
-            }
+           if (f)
+             {
+
+               if (!dpyinfo->w32_focus_frame
+                   || f == dpyinfo->w32_focus_frame)
+                 {
+                   /* Emit an Emacs wheel-up/down event.  */
+                   construct_mouse_wheel (&inev, &msg, f);
+                 }
+               /* Ignore any mouse motion that happened before this
+                  event; any subsequent mouse-movement Emacs events
+                  should reflect only motion after the
+                  ButtonPress.  */
+               f->mouse_moved = 0;
+             }
+           last_mouse_frame = f;
+           last_tool_bar_item = -1;
+         }
          break;
 
        case WM_DROPFILES:
          f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
 
          if (f)
-           {
-             construct_drag_n_drop (bufp, &msg, f);
-             bufp++;
-             count++;
-             numchars--;
-           }
+           construct_drag_n_drop (&inev, &msg, f);
          break;
 
        case WM_VSCROLL:
@@ -4420,15 +4489,8 @@ w32_read_socket (sd, bufp, numchars, expected)
            struct scroll_bar *bar =
              x_window_to_scroll_bar ((HWND)msg.msg.lParam);
 
-           if (bar && numchars >= 1)
-             {
-               if (w32_scroll_bar_handle_click (bar, &msg, bufp))
-                 {
-                   bufp++;
-                   count++;
-                   numchars--;
-                 }
-             }
+           if (bar)
+             w32_scroll_bar_handle_click (bar, &msg, &inev);
            break;
          }
 
@@ -4436,7 +4498,6 @@ w32_read_socket (sd, bufp, numchars, expected)
          f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
          if (f)
            {
-             x_check_fullscreen_move(f);
              if (f->want_fullscreen & FULLSCREEN_WAIT)
                f->want_fullscreen &= ~(FULLSCREEN_WAIT|FULLSCREEN_BOTH);
            }
@@ -4505,12 +4566,8 @@ w32_read_socket (sd, bufp, numchars, expected)
                  f->async_visible = 0;
                  f->async_iconified = 1;
 
-                 bufp->kind = ICONIFY_EVENT;
-                 XSETFRAME (bufp->frame_or_window, f);
-                 bufp->arg = Qnil;
-                 bufp++;
-                 count++;
-                 numchars--;
+                 inev.kind = ICONIFY_EVENT;
+                 XSETFRAME (inev.frame_or_window, f);
                  break;
 
                case SIZE_MAXIMIZED:
@@ -4518,7 +4575,7 @@ w32_read_socket (sd, bufp, numchars, expected)
                  f->async_visible = 1;
                  f->async_iconified = 0;
 
-                 /* wait_reading_process_input will notice this and update
+                 /* wait_reading_process_output will notice this and update
                     the frame's display structures.  */
                  SET_FRAME_GARBAGED (f);
 
@@ -4535,12 +4592,8 @@ w32_read_socket (sd, bufp, numchars, expected)
                       f->left_pos = x;
                       f->top_pos = y;
 
-                     bufp->kind = DEICONIFY_EVENT;
-                     XSETFRAME (bufp->frame_or_window, f);
-                     bufp->arg = Qnil;
-                     bufp++;
-                     count++;
-                     numchars--;
+                     inev.kind = DEICONIFY_EVENT;
+                     XSETFRAME (inev.frame_or_window, f);
                    }
                  else if (! NILP (Vframe_list)
                           && ! NILP (XCDR (Vframe_list)))
@@ -4608,42 +4661,18 @@ w32_read_socket (sd, bufp, numchars, expected)
                 Otherwise, the startup message is cleared when
                 the mouse leaves the frame.  */
              if (any_help_event_p)
-               {
-                 Lisp_Object frame;
-                 int n;
-
-                 XSETFRAME (frame, f);
-                 help_echo_string = Qnil;
-                 n = gen_help_event (bufp, numchars,
-                                     Qnil, frame, Qnil, Qnil, 0);
-                 bufp += n, count += n, numchars -= n;
-               }
+               do_help = -1;
            }
          break;
 
        case WM_SETFOCUS:
-         /* TODO: Port this change:
-            2002-06-28  Jan D.  <jan.h.d@swipnet.se>
-          * xterm.h (struct x_output): Add focus_state.
-          * xterm.c (x_focus_changed): New function.
-            (x_detect_focus_change): New function.
-            (XTread_socket): Call x_detect_focus_change for FocusIn/FocusOut
-            EnterNotify and LeaveNotify to track X focus changes.
-          */
-         f = x_any_window_to_frame (dpyinfo, msg.msg.hwnd);
-
-          dpyinfo->w32_focus_event_frame = f;
-
-          if (f)
-            x_new_focus_frame (dpyinfo, f);
-
+         w32_detect_focus_change (dpyinfo, &msg, &inev);
 
          dpyinfo->grabbed = 0;
          check_visibility = 1;
          break;
 
        case WM_KILLFOCUS:
-          /* TODO: some of this belongs in MOUSE_LEAVE */
          f = x_top_window_to_frame (dpyinfo, msg.msg.hwnd);
 
           if (f)
@@ -4667,16 +4696,7 @@ w32_read_socket (sd, bufp, numchars, expected)
                  Otherwise, the startup message is cleared when
                  the mouse leaves the frame.  */
               if (any_help_event_p)
-                {
-                  Lisp_Object frame;
-                  int n;
-
-                  XSETFRAME (frame, f);
-                  help_echo_string = Qnil;
-                  n = gen_help_event (bufp, numchars,
-                                      Qnil, frame, Qnil, Qnil, 0);
-                  bufp += n, count += n, numchars -=n;
-                }
+               do_help = -1;
             }
 
          dpyinfo->grabbed = 0;
@@ -4688,15 +4708,8 @@ w32_read_socket (sd, bufp, numchars, expected)
 
          if (f)
            {
-             if (numchars == 0)
-               abort ();
-
-             bufp->kind = DELETE_WINDOW_EVENT;
-             XSETFRAME (bufp->frame_or_window, f);
-             bufp->arg = Qnil;
-             bufp++;
-             count++;
-             numchars--;
+             inev.kind = DELETE_WINDOW_EVENT;
+             XSETFRAME (inev.frame_or_window, f);
            }
          break;
 
@@ -4705,15 +4718,8 @@ w32_read_socket (sd, bufp, numchars, expected)
 
          if (f)
            {
-             if (numchars == 0)
-               abort ();
-
-             bufp->kind = MENU_BAR_ACTIVATE_EVENT;
-             XSETFRAME (bufp->frame_or_window, f);
-             bufp->arg = Qnil;
-             bufp++;
-             count++;
-             numchars--;
+             inev.kind = MENU_BAR_ACTIVATE_EVENT;
+             XSETFRAME (inev.frame_or_window, f);
            }
          break;
 
@@ -4746,29 +4752,50 @@ w32_read_socket (sd, bufp, numchars, expected)
          break;
 
        default:
-         /* Check for messages registered at runtime. */
+         /* Check for messages registered at runtime.  */
          if (msg.msg.message == msh_mousewheel)
            {
-             if (dpyinfo->grabbed && last_mouse_frame
-                 && FRAME_LIVE_P (last_mouse_frame))
-               f = last_mouse_frame;
-             else
-               f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
+             /* Forward MSH_MOUSEWHEEL as WM_MOUSEWHEEL.  */
+             msg.msg.message = WM_MOUSEWHEEL;
+             prepend_msg (&msg);
+           }
+         break;
+       }
+
+      if (inev.kind != NO_EVENT)
+       {
+         kbd_buffer_store_event_hold (&inev, hold_quit);
+         count++;
+       }
 
-             if (f)
+      if (do_help
+         && !(hold_quit && hold_quit->kind != NO_EVENT))
+       {
+         Lisp_Object frame;
+
+         if (f)
+           XSETFRAME (frame, f);
+         else
+           frame = Qnil;
+
+         if (do_help > 0)
+           {
+             if (NILP (help_echo_string))
                {
-                 if ((!dpyinfo->w32_focus_frame
-                      || f == dpyinfo->w32_focus_frame)
-                     && (numchars >= 1))
-                   {
-                     construct_mouse_wheel (bufp, &msg, f);
-                     bufp++;
-                     count++;
-                     numchars--;
-                   }
+                 help_echo_object = help_echo_window = Qnil;
+                 help_echo_pos = -1;
                }
+
+             any_help_event_p = 1;
+             gen_help_event (help_echo_string, frame, help_echo_window,
+                             help_echo_object, help_echo_pos);
            }
-         break;
+         else
+           {
+             help_echo_string = Qnil;
+             gen_help_event (Qnil, frame, Qnil, Qnil, 0);
+           }
+         count++;
        }
     }
 
@@ -4791,65 +4818,65 @@ w32_read_socket (sd, bufp, numchars, expected)
       Lisp_Object tail, frame;
 
       FOR_EACH_FRAME (tail, frame)
-       {
-         FRAME_PTR f = XFRAME (frame);
-         /* The tooltip has been drawn already.  Avoid the
-            SET_FRAME_GARBAGED below.  */
-         if (EQ (frame, tip_frame))
-           continue;
-
-         /* Check "visible" frames and mark each as obscured or not.
-            Note that async_visible is nonzero for unobscured and
-            obscured frames, but zero for hidden and iconified frames.  */
-         if (FRAME_W32_P (f) && f->async_visible)
-           {
-             RECT clipbox;
-             HDC  hdc;
-
-             enter_crit ();
-             /* Query clipping rectangle for the entire window area
-                 (GetWindowDC), not just the client portion (GetDC).
-                 Otherwise, the scrollbars and menubar aren't counted as
-                 part of the visible area of the frame, and we may think
-                 the frame is obscured when really a scrollbar is still
-                 visible and gets WM_PAINT messages above.  */
-             hdc = GetWindowDC (FRAME_W32_WINDOW (f));
-             GetClipBox (hdc, &clipbox);
-             ReleaseDC (FRAME_W32_WINDOW (f), hdc);
-             leave_crit ();
-
-             if (clipbox.right == clipbox.left
-                 || clipbox.bottom == clipbox.top)
-               {
-                 /* Frame has become completely obscured so mark as
-                    such (we do this by setting async_visible to 2 so
-                    that FRAME_VISIBLE_P is still true, but redisplay
-                    will skip it).  */
-                 f->async_visible = 2;
+      {
+       FRAME_PTR f = XFRAME (frame);
+       /* The tooltip has been drawn already.  Avoid the
+          SET_FRAME_GARBAGED below.  */
+       if (EQ (frame, tip_frame))
+         continue;
+
+       /* Check "visible" frames and mark each as obscured or not.
+          Note that async_visible is nonzero for unobscured and
+          obscured frames, but zero for hidden and iconified frames.  */
+       if (FRAME_W32_P (f) && f->async_visible)
+         {
+           RECT clipbox;
+           HDC  hdc;
+
+           enter_crit ();
+           /* Query clipping rectangle for the entire window area
+              (GetWindowDC), not just the client portion (GetDC).
+              Otherwise, the scrollbars and menubar aren't counted as
+              part of the visible area of the frame, and we may think
+              the frame is obscured when really a scrollbar is still
+              visible and gets WM_PAINT messages above.  */
+           hdc = GetWindowDC (FRAME_W32_WINDOW (f));
+           GetClipBox (hdc, &clipbox);
+           ReleaseDC (FRAME_W32_WINDOW (f), hdc);
+           leave_crit ();
+
+           if (clipbox.right == clipbox.left
+               || clipbox.bottom == clipbox.top)
+             {
+               /* Frame has become completely obscured so mark as
+                  such (we do this by setting async_visible to 2 so
+                  that FRAME_VISIBLE_P is still true, but redisplay
+                  will skip it).  */
+               f->async_visible = 2;
 
-                 if (!FRAME_OBSCURED_P (f))
-                   {
-                     DebPrint (("frame %p (%s) obscured\n", f,
-                                SDATA (f->name)));
-                   }
-               }
-             else
-               {
-                 /* Frame is not obscured, so mark it as such.  */
-                 f->async_visible = 1;
+               if (!FRAME_OBSCURED_P (f))
+                 {
+                   DebPrint (("frame %p (%s) obscured\n", f,
+                              SDATA (f->name)));
+                 }
+             }
+           else
+             {
+               /* Frame is not obscured, so mark it as such.  */
+               f->async_visible = 1;
 
-                 if (FRAME_OBSCURED_P (f))
-                   {
-                     SET_FRAME_GARBAGED (f);
-                     DebPrint (("obscured frame %p (%s) found to be visible\n", f,
-                                SDATA (f->name)));
+               if (FRAME_OBSCURED_P (f))
+                 {
+                   SET_FRAME_GARBAGED (f);
+                   DebPrint (("obscured frame %p (%s) found to be visible\n", f,
+                              SDATA (f->name)));
 
-                     /* Force a redisplay sooner or later.  */
-                     record_asynch_buffer_change ();
-                   }
-               }
-           }
-       }
+                   /* Force a redisplay sooner or later.  */
+                   record_asynch_buffer_change ();
+                 }
+             }
+         }
+      }
     }
 
   UNBLOCK_INPUT;
@@ -4857,7 +4884,6 @@ w32_read_socket (sd, bufp, numchars, expected)
 }
 
 
-
 \f
 /***********************************************************************
                             Text Cursor
@@ -4871,18 +4897,19 @@ w32_read_socket (sd, bufp, numchars, expected)
    mode lines must be clipped to the whole window.  */
 
 static void
-w32_clip_to_row (w, row, hdc)
+w32_clip_to_row (w, row, area, hdc)
      struct window *w;
      struct glyph_row *row;
+     int area;
      HDC hdc;
 {
   struct frame *f = XFRAME (WINDOW_FRAME (w));
   RECT clip_rect;
-  int window_y, window_width;
+  int window_x, window_y, window_width;
 
-  window_box (w, -1, 0, &window_y, &window_width, 0);
+  window_box (w, area, &window_x, &window_y, &window_width, 0);
 
-  clip_rect.left = WINDOW_TO_FRAME_PIXEL_X (w, 0);
+  clip_rect.left = window_x;
   clip_rect.top = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
   clip_rect.top = max (clip_rect.top, window_y);
   clip_rect.right = clip_rect.left + window_width;
@@ -4902,37 +4929,26 @@ x_draw_hollow_cursor (w, row)
   struct frame *f = XFRAME (WINDOW_FRAME (w));
   HDC hdc;
   RECT rect;
-  int wd;
+  int left, top, h;
   struct glyph *cursor_glyph;
   HBRUSH hb = CreateSolidBrush (f->output_data.w32->cursor_pixel);
 
-  /* Compute frame-relative coordinates from window-relative
-     coordinates.  */
-  rect.left = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
-  rect.top = (WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y)
-              + row->ascent - w->phys_cursor_ascent);
-  rect.bottom = rect.top + row->height;
-
   /* Get the glyph the cursor is on.  If we can't tell because
      the current matrix is invalid or such, give up.  */
   cursor_glyph = get_phys_cursor_glyph (w);
   if (cursor_glyph == NULL)
     return;
 
-  /* Compute the width of the rectangle to draw.  If on a stretch
-     glyph, and `x-stretch-block-cursor' is nil, don't draw a
-     rectangle as wide as the glyph, but use a canonical character
-     width instead.  */
-  wd = cursor_glyph->pixel_width;
-  if (cursor_glyph->type == STRETCH_GLYPH
-      && !x_stretch_cursor_p)
-    wd = min (FRAME_COLUMN_WIDTH (f), wd);
-  w->phys_cursor_width = wd;
+  /* Compute frame-relative coordinates for phys cursor.  */
+  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;
 
-  rect.right = rect.left + wd;
   hdc = get_frame_dc (f);
   /* Set clipping, draw the rectangle, and reset clipping again.  */
-  w32_clip_to_row (w, row, hdc);
+  w32_clip_to_row (w, row, TEXT_AREA, hdc);
   FrameRect (hdc, &rect, hb);
   DeleteObject (hb);
   w32_set_clip_rectangle (hdc, NULL);
@@ -4998,7 +5014,7 @@ x_draw_bar_cursor (w, row, width, kind)
 
 
       hdc = get_frame_dc (f);
-      w32_clip_to_row (w, row, hdc);
+      w32_clip_to_row (w, row, TEXT_AREA, hdc);
 
       if (kind == BAR_CURSOR)
        {
@@ -5061,6 +5077,9 @@ w32_draw_window_cursor (w, glyph_row, x, y, cursor_type, cursor_width, on_p, act
         cursor remains invisible.  */
       if (w32_use_visible_system_caret)
        {
+         /* Call to erase_phys_cursor here seems to use the
+            wrong values of w->phys_cursor, as they have been
+            overwritten before this function was called. */
          if (w->phys_cursor_type != NO_CURSOR)
            erase_phys_cursor (w);
 
@@ -5100,6 +5119,14 @@ w32_draw_window_cursor (w, glyph_row, x, y, cursor_type, cursor_width, on_p, act
          PostMessage (hwnd, WM_EMACS_TRACK_CARET, 0, 0);
        }
 
+      if (glyph_row->exact_window_width_line_p
+         && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
+       {
+         glyph_row->cursor_in_fringe_p = 1;
+         draw_fringe_bitmap (w, glyph_row, 0);
+         return;
+       }
+
       switch (cursor_type)
        {
        case HOLLOW_BOX_CURSOR:
@@ -5137,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;
@@ -5166,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;
 }
@@ -5192,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)
@@ -5227,7 +5270,8 @@ x_new_font (f, fontname)
   FRAME_BASELINE_OFFSET (f) = fontp->baseline_offset;
   FRAME_FONTSET (f) = -1;
 
-  FRAME_COLUMN_WIDTH (f) = FONT_WIDTH (FRAME_FONT (f));
+  FRAME_COLUMN_WIDTH (f) = fontp->average_width;
+  FRAME_SPACE_WIDTH (f) = fontp->space_width;
   FRAME_LINE_HEIGHT (f) = FONT_HEIGHT (FRAME_FONT (f));
 
   compute_fringe_widths (f, 1);
@@ -5311,52 +5355,54 @@ void
 x_calc_absolute_position (f)
      struct frame *f;
 {
-  POINT pt;
   int flags = f->size_hint_flags;
 
-  pt.x = pt.y = 0;
+  /* 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;
 
-  /* Find the position of the outside upper-left corner of
-     the inner window, with respect to the outer window.
-     But do this only if we will need the results.  */
-  if (f->output_data.w32->parent_desc != FRAME_W32_DISPLAY_INFO (f)->root_window)
-    {
-      BLOCK_INPUT;
-      MapWindowPoints (FRAME_W32_WINDOW (f),
-                      f->output_data.w32->parent_desc,
-                      &pt, 1);
-      UNBLOCK_INPUT;
-    }
+  /* 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 };
 
-  {
-      RECT rt;
-      rt.left = rt.right = rt.top = rt.bottom = 0;
-
-      BLOCK_INPUT;
-      AdjustWindowRect(&rt, f->output_data.w32->dwStyle,
-                      FRAME_EXTERNAL_MENU_BAR (f));
-      UNBLOCK_INPUT;
+  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);
 
-      pt.x += (rt.right - rt.left);
-      pt.y += (rt.bottom - rt.top);
-  }
+      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 leftmost bottommost
+  /* 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
-                  - 2 * f->border_width - pt.x
                   - 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
-                 - 2 * f->border_width - pt.y
                  - 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);
 }
 
@@ -5417,9 +5463,7 @@ x_check_fullscreen (f)
       x_fullscreen_adjust (f, &width, &height, &ign, &ign);
 
       /* We do not need to move the window, it shall be taken care of
-         when setting WM manager hints.
-         If the frame is visible already, the position is checked by
-         x_check_fullscreen_move. */
+         when setting WM manager hints.  */
       if (FRAME_COLS (f) != width || FRAME_LINES (f) != height)
         {
           change_frame_size (f, height, width, 0, 1, 0);
@@ -5432,36 +5476,6 @@ x_check_fullscreen (f)
     }
 }
 
-/* If frame parameters are set after the frame is mapped, we need to move
-   the window.  This is done in xfns.c.
-   Some window managers moves the window to the right position, some
-   moves the outer window manager window to the specified position.
-   Here we check that we are in the right spot.  If not, make a second
-   move, assuming we are dealing with the second kind of window manager. */
-static void
-x_check_fullscreen_move (f)
-     struct frame *f;
-{
-  if (f->want_fullscreen & FULLSCREEN_MOVE_WAIT)
-  {
-    int expect_top = f->top_pos;
-    int expect_left = f->left_pos;
-
-    if (f->want_fullscreen & FULLSCREEN_HEIGHT)
-      expect_top = 0;
-    if (f->want_fullscreen & FULLSCREEN_WIDTH)
-      expect_left = 0;
-
-    if (expect_top != f->top_pos
-        || expect_left != f->left_pos)
-      x_set_offset (f, expect_left, expect_top, 1);
-
-    /* Just do this once */
-    f->want_fullscreen &= ~FULLSCREEN_MOVE_WAIT;
-  }
-}
-
-
 /* Call this to change the size of frame F's x-window.
    If CHANGE_GRAVITY is 1, we change to top-left-corner window gravity
    for this size change and subsequent size changes.
@@ -5507,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.
@@ -5538,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;
 }
@@ -5728,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;
 
@@ -6210,32 +6255,7 @@ w32_term_init (display_name, xrm_option, resource_name)
      horizontally reflected compared to how they appear on X, so we
      need to bitswap and convert to unsigned shorts before creating
      the bitmaps.  */
-  {
-    int i, j;
-
-    for (i = NO_FRINGE_BITMAP + 1; i < MAX_FRINGE_BITMAPS; i++)
-      {
-       int h = fringe_bitmaps[i].height;
-       int wd = fringe_bitmaps[i].width;
-       unsigned short *w32bits
-         = (unsigned short *)alloca (h * sizeof (unsigned short));
-       unsigned short *wb = w32bits;
-       unsigned char *bits = fringe_bitmaps[i].bits;
-       for (j = 0; j < h; j++)
-         {
-           static unsigned char swap_nibble[16] 
-             = { 0x0, 0x8, 0x4, 0xc,    /* 0000 1000 0100 1100 */
-                 0x2, 0xa, 0x6, 0xe,    /* 0010 1010 0110 1110 */
-                 0x1, 0x9, 0x5, 0xd,    /* 0001 1001 0101 1101 */
-                 0x3, 0xb, 0x7, 0xf };  /* 0011 1011 0111 1111 */
-                 
-           unsigned char b = *bits++;
-           *wb++ = (unsigned short)((swap_nibble[b & 0xf]<<4)
-                                    | (swap_nibble[(b>>4) & 0xf]));
-         }
-       fringe_bmp[i] = CreateBitmap (wd, h, 1, 1, w32bits);
-      }
-  }
+  w32_init_fringe ();
 
 #ifndef F_SETOWN_BUG
 #ifdef F_SETOWN
@@ -6303,18 +6323,12 @@ x_delete_display (dpyinfo)
   xfree (dpyinfo->font_table);
   xfree (dpyinfo->w32_id_name);
 
-  /* Destroy row bitmaps.  */
-  {
-    int i;
-
-    for (i = NO_FRINGE_BITMAP + 1; i < MAX_FRINGE_BITMAPS; i++)
-      DeleteObject (fringe_bmp[i]);
-  }
+  w32_reset_fringes ();
 }
 \f
 /* Set up use of W32.  */
 
-DWORD w32_msg_worker ();
+DWORD WINAPI w32_msg_worker (void * arg);
 
 void
 x_flush (struct frame * f)
@@ -6340,6 +6354,8 @@ static struct redisplay_interface w32_redisplay_interface =
   w32_get_glyph_overhangs,
   x_fix_overlapping_area,
   w32_draw_fringe_bitmap,
+  w32_define_fringe_bitmap,
+  w32_destroy_fringe_bitmap,
   w32_per_char_metric,
   w32_encode_char,
   NULL, /* w32_compute_glyph_string_overhangs */
@@ -6388,6 +6404,12 @@ w32_initialize ()
   w32_system_caret_x = 0;
   w32_system_caret_y = 0;
 
+  /* Initialize w32_use_visible_system_caret based on whether a screen
+     reader is in use.  */
+  if (!SystemParametersInfo (SPI_GETSCREENREADER, 0,
+                            &w32_use_visible_system_caret, 0))
+    w32_use_visible_system_caret = 0;
+
   last_tool_bar_item = -1;
   any_help_event_p = 0;
 
@@ -6411,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);
   }
@@ -6429,29 +6451,41 @@ w32_initialize ()
   AttachThreadInput (dwMainThreadId, dwWindowsThreadId, TRUE);
 #endif
 
-  /* Dynamically link to optional system components. */
+  /* Load system settings.  */
   {
-    HANDLE user_lib = LoadLibrary ("user32.dll");
-
-#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);
+    UINT smoothing_type;
+    BOOL smoothing_enabled;
 
     /* 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.  */
     vertical_scroll_bar_top_border = vertical_scroll_bar_bottom_border
       = GetSystemMetrics (SM_CYVSCROLL);
+
+    /* Constants that are not always defined by the system headers
+       since they only exist on certain versions of Windows.  */
+#ifndef SPI_GETFONTSMOOTHING
+#define SPI_GETFONTSMOOTHING 0x4A
+#endif
+#ifndef SPI_GETFONTSMOOTHINGTYPE
+#define SPI_GETFONTSMOOTHINGTYPE 0x0200A
+#endif
+#ifndef FE_FONTSMOOTHINGCLEARTYPE
+#define FE_FONTSMOOTHINGCLEARTYPE 0x2
+#endif
+
+    /* Determine if Cleartype is in use.  Used to enable a hack in
+       the char metric calculations which adds extra pixels to
+       compensate for the "sub-pixels" that are not counted by the
+       system APIs. */
+    cleartype_active =
+      SystemParametersInfo (SPI_GETFONTSMOOTHING, 0, &smoothing_enabled, 0)
+      && smoothing_enabled
+      && SystemParametersInfo (SPI_GETFONTSMOOTHINGTYPE, 0, &smoothing_type, 0)
+      && smoothing_type == FE_FONTSMOOTHINGCLEARTYPE;
   }
 }
 
@@ -6468,9 +6502,9 @@ syms_of_w32term ()
   Qvendor_specific_keysyms = intern ("vendor-specific-keysyms");
 
   DEFVAR_INT ("w32-num-mouse-buttons",
-             &Vw32_num_mouse_buttons,
+             &w32_num_mouse_buttons,
              doc: /* Number of physical mouse buttons.  */);
-  Vw32_num_mouse_buttons = Qnil;
+  w32_num_mouse_buttons = 2;
 
   DEFVAR_LISP ("w32-swap-mouse-buttons",
              &Vw32_swap_mouse_buttons,
@@ -6521,11 +6555,27 @@ software is running as it starts up.
 When this variable is set, other variables affecting the appearance of
 the cursor have no effect.  */);
 
-  /* Initialize w32_use_visible_system_caret based on whether a screen
-     reader is in use.  */
-  if (!SystemParametersInfo (SPI_GETSCREENREADER, 0,
-                            &w32_use_visible_system_caret, 0))
-    w32_use_visible_system_caret = 0;
+  w32_use_visible_system_caret = 0;
+
+  /* We don't yet support this, but defining this here avoids whining
+     from cus-start.el and other places, like "M-x set-variable".  */
+  DEFVAR_BOOL ("x-use-underline-position-properties",
+              &x_use_underline_position_properties,
+     doc: /* *Non-nil means make use of UNDERLINE_POSITION font properties.
+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.  */);
@@ -6534,3 +6584,6 @@ the cursor have no effect.  */);
   staticpro (&last_mouse_motion_frame);
   last_mouse_motion_frame = Qnil;
 }
+
+/* arch-tag: 5fa70624-ab86-499c-8a85-473958ee4646
+   (do not change this comment) */