(Vw32_pass_optional_keys_to_system): Variable removed.
[bpt/emacs.git] / src / w32fns.c
index c89a770..c11c3d5 100644 (file)
@@ -1,5 +1,5 @@
-/* Functions for the Win32 window system.
-   Copyright (C) 1989, 1992, 1993, 1994, 1995 Free Software Foundation.
+/* Graphical user interface functions for the Microsoft W32 API.
+   Copyright (C) 1989, 92, 93, 94, 95, 1996 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -20,11 +20,16 @@ Boston, MA 02111-1307, USA.  */
 
 /* Added by Kevin Gallo */
 
-#include <signal.h>
 #include <config.h>
+
+#include <signal.h>
 #include <stdio.h>
+#include <limits.h>
+#include <errno.h>
 
 #include "lisp.h"
+#include "charset.h"
+#include "fontset.h"
 #include "w32term.h"
 #include "frame.h"
 #include "window.h"
@@ -33,36 +38,73 @@ Boston, MA 02111-1307, USA.  */
 #include "keyboard.h"
 #include "blockinput.h"
 #include "paths.h"
-#include "ntheap.h"
+#include "w32heap.h"
 #include "termhooks.h"
+#include "coding.h"
 
 #include <commdlg.h>
+#include <shellapi.h>
 
 extern void abort ();
 extern void free_frame_menubar ();
 extern struct scroll_bar *x_window_to_scroll_bar ();
 extern int quit_char;
 
+extern char *lispy_function_keys[];
+
 /* The colormap for converting color names to RGB values */
-Lisp_Object Vwin32_color_map;
+Lisp_Object Vw32_color_map;
 
 /* Non nil if alt key presses are passed on to Windows.  */
-Lisp_Object Vwin32_pass_alt_to_system;
+Lisp_Object Vw32_pass_alt_to_system;
+
+/* Non nil if alt key is translated to meta_modifier, nil if it is translated
+   to alt_modifier.  */
+Lisp_Object Vw32_alt_is_meta;
+
+/* Non nil if left window key events are passed on to Windows (this only
+   affects whether "tapping" the key opens the Start menu).  */
+Lisp_Object Vw32_pass_lwindow_to_system;
+
+/* Non nil if right window key events are passed on to Windows (this
+   only affects whether "tapping" the key opens the Start menu).  */
+Lisp_Object Vw32_pass_rwindow_to_system;
 
-/* Non nil if left window, right window, and application key events
-   are passed on to Windows.  */
-Lisp_Object Vwin32_pass_optional_keys_to_system;
+/* Modifier associated with the left "Windows" key, or nil to act as a
+   normal key.  */
+Lisp_Object Vw32_lwindow_modifier;
+
+/* Modifier associated with the right "Windows" key, or nil to act as a
+   normal key.  */
+Lisp_Object Vw32_rwindow_modifier;
+
+/* Modifier associated with the "Apps" key, or nil to act as a normal
+   key.  */
+Lisp_Object Vw32_apps_modifier;
+
+/* Value is nil if Num Lock acts as a function key.  */
+Lisp_Object Vw32_enable_num_lock;
+
+/* Value is nil if Caps Lock acts as a function key.  */
+Lisp_Object Vw32_enable_caps_lock;
+
+/* Modifier associated with Scroll Lock, or nil to act as a normal key.  */
+Lisp_Object Vw32_scroll_lock_modifier;
 
 /* Switch to control whether we inhibit requests for italicised fonts (which
    are synthesized, look ugly, and are trashed by cursor movement under NT). */
-Lisp_Object Vwin32_enable_italics;
+Lisp_Object Vw32_enable_italics;
 
 /* Enable palette management. */
-Lisp_Object Vwin32_enable_palette;
+Lisp_Object Vw32_enable_palette;
 
 /* Control how close left/right button down events must be to
    be converted to a middle button down event. */
-Lisp_Object Vwin32_mouse_button_tolerance;
+Lisp_Object Vw32_mouse_button_tolerance;
+
+/* Minimum interval between mouse movement (and scroll bar drag)
+   events that are passed on to the event loop. */
+Lisp_Object Vw32_mouse_move_interval;
 
 /* The name we're using in resource queries.  */
 Lisp_Object Vx_resource_name;
@@ -79,9 +121,18 @@ Lisp_Object Vx_sensitive_text_pointer_shape;
 /* Color of chars displayed in cursor box.  */
 Lisp_Object Vx_cursor_fore_pixel;
 
+/* Nonzero if using Windows.  */
+static int w32_in_use;
+
 /* Search path for bitmap files.  */
 Lisp_Object Vx_bitmap_file_path;
 
+/* Regexp matching a font name whose width is the same as `PIXEL_SIZE'.  */
+Lisp_Object Vx_pixel_size_width_font_regexp;
+
+/* A flag to control how to display unibyte 8-bit character.  */
+int unibyte_display_via_language_environment;
+
 /* Evaluate this expression to rebuild the section of syms_of_w32fns
    that initializes and staticpros the symbols declared below.  Note
    that Emacs 18 has a bug that keeps C-x C-e from being able to
@@ -126,7 +177,6 @@ Lisp_Object Qborder_width;
 Lisp_Object Qbox;
 Lisp_Object Qcursor_color;
 Lisp_Object Qcursor_type;
-Lisp_Object Qfont;
 Lisp_Object Qforeground_color;
 Lisp_Object Qgeometry;
 Lisp_Object Qicon_left;
@@ -135,6 +185,7 @@ Lisp_Object Qicon_type;
 Lisp_Object Qicon_name;
 Lisp_Object Qinternal_border_width;
 Lisp_Object Qleft;
+Lisp_Object Qright;
 Lisp_Object Qmouse_color;
 Lisp_Object Qnone;
 Lisp_Object Qparent_id;
@@ -157,26 +208,52 @@ Lisp_Object Qdisplay;
 #define RMOUSE 4
 
 static int button_state = 0;
-static Win32Msg saved_mouse_msg;
-static unsigned timer_id;      /* non-zero when timer is active */
+static W32Msg saved_mouse_button_msg;
+static unsigned mouse_button_timer;    /* non-zero when timer is active */
+static W32Msg saved_mouse_move_msg;
+static unsigned mouse_move_timer;
+
+/* W95 mousewheel handler */
+unsigned int msh_mousewheel = 0;       
+
+#define MOUSE_BUTTON_ID        1
+#define MOUSE_MOVE_ID  2
 
 /* The below are defined in frame.c.  */
 extern Lisp_Object Qheight, Qminibuffer, Qname, Qonly, Qwidth;
-extern Lisp_Object Qunsplittable, Qmenu_bar_lines;
+extern Lisp_Object Qunsplittable, Qmenu_bar_lines, Qbuffer_predicate, Qtitle;
 
 extern Lisp_Object Vwindow_system_version;
 
+Lisp_Object Qface_set_after_frame_default;
+
 extern Lisp_Object last_mouse_scroll_bar;
 extern int last_mouse_scroll_bar_pos;
 
-/* From win32term.c. */
-extern Lisp_Object Vwin32_num_mouse_buttons;
-
-Time last_mouse_movement_time;
+/* From w32term.c. */
+extern Lisp_Object Vw32_num_mouse_buttons;
+extern Lisp_Object Vw32_recognize_altgr;
 
 \f
+/* Error if we are not connected to MS-Windows.  */
+void
+check_w32 ()
+{
+  if (! w32_in_use)
+    error ("MS-Windows not in use or not initialized");
+}
+
+/* Nonzero if we can use mouse menus.
+   You should not call this unless HAVE_MENUS is defined.  */
+  
+int
+have_menus_p ()
+{
+  return w32_in_use;
+}
+
 /* Extract a frame as a FRAME_PTR, defaulting to the selected frame
-   and checking validity for Win32.  */
+   and checking validity for W32.  */
 
 FRAME_PTR
 check_x_frame (frame)
@@ -191,25 +268,25 @@ check_x_frame (frame)
       CHECK_LIVE_FRAME (frame, 0);
       f = XFRAME (frame);
     }
-  if (! FRAME_WIN32_P (f))
-    error ("non-win32 frame used");
+  if (! FRAME_W32_P (f))
+    error ("non-w32 frame used");
   return f;
 }
 
 /* Let the user specify an display with a frame.
-   nil stands for the selected frame--or, if that is not a win32 frame,
+   nil stands for the selected frame--or, if that is not a w32 frame,
    the first display on the list.  */
 
-static struct win32_display_info *
+static struct w32_display_info *
 check_x_display_info (frame)
      Lisp_Object frame;
 {
   if (NILP (frame))
     {
-      if (FRAME_WIN32_P (selected_frame))
-       return FRAME_WIN32_DISPLAY_INFO (selected_frame);
+      if (FRAME_W32_P (selected_frame))
+       return FRAME_W32_DISPLAY_INFO (selected_frame);
       else
-       return &one_win32_display_info;
+       return &one_w32_display_info;
     }
   else if (STRINGP (frame))
     return x_display_info_for_name (frame);
@@ -219,20 +296,20 @@ check_x_display_info (frame)
 
       CHECK_LIVE_FRAME (frame, 0);
       f = XFRAME (frame);
-      if (! FRAME_WIN32_P (f))
-       error ("non-win32 frame used");
-      return FRAME_WIN32_DISPLAY_INFO (f);
+      if (! FRAME_W32_P (f))
+       error ("non-w32 frame used");
+      return FRAME_W32_DISPLAY_INFO (f);
     }
 }
 \f
-/* Return the Emacs frame-object corresponding to an win32 window.
+/* Return the Emacs frame-object corresponding to an w32 window.
    It could be the frame's main window or an icon window.  */
 
 /* This function can be called during GC, so use GC_xxx type test macros.  */
 
 struct frame *
 x_window_to_frame (dpyinfo, wdesc)
-     struct win32_display_info *dpyinfo;
+     struct w32_display_info *dpyinfo;
      HWND wdesc;
 {
   Lisp_Object tail, frame;
@@ -245,9 +322,9 @@ x_window_to_frame (dpyinfo, wdesc)
         continue;
       f = XFRAME (frame);
       if (f->output_data.nothing == 1 
-         || FRAME_WIN32_DISPLAY_INFO (f) != dpyinfo)
+         || FRAME_W32_DISPLAY_INFO (f) != dpyinfo)
        continue;
-      if (FRAME_WIN32_WINDOW (f) == wdesc)
+      if (FRAME_W32_WINDOW (f) == wdesc)
         return f;
     }
   return 0;
@@ -274,7 +351,7 @@ x_bitmap_height (f, id)
      FRAME_PTR f;
      int id;
 {
-  return FRAME_WIN32_DISPLAY_INFO (f)->bitmaps[id - 1].height;
+  return FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].height;
 }
 
 int
@@ -282,7 +359,7 @@ x_bitmap_width (f, id)
      FRAME_PTR f;
      int id;
 {
-  return FRAME_WIN32_DISPLAY_INFO (f)->bitmaps[id - 1].width;
+  return FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].width;
 }
 
 int
@@ -290,7 +367,7 @@ x_bitmap_pixmap (f, id)
      FRAME_PTR f;
      int id;
 {
-  return (int) FRAME_WIN32_DISPLAY_INFO (f)->bitmaps[id - 1].pixmap;
+  return (int) FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].pixmap;
 }
 
 
@@ -300,14 +377,14 @@ static int
 x_allocate_bitmap_record (f)
      FRAME_PTR f;
 {
-  struct win32_display_info *dpyinfo = FRAME_WIN32_DISPLAY_INFO (f);
+  struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
   int i;
 
   if (dpyinfo->bitmaps == NULL)
     {
       dpyinfo->bitmaps_size = 10;
       dpyinfo->bitmaps
-       = (struct win32_bitmap_record *) xmalloc (dpyinfo->bitmaps_size * sizeof (struct win32_bitmap_record));
+       = (struct w32_bitmap_record *) xmalloc (dpyinfo->bitmaps_size * sizeof (struct w32_bitmap_record));
       dpyinfo->bitmaps_last = 1;
       return 1;
     }
@@ -321,8 +398,8 @@ x_allocate_bitmap_record (f)
 
   dpyinfo->bitmaps_size *= 2;
   dpyinfo->bitmaps
-    = (struct win32_bitmap_record *) xrealloc (dpyinfo->bitmaps,
-                                          dpyinfo->bitmaps_size * sizeof (struct win32_bitmap_record));
+    = (struct w32_bitmap_record *) xrealloc (dpyinfo->bitmaps,
+                                          dpyinfo->bitmaps_size * sizeof (struct w32_bitmap_record));
   return ++dpyinfo->bitmaps_last;
 }
 
@@ -333,7 +410,7 @@ x_reference_bitmap (f, id)
      FRAME_PTR f;
      int id;
 {
-  ++FRAME_WIN32_DISPLAY_INFO (f)->bitmaps[id - 1].refcount;
+  ++FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].refcount;
 }
 
 /* Create a bitmap for frame F from a HEIGHT x WIDTH array of bits at BITS.  */
