]> code.delx.au - gnu-emacs/blobdiff - src/w32term.c
Merge branch 'emacs-24'
[gnu-emacs] / src / w32term.c
index 41ab645f31d0d3aea27b897bb8df0f053440f5e8..94b332b929f8d8203336fe0f4be0d4b76b1903a4 100644 (file)
@@ -50,6 +50,7 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include "process.h"
 #include "atimer.h"
 #include "keymap.h"
+#include "menu.h"
 
 #ifdef WINDOWSNT
 #include "w32.h"       /* for filename_from_utf16, filename_from_ansi */
@@ -157,8 +158,11 @@ DWORD dwMainThreadId = 0;
 HANDLE hMainThread = NULL;
 
 int vertical_scroll_bar_min_handle;
+int horizontal_scroll_bar_min_handle;
 int vertical_scroll_bar_top_border;
 int vertical_scroll_bar_bottom_border;
+int horizontal_scroll_bar_left_border;
+int horizontal_scroll_bar_right_border;
 
 int last_scroll_bar_drag_pos;
 
@@ -454,7 +458,7 @@ x_set_frame_alpha (struct frame *f)
   if (!pfnSetLayeredWindowAttributes)
     return;
 
-  if (dpyinfo->x_highlight_frame == f)
+  if (dpyinfo->w32_focus_frame == f)
     alpha = f->alpha[0];
   else
     alpha = f->alpha[1];
@@ -999,7 +1003,7 @@ x_set_mouse_face_gc (struct glyph_string *s)
   else
     face_id = FACE_FOR_CHAR (s->f, face, 0, -1, Qnil);
   s->face = FACE_FROM_ID (s->f, face_id);
-  PREPARE_FACE_FOR_DISPLAY (s->f, s->face);
+  prepare_face_for_display (s->f, s->face);
 
   /* If font in this face is same as S->font, use it.  */
   if (s->font == s->face->font)
@@ -1049,7 +1053,7 @@ x_set_mode_line_face_gc (struct glyph_string *s)
 static inline void
 x_set_glyph_string_gc (struct glyph_string *s)
 {
-  PREPARE_FACE_FOR_DISPLAY (s->f, s->face);
+  prepare_face_for_display (s->f, s->face);
 
   if (s->hl == DRAW_NORMAL_TEXT)
     {
@@ -1078,10 +1082,7 @@ x_set_glyph_string_gc (struct glyph_string *s)
       s->stippled_p = s->face->stipple != 0;
     }
   else
-    {
-      s->gc = s->face->gc;
-      s->stippled_p = s->face->stipple != 0;
-    }
+    emacs_abort ();
 
   /* GC must have been set.  */
   eassert (s->gc != 0);
@@ -3339,11 +3340,15 @@ note_mouse_movement (struct frame *frame, MSG *msg)
                              Mouse Face
  ************************************************************************/
 
-static struct scroll_bar *x_window_to_scroll_bar (Window);
+static struct scroll_bar *x_window_to_scroll_bar (Window, int);
 static void x_scroll_bar_report_motion (struct frame **, Lisp_Object *,
                                        enum scroll_bar_part *,
                                        Lisp_Object *, Lisp_Object *,
-                                       unsigned long *);
+                                       Time *);
+static void x_horizontal_scroll_bar_report_motion (struct frame **, Lisp_Object *,
+                                                  enum scroll_bar_part *,
+                                                  Lisp_Object *, Lisp_Object *,
+                                                  Time *);
 static void x_check_fullscreen (struct frame *);
 
 static void
@@ -3351,6 +3356,7 @@ w32_define_cursor (Window window, Cursor cursor)
 {
   PostMessage (window, WM_EMACS_SETCURSOR, (WPARAM) cursor, 0);
 }
+
 /* Return the current position of the mouse.
    *fp should be a frame which indicates which display to ask about.
 
@@ -3374,7 +3380,7 @@ w32_define_cursor (Window window, Cursor cursor)
 static void
 w32_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
                    enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
-                   unsigned long *time)
+                   Time *time)
 {
   struct frame *f1;
   struct w32_display_info *dpyinfo = FRAME_DISPLAY_INFO (*fp);
@@ -3382,7 +3388,14 @@ w32_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
   block_input ();
 
   if (dpyinfo->last_mouse_scroll_bar && insist == 0)
-    x_scroll_bar_report_motion (fp, bar_window, part, x, y, time);
+    {
+      struct scroll_bar *bar = dpyinfo->last_mouse_scroll_bar;
+
+      if (bar->horizontal)
+       x_horizontal_scroll_bar_report_motion (fp, bar_window, part, x, y, time);
+      else
+       x_scroll_bar_report_motion (fp, bar_window, part, x, y, time);
+    }
   else
     {
       POINT pt;
@@ -3410,7 +3423,7 @@ w32_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
        if (! f1)
          {
            struct scroll_bar *bar
-              = x_window_to_scroll_bar (WindowFromPoint (pt));
+              = x_window_to_scroll_bar (WindowFromPoint (pt), 2);
 
            if (bar)
              f1 = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
@@ -3435,7 +3448,7 @@ w32_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
            dpyinfo->last_mouse_glyph_frame = f1;
 
            *bar_window = Qnil;
-           *part = 0;
+           *part = scroll_bar_above_handle;
            *fp = f1;
            XSETINT (*x, pt.x);
            XSETINT (*y, pt.y);
@@ -3477,12 +3490,12 @@ w32_handle_tool_bar_click (struct frame *f, struct input_event *button_event)
 
 /* Scroll bar support.  */
 
-/* Given a window ID, find the struct scroll_bar which manages it.
-   This can be called in GC, so we have to make sure to strip off mark
-   bits.  */
+/* Given a window ID, find the struct scroll_bar which manages it
+   vertically.  This can be called in GC, so we have to make sure to
+   strip off mark bits.  */
 
 static struct scroll_bar *
-x_window_to_scroll_bar (Window window_id)
+x_window_to_scroll_bar (Window window_id, int type)
 {
   Lisp_Object tail, frame;
 
@@ -3500,7 +3513,10 @@ x_window_to_scroll_bar (Window window_id)
                               condemned = Qnil,
                               ! NILP (bar));
           bar = XSCROLL_BAR (bar)->next)
-       if (SCROLL_BAR_W32_WINDOW (XSCROLL_BAR (bar)) == window_id)
+       if (SCROLL_BAR_W32_WINDOW (XSCROLL_BAR (bar)) == window_id
+           && (type = 2
+               || (type == 1 && XSCROLL_BAR (bar)->horizontal)
+               || (type == 0 && !XSCROLL_BAR (bar)->horizontal)))
          return XSCROLL_BAR (bar);
     }
 
@@ -3509,7 +3525,7 @@ x_window_to_scroll_bar (Window window_id)
 
 
 \f
-/* Set the thumb size and position of scroll bar BAR.  We are currently
+/* Set the thumb size and position of vertical scroll bar BAR.  We are currently
    displaying PORTION out of a whole WHOLE, and our position POSITION.  */
 
 static void
