changeset 19713:043ccce224fb

(SIF_*): Win95 macros defined for NT. (struct tagSCROLLINFO): Win95 struct defined for NT. (vertical_scroll_bar_min_handle, vertical_scroll_bar_top_border, vertical_scroll_bar_bottom_border, last_scroll_bar_drag_pos, Vw32_gab_focus_on_raise, Vw32_capslock_is_shiftlock): New variables. (w32_frame_up_to_date): Block input. (do_line_dance): Use DC while erasing, release at end. (show_mouse_face): Use column and endcolumn calculated at start of loop. (my_create_scrollbar, my_show_window, my_set_window_pos, my_set_focus) [! ATTACH_THREADS]: Send message to window instead of invoking Windows procedure. (x_scroll_bar_create, x_scroll_bar_move, x_scroll_bar_handle_click, x_scroll_bar_report_motion): Use SCROLLINFO for proportional handle. (x_scroll_bar_set_handle): Create proportional sized scroll handle. (w32_set_vertical_scroll_bar): Size handle according to how much is showing in window. (x_scroll_bar_set_report_motion): Use top_range, calculated above. (x_scroll_bar_clear): Hide scroll bar until ready to repaint. (show_scroll_bars): Pass in frame to my_show_window. (w32_read_socket): Distinguish between invisible and obscured frames when handling PAINT messages. Fixup off-by-one calculation for PAINT and SIZE. Pass in new parameter to w32_kbd_mods_to_emacs. Handle WM_DISPLAYCHANGE, WINDOWPOSCHANGED, ACTIVATE, SHOWWINDOW, INITMENU, and ACTIVATEAPP messages. Explicitly check for visibile and obscured frames, and to see if any event should cause a redisplay. (x_display_bar_cursor): Don't check whether frame is updating here. (x_display_cursor): Check it here instead. (x_set_offset) [HAVE_NTGUI]: Don't add border widths. Set NOACTIVATE when setting window position. (x_set_window_size): Fixup off-by-one calculation when setting window position. Mark frame garbaged earlier. Clear mouse highlighting state. (x_focus_on_frame): Set focus by making frame the foreground window. (x_raise_frame): Support frames to be raised without grabbing focus. (x_lower_frame): Set NOACTIVATE flag when setting window position. (x_make_frame_visible, x_make_frame_invisible): Pass in frame to my_show_window. to my_show_window. (x_iconify_frame): Send a MINIMIZE message to the window. (x_wm_set_size_hint): Set font width, line height, border, and scroll bar indexes instead of X and Y unit indexes. (w32_initialize): Set input mode. Use w32_msg_worker instead of windows_msg_worker. Dynamically link proportional scroll bar functions and intialize proportional scroll bar variables. (syms_of_w32term): DEFVAR new variables. (construct_mouse_wheel): New function. Constructs an input event from a WM_MOUSEWHEEL message. (w32_read_socket): Handle WM_MOUSEWHEEL. (w32_read_socket): Pass in new parameter to key_event. Let key_event determine whether key is dead. For MOVE, use x_real_positions to map to client coords. (x_set_mouse_pixel_position): Offset to use client area as origin.
author Geoff Voelker <voelker@cs.washington.edu>
date Wed, 03 Sep 1997 01:07:37 +0000
parents 9a6e50f6b471
children 72fa0e75a0fe
files src/w32term.c
diffstat 1 files changed, 685 insertions(+), 198 deletions(-) [+]
line wrap: on
line diff
--- a/src/w32term.c	Wed Sep 03 01:05:33 1997 +0000
+++ b/src/w32term.c	Wed Sep 03 01:07:37 1997 +0000
@@ -27,7 +27,7 @@
 #include "charset.h"
 #include "blockinput.h"
 
-#include <w32term.h>
+#include "w32term.h"
 
 #include "systty.h"
 #include "systime.h"
@@ -95,6 +95,38 @@
 DWORD dwMainThreadId = 0;
 HANDLE hMainThread = NULL;
 
+#ifndef SIF_ALL
+/* These definitions are new with Windows 95. */
+#define SIF_RANGE           0x0001
+#define SIF_PAGE            0x0002
+#define SIF_POS             0x0004
+#define SIF_DISABLENOSCROLL 0x0008
+#define SIF_TRACKPOS        0x0010
+#define SIF_ALL             (SIF_RANGE | SIF_PAGE | SIF_POS | SIF_TRACKPOS)
+
+typedef struct tagSCROLLINFO
+{
+    UINT    cbSize;
+    UINT    fMask;
+    int     nMin;
+    int     nMax;
+    UINT    nPage;
+    int     nPos;
+    int     nTrackPos;
+}   SCROLLINFO, FAR *LPSCROLLINFO;
+typedef SCROLLINFO CONST FAR *LPCSCROLLINFO;
+#endif /* SIF_ALL */
+
+/* Dynamic linking to new proportional scroll bar functions. */
+int (PASCAL *pfnSetScrollInfo) (HWND hwnd, int fnBar, LPSCROLLINFO lpsi, BOOL fRedraw);
+BOOL (PASCAL *pfnGetScrollInfo) (HWND hwnd, int fnBar, LPSCROLLINFO lpsi);
+
+int vertical_scroll_bar_min_handle;
+int vertical_scroll_bar_top_border;
+int vertical_scroll_bar_bottom_border;
+
+int last_scroll_bar_drag_pos;
+
 /* Mouse movement. */
 
 /* Where the mouse was last time we reported a mouse event.  */
@@ -105,6 +137,12 @@
 
 Lisp_Object Vw32_swap_mouse_buttons;
 
+/* Control whether x_raise_frame also sets input focus.  */
+Lisp_Object Vw32_grab_focus_on_raise;
+
+/* Control whether Caps Lock affects non-ascii characters.  */
+Lisp_Object Vw32_capslock_is_shiftlock;
+
 /* The scroll bar in which the last motion event occurred.
 
    If the last motion event occurred in a scroll bar, we set this
@@ -324,6 +362,7 @@
 w32_frame_up_to_date (f)
      FRAME_PTR f;
 {
+  BLOCK_INPUT;
   if (FRAME_W32_DISPLAY_INFO (f)->mouse_face_deferred_gc
       || f == FRAME_W32_DISPLAY_INFO (f)->mouse_face_mouse_frame)
     {
@@ -332,6 +371,7 @@
 			    FRAME_W32_DISPLAY_INFO (f)->mouse_face_mouse_y);
       FRAME_W32_DISPLAY_INFO (f)->mouse_face_deferred_gc = 0;
     }
+  UNBLOCK_INPUT;
 }
 
 /* External interface to control of standout mode.
@@ -875,14 +915,12 @@
 	i = j+1;
       }
 
-  release_frame_dc (f, hdc);
-
   for (i = 0; i < ht; ++i)
     if (line_dance[i] == -1)
       {
 	for (j = i; j < ht && line_dance[j] == -1; ++j);
 	/* Clear [i,j) */
