]> code.delx.au - gnu-emacs/blobdiff - src/w32term.c
*** empty log message ***
[gnu-emacs] / src / w32term.c
index a93482672cce60530f4b1e37e5c562922057ac4c..2b5c9da39b607c178611220354b425b5e705662d 100644 (file)
@@ -1,6 +1,6 @@
 /* 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 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -16,8 +16,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 +62,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 +74,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 +87,10 @@ 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;
+
 extern unsigned int msh_mousewheel;
 
 extern void free_frame_menubar ();
@@ -128,6 +138,9 @@ 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;
@@ -170,9 +183,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 +230,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,13 +263,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, int));
+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;
 
@@ -296,8 +316,9 @@ record_event (locus, type)
 #endif /* 0 */
 \f
 
-void XChangeGC (void * ignore, XGCValues* gc, unsigned long mask,
-                XGCValues *xgcv)
+void
+XChangeGC (void * ignore, XGCValues* gc, unsigned long mask,
+          XGCValues *xgcv)
 {
   if (mask & GCForeground)
     gc->foreground = xgcv->foreground;
@@ -318,7 +339,8 @@ XGCValues *XCreateGC (void * ignore, Window window, unsigned long mask,
   return gc;
 }
 
-void XGetGCValues (void* ignore, XGCValues *gc,
+void
+XGetGCValues (void* ignore, XGCValues *gc,
                    unsigned long mask, XGCValues *xgcv)
 {
   XChangeGC (ignore, xgcv, mask, gc);
@@ -494,14 +516,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);
 }
 
@@ -535,7 +563,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;
     }
 
@@ -620,11 +650,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
@@ -651,7 +677,7 @@ x_after_update_window_line (desired_row)
       {
        HDC hdc = get_frame_dc (f);
        w32_clear_area (f, hdc, 0, y, width, height);
-       w32_clear_area (f, hdc, f->output_data.w32->pixel_width - width,
+       w32_clear_area (f, hdc, FRAME_PIXEL_WIDTH (f) - width,
                        y, width, height);
        release_frame_dc (f, hdc);
       }
@@ -674,34 +700,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, 1);
+  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);
@@ -713,6 +784,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
@@ -740,8 +842,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 *));
 
 
@@ -821,6 +922,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
@@ -878,7 +989,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;
@@ -889,7 +1000,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)
@@ -898,6 +1019,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)
@@ -1105,9 +1228,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)
@@ -1118,7 +1241,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 *,
@@ -1141,7 +1263,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 *));
 
@@ -1445,7 +1568,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);
@@ -1722,9 +1845,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;
@@ -1739,10 +1863,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)
@@ -1757,10 +1882,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)
@@ -1828,14 +1954,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 += FRAME_X_RIGHT_FRINGE_WIDTH (s->f);
-      if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (s->f))
-       last_x += FRAME_SCROLL_BAR_WIDTH (s->f) * CANON_X_UNIT (s->f);
-    }
+  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
@@ -1869,7 +1990,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);
     }
 }
 
@@ -1880,21 +2001,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);
 
@@ -1916,12 +2038,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);
@@ -1931,8 +2053,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
@@ -1945,7 +2067,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);
            }
        }
 
@@ -1956,14 +2079,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
@@ -1972,21 +2094,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)
@@ -2002,12 +2125,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);
 }
 
 
@@ -2020,21 +2148,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)
     {
@@ -2050,12 +2179,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);
@@ -2065,8 +2194,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
@@ -2078,8 +2207,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);
            }
        }
 
@@ -2089,8 +2219,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);
@@ -2149,19 +2279,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)
        {
@@ -2256,7 +2389,7 @@ 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 (CANON_X_UNIT (s->f), s->background_width);
+      int width = min (FRAME_COLUMN_WIDTH (s->f), s->background_width);
 
       /* Draw cursor.  */
       x_draw_glyph_string_bg_rect (s, s->x, s->y, width, s->height);
@@ -2316,7 +2449,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);
@@ -2329,7 +2462,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))
@@ -2355,7 +2488,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);
@@ -2363,7 +2496,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);
@@ -2374,7 +2507,7 @@ x_draw_glyph_string (s)
       abort ();
     }
 
