]> code.delx.au - gnu-emacs/blobdiff - src/w32term.c
In x_set_window_size restore do_pending_window_change calls
[gnu-emacs] / src / w32term.c
index 251c46c73cf2c864603c8a37607900c1897398a3..51743f8f94dad77257e9db79cd2f498c07d55bc6 100644 (file)
@@ -1,13 +1,13 @@
 /* Implementation of GUI terminal on the Microsoft Windows API.
 
-Copyright (C) 1989, 1993-2015 Free Software Foundation, Inc.
+Copyright (C) 1989, 1993-2016 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
 GNU Emacs is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
+the Free Software Foundation, either version 3 of the License, or (at
+your option) any later version.
 
 GNU Emacs is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -23,38 +23,29 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include "lisp.h"
 #include "blockinput.h"
 #include "w32term.h"
-
-#include "systty.h"
-#include "systime.h"
+#include "w32common.h" /* for OS version info */
 
 #include <ctype.h>
 #include <errno.h>
 #include <sys/stat.h>
+#ifdef CYGWIN
+#include <fcntl.h>     /* for O_RDWR */
+#endif
 #include <imm.h>
 
-#include "charset.h"
-#include "character.h"
 #include "coding.h"
-#include "ccl.h"
 #include "frame.h"
-#include "dispextern.h"
 #include "fontset.h"
 #include "termhooks.h"
 #include "termopts.h"
 #include "termchar.h"
-#include "disptab.h"
 #include "buffer.h"
 #include "window.h"
 #include "keyboard.h"
-#include "intervals.h"
-#include "process.h"
-#include "atimer.h"
-#include "keymap.h"
-#include "menu.h"
+#include "menu.h"      /* for w32_menu_show */
 
 #ifdef WINDOWSNT
 #include "w32.h"       /* for filename_from_utf16, filename_from_ansi */
-#include "w32heap.h"
 #endif
 
 #ifndef WINDOWSNT
@@ -65,6 +56,10 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "font.h"
 #include "w32font.h"
+
+#if 0  /* TODO: stipple */
+#include "bitmaps/gray.xbm"
+#endif
 \f
 /* Fringe bitmaps.  */
 
@@ -401,7 +396,13 @@ w32_draw_rectangle (HDC hdc, XGCValues *gc, int x, int y,
   oldhb = SelectObject (hdc, hb);
   oldhp = SelectObject (hdc, hp);
 
-  Rectangle (hdc, x, y, x + width, y + height);
+  /* We enlarge WIDTH and HEIGHT by 1 to be bug-compatible to the
+     brain-dead design of XDrawRectangle, which draws a rectangle that
+     is 1 pixel wider and higher than its arguments WIDTH and HEIGHT.
+     This allows us to keep the code that calls this function similar
+     to the corresponding code in xterm.c.  For the details, see
+     http://lists.gnu.org/archives/html/emacs-devel/2014-10/msg00546.html.  */
+  Rectangle (hdc, x, y, x + width + 1, y + height + 1);
 
   SelectObject (hdc, oldhb);
   SelectObject (hdc, oldhp);
@@ -1212,7 +1213,12 @@ x_draw_glyph_string_background (struct glyph_string *s, bool force_p)
        }
       else
 #endif
-        if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
+           if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
+              /* When xdisp.c ignores FONT_HEIGHT, we cannot trust
+                 font dimensions, since the actual glyphs might be
+                 much smaller.  So in that case we always clear the
+                 rectangle with background color.  */
+              || FONT_TOO_HIGH (s->font)
               || s->font_not_found_p
               || s->extends_to_end_of_line_p
               || force_p)