-	w32_clear_area (f, NULL,
+	w32_clear_area (f, hdc,
 			  intborder, 
 			  CHAR_TO_PIXEL_ROW (f, i),
 			  f->width * FONT_WIDTH (f->output_data.w32->font),
@@ -890,6 +928,8 @@
 	i = j-1;
       }
   line_dance_in_progress = 0;
+
+  release_frame_dc (f, hdc);
 }
 
 /* Support routines for exposure events.  */
@@ -1265,6 +1305,25 @@
   }
 }
 
+static void
+construct_mouse_wheel (result, msg, f)
+     struct input_event *result;
+     W32Msg *msg;
+     struct frame *f;
+{
+  POINT p;
+  result->kind = mouse_wheel;
+  result->code = (short) HIWORD (msg->msg.wParam);
+  result->timestamp = msg->msg.time;
+  result->modifiers = msg->dwModifiers;
+  p.x = LOWORD (msg->msg.lParam);
+  p.y = HIWORD (msg->msg.lParam);
+  ScreenToClient(msg->msg.hwnd, &p);
+  XSETINT (result->x, p.x);
+  XSETINT (result->y, p.y);
+  XSETFRAME (result->frame_or_window, f);
+}
+
 
 /* Function to report a mouse movement to the mainstream Emacs code.
    The input handler calls this.
@@ -1606,8 +1665,8 @@
       /* If the cursor's in the text we are about to rewrite,
 	 turn the cursor off.  */
       if (i == curs_y
-	  && curs_x >= FRAME_W32_DISPLAY_INFO (f)->mouse_face_beg_col - 1
-	  && curs_x <= FRAME_W32_DISPLAY_INFO (f)->mouse_face_end_col)
+	  && curs_x >= column - 1
+	  && curs_x <= endcolumn)
 	{
 	  x_display_cursor (f, 0);
 	  cursor_off = 1;
@@ -1690,6 +1749,7 @@
   BLOCK_INPUT;
 
   if (! NILP (last_mouse_scroll_bar))
+    /* This is never called at the moment.  */
     x_scroll_bar_report_motion (fp, bar_window, part, x, y, time);
   else
     {
@@ -1803,34 +1863,31 @@
      struct frame * f;
      struct scroll_bar * bar;
 {
-  MSG msg;
-  
-  PostThreadMessage (dwWindowsThreadId, WM_EMACS_CREATESCROLLBAR, (WPARAM) f, 
-		     (LPARAM) bar);
-  GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
-  
-  return ((HWND) msg.wParam);
+  return (HWND) SendMessage (FRAME_W32_WINDOW (f),
+			     WM_EMACS_CREATESCROLLBAR, (WPARAM) f, 
+			     (LPARAM) bar);
 }
 
 //#define ATTACH_THREADS
 
-void
-my_show_window (HWND hwnd, int how)
+BOOL
+my_show_window (FRAME_PTR f, HWND hwnd, int how)
 {
 #ifndef ATTACH_THREADS
-  SendMessage (hwnd, WM_EMACS_SHOWWINDOW, (WPARAM) how, 0);
+  return SendMessage (FRAME_W32_WINDOW (f), WM_EMACS_SHOWWINDOW,
+		      (WPARAM) hwnd, (LPARAM) how);
 #else
-  ShowWindow (hwnd , how);
+  return ShowWindow (hwnd, how);
 #endif
 }
 
 void
 my_set_window_pos (HWND hwnd, HWND hwndAfter,
-		   int x, int y, int cx, int cy, int flags)
+		   int x, int y, int cx, int cy, UINT flags)
 {
 #ifndef ATTACH_THREADS
-  W32WindowPos pos;
-  pos.hwndAfter = hwndAfter;
+  WINDOWPOS pos;
+  pos.hwndInsertAfter = hwndAfter;
   pos.x = x;
   pos.y = y;
   pos.cx = cx;
@@ -1842,6 +1899,15 @@
 #endif
 }
 
+BOOL
+my_set_focus (f, hwnd)
+     struct frame * f;
+     HWND hwnd;
+{
+  SendMessage (FRAME_W32_WINDOW (f), WM_EMACS_SETFOCUS, 
+	       (WPARAM) hwnd, 0);
+}
+
 void
 my_destroy_window (f, hwnd)
      struct frame * f;
@@ -1878,8 +1944,25 @@
 
   hwnd = my_create_scrollbar (f, bar);
 
-  SetScrollRange (hwnd, SB_CTL, 0, height, FALSE);
-  SetScrollPos (hwnd, SB_CTL, 0, TRUE);
+  if (pfnSetScrollInfo)
+    {
+      SCROLLINFO si;
+
+      si.cbSize = sizeof (si);
+      si.fMask = SIF_ALL;
+      si.nMin = 0;
+      si.nMax = VERTICAL_SCROLL_BAR_TOP_RANGE (height)
+	+ VERTICAL_SCROLL_BAR_MIN_HANDLE;
+      si.nPage = si.nMax;
+      si.nPos = 0;
+
+      pfnSetScrollInfo (hwnd, SB_CTL, &si, FALSE);
+    }
+  else
+    {
+      SetScrollRange (hwnd, SB_CTL, 0, VERTICAL_SCROLL_BAR_TOP_RANGE (height), FALSE);
+      SetScrollPos (hwnd, SB_CTL, 0, FALSE);
+    }
 
   SET_SCROLL_BAR_W32_WINDOW (bar, hwnd);
 
@@ -1924,11 +2007,48 @@
 
   BLOCK_INPUT;
 
+  {
+    int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (XINT (bar->height));
+
+    /* Make sure the values are reasonable, and try to preserve
+       the distance between start and end.  */
+    {
+      int length = end - start;
+
+      if (start < 0)
+	start = 0;
+      else if (start > top_range)
+	start = top_range;
+      end = start + length;
+
+      if (end < start)
+	end = start;
+      else if (end > top_range && ! dragging)
+	end = top_range;
+    }
+  }
+
   /* Store the adjusted setting in the scroll bar.  */
   XSETINT (bar->start, start);
   XSETINT (bar->end, end);
 
-  SetScrollPos (w, SB_CTL, start, TRUE);
+  /* If being dragged, let scroll bar update itself.  */
+  if (!dragging)
+    {
+      if (pfnSetScrollInfo)
+	{
+	  SCROLLINFO si;
+
+	  si.cbSize = sizeof (si);
+	  si.fMask = SIF_PAGE | SIF_POS;
+	  si.nPage = end - start + VERTICAL_SCROLL_BAR_MIN_HANDLE;
+	  si.nPos = start;
+
+	  pfnSetScrollInfo (w, SB_CTL, &si, TRUE);
+	}
+      else
+	SetScrollPos (w, SB_CTL, start, TRUE);
+    }
 
   UNBLOCK_INPUT;
 }