-  if (!s->for_overlaps_p)
+  if (!s->for_overlaps)
     {
       /* Draw underline.  */
       if (s->face->underline_p
@@ -2384,7 +2517,9 @@ x_draw_glyph_string (s)
           unsigned long dy = s->height - h;
 
          /* TODO: Use font information for positioning and thickness
-            of underline.  See OUTLINETEXTMETRIC, and xterm.c.  */
+            of underline.  See OUTLINETEXTMETRIC, and xterm.c.
+            Note: If you make this work, don't forget to change the
+            doc string of x-use-underline-position-properties below.  */
           if (s->face->underline_defaulted_p)
             {
               w32_fill_area (s->f, s->hdc, s->gc->foreground, s->x,
@@ -2409,7 +2544,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->overline_color, s->x,
                              s->y + dy, s->width, h);
             }
         }
@@ -2601,8 +2736,6 @@ x_scroll_run (w, run)
      without mode lines.  Include in this box the left and right
      fringes of W.  */
   window_box (w, -1, &x, &y, &width, &height);
-  width += FRAME_X_FRINGE_WIDTH (f);
-  x -= FRAME_X_LEFT_FRINGE_WIDTH (f);
 
   from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
   to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
@@ -2658,9 +2791,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 +2842,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
@@ -2800,106 +3004,6 @@ x_get_keysym_name (keysym)
 \f
 /* Mouse clicks and mouse movement.  Rah.  */
 
-/* Given a pixel position (PIX_X, PIX_Y) on frame F, return glyph
-   co-ordinates in (*X, *Y).  Set *BOUNDS to the rectangle that the
-   glyph at X, Y occupies, if BOUNDS != 0.  If NOCLIP is non-zero, do
-   not force the value into range.  */
-
-void
-pixel_to_glyph_coords (f, pix_x, pix_y, x, y, bounds, noclip)
-     FRAME_PTR f;
-     register int pix_x, pix_y;
-     register int *x, *y;
-     RECT *bounds;
-     int noclip;
-{
-  /* Support tty mode: if Vwindow_system is nil, behave correctly. */
-  if (NILP (Vwindow_system))
-    {
-      *x = pix_x;
-      *y = pix_y;
-      return;
-    }
-
-  /* Arrange for the division in PIXEL_TO_CHAR_COL etc. to round down
-     even for negative values.  */
-  if (pix_x < 0)
-    pix_x -= FONT_WIDTH (FRAME_FONT (f)) - 1;
-  if (pix_y < 0)
-    pix_y -= (f)->output_data.w32->line_height - 1;
-
-  pix_x = PIXEL_TO_CHAR_COL (f, pix_x);
-  pix_y = PIXEL_TO_CHAR_ROW (f, pix_y);
-
-  if (bounds)
-    {
-      bounds->left = CHAR_TO_PIXEL_COL (f, pix_x);
-      bounds->top = CHAR_TO_PIXEL_ROW (f, pix_y);
-      bounds->right  = bounds->left + FONT_WIDTH  (FRAME_FONT (f)) - 1;
-      bounds->bottom = bounds->top + f->output_data.w32->line_height - 1;
-    }
-
-  if (!noclip)
-    {
-      if (pix_x < 0)
-       pix_x = 0;
-      else if (pix_x > FRAME_WINDOW_WIDTH (f))
-       pix_x = FRAME_WINDOW_WIDTH (f);
-
-      if (pix_y < 0)
-       pix_y = 0;
-      else if (pix_y > f->height)
-       pix_y = f->height;
-    }
-
-  *x = pix_x;
-  *y = pix_y;
-}
-
-
-/* Given HPOS/VPOS in the current matrix of W, return corresponding
-   frame-relative pixel positions in *FRAME_X and *FRAME_Y.  If we
-   can't tell the positions because W's display is not up to date,
-   return 0.  */
-
-int
-glyph_to_pixel_coords (w, hpos, vpos, frame_x, frame_y)
-     struct window *w;
-     int hpos, vpos;
-     int *frame_x, *frame_y;
-{
-  int success_p;
-
-  xassert (hpos >= 0 && hpos < w->current_matrix->matrix_w);
-  xassert (vpos >= 0 && vpos < w->current_matrix->matrix_h);
-
-  if (display_completed)
-    {
-      struct glyph_row *row = MATRIX_ROW (w->current_matrix, vpos);
-      struct glyph *glyph = row->glyphs[TEXT_AREA];
-      struct glyph *end = glyph + min (hpos, row->used[TEXT_AREA]);
-
-      *frame_y = row->y;
-      *frame_x = row->x;
-      while (glyph < end)
-       {
-         *frame_x += glyph->pixel_width;
-         ++glyph;
-       }
-
-      success_p = 1;
-    }
-  else
-    {
-      *frame_y = *frame_x = 0;
-      success_p = 0;
-    }
-
-  *frame_y = WINDOW_TO_FRAME_PIXEL_Y (w, *frame_y);
-  *frame_x = WINDOW_TO_FRAME_PIXEL_X (w, *frame_x);
-  return success_p;
-}
-
 /* Parse a button MESSAGE. The button index is returned in PBUTTON, and
    the state in PUP. XBUTTON provides extra information for extended mouse
    button messages. Returns FALSE if unable to parse the message.  */
@@ -3011,12 +3115,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);
@@ -3072,8 +3190,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;
 }
 