@@ -3583,16 +3599,49 @@ w32_set_scroll_bar_thumb (struct scroll_bar *bar,
   unblock_input ();
 }
 
+/* Set the thumb size and position of horizontal scroll bar BAR.  We are currently
+   displaying PORTION out of a whole WHOLE, and our position POSITION.  */
+
+static void
+w32_set_horizontal_scroll_bar_thumb (struct scroll_bar *bar,
+                                    int portion, int position, int whole)
+{
+  Window w = SCROLL_BAR_W32_WINDOW (bar);
+  SCROLLINFO si;
+
+  block_input ();
+
+  si.cbSize = sizeof (si);
+  si.fMask = SIF_PAGE | SIF_POS | SIF_RANGE;
+  si.nMin = 0;
+  si.nMax = whole;
+  /* Allow nPage to be one larger than nPos so we don't allow to scroll
+     an already fully visible buffer.  */
+  si.nPage = min (portion, si.nMax) + 1;
+  si.nPos = min (position, si.nMax);
+  SetScrollInfo (w, SB_CTL, &si, TRUE);
+
+  unblock_input ();
+}
+
 \f
 /************************************************************************
                         Scroll bars, general
  ************************************************************************/
 
 static HWND
-my_create_scrollbar (struct frame * f, struct scroll_bar * bar)
+my_create_vscrollbar (struct frame * f, struct scroll_bar * bar)
 {
   return (HWND) SendMessage (FRAME_W32_WINDOW (f),
-                            WM_EMACS_CREATESCROLLBAR, (WPARAM) f,
+                            WM_EMACS_CREATEVSCROLLBAR, (WPARAM) f,
+                            (LPARAM) bar);
+}
+
+static HWND
+my_create_hscrollbar (struct frame * f, struct scroll_bar * bar)
+{
+  return (HWND) SendMessage (FRAME_W32_WINDOW (f),
+                            WM_EMACS_CREATEHSCROLLBAR, (WPARAM) f,
                             (LPARAM) bar);
 }
 
@@ -3662,7 +3711,7 @@ my_bring_window_to_top (HWND hwnd)
    scroll bar. */
 
 static struct scroll_bar *
-x_scroll_bar_create (struct window *w, int top, int left, int width, int height)
+x_scroll_bar_create (struct window *w, int left, int top, int width, int height, bool horizontal)
 {
   struct frame *f = XFRAME (WINDOW_FRAME (w));
   HWND hwnd;
@@ -3681,16 +3730,24 @@ x_scroll_bar_create (struct window *w, int top, int left, int width, int height)
   bar->start = 0;
   bar->end = 0;
   bar->dragging = 0;
+  bar->horizontal = horizontal;
 
   /* Requires geometry to be set before call to create the real window */
 
-  hwnd = my_create_scrollbar (f, bar);
+  if (horizontal)
+    hwnd = my_create_hscrollbar (f, bar);
+  else
+    hwnd = my_create_vscrollbar (f, bar);
 
   si.cbSize = sizeof (si);
   si.fMask = SIF_ALL;
   si.nMin = 0;
-  si.nMax = VERTICAL_SCROLL_BAR_TOP_RANGE (f, height)
-    + VERTICAL_SCROLL_BAR_MIN_HANDLE;
+  if (horizontal)
+    si.nMax = HORIZONTAL_SCROLL_BAR_LEFT_RANGE (f, width)
+      + HORIZONTAL_SCROLL_BAR_MIN_HANDLE;
+  else
+    si.nMax = VERTICAL_SCROLL_BAR_TOP_RANGE (f, height)
+      + VERTICAL_SCROLL_BAR_MIN_HANDLE;
   si.nPage = si.nMax;
   si.nPos = 0;
 
@@ -3726,15 +3783,18 @@ x_scroll_bar_remove (struct scroll_bar *bar)
   my_destroy_window (f, SCROLL_BAR_W32_WINDOW (bar));
 
   /* Dissociate this scroll bar from its window.  */
-  wset_vertical_scroll_bar (XWINDOW (bar->window), Qnil);
+  if (bar->horizontal)
+    wset_horizontal_scroll_bar (XWINDOW (bar->window), Qnil);
+  else
+    wset_vertical_scroll_bar (XWINDOW (bar->window), Qnil);
 
   unblock_input ();
 }
 
-/* Set the handle of the vertical scroll bar for WINDOW to indicate
-   that we are displaying PORTION characters out of a total of WHOLE
-   characters, starting at POSITION.  If WINDOW has no scroll bar,
-   create one.  */
+/* Set the handle of the vertical scroll bar for WINDOW to indicate that
+   we are displaying PORTION characters out of a total of WHOLE
+   characters, starting at POSITION.  If WINDOW has no vertical scroll
+   bar, create one.  */
 static void
 w32_set_vertical_scroll_bar (struct window *w,
                             int portion, int whole, int position)
@@ -3767,7 +3827,7 @@ w32_set_vertical_scroll_bar (struct window *w,
        }
       unblock_input ();
 