@@ -1943,12 +2063,40 @@
   Window w = SCROLL_BAR_W32_WINDOW (bar);
   FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
 
+  /* If already correctly positioned, do nothing.  */
+  if ( XINT (bar->left) == left
+       && XINT (bar->top) == top
+       && XINT (bar->width) ==  width
+       && XINT (bar->height) == height )
+    {
+      /* Redraw after clear_frame. */
+      if (!my_show_window (f, w, SW_NORMAL))
+	InvalidateRect (w, NULL, FALSE);
+      return;
+    }
+
   BLOCK_INPUT;
 
+  /* Make sure scroll bar is "visible" before moving, to ensure the
+     area of the parent window now exposed will be refreshed.  */
+  my_show_window (f, w, SW_HIDE);
   MoveWindow (w, left, top, width, height, TRUE);
-  SetScrollRange (w, SB_CTL, 0, height, FALSE);
-  InvalidateRect (w, NULL, FALSE);
-  my_show_window (w, SW_NORMAL);
+  if (pfnSetScrollInfo)
+    {
+      SCROLLINFO si;
+
+      si.cbSize = sizeof (si);
+      si.fMask = SIF_RANGE;
+      si.nMin = 0;
+      si.nMax = VERTICAL_SCROLL_BAR_TOP_RANGE (height)
+	+ VERTICAL_SCROLL_BAR_MIN_HANDLE;
+
+      pfnSetScrollInfo (w, SB_CTL, &si, FALSE);
+    }
+  else
+    SetScrollRange (w, SB_CTL, 0, VERTICAL_SCROLL_BAR_TOP_RANGE (height), FALSE);
+  my_show_window (f, w, SW_NORMAL);
+//  InvalidateRect (w, NULL, FALSE);
 
   XSETINT (bar->left, left);
   XSETINT (bar->top, top);
@@ -2014,22 +2162,20 @@
       x_scroll_bar_move (bar, pixel_top, pixel_left, pixel_width, pixel_height);
     }
 
-  /* Set the scroll bar's current state, unless we're currently being
-     dragged.  */
-  if (NILP (bar->dragging))
-    {
-      int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (pixel_height);
-
-      if (whole == 0)
-	x_scroll_bar_set_handle (bar, 0, top_range, 0);
-      else
-	{
-	  int start = (int) (((double) position * top_range) / whole);
-	  int end = (int) (((double) (position + portion) * top_range) / whole);
-
-	  x_scroll_bar_set_handle (bar, start, end, 0);
-	}
-    }
+  /* Set the scroll bar's current state.  */
+  {
+    int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (pixel_height);
+
+    if (whole == 0)
+      x_scroll_bar_set_handle (bar, 0, top_range, 0);
+    else
+      {
+	int start = (int) (((double) position * top_range) / whole);
+	int end = (int) (((double) (position + portion) * top_range) / whole);
+
+	x_scroll_bar_set_handle (bar, start, end, 0);
+      }
+  }
 
   XSETVECTOR (window->vertical_scroll_bar, bar);
 }
@@ -2159,19 +2305,27 @@
   emacs_event->timestamp = msg->msg.time;
 
   {
-    int internal_height
-      = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (XINT (bar->height));
-    int top_range
-      = VERTICAL_SCROLL_BAR_TOP_RANGE (XINT (bar->height));
-    int y = GetScrollPos ((HWND) msg->msg.lParam, SB_CTL);
+    int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (XINT (bar->height));
+    int y;
+    int dragging = !NILP (bar->dragging);
+
+    if (pfnGetScrollInfo)
+      {
+	SCROLLINFO si;
+
+	si.cbSize = sizeof (si);
+	si.fMask = SIF_POS;
+
+	pfnGetScrollInfo ((HWND) msg->msg.lParam, SB_CTL, &si);
+	y = si.nPos;
+      }
+    else
+      y = GetScrollPos ((HWND) msg->msg.lParam, SB_CTL);
+
+    bar->dragging = Qnil;
 
     switch (LOWORD (msg->msg.wParam))
       {
-      case SB_THUMBTRACK:
-	emacs_event->part = scroll_bar_handle;
-	if (VERTICAL_SCROLL_BAR_TOP_RANGE (XINT (bar->height)) <= 0xffff)
-	    y = HIWORD (msg->msg.wParam);
-	break;
       case SB_LINEDOWN:
 	emacs_event->part = scroll_bar_down_arrow;
 	break;
@@ -2192,12 +2346,76 @@
 	emacs_event->part = scroll_bar_handle;
 	y = top_range;
 	break;
+      case SB_THUMBTRACK:
       case SB_THUMBPOSITION:
+	if (VERTICAL_SCROLL_BAR_TOP_RANGE (XINT (bar->height)) <= 0xffff)
+	    y = HIWORD (msg->msg.wParam);
+	bar->dragging = Qt;
 	emacs_event->part = scroll_bar_handle;
+
+	/* "Silently" update current position.  */
+	if (pfnSetScrollInfo)
+	  {
+	    SCROLLINFO si;
+
+	    si.cbSize = sizeof (si);
+	    si.fMask = SIF_POS;
+
+#if 0
+	    /* Shrink handle if necessary to allow full range for position.  */
+	    {
+	      int start = XINT (bar->start);
+	      int end = XINT (bar->end);
+	      int len = end - start;
+
+	      /* If new end is nearly hitting bottom, we must shrink
+	         handle.  How much we shrink it depends on the relative
+	         sizes of len and top_range.  */
+	      if (y + len > top_range - 2)
+		{
+		  len -= min (top_range / 10, (len / 3) + 2);
+		  if (len < 0)
+		    len = 0;
+		}
+	      si.nPage = len + VERTICAL_SCROLL_BAR_MIN_HANDLE;
+	      si.fMask |= SIF_PAGE;
+	    }
+#endif
+	    si.nPos = y;
+	    /* Remember apparent position (we actually lag behind the real
+	       position, so don't set that directly.  */
+	    last_scroll_bar_drag_pos = y;
+
+	    pfnSetScrollInfo (SCROLL_BAR_W32_WINDOW (bar), SB_CTL, &si, FALSE);
+	  }
+	else
+	  SetScrollPos (SCROLL_BAR_W32_WINDOW (bar), SB_CTL, y, FALSE);
 	break;
       case SB_ENDSCROLL:
+	/* If this is the end of a drag sequence, then reset the scroll
+	   handle size to normal and do a final redraw.  Otherwise do
+	   nothing.  */
+	if (dragging)
+	  {
+	    if (pfnSetScrollInfo)
+	      {
+		SCROLLINFO si;
+		int start = XINT (bar->start);
+		int end = XINT (bar->end);
+
+		si.cbSize = sizeof (si);
+		si.fMask = SIF_PAGE | SIF_POS;
+		si.nPage = end - start + VERTICAL_SCROLL_BAR_MIN_HANDLE;
+		si.nPos = last_scroll_bar_drag_pos;
+
+		pfnSetScrollInfo (SCROLL_BAR_W32_WINDOW (bar), SB_CTL, &si, TRUE);
+	      }
+	    else
+	      SetScrollPos (SCROLL_BAR_W32_WINDOW (bar), SB_CTL, y, TRUE);
+	  }
+	/* fall through */
       default:
-	SetScrollPos (SCROLL_BAR_W32_WINDOW (bar), SB_CTL, y, TRUE);
+	emacs_event->kind = no_event;
 	return FALSE;
       }
 
@@ -2222,13 +2440,26 @@
   Window w = SCROLL_BAR_W32_WINDOW (bar);
   FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
   int pos;
+  int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (XINT (bar->height));
 
   BLOCK_INPUT;
 
   *fp = f;
   *bar_window = bar->window;
 
-  pos = GetScrollPos (w, SB_CTL);
+  if (pfnGetScrollInfo)
+    {
+      SCROLLINFO si;
+
+      si.cbSize = sizeof (si);
+      si.fMask = SIF_POS | SIF_PAGE | SIF_RANGE;
+
+      pfnGetScrollInfo (w, SB_CTL, &si);
+      pos = si.nPos;
+      top_range = si.nMax - si.nPage + 1;
+    }
+  else
+    pos = GetScrollPos (w, SB_CTL);
 
   switch (LOWORD (last_mouse_scroll_bar_pos))
   {
@@ -2248,7 +2479,7 @@
   }
 
   XSETINT(*x, pos);
-  XSETINT(*y, VERTICAL_SCROLL_BAR_TOP_RANGE (XINT (bar->height)));
+  XSETINT(*y, top_range);
 
   f->mouse_moved = 0;
   last_mouse_scroll_bar = Qnil;
@@ -2275,11 +2506,16 @@
       HDC hdc = GetDC (window);
       RECT rect;
 
-      my_show_window (window, SW_HIDE);
+      /* Hide scroll bar until ready to repaint.  x_scroll_bar_move
+         arranges to refresh the scroll bar if hidden.  */
+      my_show_window (f, window, SW_HIDE);
+
       GetClientRect (window, &rect);
       select_palette (f, hdc);
       w32_clear_rect (f, hdc, &rect);
       deselect_palette (f, hdc);
+
+      ReleaseDC (window, hdc);
     }
 }
 