@@ -3089,9 +3207,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;
@@ -3108,13 +3224,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;
@@ -3123,8 +3242,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
@@ -3135,9 +3258,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 ()
@@ -3156,103 +3276,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, 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;
-
-      frame_to_window_pixel_xy (w, &x, &y);
-
-      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.  */
-               rect->left = XINT (w->left);
-               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);
-           rect->right = XINT (w->left) + XINT (w->width);
-           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 PIXEL_TO_CHAR_COL etc. to
-        round down even for negative values.  */
-      if (gx < 0)
-       gx -= width - 1;
-      if (gy < 0)
-       gy -= height - 1;
-#if 0
-      /* This was the original code from XTmouse_position, but it seems
-        to give the position of the glyph diagonally next to the one
-        the mouse is over.  */
-      gx = (gx + width - 1) / width * width;
-      gy = (gy + height - 1) / height * height;
-#else
-      gx = gx / width * width;
-      gy = gy / height * height;
-#endif
-
-      last_mouse_glyph.left = gx;
-      last_mouse_glyph.top = gy;
-      last_mouse_glyph.right  = gx + width;
-      last_mouse_glyph.bottom = gy + height;
-    }
-}
-
 /* Return the current position of the mouse.
    *fp should be a frame which indicates which display to ask about.
 
@@ -3344,19 +3367,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;
@@ -3518,7 +3531,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
@@ -3529,7 +3542,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)
 {
@@ -3547,7 +3560,7 @@ my_set_window_pos (HWND hwnd, HWND hwndAfter,
 #endif
 }
 
-void
+static void
 my_set_focus (f, hwnd)
      struct frame * f;
      HWND hwnd;
@@ -3556,14 +3569,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;
@@ -3670,31 +3684,26 @@ w32_set_vertical_scroll_bar (w, portion, whole, position)
   struct frame *f = XFRAME (w->frame);
   struct scroll_bar *bar;
   int top, height, left, sb_left, width, sb_width;
-  int window_x, window_y, window_width, window_height;
+  int window_y, window_height;
 
   /* Get window dimensions.  */
-  window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
+  window_box (w, -1, 0, &window_y, 0, &window_height);
   top  = window_y;
-  width = FRAME_SCROLL_BAR_COLS (f) * CANON_X_UNIT (f);
+  width = WINDOW_CONFIG_SCROLL_BAR_COLS (w) * FRAME_COLUMN_WIDTH (f);
   height = window_height;
 
   /* Compute the left edge of the scroll bar area.  */
-  if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
-    left = XINT (w->left) + XINT (w->width) - FRAME_SCROLL_BAR_COLS (f);
-  else
-    left = XFASTINT (w->left);
-  left *= CANON_X_UNIT (f);
-  left += FRAME_INTERNAL_BORDER_WIDTH (f);
+  left = WINDOW_SCROLL_BAR_AREA_X (w);
 
   /* Compute the width of the scroll bar which might be less than
      the width of the area reserved for the scroll bar.  */
-  if (FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0)
-    sb_width = FRAME_SCROLL_BAR_PIXEL_WIDTH (f);
+  if (WINDOW_CONFIG_SCROLL_BAR_WIDTH (w) > 0)
+    sb_width = WINDOW_CONFIG_SCROLL_BAR_WIDTH (w);
   else
     sb_width = width;
 
   /* Compute the left edge of the scroll bar.  */
-  if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
+  if (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT (w))
     sb_left = left + width - sb_width - (width - sb_width) / 2;
   else
     sb_left = left + (width - sb_width) / 2;
@@ -4133,8 +4142,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'.
 
@@ -4150,11 +4157,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;
@@ -4174,13 +4180,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:
@@ -4209,12 +4218,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)))
@@ -4244,17 +4249,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;
 
@@ -4264,24 +4262,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;
 
@@ -4291,24 +4286,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;
 
@@ -4324,6 +4316,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))
@@ -4346,7 +4339,7 @@ w32_read_socket (sd, bufp, numchars, expected)
                  int x = LOWORD (msg.msg.lParam);
                  int y = HIWORD (msg.msg.lParam);
 
-                 window = window_from_coordinates (f, x, y, 0, 0);
+                 window = window_from_coordinates (f, x, y, 0, 0, 0, 0);
 
                  /* Window will be selected only when it is not
                     selected now and last mouse movement event was
@@ -4354,18 +4347,16 @@ w32_read_socket (sd, bufp, numchars, expected)
                     iff it is active.  */
                  if (WINDOWP(window)
                      && !EQ (window, last_window)
-                     && !EQ (window, selected_window)
-                     && numchars > 0)
+                     && !EQ (window, selected_window))
                    {
-                     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
             {
@@ -4376,29 +4367,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:
@@ -4412,13 +4390,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;
@@ -4427,35 +4402,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)
-                    && XFASTINT (XWINDOW (f->tool_bar_window)->height))
+                    && 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, 1);
+                    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),
@@ -4482,37 +4451,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:
@@ -4520,15 +4491,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;
          }
 