@@ -1410,7 +1416,7 @@ x_draw_glyphless_glyph_string_foreground (struct glyph_string *s)
 
       if (glyph->u.glyphless.method == GLYPHLESS_DISPLAY_ACRONYM)
        {
-         if (len > 1
+         if (len > 0
              && CHAR_TABLE_P (Vglyphless_char_display)
              && (CHAR_TABLE_EXTRA_SLOTS (XCHAR_TABLE (Vglyphless_char_display))
                  >= 1))
@@ -1585,7 +1591,9 @@ w32_setup_relief_color (struct frame *f, struct relief *relief, double factor,
   unsigned long mask = GCForeground;
   COLORREF pixel;
   COLORREF background = di->relief_background;
+#if 0
   struct w32_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
+#endif
 
   /* TODO: Free colors (if using palette)? */
 
@@ -3223,7 +3231,7 @@ queue_notifications (struct input_event *event, W32Msg *msg, struct frame *f,
   if (notification_buffer_in_use)
     {
       DWORD info_size = notifications_size;
-      Lisp_Object cs = intern ("utf-16le");
+      Lisp_Object cs = Qutf_16le;
       Lisp_Object obj = w32_get_watch_object (notifications_desc);
 
       /* notifications_size could be zero when the buffer of
@@ -3344,8 +3352,6 @@ 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
 w32_define_cursor (Window window, Cursor cursor)
 {
@@ -3610,8 +3616,8 @@ w32_set_horizontal_scroll_bar_thumb (struct scroll_bar *bar,
   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.  */
+  /* Allow nPage to be one larger than nPos so we don't allow the scrolling
+     of an already fully visible buffer.  */
   si.nPage = min (portion, si.nMax) + 1;
   si.nPos = min (position, si.nMax);
   SetScrollInfo (w, SB_CTL, &si, TRUE);
@@ -4341,8 +4347,6 @@ w32_horizontal_scroll_bar_handle_click (struct scroll_bar *bar, W32Msg *msg,
        if (dragging)
          {
            SCROLLINFO si;
-           int start = bar->start;
-           int end = bar->end;
 
            si.cbSize = sizeof (si);
            si.fMask = SIF_POS;
@@ -4500,18 +4504,6 @@ x_scroll_bar_clear (struct frame *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
@@ -4989,8 +4981,12 @@ w32_read_socket (struct terminal *terminal,
                 sets the WAIT flag.  */
              if ((msg.msg.message == WM_WINDOWPOSCHANGED || msg.msg.wParam)
                  && (f->want_fullscreen & FULLSCREEN_WAIT))
-               w32fullscreen_hook (f);
-             x_check_fullscreen (f);
+               {
+                 /* Must set visibility right here since otherwise
+                    w32fullscreen_hook returns immediately.  */
+                 SET_FRAME_VISIBLE (f, 1);
+                 w32fullscreen_hook (f);
+               }
            }
          check_visibility = 1;
          break;
@@ -5050,6 +5046,7 @@ w32_read_socket (struct terminal *terminal,
                case SIZE_MAXIMIZED:
                  {
                    bool iconified = FRAME_ICONIFIED_P (f);
+                   Lisp_Object fullscreen = get_frame_param (f, Qfullscreen);
 
                    SET_FRAME_VISIBLE (f, 1);
                    SET_FRAME_ICONIFIED (f, false);
@@ -5080,12 +5077,22 @@ w32_read_socket (struct terminal *terminal,
                         to update the frame titles
                         in case this is the second frame.  */
                      record_asynch_buffer_change ();
-                 }
 
-                 if (EQ (get_frame_param (f, Qfullscreen), Qnil))
-                   set_frame_param (f, Qfullscreen, Qmaximized);
-                 else if (! EQ (get_frame_param (f, Qfullscreen), Qmaximized))
-                   set_frame_param (f, Qmaximized, Qmaximized);
+                 /* Windows can send us a SIZE_MAXIMIZED message even
+                    when fullscreen is fullboth.  The following is a
+                    simple hack to check that based on the fact that
+                    only a maximized fullscreen frame should have both
+                    top/left outside the screen.  */
+                 if (EQ (fullscreen, Qfullwidth) || EQ (fullscreen, Qfullheight)
+                     || NILP (fullscreen))
+                     {
+                       int x, y;
+
+                       x_real_positions (f, &x, &y);
+                       if (x < 0 && y < 0)
+                         store_frame_param (f, Qfullscreen, Qmaximized);
+                     }
+                 }
 
                  break;
 
@@ -5126,9 +5133,7 @@ w32_read_socket (struct terminal *terminal,
                  }
 
                  if (EQ (get_frame_param (f, Qfullscreen), Qmaximized))
-                   set_frame_param (f, Qfullscreen, Qnil);
-                 else if (! EQ (get_frame_param (f, Qmaximized), Qnil))
-                   set_frame_param (f, Qmaximized, Qnil);
+                   store_frame_param (f, Qfullscreen, Qnil);
 
                  break;
                }
@@ -5137,7 +5142,7 @@ w32_read_socket (struct terminal *terminal,
          if (f && !FRAME_ICONIFIED_P (f) && msg.msg.wParam != SIZE_MINIMIZED)
            {
              RECT rect;
-             int rows, columns, width, height, text_width, text_height;
+             int /* rows, columns, */ width, height, text_width, text_height;
 
              if (GetClientRect (msg.msg.hwnd, &rect)
                  /* GetClientRect evidently returns (0, 0, 0, 0) if
@@ -5269,11 +5274,18 @@ w32_read_socket (struct terminal *terminal,
 
          if (f)
            {
+             Lisp_Object fullscreen = get_frame_param (f, Qfullscreen);
+
              dpyinfo->n_cbits = msg.msg.wParam;
              /* The new display could have a different resolution, in
-                which case we must reconsider what fullscreen
-                means.  */
-             x_check_fullscreen (f);
+                which case we must reconsider what fullscreen means.
+                The following code is untested yet.  */
+             if (!NILP (fullscreen))
+               {
+                 x_set_fullscreen (f, fullscreen, fullscreen);
+                 w32fullscreen_hook (f);
+               }
+
              DebPrint (("display change: %d %d\n",
                         (short) LOWORD (msg.msg.lParam),
                         (short) HIWORD (msg.msg.lParam)));
@@ -5803,7 +5815,7 @@ Lisp_Object
 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
 {
   struct font *font = XFONT_OBJECT (font_object);
-  int unit;
+  int unit, font_ascent, font_descent;
 
   if (fontset < 0)
     fontset = fontset_from_font (font_object);
@@ -5816,7 +5828,8 @@ x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
   FRAME_FONT (f) = font;
   FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
   FRAME_COLUMN_WIDTH (f) = unit = font->average_width;
-  FRAME_LINE_HEIGHT (f) = font->height;
+  get_font_ascent_descent (font, &font_ascent, &font_descent);
+  FRAME_LINE_HEIGHT (f) = font_ascent + font_descent;
 
   /* Compute number of scrollbar columns.  */
   unit = FRAME_COLUMN_WIDTH (f);
@@ -5901,16 +5914,49 @@ x_calc_absolute_position (struct frame *f)
       top_bottom_borders_height = 32;
     }
 
+  /* With multiple monitors, we can legitimately get negative
+     coordinates (for monitors above or to the left of the primary
+     monitor).  Find the display origin to ensure negative positions
+     are computed correctly (Bug#21173).  */
+  int display_left = 0;
+  int display_top = 0;
+  if (flags & (XNegative | YNegative))
+    {
+      Lisp_Object list;
+
+      list = Fw32_display_monitor_attributes_list (Qnil);
+      while (CONSP (list))
+        {
+          Lisp_Object attributes = CAR(list);
+          Lisp_Object geometry;
+          Lisp_Object monitor_left, monitor_top;
+
+          list = CDR(list);
+
+          geometry = Fassoc (Qgeometry, attributes);
+          if (!NILP (geometry))
+            {
+              monitor_left = Fnth (make_number (1), geometry);
+              monitor_top  = Fnth (make_number (2), geometry);
+
+              display_left = min (display_left, XINT (monitor_left));
+              display_top  = min (display_top,  XINT (monitor_top));
+            }
+        }
+    }
+
   /* Treat negative positions as relative to the rightmost bottommost
      position that fits on the screen.  */
   if (flags & XNegative)
     f->left_pos = (x_display_pixel_width (FRAME_DISPLAY_INFO (f))
+                   + display_left
                   - FRAME_PIXEL_WIDTH (f)
                   + f->left_pos
                   - (left_right_borders_width - 1));
 
   if (flags & YNegative)
     f->top_pos = (x_display_pixel_height (FRAME_DISPLAY_INFO (f))
+                  + display_top
                  - FRAME_PIXEL_HEIGHT (f)
                  + f->top_pos
                  - (top_bottom_borders_height - 1));
@@ -5959,75 +6005,6 @@ 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.  */
-static void
-x_check_fullscreen (struct frame *f)
-{
-  if (f->want_fullscreen & FULLSCREEN_BOTH)
-    {
-      int width, height, ign;
-
-      x_real_positions (f, &f->left_pos, &f->top_pos);
-
-      x_fullscreen_adjust (f, &width, &height, &ign, &ign);
-
-      /* We do not need to move the window, it shall be taken care of
-         when setting WM manager hints.  */
-      if (FRAME_COLS (f) != width || FRAME_LINES (f) != height)
-        {
-          change_frame_size (f, width, height, 0, 1, 0, 0);
-          SET_FRAME_GARBAGED (f);
-          cancel_mouse_face (f);
-
-          /* Wait for the change of frame size to occur.  */
-          f->want_fullscreen |= FULLSCREEN_WAIT;
-        }
-    }
-}
-
 static void
 w32fullscreen_hook (struct frame *f)
 {
@@ -6068,12 +6045,19 @@ w32fullscreen_hook (struct frame *f)
        }
       else if (f->want_fullscreen == FULLSCREEN_BOTH)
         {
+         int menu_bar_height = GetSystemMetrics (SM_CYMENU);
+
          w32_fullscreen_rect (hwnd, f->want_fullscreen,
                               FRAME_NORMAL_PLACEMENT (f).rcNormalPosition, &rect);
           SetWindowLong (hwnd, GWL_STYLE, dwStyle & ~WS_OVERLAPPEDWINDOW);
           SetWindowPos (hwnd, HWND_TOP, rect.left, rect.top,
                         rect.right - rect.left, rect.bottom - rect.top,
                         SWP_NOOWNERZORDER | SWP_FRAMECHANGED);
+         change_frame_size
+           (f, FRAME_PIXEL_TO_TEXT_WIDTH (f, rect.right - rect.left),
+            FRAME_PIXEL_TO_TEXT_HEIGHT (f, (rect.bottom - rect.top
+                                            - menu_bar_height)),
+            0, 1, 0, 1);
         }
       else
         {
@@ -6082,10 +6066,39 @@ w32fullscreen_hook (struct frame *f)
                               FRAME_NORMAL_PLACEMENT (f).rcNormalPosition, &rect);
           SetWindowPos (hwnd, HWND_TOP, rect.left, rect.top,
                         rect.right - rect.left, rect.bottom - rect.top, 0);
+
+         if (f->want_fullscreen == FULLSCREEN_WIDTH)
+           {
+             int border_width = GetSystemMetrics (SM_CXFRAME);
+
+             change_frame_size
+               (f, (FRAME_PIXEL_TO_TEXT_WIDTH
+                    (f, rect.right - rect.left - 2 * border_width)),
+                0, 0, 1, 0, 1);
+           }
+         else
+           {
+             int border_height = GetSystemMetrics (SM_CYFRAME);
+             /* Won't work for wrapped menu bar.  */
+             int menu_bar_height = GetSystemMetrics (SM_CYMENU);
+             int title_height = GetSystemMetrics (SM_CYCAPTION);
+
+             change_frame_size
+               (f, 0, (FRAME_PIXEL_TO_TEXT_HEIGHT
+                       (f, rect.bottom - rect.top - 2 * border_height
+                        - title_height - menu_bar_height)),
+                0, 1, 0, 1);
+           }
         }
 
       f->want_fullscreen = FULLSCREEN_NONE;
       unblock_input ();
+
+      if (f->want_fullscreen == FULLSCREEN_BOTH
+         || f->want_fullscreen == FULLSCREEN_WIDTH
+         || f->want_fullscreen == FULLSCREEN_HEIGHT)
+       do_pending_window_change (0);
+
     }
   else
     f->want_fullscreen |= FULLSCREEN_WAIT;
@@ -6101,10 +6114,24 @@ x_set_window_size (struct frame *f, bool change_gravity,
                   int width, int height, bool pixelwise)
 {
   int pixelwidth, pixelheight;
+  Lisp_Object fullscreen = get_frame_param (f, Qfullscreen);
   RECT rect;
+  MENUBARINFO info;
+  int menu_bar_height;
 
   block_input ();
 
+  /* Get the height of the menu bar here.  It's used below to detect
+     whether the menu bar is wrapped.  It's also used to specify the
+     third argument for AdjustWindowRect.  FRAME_EXTERNAL_MENU_BAR which
+     has been used before for that reason is unreliable because it only
+     specifies whether we _want_ a menu bar for this frame and not
+     whether this frame _has_ a menu bar.  See bug#22105.  */
+  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 (pixelwise)
     {
       pixelwidth = FRAME_TEXT_TO_PIXEL_WIDTH (f, width);
@@ -6119,20 +6146,14 @@ x_set_window_size (struct frame *f, bool change_gravity,
   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
+        height of the frame then 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)
@@ -6143,55 +6164,58 @@ x_set_window_size (struct frame *f, bool change_gravity,
   f->win_gravity = NorthWestGravity;
   x_wm_set_size_hint (f, (long) 0, false);
 
-  f->want_fullscreen = FULLSCREEN_NONE;
-  w32fullscreen_hook (f);
-
   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, menu_bar_height > 0);
 
-  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.
-
-     Jason Rumney earlier refused to call change_frame_size right here
-     with the following argument:
-
-     The following mirrors what is done in xterm.c. It appears to be for
-     informing lisp of the new size immediately, while the actual resize
-     will happen asynchronously. But on Windows, the menu bar
-     automatically wraps when the frame is too narrow to contain it, and
-     that causes any calculations made here to come out wrong.  The end
-     is some nasty buggy behavior, including the potential loss of the
-     minibuffer.
-
-     Disabling this code is either not sufficient to fix the problems
-     completely, or it causes fresh problems, but at least it removes
-     the most problematic symptom of the minibuffer becoming unusable.
-
-     However, as the discussion about how to handle frame size
-     parameters on Windows (Bug#1348, Bug#16028) shows, that cure seems
-     worse than the disease.  In particular, menu bar wrapping looks
-     like a non-issue - maybe so because Windows eventually gets back to
-     us with the correct client rectangle anyway.  But we have to avoid
-     calling change_frame_size with a delta of less than one canoncial
-     character size when frame_resize_pixelwise is nil, as explained in
-     the comment above.  */
-
-  if (w32_enable_frame_resize_hack)
+  if (!(f->after_make_frame)
+      && !(f->want_fullscreen & FULLSCREEN_WAIT)
+      && FRAME_VISIBLE_P (f))
+    {
+      RECT window_rect;
 
+      GetWindowRect (FRAME_W32_WINDOW (f), &window_rect);
+
+      if (EQ (fullscreen, Qmaximized)
+         || EQ (fullscreen, Qfullboth)
+         || EQ (fullscreen, Qfullwidth))
+       {
+         rect.left = window_rect.left;
+         rect.right = window_rect.right;
+         pixelwidth = 0;
+       }
+      if (EQ (fullscreen, Qmaximized)
+         || EQ (fullscreen, Qfullboth)
+         || EQ (fullscreen, Qfullheight))
+       {
+         rect.top = window_rect.top;
+         rect.bottom = window_rect.bottom;
+         pixelheight = 0;
+       }
+    }
+
+  if (pixelwidth > 0 || pixelheight > 0)
     {
-      change_frame_size (f, FRAME_PIXEL_TO_TEXT_WIDTH (f, pixelwidth),
-                        FRAME_PIXEL_TO_TEXT_HEIGHT (f, pixelheight),
+      frame_size_history_add
+       (f, Qx_set_window_size_1, width, height,
+        list2 (Fcons (make_number (pixelwidth),
+                      make_number (pixelheight)),
+               Fcons (make_number (rect.right - rect.left),
+                      make_number (rect.bottom - rect.top))));
+
+      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);
+
+      change_frame_size (f,
+                        ((pixelwidth == 0)
+                            ? 0 : FRAME_PIXEL_TO_TEXT_WIDTH (f, pixelwidth)),
+                        ((pixelheight == 0)
+                         ? 0 : FRAME_PIXEL_TO_TEXT_HEIGHT (f, pixelheight)),
                         0, 1, 0, 1);
       SET_FRAME_GARBAGED (f);
 
@@ -6208,7 +6232,7 @@ x_set_window_size (struct frame *f, bool change_gravity,
 
   unblock_input ();
 
-  do_pending_window_change (0);
+  do_pending_window_change (false);
 }
 \f
 /* Mouse warping.  */
@@ -6216,6 +6240,8 @@ x_set_window_size (struct frame *f, bool change_gravity,
 void
 frame_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
 {
+  UINT trail_num = 0;
+  BOOL ret = false;
   RECT rect;
   POINT pt;
 
@@ -6226,7 +6252,15 @@ frame_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
   pt.y = rect.top + pix_y;
   ClientToScreen (FRAME_W32_WINDOW (f), &pt);
 
+  /* When "mouse trails" are in effect, moving the mouse cursor
+     sometimes leaves behind an annoying "ghost" of the pointer.
+     Avoid that by momentarily switching off mouse trails.  */
+  if (os_subtype == OS_NT
+      && w32_major_version + w32_minor_version >= 6)
+    ret = SystemParametersInfo (SPI_GETMOUSETRAILS, 0, &trail_num, 0);
   SetCursorPos (pt.x, pt.y);
+  if (ret)
+    SystemParametersInfo (SPI_SETMOUSETRAILS, trail_num, NULL, 0);
 
   unblock_input ();
 }
@@ -6595,7 +6629,10 @@ w32_hide_hourglass (struct frame *f)
   struct w32_output *w32 = FRAME_X_OUTPUT (f);
 
   w32->hourglass_p = 0;
-  SetCursor (w32->current_cursor);
+  if (f->pointer_invisible)
+    SetCursor (NULL);
+  else
+    SetCursor (w32->current_cursor);
 }
 
 /* FIXME: old code did that, but I don't know why.  Anyway,
@@ -6607,6 +6644,21 @@ w32_arrow_cursor (void)
   SetCursor (w32_load_cursor (IDC_ARROW));
 }
 
+static void
+w32_toggle_invisible_pointer (struct frame *f, bool invisible)
+{
+  block_input ();
+
+  if (f->pointer_invisible != invisible)
+    {
+      f->pointer_invisible = invisible;
+      w32_define_cursor (FRAME_W32_WINDOW (f),
+                        f->output_data.w32->current_cursor);
+    }
+
+  unblock_input ();
+}
+
 /***********************************************************************
                            Initialization
  ***********************************************************************/
@@ -6746,6 +6798,7 @@ 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->toggle_invisible_pointer_hook = w32_toggle_invisible_pointer;
   terminal->update_begin_hook = x_update_begin;
   terminal->update_end_hook = x_update_end;
   terminal->read_socket_hook = w32_read_socket;
@@ -6891,6 +6944,15 @@ x_delete_display (struct w32_display_info *dpyinfo)
 \f
 /* Set up use of W32.  */
 
+void
+w32_init_main_thread (void)
+{
+  dwMainThreadId = GetCurrentThreadId ();
+  DuplicateHandle (GetCurrentProcess (), GetCurrentThread (),
+                  GetCurrentProcess (), &hMainThread, 0, TRUE,
+                  DUPLICATE_SAME_ACCESS);
+}
+
 DWORD WINAPI w32_msg_worker (void * arg);
 
 static void
@@ -6951,10 +7013,6 @@ w32_initialize (void)
      terminates */
   init_crit ();
 
-  dwMainThreadId = GetCurrentThreadId ();
-  DuplicateHandle (GetCurrentProcess (), GetCurrentThread (),
-                  GetCurrentProcess (), &hMainThread, 0, TRUE, DUPLICATE_SAME_ACCESS);
-
   /* Wait for thread to start */
   {
     MSG msg;
@@ -7102,7 +7160,7 @@ Windows 8.  It is set to nil on Windows 9X.  */);
   w32_unicode_filenames = 0;
 
 
-  /* FIXME: The following two variables will be (hopefully) removed
+  /* FIXME: The following variable will be (hopefully) removed
      before Emacs 25.1 gets released.  */
 
   DEFVAR_BOOL ("w32-add-wrapped-menu-bar-lines",
@@ -7116,16 +7174,6 @@ 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.
-A value of nil means to resize frames by sending a corresponding request
-to the Windows API and changing the pixel sizes of the frame and its
-windows after the latter calls back.  If this is non-nil, Emacs changes
-the pixel sizes of the frame and its windows at the time it sends the
-resize request to the API.  */);
-  w32_enable_frame_resize_hack = 1;
-
   /* Tell Emacs about this window system.  */
   Fprovide (Qw32, Qnil);
 }