@@ -2293,7 +2529,7 @@
        bar = XSCROLL_BAR (bar)->next)
     {
       HWND window = SCROLL_BAR_W32_WINDOW (XSCROLL_BAR (bar));
-      my_show_window (window, how);
+      my_show_window (f, window, how);
     }
 }
 
@@ -2310,7 +2546,7 @@
 int temp_index;
 short temp_buffer[100];
 
-extern int key_event (KEY_EVENT_RECORD *, struct input_event *);
+extern int key_event (KEY_EVENT_RECORD *, struct input_event *, int *isdead);
 
 /* Map a W32 WM_CHAR message into a KEY_EVENT_RECORD so that
    we can use the same routines to handle input in both console
@@ -2369,12 +2605,9 @@
      int expected;
 {
   int count = 0;
-  int nbytes = 0;
-  int items_pending;            /* How many items are in the X queue. */
+  int check_visibility = 0;
   W32Msg msg;
   struct frame *f;
-  int event_found = 0;
-  int prefix;
   Lisp_Object part;
   struct w32_display_info *dpyinfo = &one_w32_display_info;
 
@@ -2398,16 +2631,34 @@
       switch (msg.msg.message)
 	{
 	case WM_PAINT:
-	  {
 	    f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
 
 	    if (f) 
 	      {
-		if (f->async_visible == 0)
+	      if (f->async_visible != 1)
 		  {
+		  /* Definitely not obscured, so mark as visible.  */
 		    f->async_visible = 1;
 		    f->async_iconified = 0;
 		    SET_FRAME_GARBAGED (f);
+		  DebPrint (("frame %04x (%s) reexposed\n", f,
+			     XSTRING (f->name)->data));
+
+		    /* WM_PAINT serves as MapNotify as well, so report
+                       visibility changes properly.  */
+		    if (f->iconified)
+		      {
+			bufp->kind = deiconify_event;
+			XSETFRAME (bufp->frame_or_window, f);
+			bufp++;
+			count++;
+			numchars--;
+		      }
+		    else if (! NILP(Vframe_list)
+			     && ! NILP (XCONS (Vframe_list)->cdr))
+		      /* Force a redisplay sooner or later to update the
+			 frame titles in case this is the second frame.  */
+		      record_asynch_buffer_change ();
 		  }
 		else
 		  {
@@ -2416,12 +2667,12 @@
 		    dumprectangle (f,
 				   msg.rect.left,
 				   msg.rect.top,
-				   msg.rect.right-msg.rect.left+1,
-				   msg.rect.bottom-msg.rect.top+1);
+				   msg.rect.right - msg.rect.left,
+				   msg.rect.bottom - msg.rect.top);
 		  }
 	      }
-	  }
 	  break;
+
 	case WM_KEYDOWN:
 	case WM_SYSKEYDOWN:
 	  f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
@@ -2433,7 +2684,8 @@
 	      temp_buffer[temp_index++] = msg.msg.wParam;
 	      bufp->kind = non_ascii_keystroke;
 	      bufp->code = msg.msg.wParam;
-	      bufp->modifiers = w32_kbd_mods_to_emacs (msg.dwModifiers);
+	      bufp->modifiers = w32_kbd_mods_to_emacs (msg.dwModifiers,
+                                                         msg.msg.wParam);
 	      XSETFRAME (bufp->frame_or_window, f);
 	      bufp->timestamp = msg.msg.time;
 	      bufp++;
@@ -2441,6 +2693,7 @@
 	      count++;
 	    }
 	  break;
+
 	case WM_SYSCHAR:
 	case WM_CHAR:
 	  f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
@@ -2450,13 +2703,14 @@
 	      if (numchars > 1) 
 		{
 		  int add;
+		  int isdead = 0;
 		  KEY_EVENT_RECORD key, *keyp = &key;
 
 		  if (temp_index == sizeof temp_buffer / sizeof (short))
 		    temp_index = 0;
 		  
 		  convert_to_key_event (&msg, keyp);
-		  add = key_event (keyp, bufp);
+		  add = key_event (keyp, bufp, &isdead);
 		  XSETFRAME (bufp->frame_or_window, f);
 		  if (add == -1)
 		    {
@@ -2470,12 +2724,7 @@
 		      add = 1;
 		    }
 
-		  /* Throw dead keys away.  However, be sure not to
-		     throw away the dead key if it was produced using
-		     AltGr and there is a valid AltGr scan code for
-		     this key.  */
-		  if (is_dead_key (msg.msg.wParam) 
-		      && !((VkKeyScan ((char) bufp->code) & 0xff00) == 0x600))
+		  if (isdead)
 		    break;
 
 		  bufp += add;
@@ -2488,6 +2737,7 @@
 		}
 	    }
 	  break;