@@ -4536,10 +4500,8 @@ 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->output_data.w32->want_fullscreen & FULLSCREEN_WAIT)
-               f->output_data.w32->want_fullscreen &=
-                 ~(FULLSCREEN_WAIT|FULLSCREEN_BOTH);
+             if (f->want_fullscreen & FULLSCREEN_WAIT)
+               f->want_fullscreen &= ~(FULLSCREEN_WAIT|FULLSCREEN_BOTH);
            }
          check_visibility = 1;
          break;
@@ -4560,8 +4522,8 @@ w32_read_socket (sd, bufp, numchars, expected)
              int x, y;
 
              x_real_positions (f, &x, &y);
-             f->output_data.w32->left_pos = x;
-             f->output_data.w32->top_pos = y;
+             f->left_pos = x;
+             f->top_pos = y;
            }
 
          check_visibility = 1;
@@ -4606,12 +4568,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:
@@ -4619,7 +4577,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);
 
@@ -4633,15 +4591,11 @@ w32_read_socket (sd, bufp, numchars, expected)
                          when the Window is iconified, with 3000,3000
                          as the co-ords. */
                       x_real_positions (f, &x, &y);
-                      f->output_data.w32->left_pos = x;
-                      f->output_data.w32->top_pos = y;
-
-                     bufp->kind = DEICONIFY_EVENT;
-                     XSETFRAME (bufp->frame_or_window, f);
-                     bufp->arg = Qnil;
-                     bufp++;
-                     count++;
-                     numchars--;
+                      f->left_pos = x;
+                      f->top_pos = y;
+
+                     inev.kind = DEICONIFY_EVENT;
+                     XSETFRAME (inev.frame_or_window, f);
                    }
                  else if (! NILP (Vframe_list)
                           && ! NILP (XCDR (Vframe_list)))
@@ -4666,8 +4620,8 @@ w32_read_socket (sd, bufp, numchars, expected)
              height = rect.bottom - rect.top;
              width = rect.right - rect.left;
 
-             rows = PIXEL_TO_CHAR_HEIGHT (f, height);
-             columns = PIXEL_TO_CHAR_WIDTH (f, width);
+             rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, height);
+             columns = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, width);
 
              /* TODO: Clip size to the screen dimensions.  */
 
@@ -4675,17 +4629,17 @@ w32_read_socket (sd, bufp, numchars, expected)
                 not changed, the font size may have changed, so we need
                 to check the pixel dimensions as well.  */
 
-             if (columns != f->width
-                 || rows != f->height
-                 || width != f->output_data.w32->pixel_width
-                 || height != f->output_data.w32->pixel_height)
+             if (columns != FRAME_COLS (f)
+                 || rows != FRAME_LINES (f)
+                 || width != FRAME_PIXEL_WIDTH (f)
+                 || height != FRAME_PIXEL_HEIGHT (f))
                {
                  change_frame_size (f, rows, columns, 0, 1, 0);
                  SET_FRAME_GARBAGED (f);
                  cancel_mouse_face (f);
-                 f->output_data.w32->pixel_width = width;
-                 f->output_data.w32->pixel_height = height;
-                 f->output_data.w32->win_gravity = NorthWestGravity;
+                 FRAME_PIXEL_WIDTH (f) = width;
+                 FRAME_PIXEL_HEIGHT (f) = height;
+                 f->win_gravity = NorthWestGravity;
                }
            }
 
@@ -4709,42 +4663,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)
@@ -4768,16 +4698,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;
@@ -4789,15 +4710,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;
 
@@ -4806,15 +4720,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;
 
@@ -4847,29 +4754,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 (do_help
+         && !(hold_quit && hold_quit->kind != NO_EVENT))
+       {
+         Lisp_Object frame;
+
+         if (f)
+           XSETFRAME (frame, f);
+         else
+           frame = Qnil;
 
-             if (f)
+         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++;
        }
     }
 
@@ -4892,65 +4820,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;
@@ -4958,7 +4886,6 @@ w32_read_socket (sd, bufp, numchars, expected)
 }
 
 
-
 \f
 /***********************************************************************
                             Text Cursor
@@ -4966,40 +4893,30 @@ w32_read_socket (sd, bufp, numchars, expected)
 
 /* Set clipping for output in glyph row ROW.  W is the window in which
    we operate.  GC is the graphics context to set clipping in.
-   WHOLE_LINE_P non-zero means include the areas used for truncation
-   mark display and alike in the clipping rectangle.
 
    ROW may be a text row or, e.g., a mode line.  Text rows must be
    clipped to the interior of the window dedicated to text display,
    mode lines must be clipped to the whole window.  */
 
 static void