@@ -344,13 +421,13 @@ x_create_bitmap_from_data (f, bits, width, height)
      char *bits;
      unsigned int width, height;
 {
-  struct win32_display_info *dpyinfo = FRAME_WIN32_DISPLAY_INFO (f);
+  struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
   Pixmap bitmap;
   int id;
 
   bitmap = CreateBitmap (width, height,
-                        FRAME_WIN32_DISPLAY_INFO (XFRAME (frame))->n_planes,
-                        FRAME_WIN32_DISPLAY_INFO (XFRAME (frame))->n_cbits,
+                        FRAME_W32_DISPLAY_INFO (XFRAME (frame))->n_planes,
+                        FRAME_W32_DISPLAY_INFO (XFRAME (frame))->n_cbits,
                         bits);
 
   if (! bitmap)
@@ -377,7 +454,7 @@ x_create_bitmap_from_file (f, file)
 {
   return -1;
 #if 0
-  struct win32_display_info *dpyinfo = FRAME_WIN32_DISPLAY_INFO (f);
+  struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
   unsigned int width, height;
   Pixmap bitmap;
   int xhot, yhot, result, id;
@@ -402,6 +479,9 @@ x_create_bitmap_from_file (f, file)
   fd = openp (Vx_bitmap_file_path, file, "", &found, 0);
   if (fd < 0)
     return -1;
+  /* LoadLibraryEx won't handle special files handled by Emacs handler.  */
+  if (fd == 0)
+    return -1;
   close (fd);
 
   filename = (char *) XSTRING (found)->data;
@@ -412,7 +492,7 @@ x_create_bitmap_from_file (f, file)
       return -1;
 
   
-  result = XReadBitmapFile (FRAME_WIN32_DISPLAY (f), FRAME_WIN32_WINDOW (f),
+  result = XReadBitmapFile (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
                            filename, &width, &height, &bitmap, &xhot, &yhot);
   if (result != BitmapSuccess)
     return -1;
@@ -437,7 +517,7 @@ x_destroy_bitmap (f, id)
      FRAME_PTR f;
      int id;
 {
-  struct win32_display_info *dpyinfo = FRAME_WIN32_DISPLAY_INFO (f);
+  struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
 
   if (id > 0)
     {
@@ -460,7 +540,7 @@ x_destroy_bitmap (f, id)
 
 static void
 x_destroy_all_bitmaps (dpyinfo)
-     struct win32_display_info *dpyinfo;
+     struct w32_display_info *dpyinfo;
 {
   int i;
   for (i = 0; i < dpyinfo->bitmaps_last; i++)
@@ -473,7 +553,7 @@ x_destroy_all_bitmaps (dpyinfo)
   dpyinfo->bitmaps_last = 0;
 }
 \f
-/* Connect the frame-parameter names for Win32 frames
+/* Connect the frame-parameter names for W32 frames
    to the ways of passing the parameter values to the window system.
 
    The name of a parameter, as a Lisp symbol,
@@ -524,33 +604,35 @@ void x_set_vertical_scroll_bars ();
 void x_set_visibility ();
 void x_set_menu_bar_lines ();
 void x_set_scroll_bar_width ();
+void x_set_title ();
 void x_set_unsplittable ();
 
 static struct x_frame_parm_table x_frame_parms[] =
 {
-  "foreground-color", x_set_foreground_color,
+  "auto-raise", x_set_autoraise,
+  "auto-lower", x_set_autolower,
   "background-color", x_set_background_color,
-  "mouse-color", x_set_mouse_color,
-  "cursor-color", x_set_cursor_color,
   "border-color", x_set_border_color,
+  "border-width", x_set_border_width,
+  "cursor-color", x_set_cursor_color,
   "cursor-type", x_set_cursor_type,
-  "icon-type", x_set_icon_type,
-  "icon-name", x_set_icon_name,
   "font", x_set_font,
-  "border-width", x_set_border_width,
+  "foreground-color", x_set_foreground_color,
+  "icon-name", x_set_icon_name,
+  "icon-type", x_set_icon_type,
   "internal-border-width", x_set_internal_border_width,
-  "name", x_explicitly_set_name,
-  "auto-raise", x_set_autoraise,
-  "auto-lower", x_set_autolower,
-  "vertical-scroll-bars", x_set_vertical_scroll_bars,
-  "visibility", x_set_visibility,
   "menu-bar-lines", x_set_menu_bar_lines,
+  "mouse-color", x_set_mouse_color,
+  "name", x_explicitly_set_name,
   "scroll-bar-width", x_set_scroll_bar_width,
+  "title", x_set_title,
   "unsplittable", x_set_unsplittable,
+  "vertical-scroll-bars", x_set_vertical_scroll_bars,
+  "visibility", x_set_visibility,
 };
 
 /* Attach the `x-frame-parameter' properties to
-   the Lisp symbol names of parameters relevant to Win32.  */
+   the Lisp symbol names of parameters relevant to W32.  */
 
 init_x_parm_symbols ()
 {
@@ -575,7 +657,7 @@ x_set_frame_parameters (f, alist)
   /* If both of these parameters are present, it's more efficient to
      set them both at once.  So we wait until we've looked at the
      entire list before we set them.  */
-  Lisp_Object width, height;
+  int width, height;
 
   /* Same here.  */
   Lisp_Object left, top;
@@ -610,9 +692,13 @@ x_set_frame_parameters (f, alist)
       i++;
     }
 
-  width = height = top = left = Qunbound;
+  top = left = Qunbound;
   icon_left = icon_top = Qunbound;
 
+  /* Provide default values for HEIGHT and WIDTH.  */
+  width = FRAME_WIDTH (f);
+  height = FRAME_HEIGHT (f);
+
   /* Now process them in reverse of specified order.  */
   for (i--; i >= 0; i--)
     {
@@ -621,10 +707,10 @@ x_set_frame_parameters (f, alist)
       prop = parms[i];
       val = values[i];
 
-      if (EQ (prop, Qwidth))
-       width = val;
-      else if (EQ (prop, Qheight))
-       height = val;
+      if (EQ (prop, Qwidth) && NUMBERP (val))
+       width = XFASTINT (val);
+      else if (EQ (prop, Qheight) && NUMBERP (val))
+       height = XFASTINT (val);
       else if (EQ (prop, Qtop))
        top = val;
       else if (EQ (prop, Qleft))
@@ -651,18 +737,18 @@ x_set_frame_parameters (f, alist)
   if (EQ (left, Qunbound))
     {
       left_no_change = 1;
-      if (f->output_data.win32->left_pos < 0)
-       left = Fcons (Qplus, Fcons (make_number (f->output_data.win32->left_pos), Qnil));
+      if (f->output_data.w32->left_pos < 0)
+       left = Fcons (Qplus, Fcons (make_number (f->output_data.w32->left_pos), Qnil));
       else
-       XSETINT (left, f->output_data.win32->left_pos);
+       XSETINT (left, f->output_data.w32->left_pos);
     }
   if (EQ (top, Qunbound))
     {
       top_no_change = 1;
-      if (f->output_data.win32->top_pos < 0)
-       top = Fcons (Qplus, Fcons (make_number (f->output_data.win32->top_pos), Qnil));
+      if (f->output_data.w32->top_pos < 0)
+       top = Fcons (Qplus, Fcons (make_number (f->output_data.w32->top_pos), Qnil));
       else
-       XSETINT (top, f->output_data.win32->top_pos);
+       XSETINT (top, f->output_data.w32->top_pos);
     }
 
   /* If one of the icon positions was not set, preserve or default it.  */
@@ -681,12 +767,6 @@ x_set_frame_parameters (f, alist)
        XSETINT (icon_top, 0);
     }
 
-  /* Don't die if just one of these was set.  */
-  if (EQ (width, Qunbound))
-    XSETINT (width, FRAME_WIDTH (f));
-  if (EQ (height, Qunbound))
-    XSETINT (height, FRAME_HEIGHT (f));
-
   /* Don't set these parameters unless they've been explicitly
      specified.  The window might be mapped or resized while we're in
      this function, and we don't want to override that unless the lisp
@@ -702,34 +782,34 @@ x_set_frame_parameters (f, alist)
 
     XSETFRAME (frame, f);
 
-    if ((NUMBERP (width) && XINT (width) != FRAME_WIDTH (f))
-       || (NUMBERP (height) && XINT (height) != FRAME_HEIGHT (f)))
-      Fset_frame_size (frame, width, height);
+    if (XINT (width) != FRAME_WIDTH (f)
+       || XINT (height) != FRAME_HEIGHT (f))
+      Fset_frame_size (frame, make_number (width), make_number (height));
 
     if ((!NILP (left) || !NILP (top))
        && ! (left_no_change && top_no_change)
-       && ! (NUMBERP (left) && XINT (left) == f->output_data.win32->left_pos
-             && NUMBERP (top) && XINT (top) == f->output_data.win32->top_pos))
+       && ! (NUMBERP (left) && XINT (left) == f->output_data.w32->left_pos
+             && NUMBERP (top) && XINT (top) == f->output_data.w32->top_pos))
       {
        int leftpos = 0;
        int toppos = 0;
 
        /* Record the signs.  */
-       f->output_data.win32->size_hint_flags &= ~ (XNegative | YNegative);
+       f->output_data.w32->size_hint_flags &= ~ (XNegative | YNegative);
        if (EQ (left, Qminus))
-         f->output_data.win32->size_hint_flags |= XNegative;
+         f->output_data.w32->size_hint_flags |= XNegative;
        else if (INTEGERP (left))
          {
            leftpos = XINT (left);
            if (leftpos < 0)
-             f->output_data.win32->size_hint_flags |= XNegative;
+             f->output_data.w32->size_hint_flags |= XNegative;
          }
        else if (CONSP (left) && EQ (XCONS (left)->car, Qminus)
                 && CONSP (XCONS (left)->cdr)
                 && INTEGERP (XCONS (XCONS (left)->cdr)->car))
          {
            leftpos = - XINT (XCONS (XCONS (left)->cdr)->car);
-           f->output_data.win32->size_hint_flags |= XNegative;
+           f->output_data.w32->size_hint_flags |= XNegative;
          }
        else if (CONSP (left) && EQ (XCONS (left)->car, Qplus)
                 && CONSP (XCONS (left)->cdr)
@@ -739,19 +819,19 @@ x_set_frame_parameters (f, alist)
          }
 
        if (EQ (top, Qminus))
-         f->output_data.win32->size_hint_flags |= YNegative;
+         f->output_data.w32->size_hint_flags |= YNegative;
        else if (INTEGERP (top))
          {
            toppos = XINT (top);
            if (toppos < 0)
-             f->output_data.win32->size_hint_flags |= YNegative;
+             f->output_data.w32->size_hint_flags |= YNegative;
          }
        else if (CONSP (top) && EQ (XCONS (top)->car, Qminus)
                 && CONSP (XCONS (top)->cdr)
                 && INTEGERP (XCONS (XCONS (top)->cdr)->car))
          {
            toppos = - XINT (XCONS (XCONS (top)->cdr)->car);
-           f->output_data.win32->size_hint_flags |= YNegative;
+           f->output_data.w32->size_hint_flags |= YNegative;
          }
        else if (CONSP (top) && EQ (XCONS (top)->car, Qplus)
                 && CONSP (XCONS (top)->cdr)
@@ -762,10 +842,10 @@ x_set_frame_parameters (f, alist)
 
 
        /* Store the numeric value of the position.  */
-       f->output_data.win32->top_pos = toppos;
-       f->output_data.win32->left_pos = leftpos;
+       f->output_data.w32->top_pos = toppos;
+       f->output_data.w32->left_pos = leftpos;
 
-       f->output_data.win32->win_gravity = NorthWestGravity;
+       f->output_data.w32->win_gravity = NorthWestGravity;
 
        /* Actually set that position, and convert to absolute.  */
        x_set_offset (f, leftpos, toppos, -1);
@@ -791,14 +871,14 @@ x_real_positions (f, xptr, yptr)
   {
       RECT rect;
       
-      GetClientRect(FRAME_WIN32_WINDOW(f), &rect);
-      AdjustWindowRect(&rect, f->output_data.win32->dwStyle, FRAME_EXTERNAL_MENU_BAR(f));
+      GetClientRect(FRAME_W32_WINDOW(f), &rect);
+      AdjustWindowRect(&rect, f->output_data.w32->dwStyle, FRAME_EXTERNAL_MENU_BAR(f));
       
       pt.x = rect.left;
       pt.y = rect.top;
   }
 
-  ClientToScreen (FRAME_WIN32_WINDOW(f), &pt);
+  ClientToScreen (FRAME_W32_WINDOW(f), &pt);
 
   *xptr = pt.x;
   *yptr = pt.y;
@@ -806,7 +886,7 @@ x_real_positions (f, xptr, yptr)
 
 /* Insert a description of internally-recorded parameters of frame X
    into the parameter alist *ALISTPTR that is to be given to the user.
-   Only parameters that are specific to Win32
+   Only parameters that are specific to W32
    and whose values are not correctly recorded in the frame's
    param_alist need to be considered here.  */
 
@@ -819,23 +899,23 @@ x_report_frame_params (f, alistptr)
 
   /* Represent negative positions (off the top or left screen edge)
      in a way that Fmodify_frame_parameters will understand correctly.  */
-  XSETINT (tem, f->output_data.win32->left_pos);
-  if (f->output_data.win32->left_pos >= 0)
+  XSETINT (tem, f->output_data.w32->left_pos);
+  if (f->output_data.w32->left_pos >= 0)
     store_in_alist (alistptr, Qleft, tem);
   else
     store_in_alist (alistptr, Qleft, Fcons (Qplus, Fcons (tem, Qnil)));
 
-  XSETINT (tem, f->output_data.win32->top_pos);
-  if (f->output_data.win32->top_pos >= 0)
+  XSETINT (tem, f->output_data.w32->top_pos);
+  if (f->output_data.w32->top_pos >= 0)
     store_in_alist (alistptr, Qtop, tem);
   else
     store_in_alist (alistptr, Qtop, Fcons (Qplus, Fcons (tem, Qnil)));
 
   store_in_alist (alistptr, Qborder_width,
-                  make_number (f->output_data.win32->border_width));
+                  make_number (f->output_data.w32->border_width));
   store_in_alist (alistptr, Qinternal_border_width,
-                  make_number (f->output_data.win32->internal_border_width));
-  sprintf (buf, "%ld", (long) FRAME_WIN32_WINDOW (f));
+                  make_number (f->output_data.w32->internal_border_width));
+  sprintf (buf, "%ld", (long) FRAME_W32_WINDOW (f));
   store_in_alist (alistptr, Qwindow_id,
                   build_string (buf));
   store_in_alist (alistptr, Qicon_name, f->icon_name);
@@ -844,13 +924,13 @@ x_report_frame_params (f, alistptr)
                  (FRAME_VISIBLE_P (f) ? Qt
                   : FRAME_ICONIFIED_P (f) ? Qicon : Qnil));
   store_in_alist (alistptr, Qdisplay,
-                 XCONS (FRAME_WIN32_DISPLAY_INFO (f)->name_list_element)->car);
+                 XCONS (FRAME_W32_DISPLAY_INFO (f)->name_list_element)->car);
 }
 \f
 
-DEFUN ("win32-define-rgb-color", Fwin32_define_rgb_color, Swin32_define_rgb_color, 4, 4, 0,
+DEFUN ("w32-define-rgb-color", Fw32_define_rgb_color, Sw32_define_rgb_color, 4, 4, 0,
   "Convert RGB numbers to a windows color reference and associate with NAME (a string).\n\
-This adds or updates a named color to win32-color-map, making it available for use.\n\
+This adds or updates a named color to w32-color-map, making it available for use.\n\
 The original entry's RGB ref is returned, or nil if the entry is new.")
     (red, green, blue, name)
     Lisp_Object red, green, blue, name;
@@ -868,12 +948,12 @@ The original entry's RGB ref is returned, or nil if the entry is new.")
 
   BLOCK_INPUT;
 
-  /* replace existing entry in win32-color-map or add new entry. */
-  entry = Fassoc (name, Vwin32_color_map);
+  /* replace existing entry in w32-color-map or add new entry. */
+  entry = Fassoc (name, Vw32_color_map);
   if (NILP (entry))
     {
       entry = Fcons (name, rgb);
-      Vwin32_color_map = Fcons (entry, Vwin32_color_map);
+      Vw32_color_map = Fcons (entry, Vw32_color_map);
     }
   else
     {
@@ -886,9 +966,9 @@ The original entry's RGB ref is returned, or nil if the entry is new.")
   return (oldrgb);
 }
 
-DEFUN ("win32-load-color-file", Fwin32_load_color_file, Swin32_load_color_file, 1, 1, 0,
+DEFUN ("w32-load-color-file", Fw32_load_color_file, Sw32_load_color_file, 1, 1, 0,
   "Create an alist of color entries from an external file (ie. rgb.txt).\n\
-Assign this value to win32-color-map to replace the existing color map.\n\
+Assign this value to w32-color-map to replace the existing color map.\n\
 \
 The file should define one named RGB color per line like so:\
   R G B   name\n\
@@ -932,14 +1012,14 @@ where R,G,B are numbers between 0 and 255 and name is an arbitrary string.")
   return cmap;
 }
 
-/* The default colors for the win32 color map */
+/* The default colors for the w32 color map */
 typedef struct colormap_t 
 {
   char *name;
   COLORREF colorref;
 } colormap_t;
 
-colormap_t win32_color_map[] = 
+colormap_t w32_color_map[] = 
 {
   {"snow"                      , PALETTERGB (255,250,250)},
   {"ghost white"               , PALETTERGB (248,248,255)},
@@ -1183,19 +1263,19 @@ colormap_t win32_color_map[] =
   {"LightGreen"                , PALETTERGB (144,238,144)},
 };
 
-DEFUN ("win32-default-color-map", Fwin32_default_color_map, Swin32_default_color_map,
+DEFUN ("w32-default-color-map", Fw32_default_color_map, Sw32_default_color_map,
        0, 0, 0, "Return the default color map.")
      ()
 {
   int i;
-  colormap_t *pc = win32_color_map;
+  colormap_t *pc = w32_color_map;
   Lisp_Object cmap;
   
   BLOCK_INPUT;
   
   cmap = Qnil;
   
-  for (i = 0; i < sizeof (win32_color_map) / sizeof (win32_color_map[0]); 
+  for (i = 0; i < sizeof (w32_color_map) / sizeof (w32_color_map[0]); 
        pc++, i++)
     cmap = Fcons (Fcons (build_string (pc->name),
                         make_number (pc->colorref)),
@@ -1207,7 +1287,7 @@ DEFUN ("win32-default-color-map", Fwin32_default_color_map, Swin32_default_color
 }
 
 Lisp_Object 
-win32_to_x_color (rgb)
+w32_to_x_color (rgb)
      Lisp_Object rgb;
 {
   Lisp_Object color;
@@ -1216,7 +1296,7 @@ win32_to_x_color (rgb)
   
   BLOCK_INPUT;
   
-  color = Frassq (rgb, Vwin32_color_map);
+  color = Frassq (rgb, Vw32_color_map);
   
   UNBLOCK_INPUT;
   
@@ -1226,15 +1306,15 @@ win32_to_x_color (rgb)
     return Qnil;
 }
 
-COLORREF 
-x_to_win32_color (colorname)
-     char * colorname;
+COLORREF
+w32_color_map_lookup (colorname)
+     char *colorname;
 {
-  register Lisp_Object tail, ret = Qnil;
-  
+  Lisp_Object tail, ret = Qnil;
+
   BLOCK_INPUT;
-  
-  for (tail = Vwin32_color_map; !NILP (tail); tail = Fcdr (tail))
+
+  for (tail = Vw32_color_map; !NILP (tail); tail = Fcdr (tail))
     {
       register Lisp_Object elt, tem;
 
@@ -1245,40 +1325,232 @@ x_to_win32_color (colorname)
 
       if (lstrcmpi (XSTRING (tem)->data, colorname) == 0)
        {
-         ret = XUINT(Fcdr (elt));
+         ret = XUINT (Fcdr (elt));
          break;
        }
 
       QUIT;
     }
-  
+
+
   UNBLOCK_INPUT;
+
+  return ret;
+}
+
+COLORREF 
+x_to_w32_color (colorname)
+     char * colorname;
+{
+  register Lisp_Object tail, ret = Qnil;
+  
+  BLOCK_INPUT;
+
+  if (colorname[0] == '#')
+    {
+      /* Could be an old-style RGB Device specification.  */
+      char *color;
+      int size;
+      color = colorname + 1;
+      
+      size = strlen(color);
+      if (size == 3 || size == 6 || size == 9 || size == 12)
+       {
+         UINT colorval;
+         int i, pos;
+         pos = 0;
+         size /= 3;
+         colorval = 0;
+         
+         for (i = 0; i < 3; i++)
+           {
+             char *end;
+             char t;
+             unsigned long value;
+
+             /* The check for 'x' in the following conditional takes into
+                account the fact that strtol allows a "0x" in front of
+                our numbers, and we don't.  */
+             if (!isxdigit(color[0]) || color[1] == 'x')
+               break;
+             t = color[size];
+             color[size] = '\0';
+             value = strtoul(color, &end, 16);
+             color[size] = t;
+             if (errno == ERANGE || end - color != size)
+               break;
+             switch (size)
+               {
+               case 1:
+                 value = value * 0x10;
+                 break;
+               case 2:
+                 break;
+               case 3:
+                 value /= 0x10;
+                 break;
+               case 4:
+                 value /= 0x100;
+                 break;
+               }
+             colorval |= (value << pos);
+             pos += 0x8;
+             if (i == 2)
+               {
+                 UNBLOCK_INPUT;
+                 return (colorval);
+               }
+             color = end;
+           }
+       }
+    }
+  else if (strnicmp(colorname, "rgb:", 4) == 0)
+    {
+      char *color;
+      UINT colorval;
+      int i, pos;
+      pos = 0;
+
+      colorval = 0;
+      color = colorname + 4;
+      for (i = 0; i < 3; i++)
+       {
+         char *end;
+         unsigned long value;
+         
+         /* The check for 'x' in the following conditional takes into
+            account the fact that strtol allows a "0x" in front of
+            our numbers, and we don't.  */
+         if (!isxdigit(color[0]) || color[1] == 'x')
+           break;
+         value = strtoul(color, &end, 16);
+         if (errno == ERANGE)
+           break;
+         switch (end - color)
+           {
+           case 1:
+             value = value * 0x10 + value;
+             break;
+           case 2:
+             break;
+           case 3:
+             value /= 0x10;
+             break;
+           case 4:
+             value /= 0x100;
+             break;
+           default:
+             value = ULONG_MAX;
+           }
+         if (value == ULONG_MAX)
+           break;
+         colorval |= (value << pos);
+         pos += 0x8;
+         if (i == 2)
+           {
+             if (*end != '\0')
+               break;
+             UNBLOCK_INPUT;
+             return (colorval);
+           }
+         if (*end != '/')
+           break;
+         color = end + 1;
+       }
+    }
+  else if (strnicmp(colorname, "rgbi:", 5) == 0)
+    {
+      /* This is an RGB Intensity specification.  */
+      char *color;
+      UINT colorval;
+      int i, pos;
+      pos = 0;
+
+      colorval = 0;
+      color = colorname + 5;
+      for (i = 0; i < 3; i++)
+       {
+         char *end;
+         double value;
+         UINT val;
+
+         value = strtod(color, &end);
+         if (errno == ERANGE)
+           break;
+         if (value < 0.0 || value > 1.0)
+           break;
+         val = (UINT)(0x100 * value);
+         /* We used 0x100 instead of 0xFF to give an continuous
+             range between 0.0 and 1.0 inclusive.  The next statement
+             fixes the 1.0 case.  */
+         if (val == 0x100)
+           val = 0xFF;
+         colorval |= (val << pos);
+         pos += 0x8;
+         if (i == 2)
+           {
+             if (*end != '\0')
+               break;
+             UNBLOCK_INPUT;
+             return (colorval);
+           }
+         if (*end != '/')
+           break;
+         color = end + 1;
+       }
+    }
+  /* I am not going to attempt to handle any of the CIE color schemes
+     or TekHVC, since I don't know the algorithms for conversion to
+     RGB.  */
+
+  /* If we fail to lookup the color name in w32_color_map, then check the
+     colorname to see if it can be crudely approximated: If the X color 
+     ends in a number (e.g., "darkseagreen2"), strip the number and
+     return the result of looking up the base color name.  */
+  ret = w32_color_map_lookup (colorname);
+  if (NILP (ret)) 
+    {
+      int len = strlen (colorname);
+
+      if (isdigit (colorname[len - 1])) 
+       {
+         char *ptr, *approx = alloca (len);
+
+         strcpy (approx, colorname);
+         ptr = &approx[len - 1];
+         while (ptr > approx && isdigit (*ptr)) 
+             *ptr-- = '\0';
+
+         ret = w32_color_map_lookup (approx);
+       }
+    }
   
+  UNBLOCK_INPUT;
   return ret;
 }
 
 
 void
-win32_regenerate_palette (FRAME_PTR f)
+w32_regenerate_palette (FRAME_PTR f)
 {
-  struct win32_palette_entry * list;
+  struct w32_palette_entry * list;
   LOGPALETTE *          log_palette;
   HPALETTE              new_palette;
   int                   i;
 
   /* don't bother trying to create palette if not supported */
-  if (! FRAME_WIN32_DISPLAY_INFO (f)->has_palette)
+  if (! FRAME_W32_DISPLAY_INFO (f)->has_palette)
     return;
 
   log_palette = (LOGPALETTE *)
     alloca (sizeof (LOGPALETTE) +
-            FRAME_WIN32_DISPLAY_INFO (f)->num_colors * sizeof (PALETTEENTRY));
+            FRAME_W32_DISPLAY_INFO (f)->num_colors * sizeof (PALETTEENTRY));
   log_palette->palVersion = 0x300;
-  log_palette->palNumEntries = FRAME_WIN32_DISPLAY_INFO (f)->num_colors;
+  log_palette->palNumEntries = FRAME_W32_DISPLAY_INFO (f)->num_colors;
 
-  list = FRAME_WIN32_DISPLAY_INFO (f)->color_list;
+  list = FRAME_W32_DISPLAY_INFO (f)->color_list;
   for (i = 0;
-       i < FRAME_WIN32_DISPLAY_INFO (f)->num_colors;
+       i < FRAME_W32_DISPLAY_INFO (f)->num_colors;
        i++, list = list->next)
     log_palette->palPalEntry[i] = list->entry;
 
@@ -1286,9 +1558,9 @@ win32_regenerate_palette (FRAME_PTR f)
 
   enter_crit ();
 
-  if (FRAME_WIN32_DISPLAY_INFO (f)->palette)
-    DeleteObject (FRAME_WIN32_DISPLAY_INFO (f)->palette);
-  FRAME_WIN32_DISPLAY_INFO (f)->palette = new_palette;
+  if (FRAME_W32_DISPLAY_INFO (f)->palette)
+    DeleteObject (FRAME_W32_DISPLAY_INFO (f)->palette);
+  FRAME_W32_DISPLAY_INFO (f)->palette = new_palette;
 
   /* Realize display palette and garbage all frames. */
   release_frame_dc (f, get_frame_dc (f));
@@ -1296,8 +1568,8 @@ win32_regenerate_palette (FRAME_PTR f)
   leave_crit ();
 }
 
-#define WIN32_COLOR(pe)  RGB (pe.peRed, pe.peGreen, pe.peBlue)
-#define SET_WIN32_COLOR(pe, color) \
+#define W32_COLOR(pe)  RGB (pe.peRed, pe.peGreen, pe.peBlue)
+#define SET_W32_COLOR(pe, color) \
   do \
     { \
       pe.peRed = GetRValue (color); \
@@ -1309,17 +1581,17 @@ win32_regenerate_palette (FRAME_PTR f)
 #if 0
 /* Keep these around in case we ever want to track color usage. */
 void
-win32_map_color (FRAME_PTR f, COLORREF color)
+w32_map_color (FRAME_PTR f, COLORREF color)
 {
-  struct win32_palette_entry * list = FRAME_WIN32_DISPLAY_INFO (f)->color_list;
+  struct w32_palette_entry * list = FRAME_W32_DISPLAY_INFO (f)->color_list;
 
-  if (NILP (Vwin32_enable_palette))
+  if (NILP (Vw32_enable_palette))
     return;
 
   /* check if color is already mapped */
   while (list)
     {
-      if (WIN32_COLOR (list->entry) == color)
+      if (W32_COLOR (list->entry) == color)
         {
          ++list->refcount;
          return;
@@ -1328,37 +1600,37 @@ win32_map_color (FRAME_PTR f, COLORREF color)
     }
 
   /* not already mapped, so add to list and recreate Windows palette */
-  list = (struct win32_palette_entry *)
-    xmalloc (sizeof (struct win32_palette_entry));
-  SET_WIN32_COLOR (list->entry, color);
+  list = (struct w32_palette_entry *)
+    xmalloc (sizeof (struct w32_palette_entry));
+  SET_W32_COLOR (list->entry, color);
   list->refcount = 1;
-  list->next = FRAME_WIN32_DISPLAY_INFO (f)->color_list;
-  FRAME_WIN32_DISPLAY_INFO (f)->color_list = list;
-  FRAME_WIN32_DISPLAY_INFO (f)->num_colors++;
+  list->next = FRAME_W32_DISPLAY_INFO (f)->color_list;
+  FRAME_W32_DISPLAY_INFO (f)->color_list = list;
+  FRAME_W32_DISPLAY_INFO (f)->num_colors++;
 
   /* set flag that palette must be regenerated */
-  FRAME_WIN32_DISPLAY_INFO (f)->regen_palette = TRUE;
+  FRAME_W32_DISPLAY_INFO (f)->regen_palette = TRUE;
 }
 
 void
-win32_unmap_color (FRAME_PTR f, COLORREF color)
+w32_unmap_color (FRAME_PTR f, COLORREF color)
 {
-  struct win32_palette_entry * list = FRAME_WIN32_DISPLAY_INFO (f)->color_list;
-  struct win32_palette_entry **prev = &FRAME_WIN32_DISPLAY_INFO (f)->color_list;
+  struct w32_palette_entry * list = FRAME_W32_DISPLAY_INFO (f)->color_list;
+  struct w32_palette_entry **prev = &FRAME_W32_DISPLAY_INFO (f)->color_list;
 
-  if (NILP (Vwin32_enable_palette))
+  if (NILP (Vw32_enable_palette))
     return;
 
   /* check if color is already mapped */
   while (list)
     {
-      if (WIN32_COLOR (list->entry) == color)
+      if (W32_COLOR (list->entry) == color)
         {
          if (--list->refcount == 0)
            {
              *prev = list->next;
              xfree (list);
-             FRAME_WIN32_DISPLAY_INFO (f)->num_colors--;
+             FRAME_W32_DISPLAY_INFO (f)->num_colors--;
              break;
            }
          else
@@ -1369,7 +1641,7 @@ win32_unmap_color (FRAME_PTR f, COLORREF color)
     }
 
   /* set flag that palette must be regenerated */
-  FRAME_WIN32_DISPLAY_INFO (f)->regen_palette = TRUE;
+  FRAME_W32_DISPLAY_INFO (f)->regen_palette = TRUE;
 }
 #endif
 
@@ -1386,21 +1658,21 @@ defined_color (f, color, color_def, alloc)
 {
   register Lisp_Object tem;
 
-  tem = x_to_win32_color (color);
+  tem = x_to_w32_color (color);
 
   if (!NILP (tem)) 
     {
-      if (!NILP (Vwin32_enable_palette))
+      if (!NILP (Vw32_enable_palette))
        {
-         struct win32_palette_entry * entry =
-           FRAME_WIN32_DISPLAY_INFO (f)->color_list;
-         struct win32_palette_entry ** prev =
-           &FRAME_WIN32_DISPLAY_INFO (f)->color_list;
+         struct w32_palette_entry * entry =
+           FRAME_W32_DISPLAY_INFO (f)->color_list;
+         struct w32_palette_entry ** prev =
+           &FRAME_W32_DISPLAY_INFO (f)->color_list;
       
          /* check if color is already mapped */
          while (entry)
            {
-             if (WIN32_COLOR (entry->entry) == XUINT (tem))
+             if (W32_COLOR (entry->entry) == XUINT (tem))
                break;
              prev = &entry->next;
              entry = entry->next;
@@ -1409,15 +1681,15 @@ defined_color (f, color, color_def, alloc)
          if (entry == NULL && alloc)
            {
              /* not already mapped, so add to list */
-             entry = (struct win32_palette_entry *)
-               xmalloc (sizeof (struct win32_palette_entry));
-             SET_WIN32_COLOR (entry->entry, XUINT (tem));
+             entry = (struct w32_palette_entry *)
+               xmalloc (sizeof (struct w32_palette_entry));
+             SET_W32_COLOR (entry->entry, XUINT (tem));
              entry->next = NULL;
              *prev = entry;
-             FRAME_WIN32_DISPLAY_INFO (f)->num_colors++;
+             FRAME_W32_DISPLAY_INFO (f)->num_colors++;
 
              /* set flag that palette must be regenerated */
-             FRAME_WIN32_DISPLAY_INFO (f)->regen_palette = TRUE;
+             FRAME_W32_DISPLAY_INFO (f)->regen_palette = TRUE;
            }
        }
       /* Ensure COLORREF value is snapped to nearest color in (default)
@@ -1452,7 +1724,7 @@ x_decode_color (f, arg, def)
   else if (strcmp (XSTRING (arg)->data, "white") == 0)
     return WHITE_PIX_DEFAULT (f);
 
-  if ((FRAME_WIN32_DISPLAY_INFO (f)->n_planes * FRAME_WIN32_DISPLAY_INFO (f)->n_cbits) == 1)
+  if ((FRAME_W32_DISPLAY_INFO (f)->n_planes * FRAME_W32_DISPLAY_INFO (f)->n_cbits) == 1)
     return def;
 
   /* defined_color is responsible for coping with failures
@@ -1467,7 +1739,7 @@ x_decode_color (f, arg, def)
 /* Functions called only from `x_set_frame_param'
    to set individual parameters.
 
-   If FRAME_WIN32_WINDOW (f) is 0,
+   If FRAME_W32_WINDOW (f) is 0,
    the frame is being created and its window does not exist yet.
    In that case, just record the parameter's new value
    in the standard place; do not attempt to change the window.  */
@@ -1477,10 +1749,10 @@ x_set_foreground_color (f, arg, oldval)
      struct frame *f;
      Lisp_Object arg, oldval;
 {
-  f->output_data.win32->foreground_pixel
+  f->output_data.w32->foreground_pixel
     = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
 
-  if (FRAME_WIN32_WINDOW (f) != 0)
+  if (FRAME_W32_WINDOW (f) != 0)
     {
       recompute_basic_faces (f);
       if (FRAME_VISIBLE_P (f))
@@ -1496,12 +1768,12 @@ x_set_background_color (f, arg, oldval)
   Pixmap temp;
   int mask;
 
-  f->output_data.win32->background_pixel
+  f->output_data.w32->background_pixel
     = x_decode_color (f, arg, WHITE_PIX_DEFAULT (f));
 
-  if (FRAME_WIN32_WINDOW (f) != 0)
+  if (FRAME_W32_WINDOW (f) != 0)
     {
-      SetWindowLong (FRAME_WIN32_WINDOW (f), WND_BACKGROUND_INDEX, f->output_data.win32->background_pixel);
+      SetWindowLong (FRAME_W32_WINDOW (f), WND_BACKGROUND_INDEX, f->output_data.w32->background_pixel);
 
       recompute_basic_faces (f);
 
@@ -1518,113 +1790,114 @@ x_set_mouse_color (f, arg, oldval)
 #if 0
   Cursor cursor, nontext_cursor, mode_cursor, cross_cursor;
 #endif
+  int count;
   int mask_color;
 
   if (!EQ (Qnil, arg))
-    f->output_data.win32->mouse_pixel
+    f->output_data.w32->mouse_pixel
       = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
-  mask_color = f->output_data.win32->background_pixel;
+  mask_color = f->output_data.w32->background_pixel;
                                /* No invisible pointers.  */
-  if (mask_color == f->output_data.win32->mouse_pixel
-       && mask_color == f->output_data.win32->background_pixel)
-    f->output_data.win32->mouse_pixel = f->output_data.win32->foreground_pixel;
+  if (mask_color == f->output_data.w32->mouse_pixel
+       && mask_color == f->output_data.w32->background_pixel)
+    f->output_data.w32->mouse_pixel = f->output_data.w32->foreground_pixel;
 
 #if 0
   BLOCK_INPUT;
 
   /* It's not okay to crash if the user selects a screwy cursor.  */
-  x_catch_errors (FRAME_WIN32_DISPLAY (f));
+  count = x_catch_errors (FRAME_W32_DISPLAY (f));
 
   if (!EQ (Qnil, Vx_pointer_shape))
     {
       CHECK_NUMBER (Vx_pointer_shape, 0);
-      cursor = XCreateFontCursor (FRAME_WIN32_DISPLAY (f), XINT (Vx_pointer_shape));
+      cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XINT (Vx_pointer_shape));
     }
   else
-    cursor = XCreateFontCursor (FRAME_WIN32_DISPLAY (f), XC_xterm);
-  x_check_errors (FRAME_WIN32_DISPLAY (f), "bad text pointer cursor: %s");
+    cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_xterm);
+  x_check_errors (FRAME_W32_DISPLAY (f), "bad text pointer cursor: %s");
 
   if (!EQ (Qnil, Vx_nontext_pointer_shape))
     {
       CHECK_NUMBER (Vx_nontext_pointer_shape, 0);
-      nontext_cursor = XCreateFontCursor (FRAME_WIN32_DISPLAY (f),
+      nontext_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
                                          XINT (Vx_nontext_pointer_shape));
     }
   else
-    nontext_cursor = XCreateFontCursor (FRAME_WIN32_DISPLAY (f), XC_left_ptr);
-  x_check_errors (FRAME_WIN32_DISPLAY (f), "bad nontext pointer cursor: %s");
+    nontext_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_left_ptr);
+  x_check_errors (FRAME_W32_DISPLAY (f), "bad nontext pointer cursor: %s");
 
   if (!EQ (Qnil, Vx_mode_pointer_shape))
     {
       CHECK_NUMBER (Vx_mode_pointer_shape, 0);
-      mode_cursor = XCreateFontCursor (FRAME_WIN32_DISPLAY (f),
+      mode_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
                                       XINT (Vx_mode_pointer_shape));
     }
   else
-    mode_cursor = XCreateFontCursor (FRAME_WIN32_DISPLAY (f), XC_xterm);
-  x_check_errors (FRAME_WIN32_DISPLAY (f), "bad modeline pointer cursor: %s");
+    mode_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_xterm);
+  x_check_errors (FRAME_W32_DISPLAY (f), "bad modeline pointer cursor: %s");
 
   if (!EQ (Qnil, Vx_sensitive_text_pointer_shape))
     {
       CHECK_NUMBER (Vx_sensitive_text_pointer_shape, 0);
       cross_cursor
-       = XCreateFontCursor (FRAME_WIN32_DISPLAY (f),
+       = XCreateFontCursor (FRAME_W32_DISPLAY (f),
                             XINT (Vx_sensitive_text_pointer_shape));
     }
   else
-    cross_cursor = XCreateFontCursor (FRAME_WIN32_DISPLAY (f), XC_crosshair);
+    cross_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_crosshair);
 
   /* Check and report errors with the above calls.  */
-  x_check_errors (FRAME_WIN32_DISPLAY (f), "can't set cursor shape: %s");
-  x_uncatch_errors (FRAME_WIN32_DISPLAY (f));
+  x_check_errors (FRAME_W32_DISPLAY (f), "can't set cursor shape: %s");
+  x_uncatch_errors (FRAME_W32_DISPLAY (f), count);
 
   {
     XColor fore_color, back_color;
 
-    fore_color.pixel = f->output_data.win32->mouse_pixel;
+    fore_color.pixel = f->output_data.w32->mouse_pixel;
     back_color.pixel = mask_color;
-    XQueryColor (FRAME_WIN32_DISPLAY (f),
-                DefaultColormap (FRAME_WIN32_DISPLAY (f),
-                                 DefaultScreen (FRAME_WIN32_DISPLAY (f))),
+    XQueryColor (FRAME_W32_DISPLAY (f),
+                DefaultColormap (FRAME_W32_DISPLAY (f),
+                                 DefaultScreen (FRAME_W32_DISPLAY (f))),
                 &fore_color);
-    XQueryColor (FRAME_WIN32_DISPLAY (f),
-                DefaultColormap (FRAME_WIN32_DISPLAY (f),
-                                 DefaultScreen (FRAME_WIN32_DISPLAY (f))),
+    XQueryColor (FRAME_W32_DISPLAY (f),
+                DefaultColormap (FRAME_W32_DISPLAY (f),
+                                 DefaultScreen (FRAME_W32_DISPLAY (f))),
                 &back_color);
-    XRecolorCursor (FRAME_WIN32_DISPLAY (f), cursor,
+    XRecolorCursor (FRAME_W32_DISPLAY (f), cursor,
                    &fore_color, &back_color);
-    XRecolorCursor (FRAME_WIN32_DISPLAY (f), nontext_cursor,
+    XRecolorCursor (FRAME_W32_DISPLAY (f), nontext_cursor,
                    &fore_color, &back_color);
-    XRecolorCursor (FRAME_WIN32_DISPLAY (f), mode_cursor,
+    XRecolorCursor (FRAME_W32_DISPLAY (f), mode_cursor,
                    &fore_color, &back_color);
-    XRecolorCursor (FRAME_WIN32_DISPLAY (f), cross_cursor,
+    XRecolorCursor (FRAME_W32_DISPLAY (f), cross_cursor,
                     &fore_color, &back_color);
   }
 
-  if (FRAME_WIN32_WINDOW (f) != 0)
+  if (FRAME_W32_WINDOW (f) != 0)
     {
-      XDefineCursor (FRAME_WIN32_DISPLAY (f), FRAME_WIN32_WINDOW (f), cursor);
+      XDefineCursor (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), cursor);
     }
 
-  if (cursor != f->output_data.win32->text_cursor && f->output_data.win32->text_cursor != 0)
-    XFreeCursor (FRAME_WIN32_DISPLAY (f), f->output_data.win32->text_cursor);
-  f->output_data.win32->text_cursor = cursor;
-
-  if (nontext_cursor != f->output_data.win32->nontext_cursor
-      && f->output_data.win32->nontext_cursor != 0)
-    XFreeCursor (FRAME_WIN32_DISPLAY (f), f->output_data.win32->nontext_cursor);
-  f->output_data.win32->nontext_cursor = nontext_cursor;
-
-  if (mode_cursor != f->output_data.win32->modeline_cursor
-      && f->output_data.win32->modeline_cursor != 0)
-    XFreeCursor (FRAME_WIN32_DISPLAY (f), f->output_data.win32->modeline_cursor);
-  f->output_data.win32->modeline_cursor = mode_cursor;
-  if (cross_cursor != f->output_data.win32->cross_cursor
-      && f->output_data.win32->cross_cursor != 0)
-    XFreeCursor (FRAME_WIN32_DISPLAY (f), f->output_data.win32->cross_cursor);
-  f->output_data.win32->cross_cursor = cross_cursor;
-
-  XFlush (FRAME_WIN32_DISPLAY (f));
+  if (cursor != f->output_data.w32->text_cursor && f->output_data.w32->text_cursor != 0)
+    XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->text_cursor);
+  f->output_data.w32->text_cursor = cursor;
+
+  if (nontext_cursor != f->output_data.w32->nontext_cursor
+      && f->output_data.w32->nontext_cursor != 0)
+    XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->nontext_cursor);
+  f->output_data.w32->nontext_cursor = nontext_cursor;
+
+  if (mode_cursor != f->output_data.w32->modeline_cursor
+      && f->output_data.w32->modeline_cursor != 0)
+    XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->modeline_cursor);
+  f->output_data.w32->modeline_cursor = mode_cursor;
+  if (cross_cursor != f->output_data.w32->cross_cursor
+      && f->output_data.w32->cross_cursor != 0)
+    XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->cross_cursor);
+  f->output_data.w32->cross_cursor = cross_cursor;
+
+  XFlush (FRAME_W32_DISPLAY (f));
   UNBLOCK_INPUT;
 #endif
 }
@@ -1640,19 +1913,19 @@ x_set_cursor_color (f, arg, oldval)
     fore_pixel = x_decode_color (f, Vx_cursor_fore_pixel,
                                 WHITE_PIX_DEFAULT (f));
   else
-    fore_pixel = f->output_data.win32->background_pixel;
-  f->output_data.win32->cursor_pixel = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
+    fore_pixel = f->output_data.w32->background_pixel;
+  f->output_data.w32->cursor_pixel = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
   
   /* Make sure that the cursor color differs from the background color.  */
-  if (f->output_data.win32->cursor_pixel == f->output_data.win32->background_pixel)
+  if (f->output_data.w32->cursor_pixel == f->output_data.w32->background_pixel)
     {
-      f->output_data.win32->cursor_pixel = f->output_data.win32->mouse_pixel;
-      if (f->output_data.win32->cursor_pixel == fore_pixel)
-       fore_pixel = f->output_data.win32->background_pixel;
+      f->output_data.w32->cursor_pixel = f->output_data.w32->mouse_pixel;
+      if (f->output_data.w32->cursor_pixel == fore_pixel)
+       fore_pixel = f->output_data.w32->background_pixel;
     }
-  f->output_data.win32->cursor_foreground_pixel = fore_pixel;
+  f->output_data.w32->cursor_foreground_pixel = fore_pixel;
 
-  if (FRAME_WIN32_WINDOW (f) != 0)
+  if (FRAME_W32_WINDOW (f) != 0)
     {
       if (FRAME_VISIBLE_P (f))
        {
@@ -1692,9 +1965,9 @@ x_set_border_pixel (f, pix)
      struct frame *f;
      int pix;
 {
-  f->output_data.win32->border_pixel = pix;
+  f->output_data.w32->border_pixel = pix;
 
-  if (FRAME_WIN32_WINDOW (f) != 0 && f->output_data.win32->border_width > 0)
+  if (FRAME_W32_WINDOW (f) != 0 && f->output_data.w32->border_width > 0)
     {
       if (FRAME_VISIBLE_P (f))
         redraw_frame (f);
@@ -1709,13 +1982,13 @@ x_set_cursor_type (f, arg, oldval)
   if (EQ (arg, Qbar))
     {
       FRAME_DESIRED_CURSOR (f) = bar_cursor;
-      f->output_data.win32->cursor_width = 2;
+      f->output_data.w32->cursor_width = 2;
     }
   else if (CONSP (arg) && EQ (XCONS (arg)->car, Qbar)
           && INTEGERP (XCONS (arg)->cdr))
     {
       FRAME_DESIRED_CURSOR (f) = bar_cursor;
-      f->output_data.win32->cursor_width = XINT (XCONS (arg)->cdr);
+      f->output_data.w32->cursor_width = XINT (XCONS (arg)->cdr);
     }
   else
     /* Treat anything unknown as "box cursor".
@@ -1765,12 +2038,12 @@ x_set_icon_type (f, arg, oldval)
   if (FRAME_VISIBLE_P (f))
     {
 #ifdef USE_X_TOOLKIT
-      XtPopup (f->output_data.win32->widget, XtGrabNone);
+      XtPopup (f->output_data.w32->widget, XtGrabNone);
 #endif
-      XMapWindow (FRAME_WIN32_DISPLAY (f), FRAME_WIN32_WINDOW (f));
+      XMapWindow (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f));
     }
 
-  XFlush (FRAME_WIN32_DISPLAY (f));
+  XFlush (FRAME_W32_DISPLAY (f));
   UNBLOCK_INPUT;
 #endif
 }
@@ -1809,14 +2082,16 @@ x_set_icon_name (f, arg, oldval)
   f->icon_name = arg;
 
 #if 0
-  if (f->output_data.win32->icon_bitmap != 0)
+  if (f->output_data.w32->icon_bitmap != 0)
     return;
 
   BLOCK_INPUT;
 
   result = x_text_icon (f,
-                        (char *) XSTRING ((!NILP (f->icon_name)
+                       (char *) XSTRING ((!NILP (f->icon_name)
                                           ? f->icon_name
+                                          : !NILP (f->title)
+                                          ? f->title
                                           : f->name))->data);
 
   if (result)
@@ -1830,17 +2105,18 @@ x_set_icon_name (f, arg, oldval)
   if (FRAME_VISIBLE_P (f))
     {
 #ifdef USE_X_TOOLKIT
-      XtPopup (f->output_data.win32->widget, XtGrabNone);
+      XtPopup (f->output_data.w32->widget, XtGrabNone);
 #endif
-      XMapWindow (FRAME_WIN32_DISPLAY (f), FRAME_WIN32_WINDOW (f));
+      XMapWindow (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f));
     }
 
-  XFlush (FRAME_WIN32_DISPLAY (f));
+  XFlush (FRAME_W32_DISPLAY (f));
   UNBLOCK_INPUT;
 #endif
 }
 
 extern Lisp_Object x_new_font ();
+extern Lisp_Object x_new_fontset();
 
 void
 x_set_font (f, arg, oldval)
@@ -1848,11 +2124,17 @@ x_set_font (f, arg, oldval)
      Lisp_Object arg, oldval;
 {
   Lisp_Object result;
+  Lisp_Object fontset_name;
+  Lisp_Object frame;
 
   CHECK_STRING (arg, 1);
 
+  fontset_name = Fquery_fontset (arg, Qnil);
+
   BLOCK_INPUT;
-  result = x_new_font (f, XSTRING (arg)->data);
+  result = (STRINGP (fontset_name)
+            ? x_new_fontset (f, XSTRING (fontset_name)->data)
+            : x_new_font (f, XSTRING (arg)->data));
   UNBLOCK_INPUT;
   
   if (EQ (result, Qnil))
@@ -1866,6 +2148,9 @@ x_set_font (f, arg, oldval)
     }
   else
     abort ();
+
+  XSETFRAME (frame, f);
+  call1 (Qface_set_after_frame_default, frame);
 }
 
 void
@@ -1875,13 +2160,13 @@ x_set_border_width (f, arg, oldval)
 {
   CHECK_NUMBER (arg, 0);
 
-  if (XINT (arg) == f->output_data.win32->border_width)
+  if (XINT (arg) == f->output_data.w32->border_width)
     return;
 
-  if (FRAME_WIN32_WINDOW (f) != 0)
+  if (FRAME_W32_WINDOW (f) != 0)
     error ("Cannot change the border width of a window");
 
-  f->output_data.win32->border_width = XINT (arg);
+  f->output_data.w32->border_width = XINT (arg);
 }
 
 void
@@ -1890,17 +2175,17 @@ x_set_internal_border_width (f, arg, oldval)
      Lisp_Object arg, oldval;
 {
   int mask;
-  int old = f->output_data.win32->internal_border_width;
+  int old = f->output_data.w32->internal_border_width;
 
   CHECK_NUMBER (arg, 0);
-  f->output_data.win32->internal_border_width = XINT (arg);
-  if (f->output_data.win32->internal_border_width < 0)
-    f->output_data.win32->internal_border_width = 0;
+  f->output_data.w32->internal_border_width = XINT (arg);
+  if (f->output_data.w32->internal_border_width < 0)
+    f->output_data.w32->internal_border_width = 0;
 
-  if (f->output_data.win32->internal_border_width == old)
+  if (f->output_data.w32->internal_border_width == old)
     return;
 
-  if (FRAME_WIN32_WINDOW (f) != 0)
+  if (FRAME_W32_WINDOW (f) != 0)
     {
       BLOCK_INPUT;
       x_set_window_size (f, 0, f->width, f->height);
@@ -1953,11 +2238,16 @@ x_set_menu_bar_lines (f, value, oldval)
       if (FRAME_EXTERNAL_MENU_BAR (f) == 1)
        free_frame_menubar (f);
       FRAME_EXTERNAL_MENU_BAR (f) = 0;
+
+      /* Adjust the frame size so that the client (text) dimensions
+        remain the same.  This depends on FRAME_EXTERNAL_MENU_BAR being
+        set correctly.  */
+      x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
     }
 }
 
 /* Change the name of frame F to NAME.  If NAME is nil, set F's name to
-       win32_id_name.
+       w32_id_name.
 
    If EXPLICIT is non-zero, that indicates that lisp code is setting the
        name; if NAME is a string, set F's name to NAME and set
@@ -1987,15 +2277,15 @@ x_set_name (f, name, explicit)
   else if (f->explicit_name)
     return;
 
-  /* If NAME is nil, set the name to the win32_id_name.  */
+  /* If NAME is nil, set the name to the w32_id_name.  */
   if (NILP (name))
     {
       /* Check for no change needed in this very common case
         before we do any consing.  */
-      if (!strcmp (FRAME_WIN32_DISPLAY_INFO (f)->win32_id_name,
+      if (!strcmp (FRAME_W32_DISPLAY_INFO (f)->w32_id_name,
                   XSTRING (f->name)->data))
        return;
-      name = build_string (FRAME_WIN32_DISPLAY_INFO (f)->win32_id_name);
+      name = build_string (FRAME_W32_DISPLAY_INFO (f)->w32_id_name);
     }
   else
     CHECK_STRING (name, 0);
@@ -2004,14 +2294,19 @@ x_set_name (f, name, explicit)
   if (! NILP (Fstring_equal (name, f->name)))
     return;
 
-  if (FRAME_WIN32_WINDOW (f))
+  f->name = name;
+
+  /* For setting the frame title, the title parameter should override
+     the name parameter.  */
+  if (! NILP (f->title))
+    name = f->title;
+
+  if (FRAME_W32_WINDOW (f))
     {
       BLOCK_INPUT;
-      SetWindowText(FRAME_WIN32_WINDOW (f), XSTRING (name)->data);
+      SetWindowText(FRAME_W32_WINDOW (f), XSTRING (name)->data);
       UNBLOCK_INPUT;
     }
-
-  f->name = name;
 }
 
 /* This function should be called when the user's lisp code has
@@ -2035,7 +2330,42 @@ x_implicitly_set_name (f, arg, oldval)
 {
   x_set_name (f, arg, 0);
 }
+\f
+/* Change the title of frame F to NAME.
+   If NAME is nil, use the frame name as the title.
+
+   If EXPLICIT is non-zero, that indicates that lisp code is setting the
+       name; if NAME is a string, set F's name to NAME and set
+       F->explicit_name; if NAME is Qnil, then clear F->explicit_name.
+
+   If EXPLICIT is zero, that indicates that Emacs redisplay code is
+       suggesting a new name, which lisp code should override; if
+       F->explicit_name is set, ignore the new name; otherwise, set it.  */
+
+void
+x_set_title (f, name)
+     struct frame *f;
+     Lisp_Object name;
+{
+  /* Don't change the title if it's already NAME.  */
+  if (EQ (name, f->title))
+    return;
+
+  update_mode_lines = 1;
+
+  f->title = name;
+
+  if (NILP (name))
+    name = f->name;
 
+  if (FRAME_W32_WINDOW (f))
+    {
+      BLOCK_INPUT;
+      SetWindowText(FRAME_W32_WINDOW (f), XSTRING (name)->data);
+      UNBLOCK_INPUT;
+    }
+}
+\f
 void
 x_set_autoraise (f, arg, oldval)
      struct frame *f;
@@ -2065,15 +2395,24 @@ x_set_vertical_scroll_bars (f, arg, oldval)
      struct frame *f;
      Lisp_Object arg, oldval;
 {
-  if (NILP (arg) != ! FRAME_HAS_VERTICAL_SCROLL_BARS (f))
+  if ((EQ (arg, Qleft) && FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
+      || (EQ (arg, Qright) && FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f))
+      || (NILP (arg) && FRAME_HAS_VERTICAL_SCROLL_BARS (f))
+      || (!NILP (arg) && ! FRAME_HAS_VERTICAL_SCROLL_BARS (f)))
     {
-      FRAME_HAS_VERTICAL_SCROLL_BARS (f) = ! NILP (arg);
+      FRAME_VERTICAL_SCROLL_BAR_TYPE (f) = NILP (arg) ?
+       vertical_scroll_bar_none :
+       /* Put scroll bars on the right by default, as is conventional
+           on MS-Windows.  */
+       EQ (Qleft, arg)
+       ? vertical_scroll_bar_left 
+       : vertical_scroll_bar_right;
 
       /* We set this parameter before creating the window for the
         frame, so we can get the geometry right from the start.
         However, if the window hasn't been created yet, we shouldn't
         call x_set_window_size.  */
-      if (FRAME_WIN32_WINDOW (f))
+      if (FRAME_W32_WINDOW (f))
        x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
     }
 }
@@ -2091,10 +2430,10 @@ x_set_scroll_bar_width (f, arg, oldval)
   else if (INTEGERP (arg) && XINT (arg) > 0
           && XFASTINT (arg) != FRAME_SCROLL_BAR_PIXEL_WIDTH (f))
     {
-      int wid = FONT_WIDTH (f->output_data.win32->font);
+      int wid = FONT_WIDTH (f->output_data.w32->font);
       FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = XFASTINT (arg);
       FRAME_SCROLL_BAR_COLS (f) = (XFASTINT (arg) + wid-1) / wid;
-      if (FRAME_WIN32_WINDOW (f))
+      if (FRAME_W32_WINDOW (f))
        x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
     }
 }
@@ -2452,12 +2791,12 @@ x_figure_window_size (f, parms)
   /* Default values if we fall through.
      Actually, if that happens we should get
      window manager prompting.  */
-  f->width = DEFAULT_COLS;
+  SET_FRAME_WIDTH (f, DEFAULT_COLS);
   f->height = DEFAULT_ROWS;
   /* Window managers expect that if program-specified
      positions are not (0,0), they're intentional, not defaults.  */
-  f->output_data.win32->top_pos = 0;
-  f->output_data.win32->left_pos = 0;
+  f->output_data.w32->top_pos = 0;
+  f->output_data.w32->left_pos = 0;
 
   tem0 = x_get_arg (parms, Qheight, 0, 0, number);
   tem1 = x_get_arg (parms, Qwidth, 0, 0, number);
@@ -2472,7 +2811,7 @@ x_figure_window_size (f, parms)
       if (!EQ (tem1, Qunbound))
        {
          CHECK_NUMBER (tem1, 0);
-         f->width = XINT (tem1);
+         SET_FRAME_WIDTH (f, XINT (tem1));
        }
       if (!NILP (tem2) && !EQ (tem2, Qunbound))
        window_prompting |= USSize;
@@ -2480,14 +2819,14 @@ x_figure_window_size (f, parms)
        window_prompting |= PSize;
     }
 
-  f->output_data.win32->vertical_scroll_bar_extra
+  f->output_data.w32->vertical_scroll_bar_extra
     = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f)
        ? 0
        : FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0
        ? FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
-       : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.win32->font)));
-  f->output_data.win32->pixel_width = CHAR_TO_PIXEL_WIDTH (f, f->width);
-  f->output_data.win32->pixel_height = CHAR_TO_PIXEL_HEIGHT (f, f->height);
+       : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.w32->font)));
+  f->output_data.w32->pixel_width = CHAR_TO_PIXEL_WIDTH (f, f->width);
+  f->output_data.w32->pixel_height = CHAR_TO_PIXEL_HEIGHT (f, f->height);
 
   tem0 = x_get_arg (parms, Qtop, 0, 0, number);
   tem1 = x_get_arg (parms, Qleft, 0, 0, number);
@@ -2496,57 +2835,57 @@ x_figure_window_size (f, parms)
     {
       if (EQ (tem0, Qminus))
        {
-         f->output_data.win32->top_pos = 0;
+         f->output_data.w32->top_pos = 0;
          window_prompting |= YNegative;
        }
       else if (CONSP (tem0) && EQ (XCONS (tem0)->car, Qminus)
               && CONSP (XCONS (tem0)->cdr)
               && INTEGERP (XCONS (XCONS (tem0)->cdr)->car))
        {
-         f->output_data.win32->top_pos = - XINT (XCONS (XCONS (tem0)->cdr)->car);
+         f->output_data.w32->top_pos = - XINT (XCONS (XCONS (tem0)->cdr)->car);
          window_prompting |= YNegative;
        }
       else if (CONSP (tem0) && EQ (XCONS (tem0)->car, Qplus)
               && CONSP (XCONS (tem0)->cdr)
               && INTEGERP (XCONS (XCONS (tem0)->cdr)->car))
        {
-         f->output_data.win32->top_pos = XINT (XCONS (XCONS (tem0)->cdr)->car);
+         f->output_data.w32->top_pos = XINT (XCONS (XCONS (tem0)->cdr)->car);
        }
       else if (EQ (tem0, Qunbound))
-       f->output_data.win32->top_pos = 0;
+       f->output_data.w32->top_pos = 0;
       else
        {
          CHECK_NUMBER (tem0, 0);
-         f->output_data.win32->top_pos = XINT (tem0);
-         if (f->output_data.win32->top_pos < 0)
+         f->output_data.w32->top_pos = XINT (tem0);
+         if (f->output_data.w32->top_pos < 0)
            window_prompting |= YNegative;
        }
 
       if (EQ (tem1, Qminus))
        {
-         f->output_data.win32->left_pos = 0;
+         f->output_data.w32->left_pos = 0;
          window_prompting |= XNegative;
        }
       else if (CONSP (tem1) && EQ (XCONS (tem1)->car, Qminus)
               && CONSP (XCONS (tem1)->cdr)
               && INTEGERP (XCONS (XCONS (tem1)->cdr)->car))
        {
-         f->output_data.win32->left_pos = - XINT (XCONS (XCONS (tem1)->cdr)->car);
+         f->output_data.w32->left_pos = - XINT (XCONS (XCONS (tem1)->cdr)->car);
          window_prompting |= XNegative;
        }
       else if (CONSP (tem1) && EQ (XCONS (tem1)->car, Qplus)
               && CONSP (XCONS (tem1)->cdr)
               && INTEGERP (XCONS (XCONS (tem1)->cdr)->car))
        {
-         f->output_data.win32->left_pos = XINT (XCONS (XCONS (tem1)->cdr)->car);
+         f->output_data.w32->left_pos = XINT (XCONS (XCONS (tem1)->cdr)->car);
        }
       else if (EQ (tem1, Qunbound))
-       f->output_data.win32->left_pos = 0;
+       f->output_data.w32->left_pos = 0;
       else
        {
          CHECK_NUMBER (tem1, 0);
-         f->output_data.win32->left_pos = XINT (tem1);
-         if (f->output_data.win32->left_pos < 0)
+         f->output_data.w32->left_pos = XINT (tem1);
+         if (f->output_data.w32->left_pos < 0)
            window_prompting |= XNegative;
        }
 
@@ -2561,22 +2900,22 @@ x_figure_window_size (f, parms)
 
 \f
 
-extern LRESULT CALLBACK win32_wnd_proc ();
+extern LRESULT CALLBACK w32_wnd_proc ();
 
 BOOL 
-win32_init_class (hinst)
+w32_init_class (hinst)
      HINSTANCE hinst;
 {
   WNDCLASS wc;
 
   wc.style = CS_HREDRAW | CS_VREDRAW;
-  wc.lpfnWndProc = (WNDPROC) win32_wnd_proc;
+  wc.lpfnWndProc = (WNDPROC) w32_wnd_proc;
   wc.cbClsExtra = 0;
   wc.cbWndExtra = WND_EXTRA_BYTES;
   wc.hInstance = hinst;
   wc.hIcon = LoadIcon (hinst, EMACS_CLASS);
   wc.hCursor = LoadCursor (NULL, IDC_ARROW);
-  wc.hbrBackground = NULL; // GetStockObject (WHITE_BRUSH);
+  wc.hbrBackground = NULL; /* GetStockObject (WHITE_BRUSH);  */
   wc.lpszMenuName = NULL;
   wc.lpszClassName = EMACS_CLASS;
 
@@ -2584,7 +2923,7 @@ win32_init_class (hinst)
 }
 
 HWND 
-win32_createscrollbar (f, bar)
+w32_createscrollbar (f, bar)
      struct frame *f;
      struct scroll_bar * bar;
 {
@@ -2592,61 +2931,65 @@ win32_createscrollbar (f, bar)
                        /* Position and size of scroll bar.  */
                        XINT(bar->left), XINT(bar->top), 
                        XINT(bar->width), XINT(bar->height),
-                       FRAME_WIN32_WINDOW (f),
+                       FRAME_W32_WINDOW (f),
                        NULL,
                        hinst,
                        NULL));
 }
 
 void 
-win32_createwindow (f)
+w32_createwindow (f)
      struct frame *f;
 {
   HWND hwnd;
+  RECT rect;
+
+  rect.left = rect.top = 0;
+  rect.right = PIXEL_WIDTH (f);
+  rect.bottom = PIXEL_HEIGHT (f);
+      
+  AdjustWindowRect (&rect, f->output_data.w32->dwStyle,
+                   FRAME_EXTERNAL_MENU_BAR (f));
   
   /* Do first time app init */
   
   if (!hprevinst)
     {
-      win32_init_class (hinst);
+      w32_init_class (hinst);
     }
   
-  FRAME_WIN32_WINDOW (f) = hwnd = CreateWindow (EMACS_CLASS,
-                                               f->namebuf,
-                                               f->output_data.win32->dwStyle | WS_CLIPCHILDREN,
-                                               f->output_data.win32->left_pos,
-                                               f->output_data.win32->top_pos,
-                                               PIXEL_WIDTH (f),
-                                               PIXEL_HEIGHT (f),
-                                               NULL,
-                                               NULL,
-                                               hinst,
-                                               NULL);
-  
+  FRAME_W32_WINDOW (f) = hwnd
+    = CreateWindow (EMACS_CLASS,
+                   f->namebuf,
+                   f->output_data.w32->dwStyle | WS_CLIPCHILDREN,
+                   f->output_data.w32->left_pos,
+                   f->output_data.w32->top_pos,
+                   rect.right - rect.left,
+                   rect.bottom - rect.top,
+                   NULL,
+                   NULL,
+                   hinst,
+                   NULL);
+
   if (hwnd)
     {
-      SetWindowLong (hwnd, WND_X_UNITS_INDEX, FONT_WIDTH (f->output_data.win32->font));
-      SetWindowLong (hwnd, WND_Y_UNITS_INDEX, f->output_data.win32->line_height);
-      SetWindowLong (hwnd, WND_BACKGROUND_INDEX, f->output_data.win32->background_pixel);
-
+      SetWindowLong (hwnd, WND_FONTWIDTH_INDEX, FONT_WIDTH (f->output_data.w32->font));
+      SetWindowLong (hwnd, WND_LINEHEIGHT_INDEX, f->output_data.w32->line_height);
+      SetWindowLong (hwnd, WND_BORDER_INDEX, f->output_data.w32->internal_border_width);
+      SetWindowLong (hwnd, WND_SCROLLBAR_INDEX, f->output_data.w32->vertical_scroll_bar_extra);
+      SetWindowLong (hwnd, WND_BACKGROUND_INDEX, f->output_data.w32->background_pixel);
+
+      /* Enable drag-n-drop.  */
+      DragAcceptFiles (hwnd, TRUE);
+      
       /* Do this to discard the default setting specified by our parent. */
       ShowWindow (hwnd, SW_HIDE);
     }
 }
 
-/* Convert between the modifier bits Win32 uses and the modifier bits
-   Emacs uses.  */
-unsigned int
-win32_get_modifiers ()
-{
-  return (((GetKeyState (VK_SHIFT)&0x8000)   ? shift_modifier  : 0) |
-         ((GetKeyState (VK_CONTROL)&0x8000) ? ctrl_modifier   : 0) |
-         ((GetKeyState (VK_MENU)&0x8000)    ? meta_modifier   : 0));
-}
-
 void 
 my_post_msg (wmsg, hwnd, msg, wParam, lParam)
-     Win32Msg * wmsg;
+     W32Msg * wmsg;
      HWND hwnd;
      UINT msg;
      WPARAM wParam;
@@ -2661,7 +3004,7 @@ my_post_msg (wmsg, hwnd, msg, wParam, lParam)
   post_msg (wmsg);
 }
 
-/* GetKeyState and MapVirtualKey on Win95 do not actually distinguish
+/* GetKeyState and MapVirtualKey on Windows 95 do not actually distinguish
    between left and right keys as advertised.  We test for this
    support dynamically, and set a flag when the support is absent.  If
    absent, we keep track of the left and right control and alt keys
@@ -2745,15 +3088,53 @@ record_keyup (unsigned int wparam, unsigned int lparam)
    we cannot reconstruct the left and right modifier state.  */
 static void
 reset_modifiers ()
+{
+  SHORT ctrl, alt;
+
+  if (!modifiers_recorded)
+    return;
+
+  ctrl = GetAsyncKeyState (VK_CONTROL);
+  alt = GetAsyncKeyState (VK_MENU);
+
+  if (ctrl == 0 || alt == 0)
+    /* Emacs doesn't have keyboard focus.  Do nothing.  */
+    return;
+
+  if (!(ctrl & 0x08000))
+    /* Clear any recorded control modifier state.  */
+    modifiers[EMACS_RCONTROL] = modifiers[EMACS_LCONTROL] = 0;
+
+  if (!(alt & 0x08000))
+    /* Clear any recorded alt modifier state.  */
+    modifiers[EMACS_RMENU] = modifiers[EMACS_LMENU] = 0;
+
+  /* Otherwise, leave the modifier state as it was when Emacs lost
+     keyboard focus.  */
+}
+
+/* Synchronize modifier state with what is reported with the current
+   keystroke.  Even if we cannot distinguish between left and right
+   modifier keys, we know that, if no modifiers are set, then neither
+   the left or right modifier should be set.  */
+static void
+sync_modifiers ()
 {
   if (!modifiers_recorded)
     return;
-  bzero (modifiers, sizeof (modifiers));
+
+  if (!(GetKeyState (VK_CONTROL) & 0x8000)) 
+    modifiers[EMACS_RCONTROL] = modifiers[EMACS_LCONTROL] = 0;
+
+  if (!(GetKeyState (VK_MENU) & 0x8000)) 
+    modifiers[EMACS_RMENU] = modifiers[EMACS_LMENU] = 0;
 }
 
 static int
 modifier_set (int vkey)
 {
+  if (vkey == VK_CAPITAL || vkey == VK_SCROLL)
+    return (GetKeyState (vkey) & 0x1);
   if (!modifiers_recorded)
     return (GetKeyState (vkey) & 0x8000);
 
@@ -2767,144 +3148,431 @@ modifier_set (int vkey)
       return modifiers[EMACS_LMENU];
     case VK_RMENU:
       return modifiers[EMACS_RMENU];
-    case VK_CAPITAL:
-      return (GetKeyState (vkey) & 0x1);
-    default:
-      break;
     }
   return (GetKeyState (vkey) & 0x8000);
 }
 
+/* Convert between the modifier bits W32 uses and the modifier bits
+   Emacs uses.  */
+
+unsigned int
+w32_key_to_modifier (int key)
+{
+  Lisp_Object key_mapping;
+
+  switch (key)
+    {
+    case VK_LWIN:
+      key_mapping = Vw32_lwindow_modifier;
+      break;
+    case VK_RWIN:
+      key_mapping = Vw32_rwindow_modifier;
+      break;
+    case VK_APPS:
+      key_mapping = Vw32_apps_modifier;
+      break;
+    case VK_SCROLL:
+      key_mapping = Vw32_scroll_lock_modifier;
+      break;
+    default:
+      key_mapping = Qnil;
+    }
+
+  if (EQ (key_mapping, intern ("hyper")))
+    return hyper_modifier;
+  if (EQ (key_mapping, intern ("super")))
+    return super_modifier;
+  if (EQ (key_mapping, intern ("meta")))
+    return meta_modifier;
+  if (EQ (key_mapping, intern ("alt")))
+    return alt_modifier;
+  if (EQ (key_mapping, intern ("ctrl")))
+    return ctrl_modifier;
+  if (EQ (key_mapping, intern ("control"))) /* synonym for ctrl */
+    return ctrl_modifier;
+  if (EQ (key_mapping, intern ("shift")))
+    return shift_modifier;
+
+  /* Don't generate any modifier if not explicitly requested.  */
+  return 0;
+}
+
+unsigned int
+w32_get_modifiers ()
+{
+  return ((modifier_set (VK_SHIFT)   ? shift_modifier : 0) |
+         (modifier_set (VK_CONTROL) ? ctrl_modifier  : 0) |
+         (modifier_set (VK_LWIN)    ? w32_key_to_modifier (VK_LWIN) : 0) |
+         (modifier_set (VK_RWIN)    ? w32_key_to_modifier (VK_RWIN) : 0) |
+         (modifier_set (VK_APPS)    ? w32_key_to_modifier (VK_APPS) : 0) |
+         (modifier_set (VK_SCROLL)  ? w32_key_to_modifier (VK_SCROLL) : 0) |
+          (modifier_set (VK_MENU)    ?
+          ((NILP (Vw32_alt_is_meta)) ? alt_modifier : meta_modifier) : 0));
+}
+
 /* We map the VK_* modifiers into console modifier constants
    so that we can use the same routines to handle both console
    and window input.  */
 
 static int
-construct_modifiers (unsigned int wparam, unsigned int lparam)
+construct_console_modifiers ()
 {
   int mods;
 
-  if (wparam != VK_CONTROL && wparam != VK_MENU)
-    mods = GetLastError ();
-
   mods = 0;
   mods |= (modifier_set (VK_SHIFT)) ? SHIFT_PRESSED : 0;
   mods |= (modifier_set (VK_CAPITAL)) ? CAPSLOCK_ON : 0;
+  mods |= (modifier_set (VK_SCROLL)) ? SCROLLLOCK_ON : 0;
+  mods |= (modifier_set (VK_NUMLOCK)) ? NUMLOCK_ON : 0;
   mods |= (modifier_set (VK_LCONTROL)) ? LEFT_CTRL_PRESSED : 0;
   mods |= (modifier_set (VK_RCONTROL)) ? RIGHT_CTRL_PRESSED : 0;
   mods |= (modifier_set (VK_LMENU)) ? LEFT_ALT_PRESSED : 0;
   mods |= (modifier_set (VK_RMENU)) ? RIGHT_ALT_PRESSED : 0;
+  mods |= (modifier_set (VK_LWIN)) ? LEFT_WIN_PRESSED : 0;
+  mods |= (modifier_set (VK_RWIN)) ? RIGHT_WIN_PRESSED : 0;
+  mods |= (modifier_set (VK_APPS)) ? APPS_PRESSED : 0;
 
   return mods;
 }
 
-static unsigned int
-map_keypad_keys (unsigned int wparam, unsigned int lparam)
+static int
+w32_get_key_modifiers (unsigned int wparam, unsigned int lparam)
 {
-  unsigned int extended = (lparam & 0x1000000L);
+  int mods;
+
+  /* Convert to emacs modifiers.  */
+  mods = w32_kbd_mods_to_emacs (construct_console_modifiers (), wparam);
+
+  return mods;
+}
 
-  if (wparam < VK_CLEAR || wparam > VK_DELETE)
-    return wparam;
+unsigned int
+map_keypad_keys (unsigned int virt_key, unsigned int extended)
+{
+  if (virt_key < VK_CLEAR || virt_key > VK_DELETE)
+    return virt_key;
 
-  if (wparam == VK_RETURN)
+  if (virt_key == VK_RETURN)
     return (extended ? VK_NUMPAD_ENTER : VK_RETURN);
 
-  if (wparam >= VK_PRIOR && wparam <= VK_DOWN)
-    return (!extended ? (VK_NUMPAD_PRIOR + (wparam - VK_PRIOR)) : wparam);
+  if (virt_key >= VK_PRIOR && virt_key <= VK_DOWN)
+    return (!extended ? (VK_NUMPAD_PRIOR + (virt_key - VK_PRIOR)) : virt_key);
 
-  if (wparam == VK_INSERT || wparam == VK_DELETE)
-    return (!extended ? (VK_NUMPAD_INSERT + (wparam - VK_INSERT)) : wparam);
+  if (virt_key == VK_INSERT || virt_key == VK_DELETE)
+    return (!extended ? (VK_NUMPAD_INSERT + (virt_key - VK_INSERT)) : virt_key);
 
-  if (wparam == VK_CLEAR)
-    return (!extended ? VK_NUMPAD_CLEAR : wparam);
+  if (virt_key == VK_CLEAR)
+    return (!extended ? VK_NUMPAD_CLEAR : virt_key);
 
-  return wparam;
+  return virt_key;
 }
 
-/* Main message dispatch loop. */
+/* List of special key combinations which w32 would normally capture,
+   but emacs should grab instead.  Not directly visible to lisp, to
+   simplify synchronization.  Each item is an integer encoding a virtual
+   key code and modifier combination to capture.  */
+Lisp_Object w32_grabbed_keys;
 
-DWORD 
-win_msg_worker (dw)
-     DWORD dw;
+#define HOTKEY(vk,mods)       make_number (((vk) & 255) | ((mods) << 8))
+#define HOTKEY_ID(k)          (XFASTINT (k) & 0xbfff)
+#define HOTKEY_VK_CODE(k)     (XFASTINT (k) & 255)
+#define HOTKEY_MODIFIERS(k)   (XFASTINT (k) >> 8)
+
+/* Register hot-keys for reserved key combinations when Emacs has
+   keyboard focus, since this is the only way Emacs can receive key
+   combinations like Alt-Tab which are used by the system.  */
+
+static void
+register_hot_keys (hwnd)
+     HWND hwnd;
 {
-  MSG msg;
-  
-  /* Ensure our message queue is created */
-  
-  PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE);
-  
-  PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0);
-  
-  while (GetMessage (&msg, NULL, 0, 0))
+  Lisp_Object keylist;
+
+  /* Use GC_CONSP, since we are called asynchronously.  */
+  for (keylist = w32_grabbed_keys; GC_CONSP (keylist); keylist = XCDR (keylist))
     {
-      if (msg.hwnd == NULL)
-       {
-         switch (msg.message)
-           {
-           case WM_TIMER:
-             if (saved_mouse_msg.msg.hwnd)
-               {
-                 Win32Msg wmsg = saved_mouse_msg;
-                 my_post_msg (&wmsg, wmsg.msg.hwnd, wmsg.msg.message,
-                              wmsg.msg.wParam, wmsg.msg.lParam);
-                 saved_mouse_msg.msg.hwnd = 0;
-               }
-             timer_id = 0;
-             break;
-           case WM_EMACS_CREATEWINDOW:
-             win32_createwindow ((struct frame *) msg.wParam);
-             PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0);
-             break;
-           case WM_EMACS_CREATESCROLLBAR:
-             {
-               HWND hwnd = win32_createscrollbar ((struct frame *) msg.wParam,
-                                                  (struct scroll_bar *) msg.lParam);
-               PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, (WPARAM)hwnd, 0);
-             }
-             break;
-           case WM_EMACS_KILL:
-             return (0);
-           }
-       }
-      else
-       {
-         DispatchMessage (&msg);
-       }
+      Lisp_Object key = XCAR (keylist);
+
+      /* Deleted entries get set to nil.  */
+      if (!INTEGERP (key))
+       continue;
+
+      RegisterHotKey (hwnd, HOTKEY_ID (key),
+                     HOTKEY_MODIFIERS (key), HOTKEY_VK_CODE (key));
     }