+
 	case WM_MOUSEMOVE:
 	  if (dpyinfo->grabbed && last_mouse_frame
 	      && FRAME_LIVE_P (last_mouse_frame))
@@ -2501,6 +2751,7 @@
 	    clear_mouse_face (FRAME_W32_DISPLAY_INFO (f));
 	  
 	  break;
+
 	case WM_LBUTTONDOWN:
 	case WM_LBUTTONUP:
 	case WM_MBUTTONDOWN:
@@ -2540,12 +2791,34 @@
 		dpyinfo->grabbed |= (1 << button);
 		last_mouse_frame = f;
 	      }
+	    break;
 	  }
 	  
+      case WM_MOUSEWHEEL:
+          if (dpyinfo->grabbed && last_mouse_frame
+              && FRAME_LIVE_P (last_mouse_frame))
+            f = last_mouse_frame;
+          else
+            f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
+
+          if (f)
+            {
+              if ((!dpyinfo->w32_focus_frame 
+                   || f == dpyinfo->w32_focus_frame)
+                  && (numchars >= 1))
+                {
+                  construct_mouse_wheel (bufp, &msg, f);
+                  bufp++;
+                  count++;
+                  numchars--;
+                }
+            }
 	  break;
+
 	case WM_VSCROLL:
 	  {
-	    struct scroll_bar *bar = x_window_to_scroll_bar ((HWND)msg.msg.lParam);
+	    struct scroll_bar *bar =
+	      x_window_to_scroll_bar ((HWND)msg.msg.lParam);
 	      
 	    if (bar && numchars >= 1)
 	      {
@@ -2556,19 +2829,48 @@
 		    numchars--;
 		  }
 	      }
+	    break;
 	  }
 	  
+	case WM_WINDOWPOSCHANGED:
+	case WM_ACTIVATE:
+	case WM_ACTIVATEAPP:
+	  check_visibility = 1;
 	  break;
+
 	case WM_MOVE:
 	  f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
 	  
 	  if (f && !f->async_iconified)
 	    {
-	      f->output_data.w32->left_pos = LOWORD (msg.msg.lParam);
-	      f->output_data.w32->top_pos = HIWORD (msg.msg.lParam);
+	      int x, y;
+
+	      x_real_positions (f, &x, &y);
+	      f->output_data.w32->left_pos = x;
+	      f->output_data.w32->top_pos = y;
 	    }
-	  
+
+	  check_visibility = 1;
 	  break;
+
+	case WM_SHOWWINDOW:
+	  /* If window has been obscured or exposed by another window
+	     being maximised or minimised/restored, then recheck
+	     visibility of all frames.  Direct changes to our own
+	     windows get handled by WM_SIZE.  */
+#if 0
+	  if (msg.msg.lParam != 0)
+	    check_visibility = 1;
+	  else
+	    {
+	      f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
+	      f->async_visible = msg.msg.wParam;
+	    }
+#endif
+
+	  check_visibility = 1;
+	  break;
+
 	case WM_SIZE:
 	  f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
 	  
@@ -2582,12 +2884,14 @@
 	      
 	      GetClientRect(msg.msg.hwnd, &rect);
 	      
-	      height = rect.bottom - rect.top + 1;
-	      width = rect.right - rect.left + 1;
+	      height = rect.bottom - rect.top;
+	      width = rect.right - rect.left;
 	      
 	      rows = PIXEL_TO_CHAR_HEIGHT (f, height);
 	      columns = PIXEL_TO_CHAR_WIDTH (f, width);
 	      
+	      /* TODO: Clip size to the screen dimensions.  */
+	      
 	      /* Even if the number of character rows and columns has
 		 not changed, the font size may have changed, so we need
 		 to check the pixel dimensions as well.  */
@@ -2607,45 +2911,14 @@
 		  f->output_data.w32->win_gravity = NorthWestGravity;
 		}
 	    }
-	  
-	  break;
-	case WM_SETFOCUS:
-	case WM_KILLFOCUS:
-	  f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
-	  
-	  if (msg.msg.message == WM_SETFOCUS)
-	    {
-	      x_new_focus_frame (dpyinfo, f);
-	    }
-	  else if (f == dpyinfo->w32_focus_frame)
-	    x_new_focus_frame (dpyinfo, 0);
-	  
-	  break;
-	case WM_SYSCOMMAND:
-	  switch (msg.msg.wParam & 0xfff0)  /* Lower 4 bits used by Windows. */
+
+	  /* Inform lisp of whether frame has been iconified etc. */
+	  if (f)
 	    {
-	    case SC_CLOSE:
-	      f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
-	      
-	      if (f)
+	      switch (msg.msg.wParam)
 		{
-		  if (numchars == 0)
-		    abort ();
-		  
-		  bufp->kind = delete_window_event;
-		  XSETFRAME (bufp->frame_or_window, f);
-		  bufp++;
-		  count++;
-		  numchars--;
-		}
-	      
-	      break;
-	    case SC_MINIMIZE:
-	      f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
-	      
-	      if (f)
-		{
-		  f->async_visible = 1;
+		case SIZE_MINIMIZED:
+		  f->async_visible = 0;
 		  f->async_iconified = 1;
 		  
 		  bufp->kind = iconify_event;
@@ -2653,15 +2926,10 @@
 		  bufp++;
 		  count++;
 		  numchars--;
-		}
-	      
-	      break;
-	    case SC_MAXIMIZE:
-	    case SC_RESTORE:
-	      f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
-	      
-	      if (f)
-		{
+		  break;
+
+		case SIZE_MAXIMIZED:
+		case SIZE_RESTORED:
 		  f->async_visible = 1;
 		  f->async_iconified = 0;
 		  
@@ -2682,12 +2950,29 @@
 		       to update the frame titles
 		       in case this is the second frame.  */
 		    record_asynch_buffer_change ();
+		  break;
 		}
-	      
-	      break;
 	    }
+
+	  check_visibility = 1;
+	  break;
+
+	case WM_SETFOCUS:
+	case WM_KILLFOCUS:
+	  f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
 	  
+	  if (msg.msg.message == WM_SETFOCUS)
+	    {
+	      x_new_focus_frame (dpyinfo, f);
+	    }
+	  else if (f == dpyinfo->w32_focus_frame)
+	    {
+	      x_new_focus_frame (dpyinfo, 0);
+	    }
+
+	  check_visibility = 1;
 	  break;
+
 	case WM_CLOSE:
 	  f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
 	  
@@ -2702,11 +2987,28 @@
 	      count++;
 	      numchars--;
 	    }
+	  break;
+
+	case WM_INITMENU:
+	  f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
 	  
+	  if (f)
+	    {
+	      if (numchars == 0)
+		abort ();
+	  
+	      bufp->kind = menu_bar_activate_event;
+	      XSETFRAME (bufp->frame_or_window, f);
+	      bufp++;
+	      count++;
+	      numchars--;
+	    }
 	  break;