-w32_clip_to_row (w, row, hdc, whole_line_p)
+w32_clip_to_row (w, row, area, hdc)
      struct window *w;
      struct glyph_row *row;
+     int area;
      HDC hdc;
-     int whole_line_p;
 {
   struct frame *f = XFRAME (WINDOW_FRAME (w));
   RECT clip_rect;
-  int window_x, window_y, window_width, window_height;
+  int window_x, window_y, window_width;
 
-  window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
+  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;
   clip_rect.bottom = clip_rect.top + row->visible_height;
 
-  /* If clipping to the whole line, including trunc marks, extend
-     the rectangle to the left and increase its width.  */
-  if (whole_line_p)
-    {
-      clip_rect.left -= FRAME_X_LEFT_FRINGE_WIDTH (f);
-      clip_rect.right += FRAME_X_FRINGE_WIDTH (f);
-    }
-
   w32_set_clip_rectangle (hdc, &clip_rect);
 }
 
@@ -5014,37 +4931,25 @@ x_draw_hollow_cursor (w, row)
   struct frame *f = XFRAME (WINDOW_FRAME (w));
   HDC hdc;
   RECT rect;
-  int wd;
+  int 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 (CANON_X_UNIT (f), wd);
-  w->phys_cursor_width = wd;
+  /* Compute frame-relative coordinates for phys cursor.  */
+  rect.left = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
+  rect.top = get_phys_cursor_geometry (w, row, cursor_glyph, &h);
+  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, 0);
+  w32_clip_to_row (w, row, TEXT_AREA, hdc);
   FrameRect (hdc, &rect, hb);
   DeleteObject (hb);
   w32_set_clip_rectangle (hdc, NULL);
@@ -5110,7 +5015,7 @@ x_draw_bar_cursor (w, row, width, kind)
 
 
       hdc = get_frame_dc (f);
-      w32_clip_to_row (w, row, hdc, 0);
+      w32_clip_to_row (w, row, TEXT_AREA, hdc);
 
       if (kind == BAR_CURSOR)
        {
@@ -5160,27 +5065,31 @@ w32_clear_frame_area (f, x, y, width, height)
 /* RIF: Draw or clear cursor on window W.  */
 
 static void
-w32_draw_window_cursor (w, glyph_row, on, x, y, new_cursor_type, new_cursor_width)
+w32_draw_window_cursor (w, glyph_row, x, y, cursor_type, cursor_width, on_p, active_p)
      struct window *w;
      struct glyph_row *glyph_row;
-     int on, x, y;
-     int new_cursor_type, new_cursor_width;
+     int x, y;
+     int cursor_type, cursor_width;
+     int on_p, active_p;
 {
-  if (on)
+  if (on_p)
     {
       /* If the user wants to use the system caret, make sure our own
         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);
 
-         new_cursor_type = w->phys_cursor_type = NO_CURSOR;
+         cursor_type = w->phys_cursor_type = NO_CURSOR;
          w->phys_cursor_width = -1;
        }
       else
        {
-         w->phys_cursor_type = new_cursor_type;
+         w->phys_cursor_type = cursor_type;
        }
 
       w->phys_cursor_on_p = 1;
@@ -5188,8 +5097,9 @@ w32_draw_window_cursor (w, glyph_row, on, x, y, new_cursor_type, new_cursor_widt
       /* If this is the active cursor, we need to track it with the
         system caret, so third party software like screen magnifiers
         and speech synthesizers can follow the cursor.  */
-      if (active_cursor)
+      if (active_p)
        {
+         struct frame *f = XFRAME (WINDOW_FRAME (w));
          HWND hwnd = FRAME_W32_WINDOW (f);
 
          w32_system_caret_x
@@ -5210,7 +5120,15 @@ w32_draw_window_cursor (w, glyph_row, on, x, y, new_cursor_type, new_cursor_widt
          PostMessage (hwnd, WM_EMACS_TRACK_CARET, 0, 0);
        }
 
-      switch (new_cursor_type)
+      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:
          x_draw_hollow_cursor (w, glyph_row);
@@ -5221,11 +5139,11 @@ w32_draw_window_cursor (w, glyph_row, on, x, y, new_cursor_type, new_cursor_widt
          break;
 
        case BAR_CURSOR:
-         x_draw_bar_cursor (w, glyph_row, new_cursor_width, BAR_CURSOR);
+         x_draw_bar_cursor (w, glyph_row, cursor_width, BAR_CURSOR);
          break;
 
        case HBAR_CURSOR:
-         x_draw_bar_cursor (w, glyph_row, new_cursor_width, HBAR_CURSOR);
+         x_draw_bar_cursor (w, glyph_row, cursor_width, HBAR_CURSOR);
          break;
 
        case NO_CURSOR:
@@ -5247,16 +5165,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;
@@ -5276,16 +5203,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;
 }
@@ -5302,6 +5234,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)
@@ -5337,29 +5271,31 @@ x_new_font (f, fontname)
   FRAME_BASELINE_OFFSET (f) = fontp->baseline_offset;
   FRAME_FONTSET (f) = -1;
 
+  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);
+
   /* Compute the scroll bar width in character columns.  */
-  if (f->scroll_bar_pixel_width > 0)
+  if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
     {
-      int wid = FONT_WIDTH (FRAME_FONT (f));
-      f->scroll_bar_cols = (f->scroll_bar_pixel_width + wid-1) / wid;
+      int wid = FRAME_COLUMN_WIDTH (f);
+      FRAME_CONFIG_SCROLL_BAR_COLS (f)
+       = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid-1) / wid;
     }
   else
     {
-      int wid = FONT_WIDTH (FRAME_FONT (f));
-      f->scroll_bar_cols = (14 + wid - 1) / wid;
+      int wid = FRAME_COLUMN_WIDTH (f);
+      FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
     }
 
   /* Now make the frame display the given font.  */
   if (FRAME_W32_WINDOW (f) != 0)
     {
-      frame_update_line_height (f);
       if (NILP (tip_frame) || XFRAME (tip_frame) != f)
-        x_set_window_size (f, 0, f->width, f->height);
+        x_set_window_size (f, 0, FRAME_COLS (f), FRAME_LINES (f));
     }
-  else
-    /* If we are setting a new frame's font for the first time,
-       there are no faces yet, so this font's height is the line height.  */
-    f->output_data.w32->line_height = FONT_HEIGHT (FRAME_FONT (f));
 
   return build_string (fontp->full_name);
 }