-      bar = x_scroll_bar_create (w, top, left, width, height);
+      bar = x_scroll_bar_create (w, left, top, width, height, 0);
     }
   else
     {
@@ -3831,6 +3891,106 @@ w32_set_vertical_scroll_bar (struct window *w,
   wset_vertical_scroll_bar (w, barobj);
 }
 
+/* Set the handle of the horizontal scroll bar for WINDOW to indicate
+   that we are displaying PORTION characters out of a total of WHOLE
+   characters, starting at POSITION.  If WINDOW has no horizontal scroll
+   bar, create one.  */
+static void
+w32_set_horizontal_scroll_bar (struct window *w,
+                              int portion, int whole, int position)
+{
+  struct frame *f = XFRAME (w->frame);
+  Lisp_Object barobj;
+  struct scroll_bar *bar;
+  int top, height, left, width;
+  int window_x, window_width;
+  int clear_left = WINDOW_LEFT_EDGE_X (w);
+  int clear_width = WINDOW_PIXEL_WIDTH (w) - WINDOW_RIGHT_DIVIDER_WIDTH (w);
+
+  /* Get window dimensions.  */
+  window_box (w, ANY_AREA, &window_x, 0, &window_width, 0);
+  left  = window_x;
+  height = WINDOW_SCROLL_BAR_AREA_HEIGHT (w);
+  width = window_width;
+  top = WINDOW_SCROLL_BAR_AREA_Y (w);
+
+  /* Does the scroll bar exist yet?  */
+  if (NILP (w->horizontal_scroll_bar))
+    {
+      HDC hdc;
+      block_input ();
+      if (width > 0 && height > 0)
+       {
+         hdc = get_frame_dc (f);
+         w32_clear_area (f, hdc, clear_left, top, clear_width, height);
+         release_frame_dc (f, hdc);
+       }
+      unblock_input ();
+
+      bar = x_scroll_bar_create (w, left, top, width, height, 1);
+    }
+  else
+    {
+      /* It may just need to be moved and resized.  */
+      HWND hwnd;
+
+      bar = XSCROLL_BAR (w->horizontal_scroll_bar);
+      hwnd = SCROLL_BAR_W32_WINDOW (bar);
+
+      /* If already correctly positioned, do nothing.  */
+      if (bar->left == left && bar->top == top
+         && bar->width == width && bar->height == height)
+        {
+          /* Redraw after clear_frame. */
+          if (!my_show_window (f, hwnd, SW_NORMAL))
+            InvalidateRect (hwnd, NULL, FALSE);
+        }
+      else
+        {
+          HDC hdc;
+         SCROLLINFO si;
+
+          block_input ();
+         if (width && height)
+           {
+             hdc = get_frame_dc (f);
+             /* Since Windows scroll bars are smaller than the space reserved
+                for them on the frame, we have to clear "under" them.  */
+             w32_clear_area (f, hdc, clear_left, top, clear_width, height);
+             release_frame_dc (f, hdc);
+           }
+          /* 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, hwnd, SW_HIDE);
+          MoveWindow (hwnd, left, top, width, max (height, 1), TRUE);
+
+         /* +++ SetScrollInfo +++ */
+         si.cbSize = sizeof (si);
+         si.fMask = SIF_PAGE | SIF_POS | SIF_RANGE;
+         si.nMin = 0;
+         si.nMax = whole;
+         si.nPage = min (portion, si.nMax) + 1;
+         si.nPos = min (position, si.nMax);
+         SetScrollInfo (hwnd, SB_CTL, &si, FALSE);
+
+          my_show_window (f, hwnd, SW_NORMAL);
+          /* InvalidateRect (w, NULL, FALSE);  */
+
+          /* Remember new settings.  */
+          bar->left = left;
+          bar->top = top;
+          bar->width = width;
+          bar->height = height;
+
+          unblock_input ();
+        }
+    }
+
+  w32_set_horizontal_scroll_bar_thumb (bar, portion, position, whole);
+  XSETVECTOR (barobj, bar);
+  wset_horizontal_scroll_bar (w, barobj);
+}
+
 
 /* The following three hooks are used when we're doing a thorough
    redisplay of the frame.  We don't explicitly know which scroll bars
@@ -3847,17 +4007,22 @@ w32_set_vertical_scroll_bar (struct window *w,
 static void
 w32_condemn_scroll_bars (struct frame *frame)
 {
-  /* Transfer all the scroll bars to FRAME_CONDEMNED_SCROLL_BARS.  */
-  while (! NILP (FRAME_SCROLL_BARS (frame)))
+  if (!NILP (FRAME_SCROLL_BARS (frame)))
     {
-      Lisp_Object bar;
-      bar = FRAME_SCROLL_BARS (frame);
-      fset_scroll_bars (frame, XSCROLL_BAR (bar)->next);
-      XSCROLL_BAR (bar)->next = FRAME_CONDEMNED_SCROLL_BARS (frame);
-      XSCROLL_BAR (bar)->prev = Qnil;
-      if (! NILP (FRAME_CONDEMNED_SCROLL_BARS (frame)))
-       XSCROLL_BAR (FRAME_CONDEMNED_SCROLL_BARS (frame))->prev = bar;
-      fset_condemned_scroll_bars (frame, bar);
+      if (!NILP (FRAME_CONDEMNED_SCROLL_BARS (frame)))
+       {
+         /* Prepend scrollbars to already condemned ones.  */
+         Lisp_Object last = FRAME_SCROLL_BARS (frame);
+
+         while (!NILP (XSCROLL_BAR (last)->next))
+           last = XSCROLL_BAR (last)->next;
+
+         XSCROLL_BAR (last)->next = FRAME_CONDEMNED_SCROLL_BARS (frame);
+         XSCROLL_BAR (FRAME_CONDEMNED_SCROLL_BARS (frame))->prev = last;
+       }
+
+      fset_condemned_scroll_bars (frame, FRAME_SCROLL_BARS (frame));
+      fset_scroll_bars (frame, Qnil);
     }
 }
 
@@ -3866,47 +4031,84 @@ w32_condemn_scroll_bars (struct frame *frame)
    Note that WINDOW isn't necessarily condemned at all.  */
 
 static void
-w32_redeem_scroll_bar (struct window *window)
+w32_redeem_scroll_bar (struct window *w)
 {
   struct scroll_bar *bar;
   Lisp_Object barobj;
   struct frame *f;
 
   /* We can't redeem this window's scroll bar if it doesn't have one.  */
-  if (NILP (window->vertical_scroll_bar))
+  if (NILP (w->vertical_scroll_bar) && NILP (w->horizontal_scroll_bar))
     emacs_abort ();
 
-  bar = XSCROLL_BAR (window->vertical_scroll_bar);
-
-  /* Unlink it from the condemned list.  */
-  f = XFRAME (WINDOW_FRAME (window));
-  if (NILP (bar->prev))
+  if (!NILP (w->vertical_scroll_bar) && WINDOW_HAS_VERTICAL_SCROLL_BAR (w))
     {
-      /* If the prev pointer is nil, it must be the first in one of
-         the lists.  */
-      if (EQ (FRAME_SCROLL_BARS (f), window->vertical_scroll_bar))
-        /* It's not condemned.  Everything's fine.  */
-        return;
-      else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f),
-                   window->vertical_scroll_bar))
-        fset_condemned_scroll_bars (f, bar->next);
+      bar = XSCROLL_BAR (w->vertical_scroll_bar);
+      /* Unlink it from the condemned list.  */
+      f = XFRAME (WINDOW_FRAME (w));
+      if (NILP (bar->prev))
+       {
+         /* If the prev pointer is nil, it must be the first in one of
+            the lists.  */
+         if (EQ (FRAME_SCROLL_BARS (f), w->vertical_scroll_bar))
+           /* It's not condemned.  Everything's fine.  */
+           goto horizontal;
+         else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f),
+                      w->vertical_scroll_bar))
+           fset_condemned_scroll_bars (f, bar->next);
+         else
+           /* If its prev pointer is nil, it must be at the front of
+              one or the other!  */
+           emacs_abort ();
+       }
       else
-        /* If its prev pointer is nil, it must be at the front of
-           one or the other!  */
-        emacs_abort ();
+       XSCROLL_BAR (bar->prev)->next = bar->next;
+
+      if (! NILP (bar->next))
+       XSCROLL_BAR (bar->next)->prev = bar->prev;
+
+      bar->next = FRAME_SCROLL_BARS (f);
+      bar->prev = Qnil;
+      XSETVECTOR (barobj, bar);
+      fset_scroll_bars (f, barobj);
+      if (! NILP (bar->next))
+       XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
     }
-  else
-    XSCROLL_BAR (bar->prev)->next = bar->next;
 