+
 	case WM_COMMAND:
 	  f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
 	  
+#if 1
 	  if (f)
 	    {
 	      if (msg.msg.lParam == 0) 
@@ -2743,6 +3045,24 @@
 		  /* Came from popup menu */
 		}
 	    }
+#endif
+
+	  check_visibility = 1;
+	  break;
+
+	case WM_DISPLAYCHANGE:
+	  f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
+
+	  if (f) 
+	    {
+	      dpyinfo->width = (short) LOWORD (msg.msg.lParam);
+	      dpyinfo->height = (short) HIWORD (msg.msg.lParam);
+	      dpyinfo->n_cbits = msg.msg.wParam;
+	      DebPrint (("display change: %d %d\n", dpyinfo->width,
+			 dpyinfo->height));
+	    }
+	  
+	  check_visibility = 1;
 	  break;
 	}
     }
@@ -2756,6 +3076,62 @@
       pending_autoraise_frame = 0;
     }
 
+  /* Check which frames are still visisble, if we have enqueued any user
+     events or been notified of events that may affect visibility.  We
+     do this here because there doesn't seem to be any direct
+     notification from Windows that the visibility of a window has
+     changed (at least, not in all cases).  */
+  if (count > 0 || check_visibility)
+    {
+      Lisp_Object tail, frame;
+
+      FOR_EACH_FRAME (tail, frame)
+	{
+	  FRAME_PTR f = XFRAME (frame);
+	  /* Check "visible" frames and mark each as obscured or not.
+	     Note that async_visible is nonzero for unobscured and
+	     obscured frames, but zero for hidden and iconified frames.  */
+	  if (FRAME_W32_P (f) && f->async_visible)
+	    {
+	      RECT clipbox;
+	      HDC  hdc = get_frame_dc (f);
+	      GetClipBox (hdc, &clipbox);
+	      release_frame_dc (f, hdc);
+
+	      if (clipbox.right == clipbox.left
+		  || clipbox.bottom == clipbox.top)
+		{
+		  /* Frame has become completely obscured so mark as
+		     such (we do this by setting async_visible to 2 so
+		     that FRAME_VISIBLE_P is still true, but redisplay
+		     will skip it).  */
+		  f->async_visible = 2;
+
+		  if (!FRAME_OBSCURED_P (f))
+		    {
+		      DebPrint (("frame %04x (%s) obscured\n", f,
+				 XSTRING (f->name)->data));
+		    }
+		}
+	      else
+		{
+		  /* Frame is not obscured, so mark it as such.  */
+		  f->async_visible = 1;
+
+		  if (FRAME_OBSCURED_P (f))
+		    {
+		      SET_FRAME_GARBAGED (f);
+		      DebPrint (("frame %04x (%s) reexposed\n", f,
+				 XSTRING (f->name)->data));
+
+		      /* Force a redisplay sooner or later.  */
+		      record_asynch_buffer_change ();
+		    }
+		}
+	    }
+	}
+    }
+
   UNBLOCK_INPUT;
   return count;
 }
@@ -2838,14 +3214,6 @@
   if (! on && f->phys_cursor_x < 0)
     return;
 
-  /* If we're not updating, then we want to use the current frame's
-     cursor position, not our local idea of where the cursor ought to be.  */
-  if (f != updating_frame)
-    {
-      curs_x = FRAME_CURSOR_X (f);
-      curs_y = FRAME_CURSOR_Y (f);
-    }
-
   /* If there is anything wrong with the current cursor state, remove it.  */
   if (f->phys_cursor_x >= 0
       && (!on
@@ -2905,14 +3273,6 @@
   if (!on && f->phys_cursor_x < 0)
     return;
 
-  /* If we're not updating, then we want to use the current frame's
-     cursor position, not our local idea of where the cursor ought to be.  */
-  if (f != updating_frame)
-    {
-      curs_x = FRAME_CURSOR_X (f);
-      curs_y = FRAME_CURSOR_Y (f);
-    }
-
   /* If cursor is currently being shown and we don't want it to be
      or it is in the wrong place,
      or we want a hollow box and it's not so, (pout!)
@@ -2930,14 +3290,12 @@
       /* If the cursor is in the mouse face area, redisplay that when
 	 we clear the cursor.  */
       if (f == FRAME_W32_DISPLAY_INFO (f)->mouse_face_mouse_frame
-	  &&
-	  (f->phys_cursor_y > FRAME_W32_DISPLAY_INFO (f)->mouse_face_beg_row
-	   || (f->phys_cursor_y == FRAME_W32_DISPLAY_INFO (f)->mouse_face_beg_row
-	       && f->phys_cursor_x >= FRAME_W32_DISPLAY_INFO (f)->mouse_face_beg_col))
-	  &&
-	  (f->phys_cursor_y < FRAME_W32_DISPLAY_INFO (f)->mouse_face_end_row
-	   || (f->phys_cursor_y == FRAME_W32_DISPLAY_INFO (f)->mouse_face_end_row
-	       && f->phys_cursor_x < FRAME_W32_DISPLAY_INFO (f)->mouse_face_end_col))
+	  && (f->phys_cursor_y > FRAME_W32_DISPLAY_INFO (f)->mouse_face_beg_row
+	      || (f->phys_cursor_y == FRAME_W32_DISPLAY_INFO (f)->mouse_face_beg_row
+		  && f->phys_cursor_x >= FRAME_W32_DISPLAY_INFO (f)->mouse_face_beg_col))
+	  && (f->phys_cursor_y < FRAME_W32_DISPLAY_INFO (f)->mouse_face_end_row
+	      || (f->phys_cursor_y == FRAME_W32_DISPLAY_INFO (f)->mouse_face_end_row
+		  && f->phys_cursor_x < FRAME_W32_DISPLAY_INFO (f)->mouse_face_end_col))
 	  /* Don't redraw the cursor's spot in mouse face
 	     if it is at the end of a line (on a newline).
 	     The cursor appears there, but mouse highlighting does not.  */
@@ -2991,12 +3349,26 @@
     }
 }
 
+/* Display the cursor on frame F, or clear it, according to ON.
+   Use the position specified by curs_x and curs_y
+   if we are doing an update of frame F now.
+   Otherwise use the position in the FRAME_CURSOR_X and FRAME_CURSOR_Y fields
+   of F.  */
+
 x_display_cursor (f, on)
      struct frame *f;
      int on;
 {
   BLOCK_INPUT;
 
+  /* If we're not updating, then we want to use the current frame's
+     cursor position, not our local idea of where the cursor ought to be.  */
+  if (f != updating_frame)
+    {
+      curs_x = FRAME_CURSOR_X (f);
+      curs_y = FRAME_CURSOR_Y (f);
+    }
+
   if (FRAME_DESIRED_CURSOR (f) == filled_box_cursor)
     x_display_box_cursor (f, on);
   else if (FRAME_DESIRED_CURSOR (f) == bar_cursor)
@@ -3122,6 +3494,9 @@
   }
 }
 