@@ -5420,53 +5356,23 @@ void
 x_calc_absolute_position (f)
      struct frame *f;
 {
-  POINT pt;
-  int flags = f->output_data.w32->size_hint_flags;
-
-  pt.x = pt.y = 0;
-
-  /* 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;
-    }
-
-  {
-      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;
-
-      pt.x += (rt.right - rt.left);
-      pt.y += (rt.bottom - rt.top);
-  }
+  int flags = f->size_hint_flags;
 
   /* Treat negative positions as relative to the leftmost bottommost
      position that fits on the screen.  */
   if (flags & XNegative)
-    f->output_data.w32->left_pos = (FRAME_W32_DISPLAY_INFO (f)->width
-                             - 2 * f->output_data.w32->border_width - pt.x
-                             - PIXEL_WIDTH (f)
-                             + f->output_data.w32->left_pos);
+    f->left_pos = (FRAME_W32_DISPLAY_INFO (f)->width
+                  - FRAME_PIXEL_WIDTH (f)
+                  + f->left_pos);
 
   if (flags & YNegative)
-    f->output_data.w32->top_pos = (FRAME_W32_DISPLAY_INFO (f)->height
-                            - 2 * f->output_data.w32->border_width - pt.y
-                            - PIXEL_HEIGHT (f)
-                            + f->output_data.w32->top_pos);
+    f->top_pos = (FRAME_W32_DISPLAY_INFO (f)->height
+                 - FRAME_PIXEL_HEIGHT (f)
+                 + f->top_pos);
   /* The left_pos and top_pos
      are now relative to the top and left screen edges,
      so the flags should correspond.  */
-  f->output_data.w32->size_hint_flags &= ~ (XNegative | YNegative);
+  f->size_hint_flags &= ~ (XNegative | YNegative);
 }
 
 /* CHANGE_GRAVITY is 1 when calling from Fset_frame_position,
@@ -5485,22 +5391,22 @@ x_set_offset (f, xoff, yoff, change_gravity)
 
   if (change_gravity > 0)
     {
-      f->output_data.w32->top_pos = yoff;
-      f->output_data.w32->left_pos = xoff;
-      f->output_data.w32->size_hint_flags &= ~ (XNegative | YNegative);
+      f->top_pos = yoff;
+      f->left_pos = xoff;
+      f->size_hint_flags &= ~ (XNegative | YNegative);
       if (xoff < 0)
-       f->output_data.w32->size_hint_flags |= XNegative;
+       f->size_hint_flags |= XNegative;
       if (yoff < 0)
-       f->output_data.w32->size_hint_flags |= YNegative;
-      f->output_data.w32->win_gravity = NorthWestGravity;
+       f->size_hint_flags |= YNegative;
+      f->win_gravity = NorthWestGravity;
     }
   x_calc_absolute_position (f);
 
   BLOCK_INPUT;
   x_wm_set_size_hint (f, (long) 0, 0);
 
-  modified_left = f->output_data.w32->left_pos;
-  modified_top = f->output_data.w32->top_pos;
+  modified_left = f->left_pos;
+  modified_top = f->top_pos;
 
   my_set_window_pos (FRAME_W32_WINDOW (f),
                     NULL,
@@ -5517,108 +5423,28 @@ static void
 x_check_fullscreen (f)
      struct frame *f;
 {
-  if (f->output_data.w32->want_fullscreen & FULLSCREEN_BOTH)
+  if (f->want_fullscreen & FULLSCREEN_BOTH)
     {
       int width, height, ign;
 
-      x_real_positions (f, &f->output_data.w32->left_pos,
-                        &f->output_data.w32->top_pos);
+      x_real_positions (f, &f->left_pos, &f->top_pos);
 
       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. */