-  if (! NILP (bar->next))
-    XSCROLL_BAR (bar->next)->prev = bar->prev;
+ horizontal:
+  if (!NILP (w->horizontal_scroll_bar) && WINDOW_HAS_HORIZONTAL_SCROLL_BAR (w))
+    {
+      bar = XSCROLL_BAR (w->horizontal_scroll_bar);
+      /* Unlink it from the condemned list.  */
+      f = XFRAME (WINDOW_FRAME (w));
+      if (NILP (bar->prev))
+       {
+         /* If the prev pointer is nil, it must be the first in one of
+            the lists.  */
+         if (EQ (FRAME_SCROLL_BARS (f), w->horizontal_scroll_bar))
+           /* It's not condemned.  Everything's fine.  */
+           return;
+         else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f),
+                      w->horizontal_scroll_bar))
+           fset_condemned_scroll_bars (f, bar->next);
+         else
+           /* If its prev pointer is nil, it must be at the front of
+              one or the other!  */
+           emacs_abort ();
+       }
+      else
+       XSCROLL_BAR (bar->prev)->next = bar->next;
 
-  bar->next = FRAME_SCROLL_BARS (f);
-  bar->prev = Qnil;
-  XSETVECTOR (barobj, bar);
-  fset_scroll_bars (f, barobj);
-  if (! NILP (bar->next))
-    XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
+      if (! NILP (bar->next))
+       XSCROLL_BAR (bar->next)->prev = bar->prev;
+
+      bar->next = FRAME_SCROLL_BARS (f);
+      bar->prev = Qnil;
+      XSETVECTOR (barobj, bar);
+      fset_scroll_bars (f, barobj);
+      if (! NILP (bar->next))
+       XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
+    }
 }
 
 /* Remove all scroll bars on FRAME that haven't been saved since the
@@ -3937,8 +4139,9 @@ w32_judge_scroll_bars (struct frame *f)
      and they should get garbage-collected.  */
 }
 
-/* Handle a mouse click on the scroll bar BAR.  If *EMACS_EVENT's kind
-   is set to something other than NO_EVENT, it is enqueued.
+/* Handle a mouse click on the vertical scroll bar BAR.  If
+   *EMACS_EVENT's kind is set to something other than NO_EVENT, it is
+   enqueued.
 
    This may be called from a signal handler, so we have to ignore GC
    mark bits.  */