-  
-  return (0);
 }
 
-/* Main window procedure */
-
-extern char *lispy_function_keys[];
+static void
+unregister_hot_keys (hwnd)
+     HWND hwnd;
+{
+  Lisp_Object keylist;
+
+  /* Use GC_CONSP, since we are called asynchronously.  */
+  for (keylist = w32_grabbed_keys; GC_CONSP (keylist); keylist = XCDR (keylist))
+    {
+      Lisp_Object key = XCAR (keylist);
+
+      if (!INTEGERP (key))
+       continue;
+
+      UnregisterHotKey (hwnd, HOTKEY_ID (key));
+    }
+}
+
+static void
+post_character_message (hwnd, msg, wParam, lParam, modifiers)
+     HWND hwnd;
+     UINT msg;
+     WPARAM wParam;
+     LPARAM lParam;
+     DWORD  modifiers;
+
+{
+  W32Msg wmsg;
+
+  wmsg.dwModifiers = modifiers;
+
+  /* Detect quit_char and set quit-flag directly.  Note that we
+     still need to post a message to ensure the main thread will be
+     woken up if blocked in sys_select(), but we do NOT want to post
+     the quit_char message itself (because it will usually be as if
+     the user had typed quit_char twice).  Instead, we post a dummy
+     message that has no particular effect. */
+  {
+    int c = wParam;
+    if (isalpha (c) && wmsg.dwModifiers == ctrl_modifier)
+      c = make_ctrl_char (c) & 0377;
+    if (c == quit_char)
+      {
+       Vquit_flag = Qt;
+
+       /* The choice of message is somewhat arbitrary, as long as
+          the main thread handler just ignores it. */
+       msg = WM_NULL;
+
+       /* Interrupt any blocking system calls.  */
+       signal_quit ();
+      }
+  }
+
+  my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
+}
+
+/* Main message dispatch loop. */
+
+static void
+w32_msg_pump (deferred_msg * msg_buf)
+{
+  MSG msg;
+  int result;
+  HWND focus_window;
+
+  msh_mousewheel = RegisterWindowMessage (MSH_MOUSEWHEEL);
+  
+  while (GetMessage (&msg, NULL, 0, 0))
+    {
+      if (msg.hwnd == NULL)
+       {
+         switch (msg.message)
+           {
+           case WM_EMACS_CREATEWINDOW:
+             w32_createwindow ((struct frame *) msg.wParam);
+             if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
+               abort ();
+             break;
+           case WM_EMACS_SETLOCALE:
+             SetThreadLocale (msg.wParam);
+             /* Reply is not expected.  */
+             break;
+           case WM_EMACS_SETKEYBOARDLAYOUT:
+             result = (int) ActivateKeyboardLayout ((HKL) msg.wParam, 0);
+             if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE,
+                                     result, 0))
+               abort ();
+             break;
+           case WM_EMACS_REGISTER_HOT_KEY:
+             focus_window = GetFocus ();
+             if (focus_window != NULL)
+               RegisterHotKey (focus_window,
+                               HOTKEY_ID (msg.wParam),
+                               HOTKEY_MODIFIERS (msg.wParam),
+                               HOTKEY_VK_CODE (msg.wParam));
+             /* Reply is not expected.  */
+             break;
+           case WM_EMACS_UNREGISTER_HOT_KEY:
+             focus_window = GetFocus ();
+             if (focus_window != NULL)
+               UnregisterHotKey (focus_window, HOTKEY_ID (msg.wParam));
+             /* Mark item as erased.  */
+             XCAR ((Lisp_Object) msg.lParam) = Qnil;
+             if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
+               abort ();
+             break;
+           default:
+             DebPrint (("msg %x not expected by w32_msg_pump\n", msg.message));
+           }
+       }
+      else
+       {
+         DispatchMessage (&msg);
+       }
+
+      /* Exit nested loop when our deferred message has completed.  */
+      if (msg_buf->completed)
+       break;
+    }
+}
+
+deferred_msg * deferred_msg_head;
+
+static deferred_msg *
+find_deferred_msg (HWND hwnd, UINT msg)
+{
+  deferred_msg * item;
+
+  /* Don't actually need synchronization for read access, since
+     modification of single pointer is always atomic.  */
+  /* enter_crit (); */
+
+  for (item = deferred_msg_head; item != NULL; item = item->next)
+    if (item->w32msg.msg.hwnd == hwnd
+       && item->w32msg.msg.message == msg)
+      break;
+
+  /* leave_crit (); */
+
+  return item;
+}
+
+static LRESULT
+send_deferred_msg (deferred_msg * msg_buf,
+                  HWND hwnd,
+                  UINT msg,
+                  WPARAM wParam,
+                  LPARAM lParam)
+{
+  /* Only input thread can send deferred messages.  */
+  if (GetCurrentThreadId () != dwWindowsThreadId)
+    abort ();
+
+  /* It is an error to send a message that is already deferred.  */
+  if (find_deferred_msg (hwnd, msg) != NULL)
+    abort ();
+
+  /* Enforced synchronization is not needed because this is the only
+     function that alters deferred_msg_head, and the following critical
+     section is guaranteed to only be serially reentered (since only the
+     input thread can call us).  */
+
+  /* enter_crit (); */
+
+  msg_buf->completed = 0;
+  msg_buf->next = deferred_msg_head;
+  deferred_msg_head = msg_buf;
+  my_post_msg (&msg_buf->w32msg, hwnd, msg, wParam, lParam);
+
+  /* leave_crit (); */
+
+  /* Start a new nested message loop to process other messages until
+     this one is completed.  */
+  w32_msg_pump (msg_buf);
+
+  deferred_msg_head = msg_buf->next;
+
+  return msg_buf->result;
+}
+
+void
+complete_deferred_msg (HWND hwnd, UINT msg, LRESULT result)
+{
+  deferred_msg * msg_buf = find_deferred_msg (hwnd, msg);
+
+  if (msg_buf == NULL)
+    abort ();
+
+  msg_buf->result = result;
+  msg_buf->completed = 1;
+
+  /* Ensure input thread is woken so it notices the completion.  */
+  PostThreadMessage (dwWindowsThreadId, WM_NULL, 0, 0);
+}
+
+
+DWORD 
+w32_msg_worker (dw)
+     DWORD dw;
+{
+  MSG msg;
+  deferred_msg dummy_buf;
+
+  /* Ensure our message queue is created */
+  
+  PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE);
+  
+  if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
+    abort ();
+
+  memset (&dummy_buf, 0, sizeof (dummy_buf));
+  dummy_buf.w32msg.msg.hwnd = NULL;
+  dummy_buf.w32msg.msg.message = WM_NULL;
+
+  /* This is the inital message loop which should only exit when the
+     application quits.  */
+  w32_msg_pump (&dummy_buf);
+
+  return 0;
+}
+
+/* Main window procedure */
 
 LRESULT CALLBACK 