-      if (f->width != width || f->height != height)
+         when setting WM manager hints.  */
+      if (FRAME_COLS (f) != width || FRAME_LINES (f) != height)
         {
           change_frame_size (f, height, width, 0, 1, 0);
           SET_FRAME_GARBAGED (f);
           cancel_mouse_face (f);
 
           /* Wait for the change of frame size to occur */
-          f->output_data.w32->want_fullscreen |= FULLSCREEN_WAIT;
+          f->want_fullscreen |= FULLSCREEN_WAIT;
         }
     }
 }
 
-/* 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->output_data.w32->want_fullscreen & FULLSCREEN_MOVE_WAIT)
-  {
-    int expect_top = f->output_data.w32->top_pos;
-    int expect_left = f->output_data.w32->left_pos;
-
-    if (f->output_data.w32->want_fullscreen & FULLSCREEN_HEIGHT)
-      expect_top = 0;
-    if (f->output_data.w32->want_fullscreen & FULLSCREEN_WIDTH)
-      expect_left = 0;
-
-    if (expect_top != f->output_data.w32->top_pos
-        || expect_left != f->output_data.w32->left_pos)
-      x_set_offset (f, expect_left, expect_top, 1);
-
-    /* Just do this once */
-    f->output_data.w32->want_fullscreen &= ~FULLSCREEN_MOVE_WAIT;
-  }
-}
-
-
-/* Calculate fullscreen size.  Return in *TOP_POS and *LEFT_POS the
-   wanted positions of the WM window (not emacs window).
-   Return in *WIDTH and *HEIGHT the wanted width and height of Emacs
-   window (FRAME_X_WINDOW).
- */
-void
-x_fullscreen_adjust (f, width, height, top_pos, left_pos)
-     struct frame *f;
-     int *width;
-     int *height;
-     int *top_pos;
-     int *left_pos;
-{
-  int newwidth = f->width, newheight = f->height;
-
-  *top_pos = f->output_data.w32->top_pos;
-  *left_pos = f->output_data.w32->left_pos;
-
-  if (f->output_data.w32->want_fullscreen & FULLSCREEN_HEIGHT)
-    {
-      int ph;
-
-      ph = FRAME_X_DISPLAY_INFO (f)->height;
-      newheight = PIXEL_TO_CHAR_HEIGHT (f, ph);
-      ph = CHAR_TO_PIXEL_HEIGHT (f, newheight)
-        - f->output_data.w32->y_pixels_diff;
-      newheight = PIXEL_TO_CHAR_HEIGHT (f, ph);
-      *top_pos = 0;
-    }
-
-  if (f->output_data.w32->want_fullscreen & FULLSCREEN_WIDTH)
-    {
-      int pw;
-
-      pw = FRAME_X_DISPLAY_INFO (f)->width;
-      newwidth = PIXEL_TO_CHAR_WIDTH (f, pw);
-      pw = CHAR_TO_PIXEL_WIDTH (f, newwidth)
-        - f->output_data.w32->x_pixels_diff;
-      newwidth = PIXEL_TO_CHAR_WIDTH (f, pw);
-      *left_pos = 0;
-    }
-
-  *width = newwidth;
-  *height = newheight;
-}
-
-
 /* 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.
@@ -5635,17 +5461,15 @@ x_set_window_size (f, change_gravity, cols, rows)
   BLOCK_INPUT;
 
   check_frame_size (f, &rows, &cols);
-  f->output_data.w32->vertical_scroll_bar_extra
-    = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f)
-       ? 0
-       : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.w32->font)));
+  f->scroll_bar_actual_width
+    = FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f);
 
   compute_fringe_widths (f, 0);
 
-  pixelwidth = CHAR_TO_PIXEL_WIDTH (f, cols);
-  pixelheight = CHAR_TO_PIXEL_HEIGHT (f, rows);
+  pixelwidth = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, cols);
+  pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows);
 
-  f->output_data.w32->win_gravity = NorthWestGravity;
+  f->win_gravity = NorthWestGravity;
   x_wm_set_size_hint (f, (long) 0, 0);
 
   {
@@ -5680,8 +5504,8 @@ x_set_window_size (f, change_gravity, cols, rows)
      We pass 1 for DELAY since we can't run Lisp code inside of
      a BLOCK_INPUT.  */
   change_frame_size (f, rows, cols, 0, 1, 0);