@@ -3963,17 +4166,24 @@ w32_scroll_bar_handle_click (struct scroll_bar *bar, W32Msg *msg,
     int y;
     int dragging = bar->dragging;
     SCROLLINFO si;
+    int sb_event = LOWORD (msg->msg.wParam);
 
     si.cbSize = sizeof (si);
-    si.fMask = SIF_POS;
+    if (sb_event == SB_THUMBTRACK)
+      si.fMask = SIF_TRACKPOS;
+    else
+      si.fMask = SIF_POS;
 
     GetScrollInfo ((HWND) msg->msg.lParam, SB_CTL, &si);
-    y = si.nPos;
+    if (sb_event == SB_THUMBTRACK)
+      y = si.nTrackPos;
+    else
+      y = si.nPos;
 
     bar->dragging = 0;
     FRAME_DISPLAY_INFO (f)->last_mouse_scroll_bar_pos = msg->msg.wParam;
 
-    switch (LOWORD (msg->msg.wParam))
+    switch (sb_event)
       {
       case SB_LINEDOWN:
        emacs_event->part = scroll_bar_down_arrow;
@@ -3997,8 +4207,6 @@ w32_scroll_bar_handle_click (struct scroll_bar *bar, W32Msg *msg,
        break;
       case SB_THUMBTRACK:
       case SB_THUMBPOSITION:
-       if (VERTICAL_SCROLL_BAR_TOP_RANGE (f, bar->height) <= 0xffff)
-          y = HIWORD (msg->msg.wParam);
        bar->dragging = 1; /* ??????? */
        emacs_event->part = scroll_bar_handle;
 
@@ -4045,14 +4253,128 @@ w32_scroll_bar_handle_click (struct scroll_bar *bar, W32Msg *msg,
   }
 }
 
-/* Return information to the user about the current position of the mouse
-   on the scroll bar.  */
+/* Handle a mouse click on the horizontal scroll bar BAR.  If
+   *EMACS_EVENT's kind is set to something other than NO_EVENT, it is
+   enqueued.
+
+   This may be called from a signal handler, so we have to ignore GC
+   mark bits.  */
+
+static int
+w32_horizontal_scroll_bar_handle_click (struct scroll_bar *bar, W32Msg *msg,
+                                       struct input_event *emacs_event)
+{
+  if (! WINDOWP (bar->window))
+    emacs_abort ();
+
+  emacs_event->kind = HORIZONTAL_SCROLL_BAR_CLICK_EVENT;
+  emacs_event->code = 0;
+  /* not really meaningful to distinguish left/right */
+  emacs_event->modifiers = msg->dwModifiers;
+  emacs_event->frame_or_window = bar->window;
+  emacs_event->arg = Qnil;
+  emacs_event->timestamp = msg->msg.time;
+
+  {
+    int left_range = HORIZONTAL_SCROLL_BAR_LEFT_RANGE (f, bar->width);
+    int x, y;
+    int dragging = bar->dragging;
+    SCROLLINFO si;
+    int sb_event = LOWORD (msg->msg.wParam);
+
+    si.cbSize = sizeof (si);
+    if (sb_event == SB_THUMBTRACK)
+      si.fMask = SIF_TRACKPOS | SIF_PAGE | SIF_RANGE;
+    else
+      si.fMask = SIF_POS | SIF_PAGE | SIF_RANGE;
+
+    GetScrollInfo ((HWND) msg->msg.lParam, SB_CTL, &si);
+    if (sb_event == SB_THUMBTRACK)
+      x = si.nTrackPos;
+    else
+      x = si.nPos;
+    y = si.nMax - si.nPage;
 
+    bar->dragging = 0;
+    FRAME_DISPLAY_INFO (f)->last_mouse_scroll_bar_pos = msg->msg.wParam;
+
+    switch (sb_event)
+      {
+      case SB_LINELEFT:
+       emacs_event->part = scroll_bar_left_arrow;
+       break;
+      case SB_LINERIGHT:
+       emacs_event->part = scroll_bar_right_arrow;
+       break;
+      case SB_PAGELEFT:
+       emacs_event->part = scroll_bar_before_handle;
+       break;
+      case SB_PAGERIGHT:
+       emacs_event->part = scroll_bar_after_handle;
+       break;
+      case SB_LEFT:
+       emacs_event->part = scroll_bar_horizontal_handle;
+       x = 0;
+       break;
+      case SB_RIGHT:
+       emacs_event->part = scroll_bar_horizontal_handle;
+       x = left_range;
+       break;
+      case SB_THUMBTRACK:
+      case SB_THUMBPOSITION:
+       bar->dragging = 1;
+       emacs_event->part = scroll_bar_horizontal_handle;
+
+       /* "Silently" update current position.  */
+       {
+         SCROLLINFO si;
+
+         si.cbSize = sizeof (si);
+         si.fMask = SIF_POS;
+         si.nPos = min (x, XWINDOW (bar->window)->hscroll_whole - 1);
+         /* Remember apparent position (we actually lag behind the real
+            position, so don't set that directly).  */
+         last_scroll_bar_drag_pos = x;
+
+         SetScrollInfo (SCROLL_BAR_W32_WINDOW (bar), SB_CTL, &si, FALSE);
+       }
+       break;
+      case SB_ENDSCROLL:
+       /* If this is the end of a drag sequence, then reset the scroll
+          handle size to normal and do a final redraw.  Otherwise do
+          nothing.  */
+       if (dragging)
+         {
+           SCROLLINFO si;
+           int start = bar->start;
+           int end = bar->end;
+
+           si.cbSize = sizeof (si);
+           si.fMask = SIF_POS;
+           si.nPos = min (last_scroll_bar_drag_pos,
+                          XWINDOW (bar->window)->hscroll_whole - 1);
+           SetScrollInfo (SCROLL_BAR_W32_WINDOW (bar), SB_CTL, &si, TRUE);
+         }
+       /* fall through */
+      default:
+       emacs_event->kind = NO_EVENT;
+       return FALSE;
+      }
+
+    XSETINT (emacs_event->x, x);
+    XSETINT (emacs_event->y, y);
+
+    return TRUE;
+  }
+}
+
+/* Return information to the user about the current position of the mouse
+   on the vertical scroll bar.  */
 static void
 x_scroll_bar_report_motion (struct frame **fp, Lisp_Object *bar_window,
                            enum scroll_bar_part *part,
                            Lisp_Object *x, Lisp_Object *y,
-                           unsigned long *time)
+                           Time *time)
 {
   struct w32_display_info *dpyinfo = FRAME_DISPLAY_INFO (*fp);
   struct scroll_bar *bar = dpyinfo->last_mouse_scroll_bar;
@@ -4061,6 +4383,7 @@ x_scroll_bar_report_motion (struct frame **fp, Lisp_Object *bar_window,
   int pos;
   int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, bar->height);
   SCROLLINFO si;
+  int sb_event = LOWORD (dpyinfo->last_mouse_scroll_bar_pos);
 
   block_input ();
 
@@ -4068,28 +4391,21 @@ x_scroll_bar_report_motion (struct frame **fp, Lisp_Object *bar_window,
   *bar_window = bar->window;
 
   si.cbSize = sizeof (si);
-  si.fMask = SIF_POS | SIF_PAGE | SIF_RANGE;
+  if (sb_event == SB_THUMBTRACK)
+    si.fMask = SIF_TRACKPOS | SIF_PAGE | SIF_RANGE;
+  else
+    si.fMask = SIF_POS | SIF_PAGE | SIF_RANGE;
 
   GetScrollInfo (w, SB_CTL, &si);
-  pos = si.nPos;
+  if (sb_event == SB_THUMBTRACK)
+    pos = si.nTrackPos;
+  else
+    pos = si.nPos;
   top_range = si.nMax - si.nPage + 1;
 
-  switch (LOWORD (dpyinfo->last_mouse_scroll_bar_pos))
-  {
-  case SB_THUMBPOSITION:
-  case SB_THUMBTRACK:
-      *part = scroll_bar_handle;
-      if (VERTICAL_SCROLL_BAR_TOP_RANGE (f, bar->height) <= 0xffff)
-       pos = HIWORD (dpyinfo->last_mouse_scroll_bar_pos);
-      break;
-  case SB_LINEDOWN:
-      *part = scroll_bar_handle;
-      pos++;
-      break;
-  default:
-      *part = scroll_bar_handle;
-      break;
-  }
+  *part = scroll_bar_handle;
+  if (sb_event == SB_LINEDOWN)
+    pos++;
 
   XSETINT (*x, pos);
   XSETINT (*y, top_range);
@@ -4102,6 +4418,57 @@ x_scroll_bar_report_motion (struct frame **fp, Lisp_Object *bar_window,
   unblock_input ();
 }
 
+/* Return information to the user about the current position of the mouse
+   on the horizontal scroll bar.  */
+static void
+x_horizontal_scroll_bar_report_motion (struct frame **fp, Lisp_Object *bar_window,
+                                      enum scroll_bar_part *part,
+                                      Lisp_Object *x, Lisp_Object *y,
+                                      Time *time)
+{
+  struct w32_display_info *dpyinfo = FRAME_DISPLAY_INFO (*fp);
+  struct scroll_bar *bar = dpyinfo->last_mouse_scroll_bar;
+  Window w = SCROLL_BAR_W32_WINDOW (bar);
+  struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
+  int pos;
+  int left_range = HORIZONTAL_SCROLL_BAR_LEFT_RANGE (f, bar->width);
+  SCROLLINFO si;
+  int sb_event = LOWORD (dpyinfo->last_mouse_scroll_bar_pos);
+
+  block_input ();
+
+  *fp = f;
+  *bar_window = bar->window;
+
+  si.cbSize = sizeof (si);
+  if (sb_event == SB_THUMBTRACK)
+    si.fMask = SIF_TRACKPOS | SIF_PAGE | SIF_RANGE;
+  else
+    si.fMask = SIF_POS | SIF_PAGE | SIF_RANGE;
+
+  GetScrollInfo (w, SB_CTL, &si);
+  if (sb_event == SB_THUMBTRACK)
+    pos = si.nTrackPos;
+  else
+    pos = si.nPos;
+  left_range = si.nMax - si.nPage + 1;
+
+  *part = scroll_bar_handle;
+  if (sb_event == SB_LINERIGHT)
+    pos++;
+
+
+  XSETINT (*y, pos);
+  XSETINT (*x, left_range);
+
+  f->mouse_moved = 0;
+  dpyinfo->last_mouse_scroll_bar = NULL;
+
+  *time = dpyinfo->last_mouse_movement_time;
+
+  unblock_input ();
+}
+
 
 /* The screen has been cleared so we may have changed foreground or
    background colors, and the scroll bars may need to be redrawn.
@@ -4116,7 +4483,8 @@ x_scroll_bar_clear (struct frame *f)
   /* We can have scroll bars even if this is 0,
      if we just turned off scroll bar mode.
      But in that case we should not clear them.  */
-  if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
+  if (FRAME_HAS_VERTICAL_SCROLL_BARS (f)
+      || FRAME_HAS_HORIZONTAL_SCROLL_BARS (f))
     for (bar = FRAME_SCROLL_BARS (f); VECTORP (bar);
          bar = XSCROLL_BAR (bar)->next)
       {
@@ -4137,7 +4505,18 @@ x_scroll_bar_clear (struct frame *f)
       }
 }
 
-\f
+static void
+set_frame_param (struct frame *f, Lisp_Object prop, Lisp_Object val)
+{
+  register Lisp_Object old_alist_elt;
+
+  old_alist_elt = Fassq (prop, f->param_alist);
+  if (EQ (old_alist_elt, Qnil))
+    fset_param_alist (f, Fcons (Fcons (prop, val), f->param_alist));
+  else
+    Fsetcdr (old_alist_elt, val);
+}
+
 /* The main W32 event-reading loop - w32_read_socket.  */
 
 /* Record the last 100 characters stored
@@ -4538,10 +4917,11 @@ w32_read_socket (struct terminal *terminal,
                    Emacs events should reflect only motion after
                    the ButtonPress.  */
                 if (f != 0)
-                  f->mouse_moved = 0;
-
-                if (!tool_bar_p)
-                  last_tool_bar_item = -1;
+                 {
+                   f->mouse_moved = 0;
+                   if (!tool_bar_p)
+                     f->last_tool_bar_item = -1;
+                 }
              }
            break;
          }