-win32_wnd_proc (hwnd, msg, wParam, lParam)
+w32_wnd_proc (hwnd, msg, wParam, lParam)
      HWND hwnd;
      UINT msg;
      WPARAM wParam;
      LPARAM lParam;
 {
   struct frame *f;
-  LRESULT ret = 1;
-  struct win32_display_info *dpyinfo = &one_win32_display_info;
-  Win32Msg wmsg;
-  
+  struct w32_display_info *dpyinfo = &one_w32_display_info;
+  W32Msg wmsg;
+  int windows_translate;
+
+  /* Note that it is okay to call x_window_to_frame, even though we are
+     not running in the main lisp thread, because frame deletion
+     requires the lisp thread to synchronize with this thread.  Thus, if
+     a frame struct is returned, it can be used without concern that the
+     lisp thread might make it disappear while we are using it.
+
+     NB. Walking the frame list in this thread is safe (as long as
+     writes of Lisp_Object slots are atomic, which they are on Windows).
+     Although delete-frame can destructively modify the frame list while
+     we are walking it, a garbage collection cannot occur until after
+     delete-frame has synchronized with this thread.
+
+     It is also safe to use functions that make GDI calls, such as
+     w32_clear_rect, because these functions must obtain a DC handle
+     from the frame struct using get_frame_dc which is thread-aware.  */
+
   switch (msg) 
     {
     case WM_ERASEBKGND:
-      enter_crit ();
-      GetUpdateRect (hwnd, &wmsg.rect, FALSE);
-      leave_crit ();
-      my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
+      f = x_window_to_frame (dpyinfo, hwnd);
+      if (f)
+       {
+         GetUpdateRect (hwnd, &wmsg.rect, FALSE);
+         w32_clear_rect (f, NULL, &wmsg.rect);
+       }
       return 1;
     case WM_PALETTECHANGED:
       /* ignore our own changes */
       if ((HWND)wParam != hwnd)
         {
-         /* simply notify main thread it may need to update frames */
-         my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
+         f = x_window_to_frame (dpyinfo, hwnd);
+         if (f)
+           /* get_frame_dc will realize our palette and force all
+              frames to be redrawn if needed. */
+           release_frame_dc (f, get_frame_dc (f));
        }
       return 0;
     case WM_PAINT:
@@ -2922,6 +3590,43 @@ win32_wnd_proc (hwnd, msg, wParam, lParam)
        return (0);
       }
 
+    case WM_INPUTLANGCHANGE:
+      /* Inform lisp thread of keyboard layout changes.  */
+      my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
+
+      /* Clear dead keys in the keyboard state; for simplicity only
+         preserve modifier key states.  */
+      {
+       int i;
+       BYTE keystate[256];
+
+       GetKeyboardState (keystate);
+       for (i = 0; i < 256; i++)
+         if (1
+             && i != VK_SHIFT
+             && i != VK_LSHIFT
+             && i != VK_RSHIFT
+             && i != VK_CAPITAL
+             && i != VK_NUMLOCK
+             && i != VK_SCROLL
+             && i != VK_CONTROL
+             && i != VK_LCONTROL
+             && i != VK_RCONTROL
+             && i != VK_MENU
+             && i != VK_LMENU
+             && i != VK_RMENU
+             && i != VK_LWIN
+             && i != VK_RWIN)
+           keystate[i] = 0;
+       SetKeyboardState (keystate);
+      }
+      goto dflt;
+
+    case WM_HOTKEY:
+      /* Synchronize hot keys with normal input.  */
+      PostMessage (hwnd, WM_KEYDOWN, HIWORD (lParam), 0);
+      return (0);
+
     case WM_KEYUP:
     case WM_SYSKEYUP:
       record_keyup (wParam, lParam);
@@ -2929,70 +3634,192 @@ win32_wnd_proc (hwnd, msg, wParam, lParam)
 
     case WM_KEYDOWN:
     case WM_SYSKEYDOWN:
+      /* Ignore keystrokes we fake ourself; see below.  */
+      if (dpyinfo->faked_key == wParam)
+       {
+         dpyinfo->faked_key = 0;
+         return 0;
+       }
+
+      /* Synchronize modifiers with current keystroke.  */
+      sync_modifiers ();
       record_keydown (wParam, lParam);
+      wParam = map_keypad_keys (wParam, (lParam & 0x1000000L) != 0);
 
-      wParam = map_keypad_keys (wParam, lParam);
-      
-      switch (wParam) {
-      case VK_LWIN:
-      case VK_RWIN:
-      case VK_APPS:
-       /* More support for these keys will likely be necessary.  */
-       if (!NILP (Vwin32_pass_optional_keys_to_system))
-         goto dflt;
-       break;
-      case VK_MENU:
-       if (NILP (Vwin32_pass_alt_to_system)) 
+      windows_translate = 0;
+
+      switch (wParam)
+       {
+       case VK_LWIN:
+         if (NILP (Vw32_pass_lwindow_to_system))
+           {
+             /* Prevent system from acting on keyup (which opens the
+                Start menu if no other key was pressed) by simulating a
+                press of Space which we will ignore.  */
+             if (GetAsyncKeyState (wParam) & 1)
+               {
+                 dpyinfo->faked_key = VK_SPACE;
+                 keybd_event (VK_SPACE,
+                              (BYTE) MapVirtualKey (VK_SPACE, 0), 0, 0);
+               }
+           }
+         if (!NILP (Vw32_lwindow_modifier))
+           return 0;
+         break;
+       case VK_RWIN:
+         if (NILP (Vw32_pass_rwindow_to_system))
+           {
+             if (GetAsyncKeyState (wParam) & 1)
+               {
+                 dpyinfo->faked_key = VK_SPACE;
+                 keybd_event (VK_SPACE,
+                              (BYTE) MapVirtualKey (VK_SPACE, 0), 0, 0);
+               }
+           }
+         if (!NILP (Vw32_rwindow_modifier))
+           return 0;
+         break;
+       case VK_APPS:
+         if (!NILP (Vw32_apps_modifier))
+           return 0;
+         break;
+       case VK_MENU:
+         if (NILP (Vw32_pass_alt_to_system)) 
+           return 0;
+         windows_translate = 1;
+         break;
+       case VK_CAPITAL: 
+         /* Decide whether to treat as modifier or function key.  */
+         if (NILP (Vw32_enable_caps_lock))
+           goto disable_lock_key;
          return 0;
-       else 
+       case VK_NUMLOCK:
+         /* Decide whether to treat as modifier or function key.  */
+         if (NILP (Vw32_enable_num_lock))
+           goto disable_lock_key;
+         return 0;
+       case VK_SCROLL:
+         /* Decide whether to treat as modifier or function key.  */
+         if (NILP (Vw32_scroll_lock_modifier))
+           goto disable_lock_key;
+         return 0;
+       disable_lock_key:
+         /* Ensure the appropriate lock key state is off (and the
+             indicator light as well).  */
+         if (GetAsyncKeyState (wParam) & 0x8000)
+           {
+             /* Fake another press of the relevant key.  Apparently,
+                 this really is the only way to turn off the indicator.  */
+             dpyinfo->faked_key = wParam;
+             keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
+                          KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
+             keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
+                          KEYEVENTF_EXTENDEDKEY | 0, 0);
+             keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
+                          KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
+           }
+         break;
+       case VK_CONTROL: 
+       case VK_SHIFT:
+       case VK_PROCESSKEY:  /* Generated by IME.  */
+         windows_translate = 1;
+         break;
+       default:
+         /* If not defined as a function key, change it to a WM_CHAR message. */
+         if (lispy_function_keys[wParam] == 0)
+           {
+             if (!NILP (Vw32_recognize_altgr)
+                 && modifier_set (VK_LCONTROL) && modifier_set (VK_RMENU))
+               {
+                 /* Always let TranslateMessage handle AltGr key chords;
+                    for some reason, ToAscii doesn't always process AltGr
+                    chords correctly.  */
+                 windows_translate = 1;
+               }
+             else if (modifier_set (VK_CONTROL) || modifier_set (VK_MENU))
+               {
+                 /* Handle key chords including any modifiers other than shift
+                    directly, in order to preserve as much modifier information as
+                    possible.  */
+                 if ('A' <= wParam && wParam <= 'Z')
+                   {
+                     /* Don't translate modified alphabetic keystrokes,
+                        so the user doesn't need to constantly switch
+                        layout to type control or meta keystrokes when
+                        the normal layout translates alphabetic
+                        characters to non-ascii characters.  */
+                     if (!modifier_set (VK_SHIFT))
+                       wParam += ('a' - 'A');
+                     msg = WM_CHAR;
+                   }
+                 else
+                   {
+                     /* Try to handle other keystrokes by determining the
+                        base character (ie. translating the base key plus
+                        shift modifier).  */
+                     int add;
+                     int isdead = 0;
+                     KEY_EVENT_RECORD key;
+                 
+                     key.bKeyDown = TRUE;
+                     key.wRepeatCount = 1;
+                     key.wVirtualKeyCode = wParam;
+                     key.wVirtualScanCode = (lParam & 0xFF0000) >> 16;
+                     key.uChar.AsciiChar = 0;
+                     key.dwControlKeyState = construct_console_modifiers ();
+
+                     add = w32_kbd_patch_key (&key);
+                     /* 0 means an unrecognised keycode, negative means
+                        dead key.  Ignore both.  */
+                     while (--add >= 0)
+                       {
+                         /* Forward asciified character sequence.  */
+                         post_character_message
+                           (hwnd, WM_CHAR, key.uChar.AsciiChar, lParam,
+                            w32_get_key_modifiers (wParam, lParam));
+                         w32_kbd_patch_key (&key);
+                       }
+                     return 0;
+                   }
+               }
+             else
+               {
+                 /* Let TranslateMessage handle everything else.  */
+                 windows_translate = 1;
+               }
+           }
+       }
+
+      if (windows_translate)
+       {
+         MSG windows_msg = { hwnd, msg, wParam, lParam, 0, {0,0} };
+
+         windows_msg.time = GetMessageTime ();
+         TranslateMessage (&windows_msg);
          goto dflt;
-      case VK_CONTROL: 
-      case VK_CAPITAL: 
-      case VK_SHIFT:
-       /* Pass on to Windows.  */
-       goto dflt;
-      default:
-       /* If not defined as a function key, change it to a WM_CHAR message. */
-       if (lispy_function_keys[wParam] == 0)
-         msg = WM_CHAR;
-       break;
-      }
+       }
 
       /* Fall through */
       
     case WM_SYSCHAR:
     case WM_CHAR:
-      wmsg.dwModifiers = construct_modifiers (wParam, lParam);
-
-      enter_crit ();
-      my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
-
-      /* Detect quit_char and set quit-flag directly.  Note that we dow
-         this *after* posting the message to ensure the main thread will
-         be woken up if blocked in sys_select(). */
-      {
-       int c = wParam;
-       if (isalpha (c) && (wmsg.dwModifiers == LEFT_CTRL_PRESSED 
-                           || wmsg.dwModifiers == RIGHT_CTRL_PRESSED))
-         c = make_ctrl_char (c) & 0377;
-       if (c == quit_char)
-         Vquit_flag = Qt;
-      }
-      leave_crit ();
+      post_character_message (hwnd, msg, wParam, lParam,
+                             w32_get_key_modifiers (wParam, lParam));
       break;
 
       /* Simulate middle mouse button events when left and right buttons
         are used together, but only if user has two button mouse. */
     case WM_LBUTTONDOWN:
     case WM_RBUTTONDOWN:
-      if (XINT (Vwin32_num_mouse_buttons) == 3)
+      if (XINT (Vw32_num_mouse_buttons) == 3)
        goto handle_plain_button;
 
       {
        int this = (msg == WM_LBUTTONDOWN) ? LMOUSE : RMOUSE;
        int other = (msg == WM_LBUTTONDOWN) ? RMOUSE : LMOUSE;
 
-       if (button_state & this) abort ();
+       if (button_state & this)
+         return 0;
 
        if (button_state == 0)
          SetCapture (hwnd);
@@ -3001,10 +3828,10 @@ win32_wnd_proc (hwnd, msg, wParam, lParam)
 
        if (button_state & other)
          {
-           if (timer_id)
+           if (mouse_button_timer)
              {
-               KillTimer (NULL, timer_id);
-               timer_id = 0;
+               KillTimer (hwnd, mouse_button_timer);
+               mouse_button_timer = 0;
 
                /* Generate middle mouse event instead. */
                msg = WM_MBUTTONDOWN;
@@ -3021,41 +3848,40 @@ win32_wnd_proc (hwnd, msg, wParam, lParam)
            else
              {
                /* Flush out saved message. */
-               wmsg = saved_mouse_msg;
-               my_post_msg (&wmsg, wmsg.msg.hwnd, wmsg.msg.message,
-                            wmsg.msg.wParam, wmsg.msg.lParam);
+               post_msg (&saved_mouse_button_msg);
              }
-           wmsg.dwModifiers = win32_get_modifiers ();
+           wmsg.dwModifiers = w32_get_modifiers ();
            my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
 
            /* Clear message buffer. */
-           saved_mouse_msg.msg.hwnd = 0;
+           saved_mouse_button_msg.msg.hwnd = 0;
          }
        else
          {
            /* Hold onto message for now. */
-           timer_id =
-             SetTimer (NULL, 0, XINT (Vwin32_mouse_button_tolerance), NULL);
-           saved_mouse_msg.msg.hwnd = hwnd;
-           saved_mouse_msg.msg.message = msg;
-           saved_mouse_msg.msg.wParam = wParam;
-           saved_mouse_msg.msg.lParam = lParam;
-           saved_mouse_msg.msg.time = GetMessageTime ();
-           saved_mouse_msg.dwModifiers = win32_get_modifiers ();
+           mouse_button_timer =
+             SetTimer (hwnd, MOUSE_BUTTON_ID, XINT (Vw32_mouse_button_tolerance), NULL);
+           saved_mouse_button_msg.msg.hwnd = hwnd;
+           saved_mouse_button_msg.msg.message = msg;
+           saved_mouse_button_msg.msg.wParam = wParam;
+           saved_mouse_button_msg.msg.lParam = lParam;
+           saved_mouse_button_msg.msg.time = GetMessageTime ();
+           saved_mouse_button_msg.dwModifiers = w32_get_modifiers ();
          }
       }
       return 0;
 
     case WM_LBUTTONUP:
     case WM_RBUTTONUP:
-      if (XINT (Vwin32_num_mouse_buttons) == 3)
+      if (XINT (Vw32_num_mouse_buttons) == 3)
        goto handle_plain_button;
 
       {
        int this = (msg == WM_LBUTTONUP) ? LMOUSE : RMOUSE;
        int other = (msg == WM_LBUTTONUP) ? RMOUSE : LMOUSE;
 
-       if ((button_state & this) == 0) abort ();
+       if ((button_state & this) == 0)
+         return 0;
 
        button_state &= ~this;
 
@@ -3075,20 +3901,18 @@ win32_wnd_proc (hwnd, msg, wParam, lParam)
        else
          {
            /* Flush out saved message if necessary. */
-           if (saved_mouse_msg.msg.hwnd)
+           if (saved_mouse_button_msg.msg.hwnd)
              {
-               wmsg = saved_mouse_msg;
-               my_post_msg (&wmsg, wmsg.msg.hwnd, wmsg.msg.message,
-                            wmsg.msg.wParam, wmsg.msg.lParam);
+               post_msg (&saved_mouse_button_msg);
              }
          }
-       wmsg.dwModifiers = win32_get_modifiers ();
+       wmsg.dwModifiers = w32_get_modifiers ();
        my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
 
        /* Always clear message buffer and cancel timer. */
-       saved_mouse_msg.msg.hwnd = 0;
-       KillTimer (NULL, timer_id);
-       timer_id = 0;
+       saved_mouse_button_msg.msg.hwnd = 0;
+       KillTimer (hwnd, mouse_button_timer);
+       mouse_button_timer = 0;
 
        if (button_state == 0)
          ReleaseCapture ();
@@ -3100,53 +3924,253 @@ win32_wnd_proc (hwnd, msg, wParam, lParam)
     handle_plain_button:
       {
        BOOL up;
+       int button;
 
-       if (parse_button (msg, NULL, &up))
+       if (parse_button (msg, &button, &up))
          {
            if (up) ReleaseCapture ();
            else SetCapture (hwnd);
+           button = (button == 0) ? LMOUSE : 
+             ((button == 1) ? MMOUSE  : RMOUSE);
+           if (up)
+             button_state &= ~button;
+           else
+             button_state |= button;
          }
       }
       
-      wmsg.dwModifiers = win32_get_modifiers ();
+      wmsg.dwModifiers = w32_get_modifiers ();
       my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
       return 0;
 
-#if 0
+    case WM_VSCROLL:
     case WM_MOUSEMOVE:
-      /* Flush out saved message if necessary. */
-      if (saved_mouse_msg.msg.hwnd)
+      if (XINT (Vw32_mouse_move_interval) <= 0
+         || (msg == WM_MOUSEMOVE && button_state == 0))
+       {
+         wmsg.dwModifiers = w32_get_modifiers ();
+         my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
+         return 0;
+       }
+  
+      /* Hang onto mouse move and scroll messages for a bit, to avoid
+        sending such events to Emacs faster than it can process them.
+        If we get more events before the timer from the first message
+        expires, we just replace the first message. */
+
+      if (saved_mouse_move_msg.msg.hwnd == 0)
+       mouse_move_timer =
+         SetTimer (hwnd, MOUSE_MOVE_ID, XINT (Vw32_mouse_move_interval), NULL);
+
+      /* Hold onto message for now. */
+      saved_mouse_move_msg.msg.hwnd = hwnd;
+      saved_mouse_move_msg.msg.message = msg;
+      saved_mouse_move_msg.msg.wParam = wParam;
+      saved_mouse_move_msg.msg.lParam = lParam;
+      saved_mouse_move_msg.msg.time = GetMessageTime ();
+      saved_mouse_move_msg.dwModifiers = w32_get_modifiers ();
+  
+      return 0;
+
+    case WM_MOUSEWHEEL:
+      wmsg.dwModifiers = w32_get_modifiers ();
+      my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
+      return 0;
+
+    case WM_DROPFILES:
+      wmsg.dwModifiers = w32_get_modifiers ();
+      my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
+      return 0;
+
+    case WM_TIMER:
+      /* Flush out saved messages if necessary. */
+      if (wParam == mouse_button_timer)
        {
-         wmsg = saved_mouse_msg;
-         my_post_msg (&wmsg, wmsg.msg.hwnd, wmsg.msg.message,
-                      wmsg.msg.wParam, wmsg.msg.lParam);
+         if (saved_mouse_button_msg.msg.hwnd)
+           {
+             post_msg (&saved_mouse_button_msg);
+             saved_mouse_button_msg.msg.hwnd = 0;
+           }
+         KillTimer (hwnd, mouse_button_timer);
+         mouse_button_timer = 0;
        }
-      wmsg.dwModifiers = win32_get_modifiers ();
-      my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
+      else if (wParam == mouse_move_timer)
+       {
+         if (saved_mouse_move_msg.msg.hwnd)
+           {
+             post_msg (&saved_mouse_move_msg);
+             saved_mouse_move_msg.msg.hwnd = 0;
+           }
+         KillTimer (hwnd, mouse_move_timer);
+         mouse_move_timer = 0;
+       }
+      return 0;
+  
+    case WM_NCACTIVATE:
+      /* Windows doesn't send us focus messages when putting up and
+        taking down a system popup dialog as for Ctrl-Alt-Del on Windows 95.
+        The only indication we get that something happened is receiving
+        this message afterwards.  So this is a good time to reset our
+        keyboard modifiers' state. */
+      reset_modifiers ();
+      goto dflt;
+
+    case WM_INITMENU:
+      /* We must ensure menu bar is fully constructed and up to date
+        before allowing user interaction with it.  To achieve this
+        we send this message to the lisp thread and wait for a
+        reply (whose value is not actually needed) to indicate that
+        the menu bar is now ready for use, so we can now return.
+
+        To remain responsive in the meantime, we enter a nested message
+        loop that can process all other messages.
+
+        However, we skip all this if the message results from calling
+        TrackPopupMenu - in fact, we must NOT attempt to send the lisp
+        thread a message because it is blocked on us at this point.  We
+        set menubar_active before calling TrackPopupMenu to indicate
+        this (there is no possibility of confusion with real menubar
+        being active).  */
+
+      f = x_window_to_frame (dpyinfo, hwnd);
+      if (f
+         && (f->output_data.w32->menubar_active
+             /* We can receive this message even in the absence of a
+                menubar (ie. when the system menu is activated) - in this
+                case we do NOT want to forward the message, otherwise it
+                will cause the menubar to suddenly appear when the user
+                had requested it to be turned off!  */
+             || f->output_data.w32->menubar_widget == NULL))
+       return 0;
+
+      {
+       deferred_msg msg_buf;
+
+       /* Detect if message has already been deferred; in this case
+          we cannot return any sensible value to ignore this.  */
+       if (find_deferred_msg (hwnd, msg) != NULL)
+         abort ();
+
+       return send_deferred_msg (&msg_buf, hwnd, msg, wParam, lParam);
+      }
+
+    case WM_EXITMENULOOP:
+      f = x_window_to_frame (dpyinfo, hwnd);
+
+      /* Indicate that menubar can be modified again.  */
+      if (f)
+       f->output_data.w32->menubar_active = 0;
+      goto dflt;
+
+    case WM_MEASUREITEM:
+      f = x_window_to_frame (dpyinfo, hwnd);
+      if (f)
+       {
+         MEASUREITEMSTRUCT * pMis = (MEASUREITEMSTRUCT *) lParam;
+
+         if (pMis->CtlType == ODT_MENU)
+           {
+             /* Work out dimensions for popup menu titles. */
+             char * title = (char *) pMis->itemData;
+             HDC hdc = GetDC (hwnd);
+             HFONT menu_font = GetCurrentObject (hdc, OBJ_FONT);
+             LOGFONT menu_logfont;
+             HFONT old_font;
+             SIZE size;
+
+             GetObject (menu_font, sizeof (menu_logfont), &menu_logfont);
+             menu_logfont.lfWeight = FW_BOLD;
+             menu_font = CreateFontIndirect (&menu_logfont);
+             old_font = SelectObject (hdc, menu_font);
+
+             GetTextExtentPoint32 (hdc, title, strlen (title), &size);
+             pMis->itemWidth = size.cx;
+             pMis->itemHeight = GetSystemMetrics (SM_CYMENUSIZE);
+             if (pMis->itemHeight < size.cy)
+               pMis->itemHeight = size.cy;
+
+             SelectObject (hdc, old_font);
+             DeleteObject (menu_font);
+             ReleaseDC (hwnd, hdc);
+             return TRUE;
+           }
+       }
+      return 0;
 
-      /* Always clear message buffer and cancel timer. */
-      saved_mouse_msg.msg.hwnd = 0;
-      KillTimer (NULL, timer_id);
-      timer_id = 0;
+    case WM_DRAWITEM:
+      f = x_window_to_frame (dpyinfo, hwnd);
+      if (f)
+       {
+         DRAWITEMSTRUCT * pDis = (DRAWITEMSTRUCT *) lParam;
 
+         if (pDis->CtlType == ODT_MENU)
+           {
+             /* Draw popup menu title. */
+             char * title = (char *) pDis->itemData;
+             HDC hdc = pDis->hDC;
+             HFONT menu_font = GetCurrentObject (hdc, OBJ_FONT);
+             LOGFONT menu_logfont;
+             HFONT old_font;
+
+             GetObject (menu_font, sizeof (menu_logfont), &menu_logfont);
+             menu_logfont.lfWeight = FW_BOLD;
+             menu_font = CreateFontIndirect (&menu_logfont);
+             old_font = SelectObject (hdc, menu_font);
+
+             /* Always draw title as if not selected.  */
+             ExtTextOut (hdc,
+                         pDis->rcItem.left + GetSystemMetrics (SM_CXMENUCHECK),
+                         pDis->rcItem.top,
+                         ETO_OPAQUE, &pDis->rcItem,
+                         title, strlen (title), NULL);
+
+             SelectObject (hdc, old_font);
+             DeleteObject (menu_font);
+             return TRUE;
+           }
+       }
       return 0;
+
+#if 0
+      /* Still not right - can't distinguish between clicks in the
+        client area of the frame from clicks forwarded from the scroll
+        bars - may have to hook WM_NCHITTEST to remember the mouse
+        position and then check if it is in the client area ourselves.  */
+    case WM_MOUSEACTIVATE:
+      /* Discard the mouse click that activates a frame, allowing the
+        user to click anywhere without changing point (or worse!).
+        Don't eat mouse clicks on scrollbars though!!  */
+      if (LOWORD (lParam) == HTCLIENT )
+       return MA_ACTIVATEANDEAT;
+      goto dflt;
 #endif
 
-    case WM_SETFOCUS:
+    case WM_ACTIVATEAPP:
+      dpyinfo->faked_key = 0;
       reset_modifiers ();
-    case WM_MOUSEMOVE:
+    case WM_ACTIVATE:
+    case WM_WINDOWPOSCHANGED:
+    case WM_SHOWWINDOW:
+      /* Inform lisp thread that a frame might have just been obscured
+        or exposed, so should recheck visibility of all frames.  */
+      my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
+      goto dflt;
+
+    case WM_SETFOCUS:
+      register_hot_keys (hwnd);
+      goto command;
+    case WM_KILLFOCUS:
+      unregister_hot_keys (hwnd);
     case WM_MOVE:
     case WM_SIZE:
-    case WM_KILLFOCUS:
-    case WM_VSCROLL:
-    case WM_SYSCOMMAND:
     case WM_COMMAND:
-      wmsg.dwModifiers = win32_get_modifiers ();
+    command:
+      wmsg.dwModifiers = w32_get_modifiers ();
       my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
       goto dflt;
 
     case WM_CLOSE:
-      wmsg.dwModifiers = win32_get_modifiers ();
+      wmsg.dwModifiers = w32_get_modifiers ();
       my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
       return 0;
 
@@ -3154,16 +4178,19 @@ win32_wnd_proc (hwnd, msg, wParam, lParam)
       {
        WINDOWPLACEMENT wp;
        LPWINDOWPOS lppos = (WINDOWPOS *) lParam;
-       
+
+       wp.length = sizeof (WINDOWPLACEMENT);
        GetWindowPlacement (hwnd, &wp);
        
-       if (wp.showCmd != SW_SHOWMINIMIZED && ! (lppos->flags & SWP_NOSIZE))
+       if (wp.showCmd != SW_SHOWMINIMIZED && (lppos->flags & SWP_NOSIZE) == 0)
          {
            RECT rect;
            int wdiff;
            int hdiff;
-           DWORD dwXUnits;
-           DWORD dwYUnits;
+           DWORD font_width;
+           DWORD line_height;
+           DWORD internal_border;
+           DWORD scrollbar_extra;
            RECT wr;
            
            wp.length = sizeof(wp);
@@ -3171,8 +4198,10 @@ win32_wnd_proc (hwnd, msg, wParam, lParam)
            
            enter_crit ();
            
-           dwXUnits = GetWindowLong (hwnd, WND_X_UNITS_INDEX);
-           dwYUnits = GetWindowLong (hwnd, WND_Y_UNITS_INDEX);
+           font_width = GetWindowLong (hwnd, WND_FONTWIDTH_INDEX);
+           line_height = GetWindowLong (hwnd, WND_LINEHEIGHT_INDEX);
+           internal_border = GetWindowLong (hwnd, WND_BORDER_INDEX);
+           scrollbar_extra = GetWindowLong (hwnd, WND_SCROLLBAR_INDEX);
            
            leave_crit ();
            
@@ -3180,10 +4209,14 @@ win32_wnd_proc (hwnd, msg, wParam, lParam)
            AdjustWindowRect (&rect, GetWindowLong (hwnd, GWL_STYLE), 
                              GetMenu (hwnd) != NULL);
 
-           /* All windows have an extra pixel so subtract 1 */
-           
-           wdiff = (lppos->cx - (rect.right - rect.left) - 0) % dwXUnits;
-           hdiff = (lppos->cy - (rect.bottom - rect.top) - 0) % dwYUnits;
+           /* Force width and height of client area to be exact
+              multiples of the character cell dimensions.  */
+           wdiff = (lppos->cx - (rect.right - rect.left)
+                    - 2 * internal_border - scrollbar_extra)
+             % font_width;
+           hdiff = (lppos->cy - (rect.bottom - rect.top)
+                    - 2 * internal_border)
+             % line_height;
            
            if (wdiff || hdiff)
              {
@@ -3195,7 +4228,7 @@ win32_wnd_proc (hwnd, msg, wParam, lParam)
                lppos->cy -= hdiff;
                
                if (wp.showCmd != SW_SHOWMAXIMIZED 
-                   && ! (lppos->flags & SWP_NOMOVE))
+                   && (lppos->flags & SWP_NOMOVE) == 0)
                  {
                    if (lppos->x != wr.left || lppos->y != wr.top)
                      {
@@ -3208,31 +4241,98 @@ win32_wnd_proc (hwnd, msg, wParam, lParam)
                      }
                  }
                
-               ret = 0;
+               return 0;
              }
          }
       }
-    
-      if (ret == 0) return (0);
       
       goto dflt;
+
+    case WM_EMACS_CREATESCROLLBAR:
+      return (LRESULT) w32_createscrollbar ((struct frame *) wParam,
+                                           (struct scroll_bar *) lParam);
+
     case WM_EMACS_SHOWWINDOW:
-      return ShowWindow (hwnd, wParam);
+      return ShowWindow ((HWND) wParam, (WPARAM) lParam);
+
+    case WM_EMACS_SETFOREGROUND:
+      return SetForegroundWindow ((HWND) wParam);
+
     case WM_EMACS_SETWINDOWPOS:
       {
-       Win32WindowPos * pos = (Win32WindowPos *) wParam;
-       return SetWindowPos (hwnd, pos->hwndAfter,
+       WINDOWPOS * pos = (WINDOWPOS *) wParam;
+       return SetWindowPos (hwnd, pos->hwndInsertAfter,
                             pos->x, pos->y, pos->cx, pos->cy, pos->flags);
       }
+
     case WM_EMACS_DESTROYWINDOW:
-      DestroyWindow ((HWND) wParam);
-      break;
+      DragAcceptFiles ((HWND) wParam, FALSE);
+      return DestroyWindow ((HWND) wParam);
+
+    case WM_EMACS_TRACKPOPUPMENU:
+      {
+       UINT flags;
+       POINT *pos;
+       int retval;
+       pos = (POINT *)lParam;
+       flags = TPM_CENTERALIGN;
+       if (button_state & LMOUSE)
+         flags |= TPM_LEFTBUTTON;
+       else if (button_state & RMOUSE)
+         flags |= TPM_RIGHTBUTTON;
+       
+       /* Remember we did a SetCapture on the initial mouse down event,
+          so for safety, we make sure the capture is cancelled now.  */
+       ReleaseCapture ();
+       button_state = 0;
+
+       /* Use menubar_active to indicate that WM_INITMENU is from
+           TrackPopupMenu below, and should be ignored.  */
+       f = x_window_to_frame (dpyinfo, hwnd);
+       if (f)
+         f->output_data.w32->menubar_active = 1;
+       
+       if (TrackPopupMenu ((HMENU)wParam, flags, pos->x, pos->y, 
+                           0, hwnd, NULL))
+         {
+           MSG amsg;
+           /* Eat any mouse messages during popupmenu */
+           while (PeekMessage (&amsg, hwnd, WM_MOUSEFIRST, WM_MOUSELAST,
+                               PM_REMOVE));
+           /* Get the menu selection, if any */
+           if (PeekMessage (&amsg, hwnd, WM_COMMAND, WM_COMMAND, PM_REMOVE))
+             {
+               retval =  LOWORD (amsg.wParam);
+             }
+           else
+             {
+               retval = 0;
+             }
+         }
+       else
+         {
+           retval = -1;
+         }
+
+       return retval;
+      }
+
     default:
+      /* Check for messages registered at runtime. */
+      if (msg == msh_mousewheel)
+       {
+         wmsg.dwModifiers = w32_get_modifiers ();
+         my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
+         return 0;
+       }
+      
     dflt:
       return DefWindowProc (hwnd, msg, wParam, lParam);
     }
   
-  return (1);
+
+  /* The most common default return code for handled messages is 0.  */
+  return 0;
 }
 
 void 
@@ -3241,14 +4341,15 @@ my_create_window (f)
 {
   MSG msg;
 
-  PostThreadMessage (dwWinThreadId, WM_EMACS_CREATEWINDOW, (WPARAM)f, 0);
+  if (!PostThreadMessage (dwWindowsThreadId, WM_EMACS_CREATEWINDOW, (WPARAM)f, 0))
+    abort ();
   GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
 }
 
-/* Create and set up the win32 window for frame F.  */
+/* Create and set up the w32 window for frame F.  */
 
 static void
-win32_window (f, window_prompting, minibuffer_only)
+w32_window (f, window_prompting, minibuffer_only)
      struct frame *f;
      long window_prompting;
      int minibuffer_only;
@@ -3290,7 +4391,7 @@ win32_window (f, window_prompting, minibuffer_only)
   if (!minibuffer_only && FRAME_EXTERNAL_MENU_BAR (f))
     initialize_frame_menubar (f);
 
-  if (FRAME_WIN32_WINDOW (f) == 0)
+  if (FRAME_W32_WINDOW (f) == 0)
     error ("Unable to create window");
 }
 
@@ -3305,7 +4406,7 @@ x_icon (f, parms)
 {
   Lisp_Object icon_x, icon_y;
 
-  /* Set the position of the icon.  Note that win95 groups all
+  /* Set the position of the icon.  Note that Windows 95 groups all
      icons in the tray.  */
   icon_x = x_get_arg (parms, Qicon_left, 0, 0, number);
   icon_y = x_get_arg (parms, Qicon_top, 0, 0, number);
@@ -3322,6 +4423,18 @@ x_icon (f, parms)
   if (! EQ (icon_x, Qunbound))
     x_wm_set_icon_position (f, XINT (icon_x), XINT (icon_y));
 
+#if 0 /* TODO */
+  /* Start up iconic or window? */
+  x_wm_set_window_state
+    (f, (EQ (x_get_arg (parms, Qvisibility, 0, 0, symbol), Qicon)
+        ? IconicState
+        : NormalState));
+
+  x_text_icon (f, (char *) XSTRING ((!NILP (f->icon_name)
+                                    ? f->icon_name
+                                    : f->name))->data);
+#endif
+
   UNBLOCK_INPUT;
 }
 
@@ -3346,12 +4459,14 @@ This function is an internal primitive--use `make-frame' instead.")
   long window_prompting = 0;
   int width, height;
   int count = specpdl_ptr - specpdl;
-  struct gcpro gcpro1;
+  struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
   Lisp_Object display;
-  struct win32_display_info *dpyinfo;
+  struct w32_display_info *dpyinfo;
   Lisp_Object parent;
   struct kboard *kb;
 
+  check_w32 ();
+
   /* Use this general default value to start with
      until we know if this frame has a specified name.  */
   Vx_resource_name = Vinvocation_name;
@@ -3366,7 +4481,7 @@ This function is an internal primitive--use `make-frame' instead.")
   kb = &the_only_kboard;
 #endif
 
-  name = x_get_arg (parms, Qname, "title", "Title", string);
+  name = x_get_arg (parms, Qname, "name", "Name", string);
   if (!STRINGP (name)
       && ! EQ (name, Qunbound)
       && ! NILP (name))