-  PIXEL_WIDTH (f) = pixelwidth;
-  PIXEL_HEIGHT (f) = pixelheight;
+  FRAME_PIXEL_WIDTH (f) = pixelwidth;
+  FRAME_PIXEL_HEIGHT (f) = pixelheight;
 
   /* We've set {FRAME,PIXEL}_{WIDTH,HEIGHT} to the values we hope to
      receive in the ConfigureNotify event; if we get what we asked
@@ -5712,14 +5536,14 @@ x_set_mouse_position (f, x, y)
 {
   int pix_x, pix_y;
 
-  pix_x = CHAR_TO_PIXEL_COL (f, x) + FONT_WIDTH  (f->output_data.w32->font) / 2;
-  pix_y = CHAR_TO_PIXEL_ROW (f, y) + f->output_data.w32->line_height / 2;
+  pix_x = FRAME_COL_TO_PIXEL_X (f, x) + FRAME_COLUMN_WIDTH (f) / 2;
+  pix_y = FRAME_LINE_TO_PIXEL_Y (f, y) + FRAME_LINE_HEIGHT (f) / 2;
 
   if (pix_x < 0) pix_x = 0;
-  if (pix_x > PIXEL_WIDTH (f)) pix_x = PIXEL_WIDTH (f);
+  if (pix_x > FRAME_PIXEL_WIDTH (f)) pix_x = FRAME_PIXEL_WIDTH (f);
 
   if (pix_y < 0) pix_y = 0;
-  if (pix_y > PIXEL_HEIGHT (f)) pix_y = PIXEL_HEIGHT (f);
+  if (pix_y > FRAME_PIXEL_HEIGHT (f)) pix_y = FRAME_PIXEL_HEIGHT (f);
 
   x_set_mouse_pixel_position (f, pix_x, pix_y);
 }
@@ -5887,7 +5711,7 @@ 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->output_data.w32->left_pos, f->output_data.w32->top_pos, 0);
+       x_set_offset (f, f->left_pos, f->top_pos, 0);
 
       f->output_data.w32->asked_for_visible = 1;
 
@@ -6075,15 +5899,16 @@ x_wm_set_size_hint (f, flags, user_position)
 
   enter_crit ();
 
-  SetWindowLong (window, WND_FONTWIDTH_INDEX, FONT_WIDTH (f->output_data.w32->font));
-  SetWindowLong (window, WND_LINEHEIGHT_INDEX, f->output_data.w32->line_height);
-  SetWindowLong (window, WND_BORDER_INDEX, f->output_data.w32->internal_border_width);
-  SetWindowLong (window, WND_SCROLLBAR_INDEX, f->output_data.w32->vertical_scroll_bar_extra);
+  SetWindowLong (window, WND_FONTWIDTH_INDEX, FRAME_COLUMN_WIDTH (f));
+  SetWindowLong (window, WND_LINEHEIGHT_INDEX, FRAME_LINE_HEIGHT (f));
+  SetWindowLong (window, WND_BORDER_INDEX, FRAME_INTERNAL_BORDER_WIDTH (f));
+  SetWindowLong (window, WND_SCROLLBAR_INDEX, f->scroll_bar_actual_width);
 
   leave_crit ();
 }
 
 /* Window manager things */
+void
 x_wm_set_icon_position (f, icon_x, icon_y)
      struct frame *f;
      int icon_x, icon_y;
@@ -6368,32 +6193,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
@@ -6461,13 +6261,7 @@ 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.  */
@@ -6478,8 +6272,11 @@ void
 x_flush (struct frame * f)
 { /* Nothing to do */ }
 
+extern frame_parm_handler w32_frame_parm_handlers[];
+
 static struct redisplay_interface w32_redisplay_interface =
 {
+  w32_frame_parm_handlers,
   x_produce_glyphs,
   x_write_glyphs,
   x_insert_glyphs,
@@ -6495,6 +6292,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 */
@@ -6543,6 +6342,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;
 
@@ -6587,6 +6392,8 @@ w32_initialize ()
   /* Dynamically link to optional system components. */
   {
     HANDLE user_lib = LoadLibrary ("user32.dll");
+    UINT smoothing_type;
+    BOOL smoothing_enabled;
 
 #define LOAD_PROC(fn) pfn##fn = (void *) GetProcAddress (user_lib, #fn)
 
@@ -6607,6 +6414,28 @@ w32_initialize ()
        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;
   }
 }
 
@@ -6623,9 +6452,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,
@@ -6676,11 +6505,19 @@ 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.
+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_LISP ("x-toolkit-scroll-bars", &Vx_toolkit_scroll_bars,
               doc: /* If not nil, Emacs uses toolkit scroll bars.  */);
@@ -6689,3 +6526,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) */