+/* Calculate the absolute position in frame F
+   from its current recorded position values and gravity.  */
+
 x_calc_absolute_position (f)
      struct frame *f;
 {
@@ -3207,17 +3582,20 @@
      when the frame is already visible, but experiment says we do.  */
   modified_left = f->output_data.w32->left_pos;
   modified_top = f->output_data.w32->top_pos;
+#ifndef HAVE_NTGUI
+  /* Do not add in border widths under W32.  */
   if (change_gravity != 0)
     {
       modified_left += f->output_data.w32->border_width;
       modified_top += f->output_data.w32->border_width;
     }
+#endif
 
   my_set_window_pos (FRAME_W32_WINDOW (f),
 		     NULL,
 		     modified_left, modified_top,
 		     0,0,
-		     SWP_NOZORDER | SWP_NOSIZE);
+		     SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
   UNBLOCK_INPUT;
 }
 
@@ -3232,6 +3610,8 @@
      int cols, rows;
 {
   int pixelwidth, pixelheight;
+  Lisp_Object window;
+  struct w32_display_info *dpyinfo = &one_w32_display_info;
   
   BLOCK_INPUT;
   
@@ -3258,14 +3638,12 @@
     AdjustWindowRect(&rect, f->output_data.w32->dwStyle,
 		     FRAME_EXTERNAL_MENU_BAR (f));
       
-    /* All windows have an extra pixel */
-
     my_set_window_pos (FRAME_W32_WINDOW (f),
 		       NULL, 
 		       0, 0,
-		       rect.right - rect.left + 1,
-		       rect.bottom - rect.top + 1,
-		       SWP_NOZORDER | SWP_NOMOVE);
+		       rect.right - rect.left,
+		       rect.bottom - rect.top,
+		       SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
   }
   
   /* Now, strictly speaking, we can't be sure that this is accurate,
@@ -3282,6 +3660,12 @@
   PIXEL_WIDTH (f) = pixelwidth;
   PIXEL_HEIGHT (f) = pixelheight;
 
+  /* We've set {FRAME,PIXEL}_{WIDTH,HEIGHT} to the values we hope to
+     receive in the ConfigureNotify event; if we get what we asked
+     for, then the event won't cause the screen to become garbaged, so
+     we have to make sure to do it here.  */
+  SET_FRAME_GARBAGED (f);
+
   /* If cursor was outside the new size, mark it as off.  */
   if (f->phys_cursor_y >= rows
       || f->phys_cursor_x >= cols)
@@ -3290,11 +3674,17 @@
       f->phys_cursor_y = -1;
     }
 
-  /* We've set {FRAME,PIXEL}_{WIDTH,HEIGHT} to the values we hope to
-     receive in the ConfigureNotify event; if we get what we asked
-     for, then the event won't cause the screen to become garbaged, so
-     we have to make sure to do it here.  */
-  SET_FRAME_GARBAGED (f);
+  /* Clear out any recollection of where the mouse highlighting was,
+     since it might be in a place that's outside the new frame size. 
+     Actually checking whether it is outside is a pain in the neck,
+     so don't try--just let the highlighting be done afresh with new size.  */
+  window = dpyinfo->mouse_face_window;
+  if (! NILP (window) && XFRAME (window) == f)
+    {
+      dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
+      dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
+      dpyinfo->mouse_face_window = Qnil;
+    }
   
   UNBLOCK_INPUT;
 }
@@ -3306,12 +3696,17 @@
      struct frame *f;
      int pix_x, pix_y;
 {
+  RECT rect;
+  POINT pt;
+
   BLOCK_INPUT;
 
-  pix_x += f->output_data.w32->left_pos;
-  pix_y += f->output_data.w32->top_pos;
-
-  SetCursorPos (pix_x, pix_y);
+  GetClientRect (FRAME_W32_WINDOW (f), &rect);
+  pt.x = rect.left + pix_x;
+  pt.y = rect.top + pix_y;
+  ClientToScreen (FRAME_W32_WINDOW (f), &pt);
+
+  SetCursorPos (pt.x, pt.y);
 
   UNBLOCK_INPUT;
 }
@@ -3340,6 +3735,18 @@
 x_focus_on_frame (f)
      struct frame *f;
 {
+  struct w32_display_info *dpyinfo = &one_w32_display_info;
+
+  /* Give input focus to frame.  */
+  BLOCK_INPUT;
+#if 0
+  /* Try not to change its Z-order if possible.  */
+  if (x_window_to_frame (dpyinfo, GetForegroundWindow ()))
+    my_set_focus (f, FRAME_W32_WINDOW (f));
+  else
+#endif
+    SetForegroundWindow (FRAME_W32_WINDOW (f));
+  UNBLOCK_INPUT;
 }
 
 x_unfocus_frame (f)
