diff src/w32fns.c @ 19707:0181cc080316

Include limits.h and errno.h. Declare externs from other files. (w32_in_use): New variable. (check_w32, have_menus_p, x_set_title, w32_msg_worker, find_deferred_msg, send_deferred_msg, complete_deferred_msg, Fw32_focus_frame, W32-send-sys-command): New functions. (last_mouse_movement_time): Delete variable. (x_frame_parms): Alphabetize. Add title parm. (x_set_icon_name): Use title if set. (x_set_menu_bar_lines): Ensure client area remains the same. (x_set_name): Don't update if the name is the same. Use title for name if available. (x_icon): Initial support for creating window iconified. (x_display_info_for_name): Set w32_in_use. (Fx_open_connection): Validate Vwindow_system. Set w32_in_use. (w32_create_window): Set window size to frame dimensions. Set font width, line height, border, scrollbar indexes. Don't set X and Y units indexes. (w32_msg_pump): Renamed from windows_msg_worker. Make static. Don't post done message. No longer handle create scrollbar message. Don't abort on anomalous messages. Return when completion detected. (w32_wnd_proc): Keep track of button state. For WINDOWPOSCHANGING, force window dimensions to be multiples of character dimensions. Handle CREATESCROLLBAR. Use correct arguments for SHOWWINDOW. For SETWINDOWPOS, use WINDOWPOS structure. (my_create_window): Abort if message post fails. (Fx_create_frame): Use title instead of name. GC protect frame before make_frame_without_minibuffer. Set icon name. Use courier new as default font (has bold and italic). Set BufferPredicate and Title default parameters. (x_to_w32_weight): Support semibold weight. (x_to_w32_charset): Map # to numeric charset identifier. (w32_to_x_charset): Encode unknown charsets as a number. (enum_font_cb2): Don't restrict to ANSI and OEM charsets. (Fx_color_values): Set high and low words of color values. (syms_of_w32fns): Zero w32_in_use. defsubr new functions. (w32_wnd_proc): Pass on WM_DISPLAYCHANGE messages. (win32_wnd_proc): Capture and handle WM_MOUSEWHEEL events. Capture and handle WM_EMACS_TRACKPOPUPMENU events. Allow a dragged selection from a popup menu started up by a mouse down event. (x_to_win32_color): Support for X Windows RGB string specifications.
author Geoff Voelker <voelker@cs.washington.edu>
date Wed, 03 Sep 1997 00:47:47 +0000
parents eaa60432140c
children d191a8737145
line wrap: on
line diff
--- a/src/w32fns.c	Wed Sep 03 00:46:41 1997 +0000
+++ b/src/w32fns.c	Wed Sep 03 00:47:47 1997 +0000
@@ -20,9 +20,12 @@
 
 /* Added by Kevin Gallo */
 
+#include <config.h>
+
 #include <signal.h>
-#include <config.h>
 #include <stdio.h>
+#include <limits.h>
+#include <errno.h>
 
 #include "lisp.h"
 #include "w32term.h"
@@ -87,6 +90,9 @@
 /* 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;
 
@@ -175,7 +181,7 @@
 
 /* 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;
 
@@ -185,9 +191,24 @@
 /* From w32term.c. */
 extern Lisp_Object Vw32_num_mouse_buttons;
 
-Time last_mouse_movement_time;
-
 
+/* 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 W32.  */
 
@@ -537,29 +558,31 @@
 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,
-  "background-color", x_set_background_color,
-  "mouse-color", x_set_mouse_color,
-  "cursor-color", x_set_cursor_color,
-  "border-color", x_set_border_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,
-  "internal-border-width", x_set_internal_border_width,
-  "name", x_explicitly_set_name,
   "auto-raise", x_set_autoraise,
   "auto-lower", x_set_autolower,