@@ -4566,9 +4946,9 @@ w32_read_socket (struct terminal *terminal,
                   should reflect only motion after the
                   ButtonPress.  */
                f->mouse_moved = 0;
+               f->last_tool_bar_item = -1;
              }
            dpyinfo->last_mouse_frame = f;
-           last_tool_bar_item = -1;
          }
          break;
 
@@ -4579,10 +4959,20 @@ w32_read_socket (struct terminal *terminal,
            construct_drag_n_drop (&inev, &msg, f);
          break;
 
+       case WM_HSCROLL:
+         {
+           struct scroll_bar *bar =
+             x_window_to_scroll_bar ((HWND)msg.msg.lParam, 1);
+
+           if (bar)
+             w32_horizontal_scroll_bar_handle_click (bar, &msg, &inev);
+           break;
+         }
+
        case WM_VSCROLL:
          {
            struct scroll_bar *bar =
-             x_window_to_scroll_bar ((HWND)msg.msg.lParam);
+             x_window_to_scroll_bar ((HWND)msg.msg.lParam, 0);
 
            if (bar)
              w32_scroll_bar_handle_click (bar, &msg, &inev);
@@ -4767,8 +5157,8 @@ w32_read_socket (struct terminal *terminal,
                  width = rect.right - rect.left;
                  text_width = FRAME_PIXEL_TO_TEXT_WIDTH (f, width);
                  text_height = FRAME_PIXEL_TO_TEXT_HEIGHT (f, height);
-                 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, height);
-                 columns = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, width);
+                 /* rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, height); */
+                 /* columns = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, width); */
 
                  /* TODO: Clip size to the screen dimensions.  */
 
@@ -4784,10 +5174,6 @@ w32_read_socket (struct terminal *terminal,
                      change_frame_size (f, text_width, text_height, 0, 1, 0, 1);
                      SET_FRAME_GARBAGED (f);
                      cancel_mouse_face (f);
-                     /* Do we want to set these here ????  */
-                     /**               FRAME_PIXEL_WIDTH (f) = width; **/
-                     /**               FRAME_TEXT_WIDTH (f) = text_width; **/
-                     /**               FRAME_PIXEL_HEIGHT (f) = height; **/
                      f->win_gravity = NorthWestGravity;
                    }
                }
@@ -5437,8 +5823,6 @@ x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
   FRAME_COLUMN_WIDTH (f) = unit = font->average_width;
   FRAME_LINE_HEIGHT (f) = font->height;
 
-  compute_fringe_widths (f, 1);
-
   /* Compute number of scrollbar columns.  */
   unit = FRAME_COLUMN_WIDTH (f);
   if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
@@ -5458,8 +5842,8 @@ x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
         doing it because it's done in Fx_show_tip, and it leads to
         problems because the tip frame has no widget.  */
       if (NILP (tip_frame) || XFRAME (tip_frame) != f)
-       x_set_window_size (f, 0, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f),
-                          FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 1);
+       adjust_frame_size (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f),
+                          FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 3, 0, Qfont);
     }
 
   /* X version sets font of input methods here also.  */
@@ -5579,6 +5963,47 @@ x_set_offset (struct frame *f, register int xoff, register int yoff,
   unblock_input ();
 }
 
+/* Calculate fullscreen size.  Return in *TOP_POS and *LEFT_POS the
+   wanted positions of the WM window (not Emacs window).
+   Return in *WIDTH and *HEIGHT the wanted width and height of Emacs
+   window (FRAME_X_WINDOW).
+ */
+
+static void
+x_fullscreen_adjust (struct frame *f, int *width, int *height, int *top_pos, int *left_pos)
+{
+  int newwidth = FRAME_COLS (f);
+  int newheight = FRAME_LINES (f);
+  Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f);
+
+  *top_pos = f->top_pos;
+  *left_pos = f->left_pos;
+
+  if (f->want_fullscreen & FULLSCREEN_HEIGHT)
+    {
+      int ph;
+
+      ph = x_display_pixel_height (dpyinfo);
+      newheight = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, ph);
+      ph = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, newheight) - f->y_pixels_diff;
+      newheight = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, ph);
+      *top_pos = 0;
+    }
+
+  if (f->want_fullscreen & FULLSCREEN_WIDTH)
+    {
+      int pw;
+
+      pw = x_display_pixel_width (dpyinfo);
+      newwidth = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, pw);
+      pw = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, newwidth) - f->x_pixels_diff;
+      newwidth = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, pw);
+      *left_pos = 0;
+    }
+
+  *width = newwidth;
+  *height = newheight;
+}
 
 /* Check if we need to resize the frame due to a fullscreen request.
    If so needed, resize the frame.  */
@@ -5615,6 +6040,7 @@ w32fullscreen_hook (struct frame *f)
       HWND hwnd = FRAME_W32_WINDOW(f);
       DWORD dwStyle = GetWindowLong (hwnd, GWL_STYLE);
       RECT rect;
+      enum fullscreen_type prev_fsmode = FRAME_PREV_FSMODE (f);
 
       block_input();
       f->want_fullscreen &= ~FULLSCREEN_WAIT;
@@ -5636,7 +6062,14 @@ w32fullscreen_hook (struct frame *f)
       if (f->want_fullscreen == FULLSCREEN_NONE)
        ShowWindow (hwnd, SW_SHOWNORMAL);
       else if (f->want_fullscreen == FULLSCREEN_MAXIMIZED)