@@ -3382,6 +4497,11 @@ This function is an internal primitive--use `make-frame' instead.")
   if (! NILP (parent))
     CHECK_NUMBER (parent, 0);
 
+  /* make_frame_without_minibuffer can run Lisp code and garbage collect.  */
+  /* No need to protect DISPLAY because that's not used after passing
+     it to make_frame_without_minibuffer.  */
+  frame = Qnil;
+  GCPRO4 (parms, parent, name, frame);
   tem = x_get_arg (parms, Qminibuffer, 0, 0, symbol);
   if (EQ (tem, Qnone) || NILP (tem))
     f = make_frame_without_minibuffer (Qnil, kb, display);
@@ -3395,19 +4515,25 @@ This function is an internal primitive--use `make-frame' instead.")
   else
     f = make_frame (1);
 
+  XSETFRAME (frame, f);
+
   /* Note that Windows does support scroll bars.  */
   FRAME_CAN_HAVE_SCROLL_BARS (f) = 1;
   /* By default, make scrollbars the system standard width. */
   f->scroll_bar_pixel_width = GetSystemMetrics (SM_CXVSCROLL);
 
-  XSETFRAME (frame, f);
-  GCPRO1 (frame);
+  f->output_method = output_w32;
+  f->output_data.w32 = (struct w32_output *) xmalloc (sizeof (struct w32_output));
+  bzero (f->output_data.w32, sizeof (struct w32_output));
 
-  f->output_method = output_win32;
-  f->output_data.win32 = (struct win32_output *) xmalloc (sizeof (struct win32_output));
-  bzero (f->output_data.win32, sizeof (struct win32_output));
+  FRAME_FONTSET (f) = -1;
 
-/*  FRAME_WIN32_DISPLAY_INFO (f) = dpyinfo; */
+  f->icon_name
+    = x_get_arg (parms, Qicon_name, "iconName", "Title", string);
+  if (! STRINGP (f->icon_name))
+    f->icon_name = Qnil;
+
+/*  FRAME_W32_DISPLAY_INFO (f) = dpyinfo; */
 #ifdef MULTI_KBOARD
   FRAME_KBOARD (f) = kb;
 #endif
@@ -3416,13 +4542,13 @@ This function is an internal primitive--use `make-frame' instead.")
 
   if (!NILP (parent))
     {
-      f->output_data.win32->parent_desc = (Window) parent;
-      f->output_data.win32->explicit_parent = 1;
+      f->output_data.w32->parent_desc = (Window) parent;
+      f->output_data.w32->explicit_parent = 1;
     }
   else
     {
-      f->output_data.win32->parent_desc = FRAME_WIN32_DISPLAY_INFO (f)->root_window;
-      f->output_data.win32->explicit_parent = 0;
+      f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
+      f->output_data.w32->explicit_parent = 0;
     }
 
   /* Note that the frame has no physical cursor right now.  */
@@ -3432,7 +4558,7 @@ This function is an internal primitive--use `make-frame' instead.")
      be set.  */
   if (EQ (name, Qunbound) || NILP (name))
     {
-      f->name = build_string (dpyinfo->win32_id_name);
+      f->name = build_string (dpyinfo->w32_id_name);
       f->explicit_name = 0;
     }
   else
@@ -3443,6 +4569,10 @@ This function is an internal primitive--use `make-frame' instead.")
       specbind (Qx_resource_name, name);
     }
 
+  /* Create fontsets from `global_fontset_alist' before handling fonts.  */
+  for (tem = Vglobal_fontset_alist; CONSP (tem); tem = XCONS (tem)->cdr)
+    fs_register_fontset (f, XCONS (tem)->car);
+
   /* Extract the window parameters from the supplied values
      that are needed to determine window geometry.  */
   {
@@ -3452,28 +4582,24 @@ This function is an internal primitive--use `make-frame' instead.")
     BLOCK_INPUT;
     /* First, try whatever font the caller has specified.  */
     if (STRINGP (font))
+      {
+        tem = Fquery_fontset (font, Qnil);
+        if (STRINGP (tem))
+          font = x_new_fontset (f, XSTRING (tem)->data);
+        else
       font = x_new_font (f, XSTRING (font)->data);
-#if 0
+      }
     /* Try out a font which we hope has bold and italic variations.  */
     if (!STRINGP (font))
-      font = x_new_font (f, "-misc-fixed-medium-r-normal-*-*-140-*-*-c-*-iso8859-1");
-    if (! STRINGP (font))
-      font = x_new_font (f, "-*-*-medium-r-normal-*-*-140-*-*-c-*-iso8859-1");
+      font = x_new_font (f, "-*-Courier New-normal-r-*-*-13-*-*-*-c-*-iso8859-1");
     if (! STRINGP (font))
-      /* This was formerly the first thing tried, but it finds too many fonts
-        and takes too long.  */
-      font = x_new_font (f, "-*-*-medium-r-*-*-*-*-*-*-c-*-iso8859-1");
+      font = x_new_font (f, "-*-Courier-normal-r-*-*-*-97-*-*-c-*-iso8859-1");
     /* If those didn't work, look for something which will at least work.  */
     if (! STRINGP (font))
-      font = x_new_font (f, "-*-fixed-*-*-*-*-*-140-*-*-c-*-iso8859-1");
-    if (! STRINGP (font))
-      font = x_new_font (f, "-*-system-medium-r-normal-*-*-200-*-*-c-120-*-*");
-#endif
-    if (! STRINGP (font))
-      font = x_new_font (f, "-*-Fixedsys-*-r-*-*-12-90-*-*-c-*-*-*");
+      font = x_new_font (f, "-*-Fixedsys-normal-r-*-*-*-*-90-*-c-*-iso8859-1");
     UNBLOCK_INPUT;
     if (! STRINGP (font))
-      font = build_string ("-*-system");
+      font = build_string ("Fixedsys");
 
     x_default_parameter (f, parms, Qfont, font, 
                         "font", "Font", string);
@@ -3494,6 +4620,7 @@ This function is an internal primitive--use `make-frame' instead.")
        parms = Fcons (Fcons (Qinternal_border_width, value),
                       parms);
     }
+  /* Default internalBorderWidth to 0 on Windows to match other programs.  */
   x_default_parameter (f, parms, Qinternal_border_width, make_number (0),
                       "internalBorderWidth", "BorderWidth", number);
   x_default_parameter (f, parms, Qvertical_scroll_bars, Qt,
@@ -3515,29 +4642,33 @@ This function is an internal primitive--use `make-frame' instead.")
                       "menuBar", "MenuBar", number);
   x_default_parameter (f, parms, Qscroll_bar_width, Qnil,
                       "scrollBarWidth", "ScrollBarWidth", number);
+  x_default_parameter (f, parms, Qbuffer_predicate, Qnil,
+                      "bufferPredicate", "BufferPredicate", symbol);
+  x_default_parameter (f, parms, Qtitle, Qnil,
+                      "title", "Title", string);
 
-  f->output_data.win32->dwStyle = WS_OVERLAPPEDWINDOW;
-  f->output_data.win32->parent_desc = FRAME_WIN32_DISPLAY_INFO (f)->root_window;
+  f->output_data.w32->dwStyle = WS_OVERLAPPEDWINDOW;
+  f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
   window_prompting = x_figure_window_size (f, parms);
 
   if (window_prompting & XNegative)
     {
       if (window_prompting & YNegative)
-       f->output_data.win32->win_gravity = SouthEastGravity;
+       f->output_data.w32->win_gravity = SouthEastGravity;
       else
-       f->output_data.win32->win_gravity = NorthEastGravity;
+       f->output_data.w32->win_gravity = NorthEastGravity;
     }
   else
     {
       if (window_prompting & YNegative)
-       f->output_data.win32->win_gravity = SouthWestGravity;
+       f->output_data.w32->win_gravity = SouthWestGravity;
       else
-       f->output_data.win32->win_gravity = NorthWestGravity;
+       f->output_data.w32->win_gravity = NorthWestGravity;
     }
 
-  f->output_data.win32->size_hint_flags = window_prompting;
+  f->output_data.w32->size_hint_flags = window_prompting;
 
-  win32_window (f, window_prompting, minibuffer_only);
+  w32_window (f, window_prompting, minibuffer_only);
   x_icon (f, parms);
   init_frame_faces (f);
 
@@ -3558,7 +4689,8 @@ This function is an internal primitive--use `make-frame' instead.")
      f->height.  */
   width = f->width;
   height = f->height;
-  f->height = f->width = 0;
+  f->height = 0;
+  SET_FRAME_WIDTH (f, 0);
   change_frame_size (f, height, width, 1, 0);
 
   /* Tell the server what size and position, etc, we want,
@@ -3580,12 +4712,12 @@ This function is an internal primitive--use `make-frame' instead.")
 
   /* Now that the frame is official, it counts as a reference to
      its display.  */
-  FRAME_WIN32_DISPLAY_INFO (f)->reference_count++;
+  FRAME_W32_DISPLAY_INFO (f)->reference_count++;
 
   /* Make the window appear on the frame and enable display,
      unless the caller says not to.  However, with explicit parent,
      Emacs cannot control visibility, so don't try.  */
-  if (! f->output_data.win32->explicit_parent)
+  if (! f->output_data.w32->explicit_parent)
     {
       Lisp_Object visibility;
 
@@ -3612,44 +4744,89 @@ Lisp_Object
 x_get_focus_frame (frame)
      struct frame *frame;
 {
-  struct win32_display_info *dpyinfo = FRAME_WIN32_DISPLAY_INFO (frame);
+  struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (frame);
   Lisp_Object xfocus;
-  if (! dpyinfo->win32_focus_frame)
+  if (! dpyinfo->w32_focus_frame)
     return Qnil;
 
-  XSETFRAME (xfocus, dpyinfo->win32_focus_frame);
+  XSETFRAME (xfocus, dpyinfo->w32_focus_frame);
   return xfocus;
 }
 
-DEFUN ("focus-frame", Ffocus_frame, Sfocus_frame, 1, 1, 0,
-  "This function is obsolete, and does nothing.")
+DEFUN ("w32-focus-frame", Fw32_focus_frame, Sw32_focus_frame, 1, 1, 0,
+  "Give FRAME input focus, raising to foreground if necessary.")
   (frame)
      Lisp_Object frame;
 {
+  x_focus_on_frame (check_x_frame (frame));
   return Qnil;
 }
 
-DEFUN ("unfocus-frame", Funfocus_frame, Sunfocus_frame, 0, 0, 0,
-  "This function is obsolete, and does nothing.")
-  ()
-{
-  return Qnil;
-}
 \f
-XFontStruct *
-win32_load_font (dpyinfo,name)
-struct win32_display_info *dpyinfo;
-char * name;
+/* Load font named FONTNAME of size SIZE for frame F, and return a
+   pointer to the structure font_info while allocating it dynamically.
+   If loading fails, return NULL. */
+struct font_info *
+w32_load_font (f,fontname,size)
+struct frame *f;
+char * fontname;
+int size;
 {
-  XFontStruct * font = NULL;
-  BOOL ok;
+  struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
+  Lisp_Object font_names;
+
+#if 0   /* x_load_font attempts to get a list of fonts - presumably to
+           allow a fuzzier fontname to be specified. w32_list_fonts
+           appears to be a bit too fuzzy for this purpose. */
+
+  /* Get a list of all the fonts that match this name.  Once we
+     have a list of matching fonts, we compare them against the fonts
+     we already have loaded by comparing names.  */
+  font_names = w32_list_fonts (f, build_string (fontname), size, 100);
+
+  if (!NILP (font_names))
+  {
+      Lisp_Object tail;
+      int i;
+
+#if 0 /* This code has nasty side effects that cause Emacs to crash.  */
+
+      /* First check if any are already loaded, as that is cheaper
+         than loading another one. */
+      for (i = 0; i < dpyinfo->n_fonts; i++)
+       for (tail = font_names; CONSP (tail); tail = XCONS (tail)->cdr)
+         if (!strcmp (dpyinfo->font_table[i].name,
+                      XSTRING (XCONS (tail)->car)->data)
+             || !strcmp (dpyinfo->font_table[i].full_name,
+                         XSTRING (XCONS (tail)->car)->data))
+           return (dpyinfo->font_table + i);
+#endif
 
+      fontname = (char *) XSTRING (XCONS (font_names)->car)->data;
+    }
+  else
+    return NULL;
+#endif
+
+  /* Load the font and add it to the table. */
   {
+    char *full_name;
+    XFontStruct *font;
+    struct font_info *fontp;
     LOGFONT lf;
+    BOOL ok;
 
-    if (!name || !x_to_win32_font (name, &lf))
+    if (!fontname || !x_to_w32_font (fontname, &lf))
       return (NULL);
 
+    if (!*lf.lfFaceName)
+        /* If no name was specified for the font, we get a random font
+           from CreateFontIndirect - this is not particularly
+           desirable, especially since CreateFontIndirect does not
+           fill out the missing name in lf, so we never know what we
+           ended up with. */
+      return NULL;
+
     font = (XFontStruct *) xmalloc (sizeof (XFontStruct));
 
     if (!font) return (NULL);
@@ -3657,35 +4834,100 @@ char * name;
     BLOCK_INPUT;
 
     font->hfont = CreateFontIndirect (&lf);
-  }
 
-  if (font->hfont == NULL) 
-    {
-      ok = FALSE;
-    } 
-  else 
-    {
-      HDC hdc;
-      HANDLE oldobj;
-
-      hdc = GetDC (dpyinfo->root_window);
-      oldobj = SelectObject (hdc, font->hfont);
-      ok = GetTextMetrics (hdc, &font->tm);
-      SelectObject (hdc, oldobj);
-      ReleaseDC (dpyinfo->root_window, hdc);
-    }
+    if (font->hfont == NULL) 
+      {
+       ok = FALSE;
+      
+    else 
+      {
+       HDC hdc;
+       HANDLE oldobj;
+
+       hdc = GetDC (dpyinfo->root_window);
+       oldobj = SelectObject (hdc, font->hfont);
+       ok = GetTextMetrics (hdc, &font->tm);
+       SelectObject (hdc, oldobj);
+       ReleaseDC (dpyinfo->root_window, hdc);
+      }
 
-  UNBLOCK_INPUT;
+    UNBLOCK_INPUT;
+
+    if (!ok)
+      {
+       w32_unload_font (dpyinfo, font);
+       return (NULL);
+      }
+
+    /* Do we need to create the table?  */
+    if (dpyinfo->font_table_size == 0)
+      {
+       dpyinfo->font_table_size = 16;
+       dpyinfo->font_table
+         = (struct font_info *) xmalloc (dpyinfo->font_table_size
+                                         * sizeof (struct font_info));
+      }
+    /* Do we need to grow the table?  */
+    else if (dpyinfo->n_fonts
+            >= dpyinfo->font_table_size)
+      {
+       dpyinfo->font_table_size *= 2;
+       dpyinfo->font_table
+         = (struct font_info *) xrealloc (dpyinfo->font_table,
+                                          (dpyinfo->font_table_size
+                                           * sizeof (struct font_info)));
+      }
 
-  if (ok) return (font);
+    fontp = dpyinfo->font_table + dpyinfo->n_fonts;
 
-  win32_unload_font (dpyinfo, font);
-  return (NULL);
+    /* Now fill in the slots of *FONTP.  */
+    BLOCK_INPUT;
+    fontp->font = font;
+    fontp->font_idx = dpyinfo->n_fonts;
+    fontp->name = (char *) xmalloc (strlen (fontname) + 1);
+    bcopy (fontname, fontp->name, strlen (fontname) + 1);
+
+    /* Work out the font's full name.  */
+    full_name = (char *)xmalloc (100);
+    if (full_name && w32_to_x_font (&lf, full_name, 100))
+        fontp->full_name = full_name;
+    else
+      {
+        /* If all else fails - just use the name we used to load it.  */
+        xfree (full_name);
+        fontp->full_name = fontp->name;
+      }
+
+    fontp->size = FONT_WIDTH (font);
+    fontp->height = FONT_HEIGHT (font);
+
+    /* The slot `encoding' specifies how to map a character
+       code-points (0x20..0x7F or 0x2020..0x7F7F) of each charset to
+       the font code-points (0:0x20..0x7F, 1:0xA0..0xFF, 0:0x2020..0x7F7F,
+       the font code-points (0:0x20..0x7F, 1:0xA0..0xFF,
+       0:0x2020..0x7F7F, 1:0xA0A0..0xFFFF, 3:0x20A0..0x7FFF, or
+       2:0xA020..0xFF7F).  For the moment, we don't know which charset
+       uses this font.  So, we set informatoin in fontp->encoding[1]
+       which is never used by any charset.  If mapping can't be
+       decided, set FONT_ENCODING_NOT_DECIDED.  */
+    fontp->encoding[1] = FONT_ENCODING_NOT_DECIDED;
+
+    /* The following three values are set to 0 under W32, which is
+       what they get set to if XGetFontProperty fails under X.  */
+    fontp->baseline_offset = 0;
+    fontp->relative_compose = 0;
+    fontp->default_ascent = FONT_BASE (font);
+
+    UNBLOCK_INPUT;
+    dpyinfo->n_fonts++;
+
+    return fontp;
+  }
 }
 
 void 
-win32_unload_font (dpyinfo, font)
-     struct win32_display_info *dpyinfo;
+w32_unload_font (dpyinfo, font)
+     struct w32_display_info *dpyinfo;
      XFontStruct * font;
 {
   if (font) 
@@ -3695,7 +4937,7 @@ win32_unload_font (dpyinfo, font)
     }
 }
 
-/* The font conversion stuff between x and win32 */
+/* The font conversion stuff between x and w32 */
 
 /* X font string is as follows (from faces.el)
  * (let ((-            "[-?]")
@@ -3770,7 +5012,7 @@ win32_unload_font (dpyinfo, font)
 #define FONT_REGEXP_WEIGHT "-" FONT_WEIGHT "-"
 
 LONG 
-x_to_win32_weight (lpw)
+x_to_w32_weight (lpw)
      char * lpw;
 {
   if (!lpw) return (FW_DONTCARE);
@@ -3779,6 +5021,7 @@ x_to_win32_weight (lpw)
   else if (stricmp (lpw,"extrabold") == 0)    return FW_EXTRABOLD;
   else if (stricmp (lpw,"bold") == 0)         return FW_BOLD;
   else if (stricmp (lpw,"demibold") == 0)     return FW_SEMIBOLD;
+  else if (stricmp (lpw,"semibold") == 0)     return FW_SEMIBOLD;
   else if (stricmp (lpw,"medium") == 0)       return FW_MEDIUM;
   else if (stricmp (lpw,"normal") == 0)       return FW_NORMAL;
   else if (stricmp (lpw,"light") == 0)        return FW_LIGHT;
@@ -3790,7 +5033,7 @@ x_to_win32_weight (lpw)
 
 
 char * 
-win32_to_x_weight (fnweight)
+w32_to_x_weight (fnweight)
      int fnweight;
 {
   if (fnweight >= FW_HEAVY)      return "heavy";
@@ -3807,72 +5050,154 @@ win32_to_x_weight (fnweight)
 }
 
 LONG
-x_to_win32_charset (lpcs)
+x_to_w32_charset (lpcs)
     char * lpcs;
 {
   if (!lpcs) return (0);
 
-  if (stricmp (lpcs,"ansi") == 0)               return ANSI_CHARSET;
-  else if (stricmp (lpcs,"iso8859-1") == 0)     return ANSI_CHARSET;
-  else if (stricmp (lpcs,"iso8859") == 0)       return ANSI_CHARSET;
-  else if (stricmp (lpcs,"oem") == 0)          return OEM_CHARSET;
+  if (stricmp (lpcs,"ansi") == 0)                return ANSI_CHARSET;
+  else if (stricmp (lpcs,"iso8859-1") == 0)      return ANSI_CHARSET;
+  else if (stricmp (lpcs, "symbol") == 0)        return SYMBOL_CHARSET;
+  else if (stricmp (lpcs, "jis") == 0)           return SHIFTJIS_CHARSET;
+  else if (stricmp (lpcs, "ksc5601") == 0)       return HANGEUL_CHARSET;
+  else if (stricmp (lpcs, "gb2312") == 0)        return GB2312_CHARSET;
+  else if (stricmp (lpcs, "big5") == 0)          return CHINESEBIG5_CHARSET;
+  else if (stricmp (lpcs, "oem") == 0)          return OEM_CHARSET;
+
+#ifdef EASTEUROPE_CHARSET
+  else if (stricmp (lpcs, "iso8859-2") == 0)     return EASTEUROPE_CHARSET;
+  else if (stricmp (lpcs, "iso8859-3") == 0)     return TURKISH_CHARSET;
+  else if (stricmp (lpcs, "iso8859-4") == 0)     return BALTIC_CHARSET;
+  else if (stricmp (lpcs, "iso8859-5") == 0)     return RUSSIAN_CHARSET;
+  else if (stricmp (lpcs, "koi8") == 0)          return RUSSIAN_CHARSET;
+  else if (stricmp (lpcs, "iso8859-6") == 0)     return ARABIC_CHARSET;
+  else if (stricmp (lpcs, "iso8859-7") == 0)     return GREEK_CHARSET;
+  else if (stricmp (lpcs, "iso8859-8") == 0)     return HEBREW_CHARSET;
+  else if (stricmp (lpcs, "viscii") == 0)        return VIETNAMESE_CHARSET;
+  else if (stricmp (lpcs, "vscii") == 0)         return VIETNAMESE_CHARSET;
+  else if (stricmp (lpcs, "tis620") == 0)        return THAI_CHARSET;
+  else if (stricmp (lpcs, "mac") == 0)           return MAC_CHARSET;
+#endif
+
 #ifdef UNICODE_CHARSET
-  else if (stricmp (lpcs,"unicode") == 0)       return UNICODE_CHARSET;
-  else if (stricmp (lpcs,"iso10646") == 0)      return UNICODE_CHARSET;
+  else if (stricmp (lpcs,"iso10646") == 0)       return UNICODE_CHARSET;
+  else if (stricmp (lpcs, "unicode") == 0)       return UNICODE_CHARSET;
 #endif
+  else if (lpcs[0] == '#')                      return atoi (lpcs + 1);
   else
-    return 0;
+    return DEFAULT_CHARSET;
 }
 
 char *
-win32_to_x_charset (fncharset)
+w32_to_x_charset (fncharset)
     int fncharset;
 {
+  static char buf[16];
+
   switch (fncharset)
     {
-    case ANSI_CHARSET:     return "ansi";
-    case OEM_CHARSET:      return "oem";
-    case SYMBOL_CHARSET:   return "symbol";
+      /* ansi is considered iso8859-1, as most modern ansi fonts are.  */
+    case ANSI_CHARSET:        return "iso8859-1";
+    case DEFAULT_CHARSET:     return "ascii-*";
+    case SYMBOL_CHARSET:      return "*-symbol";
+    case SHIFTJIS_CHARSET:    return "jisx0212-sjis";
+    case HANGEUL_CHARSET:     return "ksc5601-*";
+    case GB2312_CHARSET:      return "gb2312-*";
+    case CHINESEBIG5_CHARSET: return "big5-*";
+    case OEM_CHARSET:         return "*-oem";
+
+      /* More recent versions of Windows (95 and NT4.0) define more
+         character sets.  */
+#ifdef EASTEUROPE_CHARSET
+    case EASTEUROPE_CHARSET: return "iso8859-2";
+    case TURKISH_CHARSET:    return "iso8859-3";
+    case BALTIC_CHARSET:     return "iso8859-4";
+    case RUSSIAN_CHARSET:    return "iso8859-5";
+    case ARABIC_CHARSET:     return "iso8859-6";
+    case GREEK_CHARSET:      return "iso8859-7";
+    case HEBREW_CHARSET:     return "iso8859-8";
+    case VIETNAMESE_CHARSET: return "viscii1.1-*";
+    case THAI_CHARSET:       return "tis620-*";
+    case MAC_CHARSET:        return "*-mac";
+    case JOHAB_CHARSET:      break; /* What is this? Latin-9? */
+#endif
+
 #ifdef UNICODE_CHARSET
-    case UNICODE_CHARSET:  return "unicode";
+    case UNICODE_CHARSET:  return "iso10646-unicode";
 #endif
     }
-  return "*";
+  /* Encode numerical value of unknown charset.  */
+  sprintf (buf, "*-#%u", fncharset);
+  return buf;
 }
 
 BOOL 
-win32_to_x_font (lplogfont, lpxstr, len)
+w32_to_x_font (lplogfont, lpxstr, len)
      LOGFONT * lplogfont;
      char * lpxstr;
      int len;
 {
-  if (!lpxstr) return (FALSE);
+  char fontname[50];
+  char height_pixels[8];
+  char height_dpi[8];
+  char width_pixels[8];
+  char *fontname_dash;
+
+  if (!lpxstr) abort ();
+
+  if (!lplogfont)
+    return FALSE;
+
+  strncpy (fontname, lplogfont->lfFaceName, 50);
+  fontname[49] = '\0'; /* Just in case */
 
-  if (lplogfont)
+  /* Replace dashes with underscores so the dashes are not
+     misinterpreted */
+  fontname_dash = fontname;
+  while (fontname_dash = strchr (fontname_dash, '-'))
+      *fontname_dash = '_';
+
+  if (lplogfont->lfHeight)
     {
-      _snprintf (lpxstr, len - 1,
-                "-*-%s-%s-%c-*-*-%d-%d-*-*-%c-%d-*-%s-",
-                lplogfont->lfFaceName,
-                win32_to_x_weight (lplogfont->lfWeight),
-                lplogfont->lfItalic?'i':'r',
-                abs (lplogfont->lfHeight),
-                (abs (lplogfont->lfHeight) * 720) / one_win32_display_info.height_in,
-                ((lplogfont->lfPitchAndFamily & 0x3) == VARIABLE_PITCH) ? 'p' : 'c',
-                lplogfont->lfWidth * 10,
-                win32_to_x_charset (lplogfont->lfCharSet)
-                );
+      sprintf (height_pixels, "%u", abs (lplogfont->lfHeight));
+      sprintf (height_dpi, "%u",
+              (abs (lplogfont->lfHeight) * 720) / one_w32_display_info.height_in);
     }
   else
     {
-      strncpy (lpxstr,"-*-*-*-*-*-*-*-*-*-*-*-*-*-*-", len - 1);
+      strcpy (height_pixels, "*");
+      strcpy (height_dpi, "*");
     }
-  
+  if (lplogfont->lfWidth)
+    sprintf (width_pixels, "%u", lplogfont->lfWidth * 10);
+  else
+    strcpy (width_pixels, "*");
+
+  _snprintf (lpxstr, len - 1,
+            "-*-%s-%s-%c-*-*-%s-%s-*-*-%c-%s-%s",
+                                                     /* foundry */
+            fontname,                               /* family */
+            w32_to_x_weight (lplogfont->lfWeight),  /* weight */
+            lplogfont->lfItalic?'i':'r',            /* slant */
+                                                     /* setwidth name */
+                                                     /* add style name */
+            height_pixels,                          /* pixel size */
+            height_dpi,                             /* point size */
+                                                     /* resx */
+                                                     /* resy */
+            ((lplogfont->lfPitchAndFamily & 0x3) == VARIABLE_PITCH)
+             ? 'p' : 'c',                            /* spacing */
+            width_pixels,                           /* avg width */
+            w32_to_x_charset (lplogfont->lfCharSet) /* charset registry
+                                                        and encoding*/
+            );
+
   lpxstr[len - 1] = 0;         /* just to be sure */
   return (TRUE);
 }
 
 BOOL 