+  "background-color", x_set_background_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,
+  "font", x_set_font,
+  "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,
+  "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,
-  "menu-bar-lines", x_set_menu_bar_lines,
-  "scroll-bar-width", x_set_scroll_bar_width,
-  "unsplittable", x_set_unsplittable,
 };
 
 /* Attach the `x-frame-parameter' properties to
@@ -1244,6 +1267,163 @@
   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.  */
   
   for (tail = Vw32_color_map; !NILP (tail); tail = Fcdr (tail))
     {
@@ -1827,8 +2007,10 @@
   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)
@@ -1965,6 +2147,11 @@
       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));
     }
 }
 
@@ -2016,14 +2203,19 @@
   if (! NILP (Fstring_equal (name, f->name)))
     return;
 
+  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_W32_WINDOW (f), XSTRING (name)->data);
       UNBLOCK_INPUT;
     }
-
-  f->name = name;
 }
 
 /* This function should be called when the user's lisp code has
@@ -2047,7 +2239,42 @@
 {
   x_set_name (f, arg, 0);
 }
-
+
+/* 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;
+    }
+}
+
 void
 x_set_autoraise (f, arg, oldval)
      struct frame *f;
@@ -2622,6 +2849,14 @@
      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 */
   
@@ -2630,22 +2865,25 @@
       w32_init_class (hinst);
     }
   
-  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,
-						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.w32->font));
-      SetWindowLong (hwnd, WND_Y_UNITS_INDEX, f->output_data.w32->line_height);
+      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);
 
       /* Do this to discard the default setting specified by our parent. */
@@ -2879,18 +3117,11 @@
 
 /* Main message dispatch loop. */
 
-DWORD 
-windows_msg_worker (dw)
-     DWORD dw;
+static void
+w32_msg_pump (deferred_msg * msg_buf)
 {
   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))
     {
       if (msg.hwnd == NULL)
@@ -2899,26 +3130,124 @@
 	    {
 	    case WM_EMACS_CREATEWINDOW:
 	      w32_createwindow ((struct frame *) msg.wParam);
-	      PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0);
+	      if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
+		abort ();
 	      break;
-	    case WM_EMACS_CREATESCROLLBAR:
-	      {
-		HWND hwnd = w32_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);
+	    default:
+	      /* No need to be so draconian!  */
+	      /* abort (); */
+	      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 */
   
-  return (0);
+  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 */
@@ -2933,7 +3262,6 @@
      LPARAM lParam;
 {
   struct frame *f;
-  LRESULT ret = 1;
   struct w32_display_info *dpyinfo = &one_w32_display_info;
   W32Msg wmsg;
   int windows_translate;
@@ -3191,11 +3519,18 @@
     handle_plain_button:
       {
 	BOOL up;
-
-	if (parse_button (msg, NULL, &up))
+	int button;
+
+	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;
 	  }
       }
       
@@ -3232,6 +3567,11 @@
   
       return 0;
 
+    case WM_MOUSEWHEEL:
+      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)
@@ -3265,12 +3605,81 @@
       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;
+
+#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_ACTIVATE:
+    case WM_ACTIVATEAPP:
+    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:
       reset_modifiers ();
     case WM_KILLFOCUS:
     case WM_MOVE:
     case WM_SIZE:
-    case WM_SYSCOMMAND:
     case WM_COMMAND:
       wmsg.dwModifiers = w32_get_modifiers ();
       my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
@@ -3285,16 +3694,19 @@
       {
 	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);
@@ -3302,8 +3714,10 @@
 	    
 	    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 ();
 	    
@@ -3311,10 +3725,14 @@
 	    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)
 	      {
@@ -3326,7 +3744,7 @@
 		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)
 		      {
@@ -3339,31 +3757,88 @@
 		      }
 		  }
 		
-		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_SETWINDOWPOS:
       {
-	W32WindowPos * pos = (W32WindowPos *) 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;
+      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;
+	
+	/* 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;
+	      }
+	    button_state = 0;
+
+	    /* Remember we did a SetCapture on the initial mouse down
+	       event, but window focus will usually have changed to the
+	       popup menu before we released the mouse button.  For
+	       safety, we make sure the capture is cancelled now.  */
+	    ReleaseCapture ();
+	  }
+	else
+	  {
+	    retval = -1;
+	  }
+
+	return retval;
+      }
+
     default:
     dflt:
       return DefWindowProc (hwnd, msg, wParam, lParam);
     }
   