-       ShowWindow (hwnd, SW_MAXIMIZE);
+       {
+         if (prev_fsmode == FULLSCREEN_BOTH || prev_fsmode == FULLSCREEN_WIDTH
+             || prev_fsmode == FULLSCREEN_HEIGHT)
+           /* Make window normal since otherwise the subsequent
+              maximization might fail in some cases.  */
+           ShowWindow (hwnd, SW_SHOWNORMAL);
+         ShowWindow (hwnd, SW_MAXIMIZE);
+       }
       else if (f->want_fullscreen == FULLSCREEN_BOTH)
         {
          w32_fullscreen_rect (hwnd, f->want_fullscreen,
@@ -5671,70 +6104,64 @@ void
 x_set_window_size (struct frame *f, int change_gravity, int width, int height, bool pixelwise)
 {
   int pixelwidth, pixelheight;
+  RECT rect;
 
   block_input ();
 
-  check_frame_size (f, &width, &height, pixelwise);
-
-  compute_fringe_widths (f, 0);
-
-  if (frame_resize_pixelwise)
+  if (pixelwise)
     {
-      if (pixelwise)
-       {
-         pixelwidth = FRAME_TEXT_TO_PIXEL_WIDTH (f, width);
-         pixelheight = FRAME_TEXT_TO_PIXEL_HEIGHT (f, height);
-       }
-      else
-       {
-         pixelwidth = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, width);
-         pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, height);
-       }
+      pixelwidth = FRAME_TEXT_TO_PIXEL_WIDTH (f, width);
+      pixelheight = FRAME_TEXT_TO_PIXEL_HEIGHT (f, height);
     }
   else
     {
-      /* If we don't resize frames pixelwise, round sizes to multiples
-        of character sizes here.  Otherwise, when enforcing size hints
-        while processing WM_WINDOWPOSCHANGING in w32_wnd_proc, we might
-        clip our frame rectangle to a multiple of the frame's character
-        size and subsequently lose our mode line or scroll bar.
-        Bug#16923 could be one possible consequence of this.  Carefully
-        reverse-engineer what WM_WINDOWPOSCHANGING does here since
-        otherwise we might make our frame too small, see Bug#17077.  */
-      int unit_width = FRAME_COLUMN_WIDTH (f);
-      int unit_height = FRAME_LINE_HEIGHT (f);
-
-      pixelwidth = (((((pixelwise ? width : (width * FRAME_COLUMN_WIDTH (f)))
-                      + FRAME_TOTAL_FRINGE_WIDTH (f))
-                     / unit_width) * unit_width)
-                   + FRAME_SCROLL_BAR_AREA_WIDTH (f)
-                   + 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
-
-      pixelheight = ((((pixelwise ? height : (height * FRAME_LINE_HEIGHT (f)))
-                      / unit_height) * unit_height)
-                    + 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
+      pixelwidth = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, width);
+      pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, height);
+    }
+
+  if (w32_add_wrapped_menu_bar_lines)
+    {
+      /* When the menu bar wraps sending a SetWindowPos shrinks the
+        height of the frame when the wrapped menu bar lines are not
+        accounted for (Bug#15174 and Bug#18720).  Here we add these
+        extra lines to the frame height.  */
+      MENUBARINFO info;
+      int default_menu_bar_height;
+      int menu_bar_height;
+
+      /* Why is (apparently) SM_CYMENUSIZE needed here instead of
+        SM_CYMENU ??  */
+      default_menu_bar_height = GetSystemMetrics (SM_CYMENUSIZE);
+      info.cbSize = sizeof (info);
+      info.rcBar.top = info.rcBar.bottom = 0;
+      GetMenuBarInfo (FRAME_W32_WINDOW (f), 0xFFFFFFFD, 0, &info);
+      menu_bar_height = info.rcBar.bottom - info.rcBar.top;
+
+      if ((default_menu_bar_height > 0)
+         && (menu_bar_height > default_menu_bar_height)
+         && ((menu_bar_height % default_menu_bar_height) == 0))
+       pixelheight = pixelheight + menu_bar_height - default_menu_bar_height;
     }
 
   f->win_gravity = NorthWestGravity;
   x_wm_set_size_hint (f, (long) 0, 0);
 
-  {
-    RECT rect;
+  f->want_fullscreen = FULLSCREEN_NONE;
+  w32fullscreen_hook (f);
 
-    rect.left = rect.top = 0;
-    rect.right = pixelwidth;
-    rect.bottom = pixelheight;
+  rect.left = rect.top = 0;
+  rect.right = pixelwidth;
+  rect.bottom = pixelheight;
 
-    AdjustWindowRect (&rect, f->output_data.w32->dwStyle,
-                     FRAME_EXTERNAL_MENU_BAR (f));
+  AdjustWindowRect (&rect, f->output_data.w32->dwStyle,
+                   FRAME_EXTERNAL_MENU_BAR (f));
 
-    my_set_window_pos (FRAME_W32_WINDOW (f),
-                      NULL,
-                      0, 0,
-                      rect.right - rect.left,
-                      rect.bottom - rect.top,
-                      SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
-  }
+  my_set_window_pos (FRAME_W32_WINDOW (f),
+                    NULL,
+                    0, 0,
+                    rect.right - rect.left,
+                    rect.bottom - rect.top,
+                    SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
 
   /* If w32_enable_frame_resize_hack is non-nil, immediately apply the
      new pixel sizes to the frame and its subwindows.
@@ -5783,31 +6210,14 @@ x_set_window_size (struct frame *f, int change_gravity, int width, int height, b
     }
 
   unblock_input ();
+
+  do_pending_window_change (0);
 }
 \f
 /* Mouse warping.  */
 
-void x_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y);
-
 void
-x_set_mouse_position (struct frame *f, int x, int y)
-{
-  int pix_x, pix_y;
-
-  pix_x = FRAME_COL_TO_PIXEL_X (f, x) + FRAME_COLUMN_WIDTH (f) / 2;
-  pix_y = FRAME_LINE_TO_PIXEL_Y (f, y) + FRAME_LINE_HEIGHT (f) / 2;
-
-  if (pix_x < 0) pix_x = 0;
-  if (pix_x > FRAME_PIXEL_WIDTH (f)) pix_x = FRAME_PIXEL_WIDTH (f);
-
-  if (pix_y < 0) pix_y = 0;
-  if (pix_y > FRAME_PIXEL_HEIGHT (f)) pix_y = FRAME_PIXEL_HEIGHT (f);
-
-  x_set_mouse_pixel_position (f, pix_x, pix_y);
-}
-
-void
-x_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
+frame_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
 {
   RECT rect;
   POINT pt;
@@ -5830,7 +6240,9 @@ x_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
 void
 x_focus_frame (struct frame *f)
 {
+#if 0
   struct w32_display_info *dpyinfo = &one_w32_display_info;
+#endif
 
   /* Give input focus to frame.  */
   block_input ();
@@ -6139,7 +6551,8 @@ x_wm_set_size_hint (struct frame *f, long flags, bool user_position)
   SetWindowLong (window, WND_FONTWIDTH_INDEX, FRAME_COLUMN_WIDTH (f));
   SetWindowLong (window, WND_LINEHEIGHT_INDEX, FRAME_LINE_HEIGHT (f));
   SetWindowLong (window, WND_BORDER_INDEX, FRAME_INTERNAL_BORDER_WIDTH (f));
-  SetWindowLong (window, WND_SCROLLBAR_INDEX, FRAME_SCROLL_BAR_AREA_WIDTH (f));
+  SetWindowLong (window, WND_VSCROLLBAR_INDEX, FRAME_SCROLL_BAR_AREA_WIDTH (f));
+  SetWindowLong (window, WND_HSCROLLBAR_INDEX, FRAME_SCROLL_BAR_AREA_HEIGHT (f));
 
   leave_crit ();
 }
@@ -6163,8 +6576,40 @@ x_check_font (struct frame *f, struct font *font)
 
 #endif /* GLYPH_DEBUG */
 
+/* Show hourglass cursor on frame F.  */
+
+static void
+w32_show_hourglass (struct frame *f)
+{
+  if (!menubar_in_use && !current_popup_menu)
+    {
+      struct w32_output *w32 = FRAME_X_OUTPUT (f);
+
+      w32->hourglass_p = 1;
+      SetCursor (w32->hourglass_cursor);
+    }
+}
+
+/* Hide hourglass cursor on frame F.  */
+
+static void
+w32_hide_hourglass (struct frame *f)
+{
+  struct w32_output *w32 = FRAME_X_OUTPUT (f);
+
+  w32->hourglass_p = 0;
+  SetCursor (w32->current_cursor);
+}
+
+/* FIXME: old code did that, but I don't know why.  Anyway,
+   this is used for non-GUI frames (see cancel_hourglass).  */
+
+void
+w32_arrow_cursor (void)
+{
+  SetCursor (w32_load_cursor (IDC_ARROW));
+}
 
-\f
 /***********************************************************************
                            Initialization
  ***********************************************************************/
@@ -6194,6 +6639,7 @@ w32_initialize_display_info (Lisp_Object display_name)
   dpyinfo->smallest_font_height = 1;
   dpyinfo->smallest_char_width = 1;
   dpyinfo->vertical_scroll_bar_cursor = w32_load_cursor (IDC_ARROW);
+  dpyinfo->horizontal_scroll_bar_cursor = w32_load_cursor (IDC_ARROW);
   /* TODO: dpyinfo->gray */
 
   reset_mouse_highlight (&dpyinfo->mouse_highlight);
@@ -6280,7 +6726,9 @@ static struct redisplay_interface w32_redisplay_interface =
   w32_draw_window_cursor,
   w32_draw_vertical_window_border,
   w32_draw_window_divider,
-  w32_shift_glyphs_for_insert
+  w32_shift_glyphs_for_insert,
+  w32_show_hourglass,
+  w32_hide_hourglass
 };
 
 static void x_delete_terminal (struct terminal *term);
@@ -6290,9 +6738,8 @@ w32_create_terminal (struct w32_display_info *dpyinfo)
 {
   struct terminal *terminal;
 
-  terminal = create_terminal ();
+  terminal = create_terminal (output_w32, &w32_redisplay_interface);
 
-  terminal->type = output_w32;
   terminal->display_info.w32 = dpyinfo;
   dpyinfo->terminal = terminal;
 
@@ -6302,26 +6749,24 @@ w32_create_terminal (struct w32_display_info *dpyinfo)
   terminal->ins_del_lines_hook = x_ins_del_lines;
   terminal->delete_glyphs_hook = x_delete_glyphs;
   terminal->ring_bell_hook = w32_ring_bell;
-  terminal->reset_terminal_modes_hook = NULL;
-  terminal->set_terminal_modes_hook = NULL;
   terminal->update_begin_hook = x_update_begin;
   terminal->update_end_hook = x_update_end;
-  terminal->set_terminal_window_hook = NULL;
   terminal->read_socket_hook = w32_read_socket;
   terminal->frame_up_to_date_hook = w32_frame_up_to_date;
   terminal->mouse_position_hook = w32_mouse_position;
   terminal->frame_rehighlight_hook = w32_frame_rehighlight;
   terminal->frame_raise_lower_hook = w32_frame_raise_lower;
   terminal->fullscreen_hook = w32fullscreen_hook;
+  terminal->menu_show_hook = w32_menu_show;
+  terminal->popup_dialog_hook = w32_popup_dialog;
   terminal->set_vertical_scroll_bar_hook = w32_set_vertical_scroll_bar;
+  terminal->set_horizontal_scroll_bar_hook = w32_set_horizontal_scroll_bar;
   terminal->condemn_scroll_bars_hook = w32_condemn_scroll_bars;
   terminal->redeem_scroll_bar_hook = w32_redeem_scroll_bar;
   terminal->judge_scroll_bars_hook = w32_judge_scroll_bars;
-
   terminal->delete_frame_hook = x_destroy_window;
   terminal->delete_terminal_hook = x_delete_terminal;
-
-  terminal->rif = &w32_redisplay_interface;
+  /* Other hooks are NULL by default.  */
 
   /* We don't yet support separate terminals on W32, so don't try to share
      keyboards between virtual terminals that are on the same physical
@@ -6443,12 +6888,6 @@ x_delete_display (struct w32_display_info *dpyinfo)
     if (dpyinfo->palette)
       DeleteObject (dpyinfo->palette);
   }
-  /* Avoid freeing dpyinfo->w32_id_name more than once if emacs is
-     running as a daemon; see bug#17510. */
-#ifndef CYGWIN
-  xfree (dpyinfo->w32_id_name);
-#endif
-
   w32_reset_fringes ();
 }
 
@@ -6500,7 +6939,6 @@ w32_initialize (void)
                             &w32_use_visible_system_caret, 0))
     w32_use_visible_system_caret = 0;
 