-x_to_win32_font (lpxstr, lplogfont)
+x_to_w32_font (lpxstr, lplogfont)
      char * lpxstr;
      LOGFONT * lplogfont;
 {
@@ -3880,7 +5205,8 @@ x_to_win32_font (lpxstr, lplogfont)
   
   memset (lplogfont, 0, sizeof (*lplogfont));
 
-#if 0
+  /* Set default value for each field.  */
+#if 1
   lplogfont->lfOutPrecision = OUT_DEFAULT_PRECIS;
   lplogfont->lfClipPrecision = CLIP_DEFAULT_PRECIS;
   lplogfont->lfQuality = DEFAULT_QUALITY;
@@ -3891,6 +5217,10 @@ x_to_win32_font (lpxstr, lplogfont)
   lplogfont->lfQuality = PROOF_QUALITY;
 #endif
 
+  lplogfont->lfCharSet = DEFAULT_CHARSET;
+  lplogfont->lfWeight = FW_DONTCARE;
+  lplogfont->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
+
   if (!lpxstr)
     return FALSE;
 
@@ -3924,11 +5254,11 @@ x_to_win32_font (lpxstr, lplogfont)
 
       fields--;
 
-      lplogfont->lfWeight = x_to_win32_weight ((fields > 0 ? weight : ""));
+      lplogfont->lfWeight = x_to_w32_weight ((fields > 0 ? weight : ""));
 
       fields--;
 
-      if (!NILP (Vwin32_enable_italics))
+      if (!NILP (Vw32_enable_italics))
        lplogfont->lfItalic = (fields > 0 && slant == 'i');
 
       fields--;
@@ -3940,7 +5270,7 @@ x_to_win32_font (lpxstr, lplogfont)
 
       if (fields > 0 && lplogfont->lfHeight == 0 && height[0] != '*')
        lplogfont->lfHeight = (atoi (height)
-                              * one_win32_display_info.height_in) / 720;
+                              * one_w32_display_info.height_in) / 720;
 
       fields--;
 
@@ -3954,9 +5284,8 @@ x_to_win32_font (lpxstr, lplogfont)
 
       fields--;
 
-      /* Not all font specs include the registry field, so we allow for an
-        optional registry field before the encoding when parsing
-        remainder.  Also we strip the trailing '-' if present. */
+      /* Strip the trailing '-' if present. (it shouldn't be, as it
+         fails the test against xlfn-tight-regexp in fontset.el).  */
       {
        int len = strlen (remainder);
        if (len > 0 && remainder[len-1] == '-')
@@ -3965,7 +5294,7 @@ x_to_win32_font (lpxstr, lplogfont)
       encoding = remainder;
       if (strncmp (encoding, "*-", 2) == 0)
        encoding += 2;
-      lplogfont->lfCharSet = x_to_win32_charset (fields > 0 ? encoding : "");
+      lplogfont->lfCharSet = x_to_w32_charset (fields > 0 ? encoding : "");
     }
   else
     {
@@ -4000,7 +5329,7 @@ x_to_win32_font (lpxstr, lplogfont)
 
       fields--;
 
-      lplogfont->lfWeight = x_to_win32_weight ((fields > 0 ? weight : ""));
+      lplogfont->lfWeight = x_to_w32_weight ((fields > 0 ? weight : ""));
     }
 
   /* This makes TrueType fonts work better. */
@@ -4010,7 +5339,7 @@ x_to_win32_font (lpxstr, lplogfont)
 }
 
 BOOL 