@@ -3352,15 +3759,59 @@
 x_raise_frame (f)
      struct frame *f;
 {
-//  if (f->async_visible)
+  BLOCK_INPUT;
+
+  /* Strictly speaking, raise-frame should only change the frame's Z
+     order, leaving input focus unchanged.  This is reasonable behaviour
+     on X where the usual policy is point-to-focus.  However, this
+     behaviour would be very odd on Windows where the usual policy is
+     click-to-focus.
+
+     On X, if the mouse happens to be over the raised frame, it gets
+     input focus anyway (so the window with focus will never be
+     completely obscured) - if not, then just moving the mouse over it
+     is sufficient to give it focus.  On Windows, the user must actually
+     click on the frame (preferrably the title bar so as not to move
+     point), which is more awkward.  Also, no other Windows program
+     raises a window to the top but leaves another window (possibly now
+     completely obscured) with input focus.
+
+     Because there is a system setting on Windows that allows the user
+     to choose the point to focus policy, we make the strict semantics
+     optional, but by default we grab focus when raising.  */
+
+  if (NILP (Vw32_grab_focus_on_raise))
     {
-      BLOCK_INPUT;
-      my_set_window_pos (FRAME_W32_WINDOW (f),
-		         HWND_TOP,
-		         0, 0, 0, 0,
-		         SWP_NOSIZE | SWP_NOMOVE);
-      UNBLOCK_INPUT;
+      /* The obvious call to my_set_window_pos doesn't work if Emacs is
+	 not already the foreground application: the frame is raised
+	 above all other frames belonging to us, but not above the
+	 current top window.  To achieve that, we have to resort to this
+	 more cumbersome method.  */
+
+      HDWP handle = BeginDeferWindowPos (2);
+      if (handle)
+	{
+	  DeferWindowPos (handle,
+			  FRAME_W32_WINDOW (f),
+  			  HWND_TOP,
+  			  0, 0, 0, 0,
+  			  SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
+
+	  DeferWindowPos (handle,
+			  GetForegroundWindow (),
+			  FRAME_W32_WINDOW (f),
+			  0, 0, 0, 0,
+			  SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
+
+	  EndDeferWindowPos (handle);
+	}
     }
+  else
+    {
+      SetForegroundWindow (FRAME_W32_WINDOW (f));
+    }
+
+  UNBLOCK_INPUT;
 }
 
 /* Lower frame F.  */
@@ -3368,15 +3819,12 @@
 x_lower_frame (f)
      struct frame *f;
 {
-//  if (f->async_visible)
-    {
-      BLOCK_INPUT;
-      my_set_window_pos (FRAME_W32_WINDOW (f),
-		         HWND_BOTTOM,
-		         0, 0, 0, 0,
-		         SWP_NOSIZE | SWP_NOMOVE);
-      UNBLOCK_INPUT;
-    }
+  BLOCK_INPUT;
+  my_set_window_pos (FRAME_W32_WINDOW (f),
+		     HWND_BOTTOM,
+		     0, 0, 0, 0,
+		     SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
+  UNBLOCK_INPUT;
 }
 
 static void
@@ -3412,14 +3860,12 @@
 	 before the window gets really visible.  */
       if (! FRAME_ICONIFIED_P (f)
 	  && ! f->output_data.w32->asked_for_visible)
-      {
 	x_set_offset (f, f->output_data.w32->left_pos, f->output_data.w32->top_pos, 0);
-//	SetForegroundWindow (FRAME_W32_WINDOW (f));
-      }
 
       f->output_data.w32->asked_for_visible = 1;
 
-      my_show_window (FRAME_W32_WINDOW (f), SW_SHOWNORMAL);
+//      my_show_window (f, FRAME_W32_WINDOW (f), f->async_iconified ? SW_RESTORE : SW_SHOW);
+      my_show_window (f, FRAME_W32_WINDOW (f), SW_SHOWNORMAL);
     }
 
   /* Synchronize to ensure Emacs knows the frame is visible
@@ -3482,7 +3928,7 @@
   
   BLOCK_INPUT;
   
-  my_show_window (FRAME_W32_WINDOW (f), SW_HIDE);
+  my_show_window (f, FRAME_W32_WINDOW (f), SW_HIDE);
   
   /* We can't distinguish this from iconification
      just by the event that we get from the server.
@@ -3514,9 +3960,8 @@
 
   BLOCK_INPUT;
 
-  my_show_window (FRAME_W32_WINDOW (f), SW_SHOWMINIMIZED);
-  /* The frame doesn't seem to be lowered automatically. */
-  x_lower_frame (f);
+  /* Simulate the user minimizing the frame.  */
+  PostMessage (FRAME_W32_WINDOW (f), WM_SYSCOMMAND, SC_MINIMIZE, 0);
 
   f->async_iconified = 1;
 
@@ -3578,8 +4023,10 @@
 
   enter_crit ();
 
-  SetWindowLong (window, WND_X_UNITS_INDEX, FONT_WIDTH (f->output_data.w32->font));
-  SetWindowLong (window, WND_Y_UNITS_INDEX, f->output_data.w32->line_height);
+  SetWindowLong (window, WND_FONTWIDTH_INDEX, FONT_WIDTH (f->output_data.w32->font));
+  SetWindowLong (window, WND_LINEHEIGHT_INDEX, f->output_data.w32->line_height);
+  SetWindowLong (window, WND_BORDER_INDEX, f->output_data.w32->internal_border_width);
+  SetWindowLong (window, WND_SCROLLBAR_INDEX, f->output_data.w32->vertical_scroll_bar_extra);
 
   leave_crit ();
 }
@@ -3794,7 +4241,7 @@
 
 /* Set up use of W32.  */
 
-DWORD windows_msg_worker ();
+DWORD w32_msg_worker ();
 
 w32_initialize ()
 {
@@ -3831,8 +4278,9 @@
 				   off the bottom */
   baud_rate = 19200;
 
-  /* Try to use interrupt input; if we can't, then start polling.  */
-  Fset_input_mode (Qt, Qnil, Qt, Qnil);
+  /* Initialize input mode: interrupt_input off, no flow control, allow
+     8 bit character input, standard quit char.  */
+  Fset_input_mode (Qnil, Qnil, make_number (2), Qnil);
 
   /* Create the window thread - it will terminate itself or when the app terminates */
 
@@ -3850,7 +4298,7 @@
     PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE);
 
     hWindowsThread = CreateThread (NULL, 0, 
-			       (LPTHREAD_START_ROUTINE) windows_msg_worker, 
+			       (LPTHREAD_START_ROUTINE) w32_msg_worker, 
 			       0, 0, &dwWindowsThreadId);
 
     GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
@@ -3867,6 +4315,31 @@
 #ifdef ATTACH_THREADS
   AttachThreadInput (dwMainThreadId, dwWindowsThreadId, TRUE);
 #endif
+
+  /* Dynamically link to optional system components. */
+  {
+    HANDLE user_lib = LoadLibrary ("user32.dll");
+
+#define LOAD_PROC(fn) pfn##fn = (void *) GetProcAddress (user_lib, #fn)
+
+    /* New proportional scroll bar functions. */
+    LOAD_PROC( SetScrollInfo );
+    LOAD_PROC( GetScrollInfo );
+
+#undef LOAD_PROC
+
+    FreeLibrary (user_lib);
+
+    /* If using proportional scroll bars, ensure handle is at least 5 pixels;
+       otherwise use the fixed height.  */
+    vertical_scroll_bar_min_handle = (pfnSetScrollInfo != NULL) ? 5 :
+      GetSystemMetrics (SM_CYVTHUMB);
+
+    /* For either kind of scroll bar, take account of the arrows; these
+       effectively form the border of the main scroll bar range.  */
+    vertical_scroll_bar_top_border = vertical_scroll_bar_bottom_border
+      = GetSystemMetrics (SM_CYVSCROLL);
+  }
 }
 
 void
@@ -3891,4 +4364,18 @@
 	      "Swap the mapping of middle and right mouse buttons.\n\
 When nil, middle button is mouse-2 and right button is mouse-3.");
   Vw32_swap_mouse_buttons = Qnil;
+
+  DEFVAR_LISP ("w32-grab-focus-on-raise",
+	       &Vw32_grab_focus_on_raise,
+	       "Raised frame grabs input focus.\n\
+When t, `raise-frame' grabs input focus as well.  This fits well\n\
+with the normal Windows click-to-focus policy, but might not be\n\
+desirable when using a point-to-focus policy.");
+  Vw32_grab_focus_on_raise = Qt;
+
+  DEFVAR_LISP ("w32-capslock-is-shiftlock",
+	       &Vw32_capslock_is_shiftlock,
+	       "Apply CapsLock state to non character input keys.\n\
+When nil, CapsLock only affects normal character input keys.");
+  Vw32_capslock_is_shiftlock = Qnil;
 }