-  last_tool_bar_item = -1;
   any_help_event_p = 0;
 
   /* Initialize input mode: interrupt_input off, no flow control, allow
@@ -6555,13 +6993,16 @@ w32_initialize (void)
 
 #undef LOAD_PROC
 
-    /* Ensure scrollbar handle is at least 5 pixels.  */
+    /* Ensure scrollbar handles are at least 5 pixels.  */
     vertical_scroll_bar_min_handle = 5;
+    horizontal_scroll_bar_min_handle = 5;
 
     /* For either kind of scroll bar, take account of the arrows; these
        effectively form the border of the main scroll bar range.  */
     vertical_scroll_bar_top_border = vertical_scroll_bar_bottom_border
       = GetSystemMetrics (SM_CYVSCROLL);
+    horizontal_scroll_bar_left_border = horizontal_scroll_bar_right_border
+      = GetSystemMetrics (SM_CYHSCROLL);
   }
 }
 
@@ -6663,6 +7104,21 @@ systems of the NT family, including W2K, XP, Vista, Windows 7 and
 Windows 8.  It is set to nil on Windows 9X.  */);
   w32_unicode_filenames = 0;
 
+
+  /* FIXME: The following two variables will be (hopefully) removed
+     before Emacs 25.1 gets released.  */
+
+  DEFVAR_BOOL ("w32-add-wrapped-menu-bar-lines",
+              w32_add_wrapped_menu_bar_lines,
+     doc: /* Non-nil means frame resizing accounts for wrapped menu bar lines.
+A value of nil means frame resizing does not add the height of wrapped
+menu bar lines when sending a frame resize request to the Windows API.
+This usually means that the resulting frame height is off by the number
+of wrapped menu bar lines.  If this is non-nil, Emacs adds the height of
+wrapped menu bar lines when sending frame resize requests to the Windows
+API.  */);
+  w32_add_wrapped_menu_bar_lines = 1;
+
   DEFVAR_BOOL ("w32-enable-frame-resize-hack",
               w32_enable_frame_resize_hack,
      doc: /* Non-nil means enable hack for frame resizing on Windows.