-win32_font_match (lpszfont1, lpszfont2)
+w32_font_match (lpszfont1, lpszfont2)
     char * lpszfont1;
     char * lpszfont2;
 {
@@ -4047,6 +5376,7 @@ typedef struct enumfont_t
 {
   HDC hdc;
   int numFonts;
+  LOGFONT logfont;
   XFontStruct *size_ref;
   Lisp_Object *pattern;
   Lisp_Object *head;
@@ -4060,20 +5390,37 @@ enum_font_cb2 (lplf, lptm, FontType, lpef)
     int FontType;
     enumfont_t * lpef;
 {
-  if (lplf->elfLogFont.lfStrikeOut || lplf->elfLogFont.lfUnderline
-      || (lplf->elfLogFont.lfCharSet != ANSI_CHARSET && lplf->elfLogFont.lfCharSet != OEM_CHARSET))
+  if (lplf->elfLogFont.lfStrikeOut || lplf->elfLogFont.lfUnderline)
     return (1);
   
+  /* Check that the character set matches if it was specified */
+  if (lpef->logfont.lfCharSet != DEFAULT_CHARSET &&
+      lplf->elfLogFont.lfCharSet != lpef->logfont.lfCharSet)
+    return (1);
+
+  /* We want all fonts cached, so don't compare sizes just yet */
   /*    if (!lpef->size_ref || lptm->tmMaxCharWidth == FONT_WIDTH (lpef->size_ref)) */
   {
     char buf[100];
+    Lisp_Object width = Qnil;
 
-    if (!win32_to_x_font (lplf, buf, 100)) return (0);
+    if (!NILP (*(lpef->pattern)) && FontType != RASTER_FONTTYPE)
+      {
+        /* Scalable fonts are as big as you want them to be.  */
+       lplf->elfLogFont.lfHeight = lpef->logfont.lfHeight;
+       lplf->elfLogFont.lfWidth = lpef->logfont.lfWidth;
+      }
+
+    /* The MaxCharWidth is not valid at this stage for scalable fonts. */
+    if (FontType == RASTER_FONTTYPE)
+        width = make_number (lptm->tmMaxCharWidth);
+
+    if (!w32_to_x_font (lplf, buf, 100)) return (0);
 
-    if (NILP (*(lpef->pattern)) || win32_font_match (buf, XSTRING (*(lpef->pattern))->data))
+    if (NILP (*(lpef->pattern)) || w32_font_match (buf, XSTRING (*(lpef->pattern))->data))
       {
-       *lpef->tail = Fcons (build_string (buf), Qnil);
-       lpef->tail = &XCONS (*lpef->tail)->cdr;
+       *lpef->tail = Fcons (Fcons (build_string (buf), width), Qnil);
+       lpef->tail = &(XCONS (*lpef->tail)->cdr);
        lpef->numFonts++;
       }
   }
@@ -4095,7 +5442,250 @@ enum_font_cb1 (lplf, lptm, FontType, lpef)
 }
 
 
-DEFUN ("x-list-fonts", Fx_list_fonts, Sx_list_fonts, 1, 3, 0,
+/* Interface to fontset handler. (adapted from mw32font.c in Meadow
+   and xterm.c in Emacs 20.3) */
+
+/* Return a list of names of available fonts matching PATTERN on frame
+   F.  If SIZE is not 0, it is the size (maximum bound width) of fonts
+   to be listed.  Frame F NULL means we have not yet created any
+   frame, which means we can't get proper size info, as we don't have
+   a device context to use for GetTextMetrics.
+   MAXNAMES sets a limit on how many fonts to match.  */
+
+Lisp_Object
+w32_list_fonts (FRAME_PTR f, Lisp_Object pattern, int size, int maxnames )
+{
+  Lisp_Object patterns, key, tem;
+  Lisp_Object list = Qnil, newlist = Qnil, second_best = Qnil;
+
+  /* If we don't have a frame, we can't use the Windows API to list
+     fonts, as it requires a device context for the Window.  This will
+     only happen during startup if the user specifies a font on the
+     command line.  Print a message on stderr and return nil.  */
+  if (!f)
+    {
+      char buffer[256];
+
+      sprintf (buffer, 
+              "Emacs cannot get a list of fonts before the initial frame "
+              "is created.\nThe font specified on the command line may not "
+              "be found.\n");
+      MessageBox (NULL, buffer, "Emacs Warning Dialog",
+                 MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
+      return Qnil;
+    }
+
+
+  patterns = Fassoc (pattern, Valternate_fontname_alist);
+  if (NILP (patterns))
+    patterns = Fcons (pattern, Qnil);
+
+  for (; CONSP (patterns); patterns = XCONS (patterns)->cdr)
+    {
+      enumfont_t ef;
+
+      pattern = XCONS (patterns)->car;
+
+      /* See if we cached the result for this particular query.
+         The cache is an alist of the form:
+           ((PATTERN (FONTNAME . WIDTH) ...) ...)
+      */
+      if ( f &&
+           (tem = XCONS (FRAME_W32_DISPLAY_INFO (f)->name_list_element)->cdr,
+            !NILP (list = Fassoc (pattern, tem))))
+        {
+          list = Fcdr_safe (list);
+          /* We have a cached list. Don't have to get the list again.  */
+          goto label_cached;
+        }
+
+      BLOCK_INPUT;
+      /* At first, put PATTERN in the cache.  */
+      list = Qnil;
+      ef.pattern = &pattern;
+      ef.tail = ef.head = &list;
+      ef.numFonts = 0;
+      x_to_w32_font (STRINGP (pattern) ? XSTRING (pattern)->data :
+                     NULL, &ef.logfont);
+      {
+        ef.hdc = GetDC (FRAME_W32_WINDOW (f));
+
+        EnumFontFamilies (ef.hdc, NULL, (FONTENUMPROC) enum_font_cb1,
+                          (LPARAM)&ef);
+
+        ReleaseDC (FRAME_W32_WINDOW (f), ef.hdc);
+      }
+
+      UNBLOCK_INPUT;
+
+      /* Make a list of the fonts we got back.
+         Store that in the font cache for the display. */
+      if (f != NULL)
+        XCONS (FRAME_W32_DISPLAY_INFO (f)->name_list_element)->cdr
+          = Fcons (Fcons (pattern, list),
+                   XCONS (FRAME_W32_DISPLAY_INFO (f)->name_list_element)->cdr);
+
+    label_cached:
+      if (NILP (list)) continue; /* Try the remaining alternatives.  */
+
+      newlist = second_best = Qnil;
+
+      /* Make a list of the fonts that have the right width.  */          
+      for (; CONSP (list); list = XCONS (list)->cdr)
+        {
+          int found_size;
+          tem = XCONS (list)->car;
+
+          if (!CONSP (tem))
+            continue;
+          if (NILP (XCONS (tem)->car))
+            continue;
+          if (!size)
+            {
+              newlist = Fcons (XCONS (tem)->car, newlist);
+              continue;
+            }
+          if (!INTEGERP (XCONS (tem)->cdr))
+            {
+              /* Since we don't yet know the size of the font, we must
+                 load it and try GetTextMetrics.  */
+              struct w32_display_info *dpyinfo
+                = FRAME_W32_DISPLAY_INFO (f);
+              W32FontStruct thisinfo;
+              LOGFONT lf;
+              HDC hdc;
+              HANDLE oldobj;
+
+              if (!x_to_w32_font (XSTRING (XCONS (tem)->car)->data, &lf))
+                continue;
+
+              BLOCK_INPUT;
+              thisinfo.hfont = CreateFontIndirect (&lf);
+              if (thisinfo.hfont == NULL)
+                continue;
+
+              hdc = GetDC (dpyinfo->root_window);
+              oldobj = SelectObject (hdc, thisinfo.hfont);
+              if (GetTextMetrics (hdc, &thisinfo.tm))
+                XCONS (tem)->cdr = make_number (FONT_WIDTH (&thisinfo));
+              else
+                XCONS (tem)->cdr = make_number (0);
+              SelectObject (hdc, oldobj);
+              ReleaseDC (dpyinfo->root_window, hdc);
+              DeleteObject(thisinfo.hfont);
+              UNBLOCK_INPUT;
+            }
+          found_size = XINT (XCONS (tem)->cdr);
+          if (found_size == size)
+            newlist = Fcons (XCONS (tem)->car, newlist);
+
+          /* keep track of the closest matching size in case
+             no exact match is found.  */
+          else if (found_size > 0)
+            {
+              if (NILP (second_best))
+                second_best = tem;
+              else if (found_size < size)
+                {
+                  if (XINT (XCONS (second_best)->cdr) > size
+                      || XINT (XCONS (second_best)->cdr) < found_size)
+                    second_best = tem;
+                }
+              else
+                {
+                  if (XINT (XCONS (second_best)->cdr) > size
+                      && XINT (XCONS (second_best)->cdr) >
+                      found_size)
+                    second_best = tem;
+                }
+            }
+        }
+
+      if (!NILP (newlist))
+        break;
+      else if (!NILP (second_best))
+        {
+          newlist = Fcons (XCONS (second_best)->car, Qnil);
+          break;
+        }
+    }
+
+  return newlist;
+}
+
+/* Return a pointer to struct font_info of font FONT_IDX of frame F.  */
+struct font_info *
+w32_get_font_info (f, font_idx)
+     FRAME_PTR f;
+     int font_idx;
+{
+  return (FRAME_W32_FONT_TABLE (f) + font_idx);
+}
+
+
+struct font_info*
+w32_query_font (struct frame *f, char *fontname)
+{
+  int i;
+  struct font_info *pfi;
+
+  pfi = FRAME_W32_FONT_TABLE (f);
+
+  for (i = 0; i < one_w32_display_info.n_fonts ;i++, pfi++)
+    {
+      if (strcmp(pfi->name, fontname) == 0) return pfi;
+    }
+
+  return NULL;
+}
+
+/* Find a CCL program for a font specified by FONTP, and set the member
+ `encoder' of the structure.  */
+
+void
+w32_find_ccl_program (fontp)
+     struct font_info *fontp;
+{
+  extern Lisp_Object Vfont_ccl_encoder_alist, Vccl_program_table;
+  extern Lisp_Object Qccl_program_idx;
+  extern Lisp_Object resolve_symbol_ccl_program ();
+  Lisp_Object list, elt, ccl_prog, ccl_id;
+
+  for (list = Vfont_ccl_encoder_alist; CONSP (list); list = XCONS (list)->cdr)
+    {
+      elt = XCONS (list)->car;
+      if (CONSP (elt)
+         && STRINGP (XCONS (elt)->car)
+         && (fast_c_string_match_ignore_case (XCONS (elt)->car, fontp->name)
+             >= 0))
+       {
+         if (SYMBOLP (XCONS (elt)->cdr) &&
+             (!NILP (ccl_id = Fget (XCONS (elt)->cdr, Qccl_program_idx))))
+           {
+             ccl_prog = XVECTOR (Vccl_program_table)->contents[XUINT (ccl_id)];
+             if (!CONSP (ccl_prog)) continue;
+             ccl_prog = XCONS (ccl_prog)->cdr;
+           }
+         else
+           {
+             ccl_prog = XCONS (elt)->cdr;
+             if (!VECTORP (ccl_prog)) continue;
+           }
+           
+         fontp->font_encoder
+           = (struct ccl_program *) xmalloc (sizeof (struct ccl_program));
+         setup_ccl_program (fontp->font_encoder,
+                            resolve_symbol_ccl_program (ccl_prog));
+         break;
+       }
+    }
+}
+
+\f
+#if 1
+#include "x-list-font.c"
+#else
+DEFUN ("x-list-fonts", Fx_list_fonts, Sx_list_fonts, 1, 4, 0,
   "Return a list of the names of available fonts matching PATTERN.\n\
 If optional arguments FACE and FRAME are specified, return only fonts\n\
 the same size as FACE on FRAME.\n\
@@ -4110,9 +5700,12 @@ The return value is a list of strings, suitable as arguments to\n\
 set-face-font.\n\
 \n\
 Fonts Emacs can't use (i.e. proportional fonts) may or may not be excluded\n\
-even if they match PATTERN and FACE.")
-  (pattern, face, frame)
-    Lisp_Object pattern, face, frame;
+even if they match PATTERN and FACE.\n\
+\n\
+The optional fourth argument MAXIMUM sets a limit on how many\n\
+fonts to match.  The first MAXIMUM fonts are reported.")
+  (pattern, face, frame, maximum)
+    Lisp_Object pattern, face, frame, maximum;
 {
   int num_fonts;
   char **names;
@@ -4138,25 +5731,25 @@ even if they match PATTERN and FACE.")
       int face_id;
 
       /* Don't die if we get called with a terminal frame.  */
-      if (! FRAME_WIN32_P (f))
-       error ("non-win32 frame used in `x-list-fonts'");
+      if (! FRAME_W32_P (f))
+       error ("non-w32 frame used in `x-list-fonts'");
 
       face_id = face_name_id_number (f, face);
 
       if (face_id < 0 || face_id >= FRAME_N_PARAM_FACES (f)
          || FRAME_PARAM_FACES (f) [face_id] == 0)
-       size_ref = f->output_data.win32->font;
+       size_ref = f->output_data.w32->font;
       else
        {
          size_ref = FRAME_PARAM_FACES (f) [face_id]->font;
          if (size_ref == (XFontStruct *) (~0))
-           size_ref = f->output_data.win32->font;
+           size_ref = f->output_data.w32->font;
        }
     }
 
   /* See if we cached the result for this particular query.  */
   list = Fassoc (pattern,
-                XCONS (FRAME_WIN32_DISPLAY_INFO (f)->name_list_element)->cdr);
+                XCONS (FRAME_W32_DISPLAY_INFO (f)->name_list_element)->cdr);
 
   /* We have info in the cache for this PATTERN.  */
   if (!NILP (list))
@@ -4175,14 +5768,16 @@ even if they match PATTERN and FACE.")
       newlist = Qnil;
       for (tem = list; CONSP (tem); tem = XCONS (tem)->cdr)
        {
-         XFontStruct *thisinfo;
-
-          thisinfo = win32_load_font (FRAME_WIN32_DISPLAY_INFO (f), XSTRING (XCONS (tem)->car)->data);
+         struct font_info *fontinf;
+          XFontStruct *thisinfo = NULL;
 
+          fontinf = w32_load_font (f, XSTRING (XCONS (tem)->car)->data, 0);
+          if (fontinf)
+            thisinfo = (XFontStruct *)fontinf->font;
           if (thisinfo && same_size_fonts (thisinfo, size_ref))
            newlist = Fcons (XCONS (tem)->car, newlist);
 
-         win32_unload_font (FRAME_WIN32_DISPLAY_INFO (f), thisinfo);
+         w32_unload_font (FRAME_W32_DISPLAY_INFO (f), thisinfo);
         }
 
       UNBLOCK_INPUT;
@@ -4196,13 +5791,14 @@ even if they match PATTERN and FACE.")
   ef.pattern = &pattern;
   ef.tail = ef.head = &namelist;
   ef.numFonts = 0;
+  x_to_w32_font (STRINGP (pattern) ? XSTRING (pattern)->data : NULL, &ef.logfont);
 
   {
-    ef.hdc = GetDC (FRAME_WIN32_WINDOW (f));
+    ef.hdc = GetDC (FRAME_W32_WINDOW (f));
 
     EnumFontFamilies (ef.hdc, NULL, (FONTENUMPROC) enum_font_cb1, (LPARAM)&ef);
     
-    ReleaseDC  (FRAME_WIN32_WINDOW (f), ef.hdc);
+    ReleaseDC  (FRAME_W32_WINDOW (f), ef.hdc);
   }
 
   UNBLOCK_INPUT;
@@ -4214,9 +5810,9 @@ even if they match PATTERN and FACE.")
 
       /* Make a list of all the fonts we got back.
         Store that in the font cache for the display.  */
-      XCONS (FRAME_WIN32_DISPLAY_INFO (f)->name_list_element)->cdr
+      XCONS (FRAME_W32_DISPLAY_INFO (f)->name_list_element)->cdr
        = Fcons (Fcons (pattern, namelist),
-                XCONS (FRAME_WIN32_DISPLAY_INFO (f)->name_list_element)->cdr);
+                XCONS (FRAME_W32_DISPLAY_INFO (f)->name_list_element)->cdr);
 
       /* Make a list of the fonts that have the right width.  */
       list = Qnil;
@@ -4229,14 +5825,17 @@ even if they match PATTERN and FACE.")
            keeper = 1;
          else
            {
-             XFontStruct *thisinfo;
+             struct font_info *fontinf;
+              XFontStruct *thisinfo = NULL;
 
              BLOCK_INPUT;
-             thisinfo = win32_load_font (FRAME_WIN32_DISPLAY_INFO (f), XSTRING (Fcar (cur))->data);
+             fontinf = w32_load_font (f, XSTRING (Fcar (cur))->data, 0);
+              if (fontinf)
+                thisinfo = (XFontStruct *)fontinf->font;
 
              keeper = thisinfo && same_size_fonts (thisinfo, size_ref);
 
-             win32_unload_font (FRAME_WIN32_DISPLAY_INFO (f), thisinfo);
+             w32_unload_font (FRAME_W32_DISPLAY_INFO (f), thisinfo);
 
              UNBLOCK_INPUT;
            }
@@ -4250,6 +5849,7 @@ even if they match PATTERN and FACE.")
 
   return list;
 }
+#endif
 \f
 DEFUN ("x-color-defined-p", Fx_color_defined_p, Sx_color_defined_p, 1, 2, 0,
        "Return non-nil if color COLOR is supported on frame FRAME.\n\
@@ -4286,9 +5886,9 @@ If FRAME is omitted or nil, use the selected frame.")
     {
       Lisp_Object rgb[3];
 
-      rgb[0] = make_number (GetRValue (foo));
-      rgb[1] = make_number (GetGValue (foo));
-      rgb[2] = make_number (GetBValue (foo));
+      rgb[0] = make_number ((GetRValue (foo) << 8) | GetRValue (foo));
+      rgb[1] = make_number ((GetGValue (foo) << 8) | GetGValue (foo));
+      rgb[2] = make_number ((GetBValue (foo) << 8) | GetBValue (foo));
       return Flist (3, rgb);
     }
   else
@@ -4303,7 +5903,7 @@ If omitted or nil, that stands for the selected frame's display.")
   (display)
      Lisp_Object display;
 {
-  struct win32_display_info *dpyinfo = check_x_display_info (display);
+  struct w32_display_info *dpyinfo = check_x_display_info (display);
 
   if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 2)
     return Qnil;
@@ -4321,7 +5921,7 @@ If omitted or nil, that stands for the selected frame's display.")
   (display)
      Lisp_Object display;
 {
-  struct win32_display_info *dpyinfo = check_x_display_info (display);
+  struct w32_display_info *dpyinfo = check_x_display_info (display);
 
   if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 1)
     return Qnil;
@@ -4338,7 +5938,7 @@ If omitted or nil, that stands for the selected frame's display.")
   (display)
      Lisp_Object display;
 {
-  struct win32_display_info *dpyinfo = check_x_display_info (display);
+  struct w32_display_info *dpyinfo = check_x_display_info (display);
 
   return make_number (dpyinfo->width);
 }
@@ -4352,7 +5952,7 @@ If omitted or nil, that stands for the selected frame's display.")
   (display)
      Lisp_Object display;
 {
-  struct win32_display_info *dpyinfo = check_x_display_info (display);
+  struct w32_display_info *dpyinfo = check_x_display_info (display);
 
   return make_number (dpyinfo->height);
 }
@@ -4366,7 +5966,7 @@ If omitted or nil, that stands for the selected frame's display.")
   (display)
      Lisp_Object display;
 {
-  struct win32_display_info *dpyinfo = check_x_display_info (display);
+  struct w32_display_info *dpyinfo = check_x_display_info (display);
 
   return make_number (dpyinfo->n_planes * dpyinfo->n_cbits);
 }
@@ -4380,7 +5980,7 @@ If omitted or nil, that stands for the selected frame's display.")
   (display)
      Lisp_Object display;
 {
-  struct win32_display_info *dpyinfo = check_x_display_info (display);
+  struct w32_display_info *dpyinfo = check_x_display_info (display);
   HDC hdc;
   int cap;
 
@@ -4405,20 +6005,20 @@ If omitted or nil, that stands for the selected frame's display.")
   (display)
      Lisp_Object display;
 {
-  struct win32_display_info *dpyinfo = check_x_display_info (display);
+  struct w32_display_info *dpyinfo = check_x_display_info (display);
 
   return make_number (1);
 }
 
 DEFUN ("x-server-vendor", Fx_server_vendor, Sx_server_vendor, 0, 1, 0,
-  "Returns the vendor ID string of the Win32 system (Microsoft).\n\
+  "Returns the vendor ID string of the W32 system (Microsoft).\n\
 The optional argument DISPLAY specifies which display to ask about.\n\
 DISPLAY should be either a frame or a display name (a string).\n\
 If omitted or nil, that stands for the selected frame's display.")
   (display)
      Lisp_Object display;
 {
-  struct win32_display_info *dpyinfo = check_x_display_info (display);
+  struct w32_display_info *dpyinfo = check_x_display_info (display);
   char *vendor = "Microsoft Corp.";
 
   if (! vendor) vendor = "";
@@ -4436,10 +6036,10 @@ If omitted or nil, that stands for the selected frame's display.")
   (display)
      Lisp_Object display;
 {
-  struct win32_display_info *dpyinfo = check_x_display_info (display);
+  struct w32_display_info *dpyinfo = check_x_display_info (display);
 
-  return Fcons (make_number (nt_major_version),
-               Fcons (make_number (nt_minor_version), Qnil));
+  return Fcons (make_number (w32_major_version),
+               Fcons (make_number (w32_minor_version), Qnil));
 }
 
 DEFUN ("x-display-screens", Fx_display_screens, Sx_display_screens, 0, 1, 0,
@@ -4450,7 +6050,7 @@ If omitted or nil, that stands for the selected frame's display.")
   (display)
      Lisp_Object display;
 {
-  struct win32_display_info *dpyinfo = check_x_display_info (display);
+  struct w32_display_info *dpyinfo = check_x_display_info (display);
 
   return make_number (1);
 }
@@ -4463,7 +6063,7 @@ If omitted or nil, that stands for the selected frame's display.")
   (display)
      Lisp_Object display;
 {
-  struct win32_display_info *dpyinfo = check_x_display_info (display);
+  struct w32_display_info *dpyinfo = check_x_display_info (display);
   HDC hdc;
   int cap;
 
@@ -4484,7 +6084,7 @@ If omitted or nil, that stands for the selected frame's display.")
   (display)
      Lisp_Object display;
 {
-  struct win32_display_info *dpyinfo = check_x_display_info (display);
+  struct w32_display_info *dpyinfo = check_x_display_info (display);
 
   HDC hdc;
   int cap;
@@ -4522,7 +6122,7 @@ If omitted or nil, that stands for the selected frame's display.")
        (display)
      Lisp_Object display;
 {
-  struct win32_display_info *dpyinfo = check_x_display_info (display);
+  struct w32_display_info *dpyinfo = check_x_display_info (display);
 
 #if 0
   switch (dpyinfo->visual->class)
@@ -4550,7 +6150,7 @@ If omitted or nil, that stands for the selected frame's display.")
   (display)
      Lisp_Object display;
 {
-  struct win32_display_info *dpyinfo = check_x_display_info (display);
+  struct w32_display_info *dpyinfo = check_x_display_info (display);
 
   return Qnil;
 }
@@ -4573,37 +6173,37 @@ int
 x_char_width (f)
      register struct frame *f;
 {
-  return FONT_WIDTH (f->output_data.win32->font);
+  return FONT_WIDTH (f->output_data.w32->font);
 }
 
 int
 x_char_height (f)
      register struct frame *f;
 {
-  return f->output_data.win32->line_height;
+  return f->output_data.w32->line_height;
 }
 
 int
 x_screen_planes (frame)
      Lisp_Object frame;
 {
-  return (FRAME_WIN32_DISPLAY_INFO (XFRAME (frame))->n_planes * 
-         FRAME_WIN32_DISPLAY_INFO (XFRAME (frame))->n_cbits);
+  return (FRAME_W32_DISPLAY_INFO (XFRAME (frame))->n_planes * 
+         FRAME_W32_DISPLAY_INFO (XFRAME (frame))->n_cbits);
 }
 \f
 /* Return the display structure for the display named NAME.
    Open a new connection if necessary.  */
 
-struct win32_display_info *
+struct w32_display_info *
 x_display_info_for_name (name)
      Lisp_Object name;
 {
   Lisp_Object names;
-  struct win32_display_info *dpyinfo;
+  struct w32_display_info *dpyinfo;
 
   CHECK_STRING (name, 0);
 
-  for (dpyinfo = &one_win32_display_info, names = win32_display_name_list;
+  for (dpyinfo = &one_w32_display_info, names = w32_display_name_list;
        dpyinfo;
        dpyinfo = dpyinfo->next, names = XCONS (names)->cdr)
     {
@@ -4618,12 +6218,13 @@ x_display_info_for_name (name)
 
   validate_x_resource_name ();
 
-  dpyinfo = win32_term_init (name, (unsigned char *)0,
+  dpyinfo = w32_term_init (name, (unsigned char *)0,
                             (char *) XSTRING (Vx_resource_name)->data);
 
   if (dpyinfo == 0)
     error ("Cannot connect to server %s", XSTRING (name)->data);
 
+  w32_in_use = 1;
   XSETFASTINT (Vwindow_system_version, 3);
 
   return dpyinfo;
@@ -4640,12 +6241,15 @@ terminate Emacs if we can't open the connection.")
 {
   unsigned int n_planes;
   unsigned char *xrm_option;
-  struct win32_display_info *dpyinfo;
+  struct w32_display_info *dpyinfo;
 
   CHECK_STRING (display, 0);
   if (! NILP (xrm_string))
     CHECK_STRING (xrm_string, 1);
 
+  if (! EQ (Vwindow_system, intern ("w32")))
+    error ("Not using Microsoft Windows");
+
   /* Allow color mapping to be defined externally; first look in user's
      HOME directory, then in Emacs etc dir for a file called rgb.txt. */
   {
@@ -4661,12 +6265,12 @@ terminate Emacs if we can't open the connection.")
        Fexpand_file_name (build_string ("rgb.txt"),
                           Fsymbol_value (intern ("data-directory")));
 
-    Vwin32_color_map = Fwin32_load_color_file (color_file);
+    Vw32_color_map = Fw32_load_color_file (color_file);
 
     UNGCPRO;
   }
-  if (NILP (Vwin32_color_map))
-    Vwin32_color_map = Fwin32_default_color_map ();
+  if (NILP (Vw32_color_map))
+    Vw32_color_map = Fw32_default_color_map ();
 
   if (! NILP (xrm_string))
     xrm_option = (unsigned char *) XSTRING (xrm_string)->data;
@@ -4689,7 +6293,7 @@ terminate Emacs if we can't open the connection.")
 
   /* This is what opens the connection and sets x_current_display.
      This also initializes many symbols, such as those used for input.  */
-  dpyinfo = win32_term_init (display, xrm_option,
+  dpyinfo = w32_term_init (display, xrm_option,
                             (char *) XSTRING (Vx_resource_name)->data);
 
   if (dpyinfo == 0)
@@ -4701,6 +6305,8 @@ terminate Emacs if we can't open the connection.")
        error ("Cannot connect to server %s", XSTRING (display)->data);
     }
 
+  w32_in_use = 1;
+
   XSETFASTINT (Vwindow_system_version, 3);
   return Qnil;
 }
@@ -4713,8 +6319,8 @@ If DISPLAY is nil, that stands for the selected frame's display.")
   (display)
   Lisp_Object display;
 {
-  struct win32_display_info *dpyinfo = check_x_display_info (display);
-  struct win32_display_info *tail;
+  struct w32_display_info *dpyinfo = check_x_display_info (display);
+  struct w32_display_info *tail;
   int i;
 
   if (dpyinfo->reference_count > 0)
@@ -4728,7 +6334,7 @@ If DISPLAY is nil, that stands for the selected frame's display.")
        free (dpyinfo->font_table[i].name);
       /* Don't free the full_name string;
         it is always shared with something else.  */
-      win32_unload_font (dpyinfo, dpyinfo->font_table[i].font);
+      w32_unload_font (dpyinfo, dpyinfo->font_table[i].font);
     }
   x_destroy_all_bitmaps (dpyinfo);
 
@@ -4745,7 +6351,7 @@ DEFUN ("x-display-list", Fx_display_list, Sx_display_list, 0, 0, 0,
   Lisp_Object tail, result;
 
   result = Qnil;
-  for (tail = win32_display_name_list; ! NILP (tail); tail = XCONS (tail)->cdr)
+  for (tail = w32_display_name_list; ! NILP (tail); tail = XCONS (tail)->cdr)
     result = Fcons (XCONS (XCONS (tail)->car)->car, result);
 
   return result;
@@ -4754,23 +6360,23 @@ DEFUN ("x-display-list", Fx_display_list, Sx_display_list, 0, 0, 0,
 DEFUN ("x-synchronize", Fx_synchronize, Sx_synchronize, 1, 2, 0,
    "If ON is non-nil, report errors as soon as the erring request is made.\n\
 If ON is nil, allow buffering of requests.\n\
-This is a noop on Win32 systems.\n\
+This is a noop on W32 systems.\n\
 The optional second argument DISPLAY specifies which display to act on.\n\
 DISPLAY should be either a frame or a display name (a string).\n\
 If DISPLAY is omitted or nil, that stands for the selected frame's display.")
   (on, display)
     Lisp_Object display, on;
 {
-  struct win32_display_info *dpyinfo = check_x_display_info (display);
+  struct w32_display_info *dpyinfo = check_x_display_info (display);
 
   return Qnil;
 }
 
 \f
-/* These are the win32 specialized functions */
+/* These are the w32 specialized functions */
 
-DEFUN ("win32-select-font", Fwin32_select_font, Swin32_select_font, 0, 1, 0,
-   "This will display the Win32 font dialog and return an X font string corresponding to the selection.")
+DEFUN ("w32-select-font", Fw32_select_font, Sw32_select_font, 0, 1, 0,
+   "This will display the W32 font dialog and return an X font string corresponding to the selection.")
   (frame)
      Lisp_Object frame;
 {
@@ -4782,19 +6388,224 @@ DEFUN ("win32-select-font", Fwin32_select_font, Swin32_select_font, 0, 1, 0,
   bzero (&cf, sizeof (cf));
 
   cf.lStructSize = sizeof (cf);
-  cf.hwndOwner = FRAME_WIN32_WINDOW (f);
+  cf.hwndOwner = FRAME_W32_WINDOW (f);
   cf.Flags = CF_FIXEDPITCHONLY | CF_FORCEFONTEXIST | CF_SCREENFONTS;
   cf.lpLogFont = &lf;
 
-  if (!ChooseFont (&cf) || !win32_to_x_font (&lf, buf, 100))
+  if (!ChooseFont (&cf) || !w32_to_x_font (&lf, buf, 100))
       return Qnil;
 
   return build_string (buf);
 }
 
+DEFUN ("w32-send-sys-command", Fw32_send_sys_command, Sw32_send_sys_command, 1, 2, 0,
+   "Send frame a Windows WM_SYSCOMMAND message of type COMMAND.\n\
+Some useful values for command are 0xf030 to maximise frame (0xf020\n\
+to minimize), 0xf120 to restore frame to original size, and 0xf100\n\
+to activate the menubar for keyboard access.  0xf140 activates the\n\
+screen saver if defined.\n\
+\n\
+If optional parameter FRAME is not specified, use selected frame.")
+  (command, frame)
+     Lisp_Object command, frame;
+{
+  WPARAM code;
+  FRAME_PTR f = check_x_frame (frame);
+
+  CHECK_NUMBER (command, 0);
+
+  PostMessage (FRAME_W32_WINDOW (f), WM_SYSCOMMAND, XINT (command), 0);
+
+  return Qnil;
+}
+
+/* Lookup virtual keycode from string representing the name of a
+   non-ascii keystroke into the corresponding virtual key, using
+   lispy_function_keys.  */
+static int
+lookup_vk_code (char *key)
+{
+  int i;
+
+  for (i = 0; i < 256; i++)
+    if (lispy_function_keys[i] != 0
+       && strcmp (lispy_function_keys[i], key) == 0)
+      return i;
+
+  return -1;
+}
+
+/* Convert a one-element vector style key sequence to a hot key
+   definition.  */
+static int
+w32_parse_hot_key (key)
+     Lisp_Object key;
+{
+  /* Copied from Fdefine_key and store_in_keymap.  */
+  register Lisp_Object c;
+  int vk_code;
+  int lisp_modifiers;
+  int w32_modifiers;
+  struct gcpro gcpro1;
+
+  CHECK_VECTOR (key, 0);
+
+  if (XFASTINT (Flength (key)) != 1)
+    return Qnil;
+
+  GCPRO1 (key);
+
+  c = Faref (key, make_number (0));
+
+  if (CONSP (c) && lucid_event_type_list_p (c))
+    c = Fevent_convert_list (c);
+
+  UNGCPRO;
+
+  if (! INTEGERP (c) && ! SYMBOLP (c))
+    error ("Key definition is invalid");
+
+  /* Work out the base key and the modifiers.  */
+  if (SYMBOLP (c))
+    {
+      c = parse_modifiers (c);
+      lisp_modifiers = Fcar (Fcdr (c));
+      c = Fcar (c);
+      if (!SYMBOLP (c))
+       abort ();
+      vk_code = lookup_vk_code (XSYMBOL (c)->name->data);
+    }
+  else if (INTEGERP (c))
+    {
+      lisp_modifiers = XINT (c) & ~CHARACTERBITS;
+      /* Many ascii characters are their own virtual key code.  */
+      vk_code = XINT (c) & CHARACTERBITS;
+    }
+
+  if (vk_code < 0 || vk_code > 255)
+    return Qnil;
+
+  if ((lisp_modifiers & meta_modifier) != 0
+      && !NILP (Vw32_alt_is_meta))
+    lisp_modifiers |= alt_modifier;
+
+  /* Convert lisp modifiers to Windows hot-key form.  */
+  w32_modifiers  = (lisp_modifiers & hyper_modifier)    ? MOD_WIN : 0;
+  w32_modifiers |= (lisp_modifiers & alt_modifier)      ? MOD_ALT : 0;
+  w32_modifiers |= (lisp_modifiers & ctrl_modifier)     ? MOD_CONTROL : 0;
+  w32_modifiers |= (lisp_modifiers & shift_modifier)    ? MOD_SHIFT : 0;
+
+  return HOTKEY (vk_code, w32_modifiers);
+}
+
+DEFUN ("w32-register-hot-key", Fw32_register_hot_key, Sw32_register_hot_key, 1, 1, 0,
+   "Register KEY as a hot-key combination.\n\
+Certain key combinations like Alt-Tab are reserved for system use on\n\
+Windows, and therefore are normally intercepted by the system.  However,\n\
+most of these key combinations can be received by registering them as\n\
+hot-keys, overriding their special meaning.\n\
+\n\
+KEY must be a one element key definition in vector form that would be\n\
+acceptable to `define-key' (e.g. [A-tab] for Alt-Tab).  The meta\n\
+modifier is interpreted as Alt if `w32-alt-is-meta' is t, and hyper\n\
+is always interpreted as the Windows modifier keys.\n\
+\n\
+The return value is the hotkey-id if registered, otherwise nil.")
+  (key)
+     Lisp_Object key;
+{
+  key = w32_parse_hot_key (key);
+
+  if (NILP (Fmemq (key, w32_grabbed_keys)))
+    {
+      /* Reuse an empty slot if possible.  */
+      Lisp_Object item = Fmemq (Qnil, w32_grabbed_keys);
+
+      /* Safe to add new key to list, even if we have focus.  */
+      if (NILP (item))
+       w32_grabbed_keys = Fcons (key, w32_grabbed_keys);
+      else
+       XCAR (item) = key;
+
+      /* Notify input thread about new hot-key definition, so that it
+        takes effect without needing to switch focus.  */
+      PostThreadMessage (dwWindowsThreadId, WM_EMACS_REGISTER_HOT_KEY,
+                        (WPARAM) key, 0);
+    }
+
+  return key;
+}
+
+DEFUN ("w32-unregister-hot-key", Fw32_unregister_hot_key, Sw32_unregister_hot_key, 1, 1, 0,
+   "Unregister HOTKEY as a hot-key combination.")
+  (key)
+     Lisp_Object key;
+{
+  Lisp_Object item;
+
+  if (!INTEGERP (key))
+    key = w32_parse_hot_key (key);
+
+  item = Fmemq (key, w32_grabbed_keys);
+
+  if (!NILP (item))
+    {
+      /* Notify input thread about hot-key definition being removed, so
+        that it takes effect without needing focus switch.  */
+      if (PostThreadMessage (dwWindowsThreadId, WM_EMACS_UNREGISTER_HOT_KEY,
+                            (WPARAM) XINT (XCAR (item)), (LPARAM) item))
+       {
+         MSG msg;
+         GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
+       }
+      return Qt;
+    }
+  return Qnil;
+}
+
+DEFUN ("w32-registered-hot-keys", Fw32_registered_hot_keys, Sw32_registered_hot_keys, 0, 0, 0,
+   "Return list of registered hot-key IDs.")
+  ()
+{
+  return Fcopy_sequence (w32_grabbed_keys);
+}
+
+DEFUN ("w32-reconstruct-hot-key", Fw32_reconstruct_hot_key, Sw32_reconstruct_hot_key, 1, 1, 0,
+   "Convert hot-key ID to a lisp key combination.")
+  (hotkeyid)
+     Lisp_Object hotkeyid;
+{
+  int vk_code, w32_modifiers;
+  Lisp_Object key;
+
+  CHECK_NUMBER (hotkeyid, 0);
+
+  vk_code = HOTKEY_VK_CODE (hotkeyid);
+  w32_modifiers = HOTKEY_MODIFIERS (hotkeyid);
+
+  if (lispy_function_keys[vk_code])
+    key = intern (lispy_function_keys[vk_code]);
+  else
+    key = make_number (vk_code);
+
+  key = Fcons (key, Qnil);
+  if (w32_modifiers & MOD_SHIFT)
+    key = Fcons (intern ("shift"), key);
+  if (w32_modifiers & MOD_CONTROL)
+    key = Fcons (intern ("control"), key);
+  if (w32_modifiers & MOD_ALT)
+    key = Fcons (intern (NILP (Vw32_alt_is_meta) ? "alt" : "meta"), key);
+  if (w32_modifiers & MOD_WIN)
+    key = Fcons (intern ("hyper"), key);
+
+  return key;
+}
 \f
-syms_of_win32fns ()
+syms_of_w32fns ()
 {
+  /* This is zero if not using MS-Windows.  */
+  w32_in_use = 0;
+
   /* The section below is built by the lisp expression at the top of the file,
      just above where these variables are declared.  */
   /*&&& init symbols here &&&*/
@@ -4816,8 +6627,6 @@ syms_of_win32fns ()
   staticpro (&Qcursor_color);
   Qcursor_type = intern ("cursor-type");
   staticpro (&Qcursor_type);
-  Qfont = intern ("font");
-  staticpro (&Qfont);
   Qforeground_color = intern ("foreground-color");
   staticpro (&Qforeground_color);
   Qgeometry = intern ("geometry");
@@ -4834,6 +6643,8 @@ syms_of_win32fns ()
   staticpro (&Qinternal_border_width);
   Qleft = intern ("left");
   staticpro (&Qleft);
+  Qright = intern ("right");
+  staticpro (&Qright);
   Qmouse_color = intern ("mouse-color");
   staticpro (&Qmouse_color);
   Qnone = intern ("none");
@@ -4866,48 +6677,117 @@ syms_of_win32fns ()
   staticpro (&Qdisplay);
   /* This is the end of symbol initialization.  */
 
+  Qface_set_after_frame_default = intern ("face-set-after-frame-default");
+  staticpro (&Qface_set_after_frame_default);
+
   Fput (Qundefined_color, Qerror_conditions,
        Fcons (Qundefined_color, Fcons (Qerror, Qnil)));
   Fput (Qundefined_color, Qerror_message,
        build_string ("Undefined color"));
 
-  DEFVAR_LISP ("win32-color-map", &Vwin32_color_map,
-              "A array of color name mappings for windows.");
-  Vwin32_color_map = Qnil;
+  staticpro (&w32_grabbed_keys);
+  w32_grabbed_keys = Qnil;
 
-  DEFVAR_LISP ("win32-pass-alt-to-system", &Vwin32_pass_alt_to_system,
+  DEFVAR_LISP ("w32-color-map", &Vw32_color_map,
+              "An array of color name mappings for windows.");
+  Vw32_color_map = Qnil;
+
+  DEFVAR_LISP ("w32-pass-alt-to-system", &Vw32_pass_alt_to_system,
               "Non-nil if alt key presses are passed on to Windows.\n\
 When non-nil, for example, alt pressed and released and then space will\n\
 open the System menu.  When nil, Emacs silently swallows alt key events.");
-  Vwin32_pass_alt_to_system = Qnil;
-
-  DEFVAR_LISP ("win32-pass-optional-keys-to-system", 
-              &Vwin32_pass_optional_keys_to_system,
-              "Non-nil if the 'optional' keys (left window, right window,\n\
-and application keys) are passed on to Windows.");
-  Vwin32_pass_optional_keys_to_system = Qnil;
-
-  DEFVAR_LISP ("win32-enable-italics", &Vwin32_enable_italics,
+  Vw32_pass_alt_to_system = Qnil;
+
+  DEFVAR_LISP ("w32-alt-is-meta", &Vw32_alt_is_meta,
+              "Non-nil if the alt key is to be considered the same as the meta key.\n\
+When nil, Emacs will translate the alt key to the Alt modifier, and not Meta.");
+  Vw32_alt_is_meta = Qt;
+
+  DEFVAR_LISP ("w32-pass-lwindow-to-system", 
+              &Vw32_pass_lwindow_to_system,
+              "Non-nil if the left \"Windows\" key is passed on to Windows.\n\
+When non-nil, the Start menu is opened by tapping the key.");
+  Vw32_pass_lwindow_to_system = Qt;
+
+  DEFVAR_LISP ("w32-pass-rwindow-to-system", 
+              &Vw32_pass_rwindow_to_system,
+              "Non-nil if the right \"Windows\" key is passed on to Windows.\n\
+When non-nil, the Start menu is opened by tapping the key.");
+  Vw32_pass_rwindow_to_system = Qt;
+
+  DEFVAR_LISP ("w32-enable-num-lock", 
+              &Vw32_enable_num_lock,
+              "Non-nil if Num Lock should act normally.\n\
+Set to nil to see Num Lock as the key `kp-numlock'.");
+  Vw32_enable_num_lock = Qt;
+
+  DEFVAR_LISP ("w32-enable-caps-lock", 
+              &Vw32_enable_caps_lock,
+              "Non-nil if Caps Lock should act normally.\n\
+Set to nil to see Caps Lock as the key `capslock'.");
+  Vw32_enable_caps_lock = Qt;
+
+  DEFVAR_LISP ("w32-scroll-lock-modifier",
+              &Vw32_scroll_lock_modifier,
+              "Modifier to use for the Scroll Lock on state.\n\
+The value can be hyper, super, meta, alt, control or shift for the\n\
+respective modifier, or nil to see Scroll Lock as the key `scroll'.\n\
+Any other value will cause the key to be ignored.");
+  Vw32_scroll_lock_modifier = Qt;
+
+  DEFVAR_LISP ("w32-lwindow-modifier",
+              &Vw32_lwindow_modifier,
+              "Modifier to use for the left \"Windows\" key.\n\
+The value can be hyper, super, meta, alt, control or shift for the\n\
+respective modifier, or nil to appear as the key `lwindow'.\n\
+Any other value will cause the key to be ignored.");
+  Vw32_lwindow_modifier = Qnil;
+
+  DEFVAR_LISP ("w32-rwindow-modifier",
+              &Vw32_rwindow_modifier,
+              "Modifier to use for the right \"Windows\" key.\n\
+The value can be hyper, super, meta, alt, control or shift for the\n\
+respective modifier, or nil to appear as the key `rwindow'.\n\
+Any other value will cause the key to be ignored.");
+  Vw32_rwindow_modifier = Qnil;
+
+  DEFVAR_LISP ("w32-apps-modifier",
+              &Vw32_apps_modifier,
+              "Modifier to use for the \"Apps\" key.\n\
+The value can be hyper, super, meta, alt, control or shift for the\n\
+respective modifier, or nil to appear as the key `apps'.\n\
+Any other value will cause the key to be ignored.");
+  Vw32_apps_modifier = Qnil;
+
+  DEFVAR_LISP ("w32-enable-italics", &Vw32_enable_italics,
               "Non-nil enables selection of artificially italicized fonts.");
-  Vwin32_enable_italics = Qnil;
+  Vw32_enable_italics = Qnil;
 
-  DEFVAR_LISP ("win32-enable-palette", &Vwin32_enable_palette,
+  DEFVAR_LISP ("w32-enable-palette", &Vw32_enable_palette,
               "Non-nil enables Windows palette management to map colors exactly.");
-  Vwin32_enable_palette = Qt;
+  Vw32_enable_palette = Qt;
 
-  DEFVAR_INT ("win32-mouse-button-tolerance",
-             &Vwin32_mouse_button_tolerance,
+  DEFVAR_INT ("w32-mouse-button-tolerance",
+             &Vw32_mouse_button_tolerance,
              "Analogue of double click interval for faking middle mouse events.\n\
 The value is the minimum time in milliseconds that must elapse between\n\
 left/right button down events before they are considered distinct events.\n\
 If both mouse buttons are depressed within this interval, a middle mouse\n\
 button down event is generated instead.");
-  XSETINT (Vwin32_mouse_button_tolerance, GetDoubleClickTime () / 2);
+  XSETINT (Vw32_mouse_button_tolerance, GetDoubleClickTime () / 2);
+
+  DEFVAR_INT ("w32-mouse-move-interval",
+             &Vw32_mouse_move_interval,
+             "Minimum interval between mouse move events.\n\
+The value is the minimum time in milliseconds that must elapse between\n\
+successive mouse move (or scroll bar drag) events before they are\n\
+reported as lisp events.");
+  XSETINT (Vw32_mouse_move_interval, 50);
 
   init_x_parm_symbols ();
 
   DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path,
-    "List of directories to search for bitmap files for win32.");
+    "List of directories to search for bitmap files for w32.");
   Vx_bitmap_file_path = decode_env_path ((char *) 0, "PATH");
 
   DEFVAR_LISP ("x-pointer-shape", &Vx_pointer_shape,
@@ -4948,6 +6828,25 @@ unless you set it to something else.");
      and maybe the user would like to set it to t.  */
   Vx_no_window_manager = Qnil;
 
+  DEFVAR_LISP ("x-pixel-size-width-font-regexp",
+              &Vx_pixel_size_width_font_regexp,
+     "Regexp matching a font name whose width is the same as `PIXEL_SIZE'.\n\
+\n\
+Since Emacs gets width of a font matching with this regexp from\n\
+PIXEL_SIZE field of the name, font finding mechanism gets faster for\n\
+such a font.  This is especially effective for such large fonts as\n\
+Chinese, Japanese, and Korean.");
+  Vx_pixel_size_width_font_regexp = Qnil;
+
+  DEFVAR_BOOL ("unibyte-display-via-language-environment",
+              &unibyte_display_via_language_environment,
+   "*Non-nil means display unibyte text according to language environment.\n\
+Specifically this means that unibyte non-ASCII characters\n\
+are displayed by converting them to the equivalent multibyte characters\n\
+according to the current language environment.  As a result, they are\n\
+displayed according to the current fontset.");
+  unibyte_display_via_language_environment = 0;
+
   defsubr (&Sx_get_resource);
   defsubr (&Sx_list_fonts);
   defsubr (&Sx_display_color_p);
@@ -4969,25 +6868,44 @@ unless you set it to something else.");
   defsubr (&Sx_display_save_under);
   defsubr (&Sx_parse_geometry);
   defsubr (&Sx_create_frame);
-  defsubr (&Sfocus_frame);
-  defsubr (&Sunfocus_frame);
   defsubr (&Sx_open_connection);
   defsubr (&Sx_close_connection);
   defsubr (&Sx_display_list);
   defsubr (&Sx_synchronize);
 
-  /* Win32 specific functions */
-
-  defsubr (&Swin32_select_font);
-  defsubr (&Swin32_define_rgb_color);
-  defsubr (&Swin32_default_color_map);
-  defsubr (&Swin32_load_color_file);
+  /* W32 specific functions */
+
+  defsubr (&Sw32_focus_frame);
+  defsubr (&Sw32_select_font);
+  defsubr (&Sw32_define_rgb_color);
+  defsubr (&Sw32_default_color_map);
+  defsubr (&Sw32_load_color_file);
+  defsubr (&Sw32_send_sys_command);
+  defsubr (&Sw32_register_hot_key);
+  defsubr (&Sw32_unregister_hot_key);
+  defsubr (&Sw32_registered_hot_keys);
+  defsubr (&Sw32_reconstruct_hot_key);
+
+  /* Setting callback functions for fontset handler.  */
+  get_font_info_func = w32_get_font_info;
+  list_fonts_func = w32_list_fonts;
+  load_font_func = w32_load_font;
+  find_ccl_program_func = w32_find_ccl_program;
+  query_font_func = w32_query_font;
+  set_frame_fontset_func = x_set_font;
+  check_window_system_func = check_w32;
 }
 
 #undef abort
 
 void 
-win32_abort()
+/* For convenience when debugging.  */
+int
+w32_last_error()
+{
+  return GetLastError ();
+}
+w32_abort()
 {
   int button;
   button = MessageBox (NULL,