-  return (1);
+
+  /* The most common default return code for handled messages is 0.  */
+  return 0;
 }
 
 void 
@@ -3372,7 +3847,8 @@
 {
   MSG msg;
 
-  PostThreadMessage (dwWindowsThreadId, 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);
 }
 
@@ -3453,6 +3929,18 @@
   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;
 }
 
@@ -3477,7 +3965,7 @@
   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 w32_display_info *dpyinfo;
   Lisp_Object parent;
@@ -3497,7 +3985,7 @@
   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))
@@ -3513,6 +4001,11 @@
   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);
@@ -3526,18 +4019,22 @@
   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->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;
@@ -3584,27 +4081,17 @@
     /* First, try whatever font the caller has specified.  */
     if (STRINGP (font))
       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-97-*-*-c-*-*-ansi-");
     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-*-*-13-97-*-*-c-*-*-ansi-");
     /* 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-*-*-13-97-*-*-c-*-*-ansi-");
     UNBLOCK_INPUT;
     if (! STRINGP (font))
-      font = build_string ("-*-system");
+      font = build_string ("Fixedsys");
 
     x_default_parameter (f, parms, Qfont, font, 
 			 "font", "Font", string);
@@ -3625,6 +4112,7 @@
 	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,
@@ -3646,6 +4134,10 @@
 		       "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.w32->dwStyle = WS_OVERLAPPEDWINDOW;
   f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
@@ -3752,6 +4244,16 @@
   XSETFRAME (xfocus, dpyinfo->w32_focus_frame);
   return xfocus;
 }
+
+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;
+}
+
 
 XFontStruct *
 w32_load_font (dpyinfo,name)
@@ -3896,6 +4398,7 @@
   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;
@@ -3937,14 +4440,17 @@
   else if (stricmp (lpcs,"unicode") == 0)       return UNICODE_CHARSET;
   else if (stricmp (lpcs,"iso10646") == 0)      return UNICODE_CHARSET;
 #endif
+  else if (lpcs[0] == '#')			return atoi (lpcs + 1);
   else
-    return 0;
+    return DEFAULT_CHARSET;
 }
 
 char *
 w32_to_x_charset (fncharset)
     int fncharset;
 {
+  static char buf[16];
+
   switch (fncharset)
     {
     case ANSI_CHARSET:     return "ansi";
@@ -3954,7 +4460,9 @@
     case UNICODE_CHARSET:  return "unicode";
 #endif
     }
-  return "*";
+  /* Encode numerical value of unknown charset.  */
+  sprintf (buf, "#%u", fncharset);
+  return buf;
 }
 
 BOOL 
@@ -4194,8 +4702,7 @@
     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);
   
   /*    if (!lpef->size_ref || lptm->tmMaxCharWidth == FONT_WIDTH (lpef->size_ref)) */
@@ -4427,9 +4934,9 @@
     {
       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
@@ -4765,6 +5272,7 @@
   if (dpyinfo == 0)
     error ("Cannot connect to server %s", XSTRING (name)->data);
 
+  w32_in_use = 1;
   XSETFASTINT (Vwindow_system_version, 3);
 
   return dpyinfo;
@@ -4787,6 +5295,9 @@
   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. */
   {
@@ -4842,6 +5353,8 @@
 	error ("Cannot connect to server %s", XSTRING (display)->data);
     }
 
+  w32_in_use = 1;
+
   XSETFASTINT (Vwindow_system_version, 3);
   return Qnil;
 }
@@ -4933,9 +5446,33 @@
   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;
+}
+
 
 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 &&&*/
@@ -5130,10 +5667,12 @@
 
   /* 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);
 }
 
 #undef abort