]> code.delx.au - gnu-emacs/blobdiff - src/w32fns.c
Fix removal of variables from process-environment
[gnu-emacs] / src / w32fns.c
index 31d23c4d37d2a97486ce356e5306598a3a86591f..c57b5a188b238832858815a76a548db49c8dc8cf 100644 (file)
@@ -1,13 +1,13 @@
 /* Graphical user interface functions for the Microsoft Windows API.
 
-Copyright (C) 1989, 1992-2015 Free Software Foundation, Inc.
+Copyright (C) 1989, 1992-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
@@ -35,24 +35,14 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include "w32term.h"
 #include "frame.h"
 #include "window.h"
-#include "character.h"
 #include "buffer.h"
-#include "intervals.h"
-#include "dispextern.h"
 #include "keyboard.h"
 #include "blockinput.h"
-#include "epaths.h"
-#include "charset.h"
 #include "coding.h"
-#include "ccl.h"
-#include "fontset.h"
-#include "systime.h"
-#include "termhooks.h"
 
 #include "w32common.h"
 
 #ifdef WINDOWSNT
-#include "w32heap.h"
 #include <mbstring.h>
 #endif /* WINDOWSNT */
 
@@ -62,11 +52,10 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include "w32.h"
 #endif
 
-#include "bitmaps/gray.xbm"
-
 #include <commctrl.h>
 #include <commdlg.h>
 #include <shellapi.h>
+#include <shlwapi.h>
 #include <ctype.h>
 #include <winspool.h>
 #include <objbase.h>
@@ -75,9 +64,6 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include <imm.h>
 #include <windowsx.h>
 
-#include "font.h"
-#include "w32font.h"
-
 #ifndef FOF_NO_CONNECTED_ELEMENTS
 #define FOF_NO_CONNECTED_ELEMENTS 0x2000
 #endif
@@ -138,6 +124,19 @@ struct MONITOR_INFO
     DWORD   dwFlags;
 };
 
+#if _WIN32_WINDOWS >= 0x0410
+#define C_CHILDREN_TITLEBAR CCHILDREN_TITLEBAR
+typedef TITLEBARINFO TITLEBAR_INFO;
+#else
+#define C_CHILDREN_TITLEBAR 5
+typedef struct
+{
+  DWORD cbSize;
+  RECT  rcTitleBar;
+  DWORD rgstate[C_CHILDREN_TITLEBAR+1];
+} TITLEBAR_INFO, *PTITLEBAR_INFO;
+#endif
+
 #ifndef CCHDEVICENAME
 #define CCHDEVICENAME 32
 #endif
@@ -172,6 +171,8 @@ typedef BOOL CALLBACK (* MonitorEnum_Proc)
   (IN HMONITOR monitor, IN HDC hdc, IN RECT *rcMonitor, IN LPARAM dwData);
 typedef BOOL (WINAPI * EnumDisplayMonitors_Proc)
   (IN HDC hdc, IN RECT *rcClip, IN MonitorEnum_Proc fnEnum, IN LPARAM dwData);
+typedef BOOL (WINAPI * GetTitleBarInfo_Proc)
+  (IN HWND hwnd, OUT TITLEBAR_INFO* info);
 
 TrackMouseEvent_Proc track_mouse_event_fn = NULL;
 ImmGetCompositionString_Proc get_composition_string_fn = NULL;
@@ -182,6 +183,7 @@ MonitorFromPoint_Proc monitor_from_point_fn = NULL;
 GetMonitorInfo_Proc get_monitor_info_fn = NULL;
 MonitorFromWindow_Proc monitor_from_window_fn = NULL;
 EnumDisplayMonitors_Proc enum_display_monitors_fn = NULL;
+GetTitleBarInfo_Proc get_title_bar_info_fn = NULL;
 
 #ifdef NTGUI_UNICODE
 #define unicode_append_menu AppendMenuW
@@ -743,7 +745,7 @@ w32_color_map_lookup (const char *colorname)
 
       tem = XCAR (elt);
 
-      if (lstrcmpi (SDATA (tem), colorname) == 0)
+      if (lstrcmpi (SSDATA (tem), colorname) == 0)
        {
          ret = Fcdr (elt);
          break;
@@ -786,7 +788,7 @@ add_system_logical_colors_to_map (Lisp_Object *system_colors)
       strcpy (full_name_buffer, SYSTEM_COLOR_PREFIX);
 
       while (RegEnumValueA (colors_key, index, name_buffer, &name_size,
-                           NULL, NULL, color_buffer, &color_size)
+                           NULL, NULL, (LPBYTE)color_buffer, &color_size)
             == ERROR_SUCCESS)
        {
          int r, g, b;
@@ -1211,9 +1213,9 @@ x_decode_color (struct frame *f, Lisp_Object arg, int def)
 
   CHECK_STRING (arg);
 
-  if (strcmp (SDATA (arg), "black") == 0)
+  if (strcmp (SSDATA (arg), "black") == 0)
     return BLACK_PIX_DEFAULT (f);
-  else if (strcmp (SDATA (arg), "white") == 0)
+  else if (strcmp (SSDATA (arg), "white") == 0)
     return WHITE_PIX_DEFAULT (f);
 
   if ((FRAME_DISPLAY_INFO (f)->n_planes * FRAME_DISPLAY_INFO (f)->n_cbits) == 1)
@@ -1221,7 +1223,7 @@ x_decode_color (struct frame *f, Lisp_Object arg, int def)
 
   /* w32_defined_color is responsible for coping with failures
      by looking for a near-miss.  */
-  if (w32_defined_color (f, SDATA (arg), &cdef, true))
+  if (w32_defined_color (f, SSDATA (arg), &cdef, true))
     return cdef.pixel;
 
   /* defined_color failed; return an ultimate default.  */
@@ -1283,8 +1285,10 @@ x_set_background_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
 void
 x_set_mouse_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
 {
+#if 0
   Cursor cursor, nontext_cursor, mode_cursor, hand_cursor;
   int count;
+#endif
   int mask_color;
 
   if (!EQ (Qnil, arg))
@@ -1662,10 +1666,7 @@ x_set_menu_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval)
   FRAME_MENU_BAR_LINES (f) = 0;
   FRAME_MENU_BAR_HEIGHT (f) = 0;
   if (nlines)
-    {
-      FRAME_EXTERNAL_MENU_BAR (f) = 1;
-      windows_or_buffers_changed = 23;
-    }
+    FRAME_EXTERNAL_MENU_BAR (f) = 1;
   else
     {
       if (FRAME_EXTERNAL_MENU_BAR (f) == 1)
@@ -1717,11 +1718,9 @@ x_set_tool_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval)
 void
 x_change_tool_bar_height (struct frame *f, int height)
 {
-  Lisp_Object frame;
   int unit = FRAME_LINE_HEIGHT (f);
   int old_height = FRAME_TOOL_BAR_HEIGHT (f);
   int lines = (height + unit - 1) / unit;
-  int old_text_height = FRAME_TEXT_HEIGHT (f);
   Lisp_Object fullscreen;
 
   /* Make sure we redisplay all windows in this frame.  */
@@ -1745,9 +1744,15 @@ x_change_tool_bar_height (struct frame *f, int height)
 
   /* Recalculate toolbar height.  */
   f->n_tool_bar_rows = 0;
+  if (old_height == 0
+      && (!f->after_make_frame
+         || NILP (frame_inhibit_implied_resize)
+         || (CONSP (frame_inhibit_implied_resize)
+             && NILP (Fmemq (Qtool_bar_lines, frame_inhibit_implied_resize)))))
+    f->tool_bar_redisplayed = f->tool_bar_resized = false;
 
   adjust_frame_size (f, -1, -1,
-                    ((!f->tool_bar_redisplayed_once
+                    ((!f->tool_bar_resized
                       && (NILP (fullscreen =
                                 get_frame_param (f, Qfullscreen))
                           || EQ (fullscreen, Qfullwidth))) ? 1
@@ -1755,6 +1760,8 @@ x_change_tool_bar_height (struct frame *f, int height)
                      : 4),
                     false, Qtool_bar_lines);
 
+  f->tool_bar_resized = f->tool_bar_redisplayed;
+
   /* adjust_frame_size might not have done anything, garbage frame
      here.  */
   adjust_frame_glyphs (f);
@@ -1842,7 +1849,7 @@ x_set_name (struct frame *f, Lisp_Object name, bool explicit)
       /* Check for no change needed in this very common case
         before we do any consing.  */
       if (!strcmp (FRAME_DISPLAY_INFO (f)->w32_id_name,
-                  SDATA (f->name)))
+                  SSDATA (f->name)))
        return;
       name = build_string (FRAME_DISPLAY_INFO (f)->w32_id_name);
     }
@@ -2848,11 +2855,11 @@ get_wm_chars (HWND aWnd, int *buf, int buflen, int ignore_ctrl, int ctrl,
     *ctrl_cnt = 0;
   if (is_dead)
     *is_dead = -1;
-  eassert(w32_unicode_gui);
+  eassert (w32_unicode_gui);
   while (buflen
         /* Should be called only when w32_unicode_gui:  */
-        && PeekMessageW(&msg, aWnd, WM_KEYFIRST, WM_KEYLAST,
-                     PM_NOREMOVE | PM_NOYIELD)
+        && PeekMessageW (&msg, aWnd, WM_KEYFIRST, WM_KEYLAST,
+                         PM_NOREMOVE | PM_NOYIELD)
         && (msg.message == WM_CHAR || msg.message == WM_SYSCHAR
             || msg.message == WM_DEADCHAR || msg.message == WM_SYSDEADCHAR
             || msg.message == WM_UNICHAR))
@@ -2861,7 +2868,7 @@ get_wm_chars (HWND aWnd, int *buf, int buflen, int ignore_ctrl, int ctrl,
         characters which come BEFORE the next keyup/keydown message.  */
       int dead;
 
-      GetMessageW(&msg, aWnd, msg.message, msg.message);
+      GetMessageW (&msg, aWnd, msg.message, msg.message);
       dead = (msg.message == WM_DEADCHAR || msg.message == WM_SYSDEADCHAR);
       if (is_dead)
        *is_dead = (dead ? msg.wParam : -1);
@@ -2903,7 +2910,7 @@ get_wm_chars (HWND aWnd, int *buf, int buflen, int ignore_ctrl, int ctrl,
          /* Non-character payload in a WM_CHAR
             (Ctrl-something pressed, see above).  Ignore, and report.  */
          if (ctrl_cnt)
-           *ctrl_cnt++;
+           (*ctrl_cnt)++;
          continue;
        }
       /* Traditionally, Emacs would ignore the character payload of VK_NUMPAD*
@@ -2920,7 +2927,7 @@ get_wm_chars (HWND aWnd, int *buf, int buflen, int ignore_ctrl, int ctrl,
          && ((vk >= VK_NUMPAD0 && vk <= VK_DIVIDE)
              || (exp && ((vk >= VK_PRIOR && vk <= VK_DOWN) ||
                     vk == VK_INSERT || vk == VK_DELETE || vk == VK_CLEAR)))
-         && strchr("0123456789/*-+.,", code_unit))
+         && strchr ("0123456789/*-+.,", code_unit))
        continue;
       *buf++ = code_unit;
       buflen--;
@@ -2931,7 +2938,7 @@ get_wm_chars (HWND aWnd, int *buf, int buflen, int ignore_ctrl, int ctrl,
 #ifdef DBG_WM_CHARS
 #  define FPRINTF_WM_CHARS(ARG)        fprintf ARG
 #else
-#  define FPRINTF_WM_CHARS(ARG)        0
+#  define FPRINTF_WM_CHARS(ARG)        (void)0
 #endif
 
 /* This is a heuristic only.  This is supposed to track the state of the
@@ -2941,7 +2948,11 @@ get_wm_chars (HWND aWnd, int *buf, int buflen, int ignore_ctrl, int ctrl,
    environments!) should  have different values.  Moreover, switching to a
    non-Emacs window with the same language environment, and using (dead)keys
    there would change the value stored in the kernel, but not this value.  */
-static int after_deadkey = 0;
+/* A layout may emit deadkey=0.  It looks like this would reset the state
+   of the kernel's finite automaton (equivalent to emiting 0-length string,
+   which is otherwise impossible in the dead-key map of a layout).
+   Be ready to treat the case when this delivers WM_(SYS)DEADCHAR. */
+static int after_deadkey = -1;
 
 int
 deliver_wm_chars (int do_translate, HWND hwnd, UINT msg, UINT wParam,
@@ -2951,7 +2962,7 @@ deliver_wm_chars (int do_translate, HWND hwnd, UINT msg, UINT wParam,
      points to a keypress.
      (However, the "old style" TranslateMessage() would deliver at most 16 of
      them.)  Be on a safe side, and prepare to treat many more.  */
-  int ctrl_cnt, buf[1024], count, is_dead, after_dead = (after_deadkey != -1);
+  int ctrl_cnt, buf[1024], count, is_dead, after_dead = (after_deadkey > 0);
 
   /* Since the keypress processing logic of Windows has a lot of state, it
      is important to call TranslateMessage() for every keyup/keydown, AND
@@ -2974,7 +2985,7 @@ deliver_wm_chars (int do_translate, HWND hwnd, UINT msg, UINT wParam,
       windows_msg.time = GetMessageTime ();
       TranslateMessage (&windows_msg);
     }
-  count = get_wm_chars (hwnd, buf, sizeof(buf)/sizeof(*buf), 1,
+  count = get_wm_chars (hwnd, buf, sizeof (buf)/sizeof (*buf), 1,
                        /* The message may have been synthesized by
                           who knows what; be conservative.  */
                        modifier_set (VK_LCONTROL)
@@ -2986,7 +2997,7 @@ deliver_wm_chars (int do_translate, HWND hwnd, UINT msg, UINT wParam,
     {
       W32Msg wmsg;
       DWORD console_modifiers = construct_console_modifiers ();
-      int *b = buf, strip_Alt = 1, strip_ExtraMods = 1, hairy = 0;
+      int *b = buf, strip_ExtraMods = 1, hairy = 0;
       char *type_CtrlAlt = NULL;
 
       /*  XXXX In fact, there may be another case when we need to do the same:
@@ -3114,25 +3125,25 @@ deliver_wm_chars (int do_translate, HWND hwnd, UINT msg, UINT wParam,
              && console_modifiers & (RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED))
            {
              type_CtrlAlt = "bB";   /* generic bindable Ctrl-Alt- modifiers */
-             if (console_modifiers & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)
+             if ((console_modifiers & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))
                  == (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))
                 /* double-Ctrl:
                    e.g. AltGr-rCtrl on some layouts (in this order!) */
                type_CtrlAlt = "dD";
-             else if (console_modifiers
-                      & (LEFT_CTRL_PRESSED | LEFT_ALT_PRESSED)
+             else if ((console_modifiers
+                       & (LEFT_CTRL_PRESSED | LEFT_ALT_PRESSED))
                       == (LEFT_CTRL_PRESSED | LEFT_ALT_PRESSED))
                type_CtrlAlt = "lL"; /* Ctrl-Alt- modifiers on the left */
              else if (!NILP (Vw32_recognize_altgr)
-                      && (console_modifiers
-                          & (RIGHT_ALT_PRESSED | LEFT_CTRL_PRESSED))
+                      && ((console_modifiers
+                           & (RIGHT_ALT_PRESSED | LEFT_CTRL_PRESSED)))
                          == (RIGHT_ALT_PRESSED | LEFT_CTRL_PRESSED))
                type_CtrlAlt = "gG"; /* modifiers as in AltGr */
            }
          else if (wmsg.dwModifiers & (alt_modifier | meta_modifier)
-                  || (console_modifiers
-                      & (RIGHT_WIN_PRESSED | RIGHT_WIN_PRESSED
-                         | APPS_PRESSED | SCROLLLOCK_ON)))
+                  || ((console_modifiers
+                       & (LEFT_WIN_PRESSED | RIGHT_WIN_PRESSED
+                          | APPS_PRESSED | SCROLLLOCK_ON))))
            {
              /* Pure Alt (or combination of Alt, Win, APPS, scrolllock.  */
              type_CtrlAlt = "aA";
@@ -3140,12 +3151,48 @@ deliver_wm_chars (int do_translate, HWND hwnd, UINT msg, UINT wParam,
          if (type_CtrlAlt)
            {
              /* Out of bound bitmap:  */
-             SHORT r = VkKeyScanW( *b ), bitmap = 0x1FF;
+             SHORT r = VkKeyScanW (*b), bitmap = 0x1FF;
 
              FPRINTF_WM_CHARS((stderr, "VkKeyScanW %#06x %#04x\n", (int)r,
-                              wParam));
+                               wParam));
              if ((r & 0xFF) == wParam)
                bitmap = r>>8; /* *b is reachable via simple interface */
+             else
+               {
+                 /* VkKeyScanW() (essentially) returns the FIRST key with
+                    the specified character; so here the pressed key is the
+                    SECONDARY key producing the character.
+
+                    Essentially, we have no information about the "role" of
+                    modifiers on this key: which contribute into the
+                    produced character (so "are consumed"), and which are
+                    "extra" (must attache to bindable events).
+
+                    The default above would consume ALL modifiers, so the
+                    character is reported "as is".  However, on many layouts
+                    the ordering of the keys (in the layout table) is not
+                    thought out well, so the "secondary" keys are often those
+                    which the users would prefer to use with Alt-CHAR.
+                    (Moreover - with e.g. Czech-QWERTY - the ASCII
+                    punctuation is accessible from two equally [nu]preferable
+                    AltGr-keys.)
+
+                    SO:   Heuristic: if the reported char is ASCII, AND Meta
+                    modifier is a candidate, behave as if Meta is present
+                    (fallback to the legacy branch; bug#23251).
+
+                    (This would break layouts
+                    - delivering ASCII characters
+                    - on SECONDARY keys
+                    - with not Shift/AltGr-like modifier combinations.
+                    All 3 conditions together must be pretty exotic
+                    cases - and a workaround exists: use "primary" keys!) */
+                 if (*b < 0x80
+                     && (wmsg.dwModifiers
+                         & (alt_modifier | meta_modifier
+                            | super_modifier | hyper_modifier)))
+                   return 0;
+               }
              if (*type_CtrlAlt == 'a') /* Simple Alt seen */
                {
                  if ((bitmap & ~1) == 0) /* 1: KBDSHIFT */
@@ -3203,12 +3250,12 @@ deliver_wm_chars (int do_translate, HWND hwnd, UINT msg, UINT wParam,
                 other cases, we ignore the delivered character.  */
 #define S_TYPES_TO_IGNORE_CHARACTER_PAYLOAD "aldb"
 #define S_TYPES_TO_REPORT_CHARACTER_PAYLOAD_WITH_MODIFIERS ""
-             if (strchr(S_TYPES_TO_IGNORE_CHARACTER_PAYLOAD,
-                        type_CtrlAlt[hairy]))
+             if (strchr (S_TYPES_TO_IGNORE_CHARACTER_PAYLOAD,
+                         type_CtrlAlt[hairy]))
                return 0;
              /* If in neither list, report all the modifiers we see COMBINED
                 WITH the reported character.  */
-             if (strchr(S_TYPES_TO_REPORT_CHARACTER_PAYLOAD_WITH_MODIFIERS,
+             if (strchr (S_TYPES_TO_REPORT_CHARACTER_PAYLOAD_WITH_MODIFIERS,
                          type_CtrlAlt[hairy]))
                strip_ExtraMods = 0;
            }
@@ -3572,7 +3619,7 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
                 keycode, and expansion.  (Additionally, one knows
                 boundaries of expansion of different keypresses.)  */
              res = deliver_wm_chars (1, hwnd, msg, wParam, lParam, 1);
-             windows_translate = -( res != 0 );
+             windows_translate = -(res != 0);
              if (res > 0) /* Bound to character(s) or a deadkey */
                break;
              /* deliver_wm_chars may make some branches after this vestigal.  */
@@ -4349,97 +4396,7 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
     case WM_WINDOWPOSCHANGING:
       /* Don't restrict the sizing of any kind of frames.  If the window
         manager doesn't, there's no reason to do it ourselves.  */
-#if 0
-       if (frame_resize_pixelwise || hwnd == tip_window)
-#endif
-         return 0;
-
-#if 0
-      /* Don't restrict the sizing of fullscreened frames, allowing them to be
-        flush with the sides of the screen.  */
-      f = x_window_to_frame (dpyinfo, hwnd);
-      if (f && FRAME_PREV_FSMODE (f) != FULLSCREEN_NONE)
-       return 0;
-
-      {
-       WINDOWPLACEMENT wp;
-       LPWINDOWPOS lppos = (WINDOWPOS *) lParam;
-
-       wp.length = sizeof (WINDOWPLACEMENT);
-       GetWindowPlacement (hwnd, &wp);
-
-       if (wp.showCmd != SW_SHOWMAXIMIZED && wp.showCmd != SW_SHOWMINIMIZED
-           && (lppos->flags & SWP_NOSIZE) == 0)
-         {
-           RECT rect;
-           int wdiff;
-           int hdiff;
-           DWORD font_width;
-           DWORD line_height;
-           DWORD internal_border;
-           DWORD vscrollbar_extra;
-           DWORD hscrollbar_extra;
-           RECT wr;
-
-           wp.length = sizeof (wp);
-           GetWindowRect (hwnd, &wr);
-
-           enter_crit ();
-
-           font_width = GetWindowLong (hwnd, WND_FONTWIDTH_INDEX);
-           line_height = GetWindowLong (hwnd, WND_LINEHEIGHT_INDEX);
-           internal_border = GetWindowLong (hwnd, WND_BORDER_INDEX);
-           vscrollbar_extra = GetWindowLong (hwnd, WND_VSCROLLBAR_INDEX);
-           hscrollbar_extra = GetWindowLong (hwnd, WND_HSCROLLBAR_INDEX);
-
-           leave_crit ();
-
-           memset (&rect, 0, sizeof (rect));
-           AdjustWindowRect (&rect, GetWindowLong (hwnd, GWL_STYLE),
-                             GetMenu (hwnd) != NULL);
-
-           /* Force width and height of client area to be exact
-              multiples of the character cell dimensions.  */
-           wdiff = (lppos->cx - (rect.right - rect.left)
-                    - 2 * internal_border - vscrollbar_extra)
-             % font_width;
-           hdiff = (lppos->cy - (rect.bottom - rect.top)
-                    - 2 * internal_border - hscrollbar_extra)
-             % line_height;
-
-           if (wdiff || hdiff)
-             {
-               /* For right/bottom sizing we can just fix the sizes.
-                  However for top/left sizing we will need to fix the X
-                  and Y positions as well.  */
-
-               int cx_mintrack = GetSystemMetrics (SM_CXMINTRACK);
-               int cy_mintrack = GetSystemMetrics (SM_CYMINTRACK);
-
-               lppos->cx = max (lppos->cx - wdiff, cx_mintrack);
-               lppos->cy = max (lppos->cy - hdiff, cy_mintrack);
-
-               if (wp.showCmd != SW_SHOWMAXIMIZED
-                   && (lppos->flags & SWP_NOMOVE) == 0)
-                 {
-                   if (lppos->x != wr.left || lppos->y != wr.top)
-                     {
-                       lppos->x += wdiff;
-                       lppos->y += hdiff;
-                     }
-                   else
-                     {
-                       lppos->flags |= SWP_NOMOVE;
-                     }
-                 }
-
-               return 0;
-             }
-         }
-      }
-
-      goto dflt;
-#endif
+      return 0;
 
     case WM_GETMINMAXINFO:
       /* Hack to allow resizing the Emacs frame above the screen size.
@@ -4696,8 +4653,7 @@ my_create_tip_window (struct frame *f)
   rect.right = FRAME_PIXEL_WIDTH (f);
   rect.bottom = FRAME_PIXEL_HEIGHT (f);
 
-  AdjustWindowRect (&rect, f->output_data.w32->dwStyle,
-                   FRAME_EXTERNAL_MENU_BAR (f));
+  AdjustWindowRect (&rect, f->output_data.w32->dwStyle, false);
 
   tip_window = FRAME_W32_WINDOW (f)
     = CreateWindow (EMACS_CLASS,
@@ -4889,12 +4845,6 @@ do_unwind_create_frame (Lisp_Object frame)
   unwind_create_frame (frame);
 }
 
-static void
-unwind_create_frame_1 (Lisp_Object val)
-{
-  inhibit_lisp_code = val;
-}
-
 static void
 x_default_font_parameter (struct frame *f, Lisp_Object parms)
 {
@@ -4954,11 +4904,11 @@ This function is an internal primitive--use `make-frame' instead.  */)
   bool minibuffer_only = false;
   long window_prompting = 0;
   ptrdiff_t count = SPECPDL_INDEX ();
-  struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
   Lisp_Object display;
   struct w32_display_info *dpyinfo = NULL;
   Lisp_Object parent;
   struct kboard *kb;
+  int x_width = 0, x_height = 0;
 
   if (!FRAME_W32_P (SELECTED_FRAME ())
       && !FRAME_INITIAL_P (SELECTED_FRAME ()))
@@ -5003,7 +4953,6 @@ This function is an internal primitive--use `make-frame' instead.  */)
   /* No need to protect DISPLAY because that's not used after passing
      it to make_frame_without_minibuffer.  */
   frame = Qnil;
-  GCPRO4 (parameters, parent, name, frame);
   tem = x_get_arg (dpyinfo, parameters, Qminibuffer, "minibuffer", "Minibuffer",
                   RES_TYPE_SYMBOL);
   if (EQ (tem, Qnone) || NILP (tem))
@@ -5182,7 +5131,7 @@ This function is an internal primitive--use `make-frame' instead.  */)
 
   f->output_data.w32->current_cursor = f->output_data.w32->nontext_cursor;
 
-  window_prompting = x_figure_window_size (f, parameters, true);
+  window_prompting = x_figure_window_size (f, parameters, true, &x_width, &x_height);
 
   tem = x_get_arg (dpyinfo, parameters, Qunsplittable, 0, 0, RES_TYPE_BOOLEAN);
   f->no_split = minibuffer_only || EQ (tem, Qt);
@@ -5216,8 +5165,10 @@ This function is an internal primitive--use `make-frame' instead.  */)
   /* Allow x_set_window_size, now.  */
   f->can_x_set_window_size = true;
 
-  adjust_frame_size (f, FRAME_TEXT_WIDTH (f), FRAME_TEXT_HEIGHT (f), 0, true,
-                    Qx_create_frame_2);
+  if (x_width > 0)
+    SET_FRAME_WIDTH (f, x_width);
+  if (x_height > 0)
+    SET_FRAME_HEIGHT (f, x_height);
 
   /* Tell the server what size and position, etc, we want, and how
      badly we want them.  This should be done after we have the menu
@@ -5226,6 +5177,9 @@ This function is an internal primitive--use `make-frame' instead.  */)
   x_wm_set_size_hint (f, window_prompting, false);
   unblock_input ();
 
+  adjust_frame_size (f, FRAME_TEXT_WIDTH (f), FRAME_TEXT_HEIGHT (f), 0, true,
+                    Qx_create_frame_2);
+
   /* Process fullscreen parameter here in the hope that normalizing a
      fullheight/fullwidth frame will produce the size set by the last
      adjust_frame_size call.  */
@@ -5265,8 +5219,6 @@ This function is an internal primitive--use `make-frame' instead.  */)
     if (CONSP (XCAR (tem)) && !NILP (XCAR (XCAR (tem))))
       fset_param_alist (f, Fcons (XCAR (tem), f->param_alist));
 
-  UNGCPRO;
-
   /* Make sure windows on this frame appear in calls to next-window
      and similar functions.  */
   Vwindow_list = Qnil;
@@ -5299,7 +5251,7 @@ DEFUN ("xw-color-defined-p", Fxw_color_defined_p, Sxw_color_defined_p, 1, 2, 0,
 
   CHECK_STRING (color);
 
-  if (w32_defined_color (f, SDATA (color), &foo, false))
+  if (w32_defined_color (f, SSDATA (color), &foo, false))
     return Qt;
   else
     return Qnil;
@@ -5314,7 +5266,7 @@ DEFUN ("xw-color-values", Fxw_color_values, Sxw_color_values, 1, 2, 0,
 
   CHECK_STRING (color);
 
-  if (w32_defined_color (f, SDATA (color), &foo, false))
+  if (w32_defined_color (f, SSDATA (color), &foo, false))
     return list3i ((GetRValue (foo.pixel) << 8) | GetRValue (foo.pixel),
                   (GetGValue (foo.pixel) << 8) | GetGValue (foo.pixel),
                   (GetBValue (foo.pixel) << 8) | GetBValue (foo.pixel));
@@ -5590,7 +5542,6 @@ w32_display_monitor_attributes_list (void)
   Lisp_Object monitor_list = Qnil, monitor_frames, rest, frame;
   int i, n_monitors;
   HMONITOR *monitors;
-  struct gcpro gcpro1, gcpro2, gcpro3;
 
   if (!(enum_display_monitors_fn && get_monitor_info_fn
        && monitor_from_window_fn))
@@ -5632,8 +5583,6 @@ w32_display_monitor_attributes_list (void)
        }
     }
 
-  GCPRO3 (attributes_list, primary_monitor_attributes, monitor_frames);
-
   for (i = 0; i < n_monitors; i++)
     {
       Lisp_Object geometry, workarea, name, attributes = Qnil;
@@ -5681,8 +5630,6 @@ w32_display_monitor_attributes_list (void)
   if (!NILP (primary_monitor_attributes))
     attributes_list = Fcons (primary_monitor_attributes, attributes_list);
 
-  UNGCPRO;
-
   xfree (monitors);
 
   return attributes_list;
@@ -5771,8 +5718,8 @@ Internal use only, use `display-monitor-attributes-list' instead.  */)
 
 DEFUN ("set-message-beep", Fset_message_beep, Sset_message_beep, 1, 1, 0,
        doc: /* Set the sound generated when the bell is rung.
-SOUND is 'asterisk, 'exclamation, 'hand, 'question, 'ok, or 'silent
-to use the corresponding system sound for the bell.  The 'silent sound
+SOUND is `asterisk', `exclamation', `hand', `question', `ok', or `silent'
+to use the corresponding system sound for the bell.  The `silent' sound
 prevents Emacs from making any sound at all.
 SOUND is nil to use the normal beep.  */)
   (Lisp_Object sound)
@@ -5824,8 +5771,7 @@ x_display_info_for_name (Lisp_Object name)
 
   validate_x_resource_name ();
 
-  dpyinfo = w32_term_init (name, (unsigned char *)0,
-                          SSDATA (Vx_resource_name));
+  dpyinfo = w32_term_init (name, NULL, SSDATA (Vx_resource_name));
 
   if (dpyinfo == 0)
     error ("Cannot connect to server %s", SDATA (name));
@@ -5844,7 +5790,7 @@ terminate Emacs if we can't open the connection.
 \(In the Nextstep version, the last two arguments are currently ignored.)  */)
   (Lisp_Object display, Lisp_Object xrm_string, Lisp_Object must_succeed)
 {
-  unsigned char *xrm_option;
+  char *xrm_option;
   struct w32_display_info *dpyinfo;
 
   CHECK_STRING (display);
@@ -5869,20 +5815,15 @@ terminate Emacs if we can't open the connection.
      HOME directory, then in Emacs etc dir for a file called rgb.txt. */
   {
     Lisp_Object color_file;
-    struct gcpro gcpro1;
 
     color_file = build_string ("~/rgb.txt");
 
-    GCPRO1 (color_file);
-
     if (NILP (Ffile_readable_p (color_file)))
       color_file =
        Fexpand_file_name (build_string ("rgb.txt"),
                           Fsymbol_value (intern ("data-directory")));
 
     Vw32_color_map = Fx_load_color_file (color_file);
-
-    UNGCPRO;
   }
   if (NILP (Vw32_color_map))
     Vw32_color_map = w32_default_color_map ();
@@ -5891,9 +5832,9 @@ terminate Emacs if we can't open the connection.
   add_system_logical_colors_to_map (&Vw32_color_map);
 
   if (! NILP (xrm_string))
-    xrm_option = SDATA (xrm_string);
+    xrm_option = SSDATA (xrm_string);
   else
-    xrm_option = (unsigned char *) 0;
+    xrm_option = NULL;
 
   /* Use this general default value to start with.  */
   /* First remove .exe suffix from invocation-name - it looks ugly. */
@@ -5911,8 +5852,7 @@ terminate Emacs if we can't open the connection.
 
   /* This is what opens the connection and sets x_current_display.
      This also initializes many symbols, such as those used for input.  */
-  dpyinfo = w32_term_init (display, xrm_option,
-                          SSDATA (Vx_resource_name));
+  dpyinfo = w32_term_init (display, xrm_option, SSDATA (Vx_resource_name));
 
   if (dpyinfo == 0)
     {
@@ -6167,14 +6107,13 @@ x_create_tip_frame (struct w32_display_info *dpyinfo,
   struct frame *f;
   Lisp_Object frame;
   Lisp_Object name;
-  long window_prompting = 0;
   int width, height;
   ptrdiff_t count = SPECPDL_INDEX ();
-  struct gcpro gcpro1, gcpro2, gcpro3;
   struct kboard *kb;
   bool face_change_before = face_change;
   Lisp_Object buffer;
   struct buffer *old_buffer;
+  int x_width = 0, x_height = 0;
 
   /* Use this general default value to start with until we know if
      this frame has a specified name.  */
@@ -6195,7 +6134,6 @@ x_create_tip_frame (struct w32_display_info *dpyinfo,
   Vx_resource_name = name;
 
   frame = Qnil;
-  GCPRO3 (parms, name, frame);
   /* Make a frame without minibuffer nor mode-line.  */
   f = make_frame (false);
   f->wants_modeline = 0;
@@ -6306,7 +6244,7 @@ x_create_tip_frame (struct w32_display_info *dpyinfo,
   f->output_data.w32->dwStyle = WS_BORDER | WS_POPUP | WS_DISABLED;
   f->output_data.w32->parent_desc = FRAME_DISPLAY_INFO (f)->root_window;
 
-  window_prompting = x_figure_window_size (f, parms, false);
+  x_figure_window_size (f, parms, true, &x_width, &x_height);
 
   /* No fringes on tip frame.  */
   f->fringe_cols = 0;
@@ -6371,8 +6309,6 @@ x_create_tip_frame (struct w32_display_info *dpyinfo,
 
   f->no_split = true;
 
-  UNGCPRO;
-
   /* Now that the frame is official, it counts as a reference to
      its display.  */
   FRAME_DISPLAY_INFO (f)->reference_count++;
@@ -6477,7 +6413,7 @@ compute_tip_xy (struct frame *f,
   if (INTEGERP (left))
     *root_x = XINT (left);
   else if (INTEGERP (right))
-    *root_y = XINT (right) - width;
+    *root_x = XINT (right) - width;
   else if (*root_x + XINT (dx) <= min_x)
     *root_x = 0; /* Can happen for negative dx */
   else if (*root_x + XINT (dx) + width <= max_x)
@@ -6531,14 +6467,11 @@ Text larger than the specified size is clipped.  */)
   struct text_pos pos;
   int i, width, height;
   bool seen_reversed_p;
-  struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
   int old_windows_or_buffers_changed = windows_or_buffers_changed;
   ptrdiff_t count = SPECPDL_INDEX ();
 
   specbind (Qinhibit_redisplay, Qt);
 
-  GCPRO4 (string, parms, frame, timeout);
-
   CHECK_STRING (string);
   f = decode_window_system_frame (frame);
   if (NILP (timeout))
@@ -6780,8 +6713,7 @@ Text larger than the specified size is clipped.  */)
     rect.left = rect.top = 0;
     rect.right = width;
     rect.bottom = height;
-    AdjustWindowRect (&rect, f->output_data.w32->dwStyle,
-                     FRAME_EXTERNAL_MENU_BAR (f));
+    AdjustWindowRect (&rect, f->output_data.w32->dwStyle, false);
 
     /* Position and size tooltip, and put it in the topmost group.
        The add-on of FRAME_COLUMN_WIDTH to the 5th argument is a
@@ -6820,7 +6752,6 @@ Text larger than the specified size is clipped.  */)
   tip_timer = call3 (intern ("run-at-time"), timeout, Qnil,
                     intern ("x-hide-tip"));
 
-  UNGCPRO;
   return unbind_to (count, Qnil);
 }
 
@@ -6832,7 +6763,6 @@ Value is t if tooltip was open, nil otherwise.  */)
 {
   ptrdiff_t count;
   Lisp_Object deleted, frame, timer;
-  struct gcpro gcpro1, gcpro2;
 
   /* Return quickly if nothing to do.  */
   if (NILP (tip_timer) && NILP (tip_frame))
@@ -6840,7 +6770,6 @@ Value is t if tooltip was open, nil otherwise.  */)
 
   frame = tip_frame;
   timer = tip_timer;
-  GCPRO2 (frame, timer);
   tip_frame = tip_timer = deleted = Qnil;
 
   count = SPECPDL_INDEX ();
@@ -6856,7 +6785,6 @@ Value is t if tooltip was open, nil otherwise.  */)
       deleted = Qt;
     }
 
-  UNGCPRO;
   return unbind_to (count, deleted);
 }
 \f
@@ -7029,13 +6957,7 @@ value of DIR as in previous invocations; this is standard Windows behavior.  */)
   char fname_ret[MAX_UTF8_PATH];
 #endif /* NTGUI_UNICODE */
 
-  struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5, gcpro6;
-  GCPRO6 (prompt, dir, default_filename, mustmatch, only_dir_p, filename);
-
   {
-    struct gcpro gcpro1, gcpro2;
-    GCPRO2 (orig_dir, orig_prompt); /* There is no GCPRON, N>6.  */
-
     /* Note: under NTGUI_UNICODE, we do _NOT_ use ENCODE_FILE: the
        system file encoding expected by the platform APIs (e.g. Cygwin's
        POSIX implementation) may not be the same as the encoding expected
@@ -7083,9 +7005,9 @@ value of DIR as in previous invocations; this is standard Windows behavior.  */)
 
     /* We modify these in-place, so make copies for safety.  */
     dir = Fcopy_sequence (dir);
-    unixtodos_filename (SDATA (dir));
+    unixtodos_filename (SSDATA (dir));
     filename = Fcopy_sequence (filename);
-    unixtodos_filename (SDATA (filename));
+    unixtodos_filename (SSDATA (filename));
     if (SBYTES (filename) >= MAX_UTF8_PATH)
       report_file_error ("filename too long", default_filename);
     if (w32_unicode_filenames)
@@ -7098,12 +7020,12 @@ value of DIR as in previous invocations; this is standard Windows behavior.  */)
            if (errno == ENOENT && filename_buf_w[MAX_PATH - 1] != 0)
              report_file_error ("filename too long", default_filename);
          }
-       len = pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS,
+       len = pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags,
                                    SSDATA (prompt), -1, NULL, 0);
        if (len > 32768)
          len = 32768;
        prompt_w = alloca (len * sizeof (wchar_t));
-       pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS,
+       pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags,
                              SSDATA (prompt), -1, prompt_w, len);
       }
     else
@@ -7116,12 +7038,12 @@ value of DIR as in previous invocations; this is standard Windows behavior.  */)
            if (errno == ENOENT && filename_buf_a[MAX_PATH - 1] != 0)
              report_file_error ("filename too long", default_filename);
          }
-       len = pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS,
+       len = pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags,
                                    SSDATA (prompt), -1, NULL, 0);
        if (len > 32768)
          len = 32768;
        prompt_w = alloca (len * sizeof (wchar_t));
-       pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS,
+       pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags,
                              SSDATA (prompt), -1, prompt_w, len);
        len = pWideCharToMultiByte (CP_ACP, 0, prompt_w, -1, NULL, 0, NULL, NULL);
        if (len > 32768)
@@ -7264,15 +7186,13 @@ value of DIR as in previous invocations; this is standard Windows behavior.  */)
        Qfile_name_history,
        default_filename,
        Qnil);
-
-    UNGCPRO;
   }
 
   /* Make "Cancel" equivalent to C-g.  */
   if (NILP (filename))
     Fsignal (Qquit, Qnil);
 
-  RETURN_UNGCPRO (filename);
+  return filename;
 }
 
 \f
@@ -7310,7 +7230,7 @@ DEFUN ("system-move-file-to-trash", Fsystem_move_file_to_trash,
 
       encoded_file = ENCODE_FILE (filename);
 
-      path = map_w32_filename (SDATA (encoded_file), NULL);
+      path = map_w32_filename (SSDATA (encoded_file), NULL);
 
       /* The Unicode version of SHFileOperation is not supported on
         Windows 9X. */
@@ -7349,7 +7269,8 @@ DEFUN ("system-move-file-to-trash", Fsystem_move_file_to_trash,
          /* If a file cannot be represented in ANSI codepage, don't
             let them inadvertently delete other files because some
             characters are interpreted as a wildcards.  */
-         if (_mbspbrk (tmp_path_a, "?*"))
+         if (_mbspbrk ((unsigned char *)tmp_path_a,
+                       (const unsigned char *)"?*"))
            result = ERROR_FILE_NOT_FOUND;
          else
            {
@@ -7478,7 +7399,6 @@ a ShowWindow flag:
   char *doc_a = NULL, *params_a = NULL, *ops_a = NULL;
   Lisp_Object absdoc, handler;
   BOOL success;
-  struct gcpro gcpro1;
 #endif
 
   CHECK_STRING (document);
@@ -7578,7 +7498,6 @@ a ShowWindow flag:
      absolute.  But DOCUMENT does not have to be a file, it can be a
      URL, for example.  So we make it absolute only if it is an
      existing file; if it is a file that does not exist, tough.  */
-  GCPRO1 (absdoc);
   absdoc = Fexpand_file_name (document, Qnil);
   /* Don't call file handlers for file-exists-p, since they might
      attempt to access the file, which could fail or produce undesired
@@ -7602,15 +7521,14 @@ a ShowWindow flag:
     }
   else
     document = ENCODE_FILE (document);
-  UNGCPRO;
 
   current_dir = ENCODE_FILE (current_dir);
   /* Cannot use filename_to_utf16/ansi with DOCUMENT, since it could
      be a URL that is not limited to MAX_PATH chararcters.  */
-  doclen = pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS,
+  doclen = pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags,
                                 SSDATA (document), -1, NULL, 0);
   doc_w = xmalloc (doclen * sizeof (wchar_t));
-  pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS,
+  pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags,
                        SSDATA (document), -1, doc_w, doclen);
   if (use_unicode)
     {
@@ -7625,12 +7543,12 @@ a ShowWindow flag:
          int len;
 
          parameters = ENCODE_SYSTEM (parameters);
-         len = pMultiByteToWideChar (CP_ACP, MB_ERR_INVALID_CHARS,
+         len = pMultiByteToWideChar (CP_ACP, multiByteToWideCharFlags,
                                      SSDATA (parameters), -1, NULL, 0);
          if (len > 32768)
            len = 32768;
          params_w = alloca (len * sizeof (wchar_t));
-         pMultiByteToWideChar (CP_ACP, MB_ERR_INVALID_CHARS,
+         pMultiByteToWideChar (CP_ACP, multiByteToWideCharFlags,
                                SSDATA (parameters), -1, params_w, len);
          params_w[len - 1] = 0;
        }
@@ -7669,7 +7587,7 @@ a ShowWindow flag:
     }
   else
     {
-      char document_a[MAX_PATH], current_dir_a[MAX_PATH];
+      char current_dir_a[MAX_PATH];
       SHELLEXECUTEINFOA shexinfo_a;
       int codepage = codepage_for_filenames (NULL);
       int ldoc_a = pWideCharToMultiByte (codepage, 0, doc_w, -1, NULL, 0,
@@ -7748,22 +7666,17 @@ w32_parse_hot_key (Lisp_Object key)
   int vk_code;
   int lisp_modifiers;
   int w32_modifiers;
-  struct gcpro gcpro1;
 
   CHECK_VECTOR (key);
 
   if (ASIZE (key) != 1)
     return Qnil;
 
-  GCPRO1 (key);
-
   c = AREF (key, 0);
 
   if (CONSP (c) && lucid_event_type_list_p (c))
     c = Fevent_convert_list (c);
 
-  UNGCPRO;
-
   if (! INTEGERP (c) && ! SYMBOLP (c))
     error ("Key definition is invalid");
 
@@ -7775,7 +7688,7 @@ w32_parse_hot_key (Lisp_Object key)
       c = Fcar (c);
       if (!SYMBOLP (c))
        emacs_abort ();
-      vk_code = lookup_vk_code (SDATA (SYMBOL_NAME (c)));
+      vk_code = lookup_vk_code (SSDATA (SYMBOL_NAME (c)));
     }
   else if (INTEGERP (c))
     {
@@ -7982,183 +7895,259 @@ This is a direct interface to the Windows API FindWindow function.  */)
   return Qt;
 }
 
-DEFUN ("w32-frame-menu-bar-size", Fw32_frame_menu_bar_size, Sw32_frame_menu_bar_size, 0, 1, 0,
-       doc: /* Return sizes of menu bar on frame FRAME.
-The return value is a list of four elements: The current width and
-height of FRAME's menu bar in pixels, the height of one menu bar line in
-a wrapped menu bar in pixels, and the height of a single line menu bar
-in pixels.
+DEFUN ("w32-frame-geometry", Fw32_frame_geometry, Sw32_frame_geometry, 0, 1, 0,
+       doc: /* Return geometric attributes of FRAME.
+FRAME must be a live frame and defaults to the selected one.  The return
+value is an association list of the attributes listed below.  All height
+and width values are in pixels.
 
-If FRAME is omitted or nil, the selected frame is used.  */)
-  (Lisp_Object frame)
-{
-  struct frame *f = decode_any_frame (frame);
-  MENUBARINFO menu_bar;
-  int width, height, single_height, wrapped_height;
+`outer-position' is a cons of the outer left and top edges of FRAME
+  relative to the origin - the position (0, 0) - of FRAME's display.
 
-  if (FRAME_INITIAL_P (f) || !FRAME_W32_P (f))
-    return Qnil;
-
-  block_input ();
-
-  single_height = GetSystemMetrics (SM_CYMENU);
-  wrapped_height = GetSystemMetrics (SM_CYMENUSIZE);
-  menu_bar.cbSize = sizeof (menu_bar);
-  menu_bar.rcBar.right = menu_bar.rcBar.left = 0;
-  menu_bar.rcBar.top = menu_bar.rcBar.bottom = 0;
-  GetMenuBarInfo (FRAME_W32_WINDOW (f), 0xFFFFFFFD, 0, &menu_bar);
-  width = menu_bar.rcBar.right - menu_bar.rcBar.left;
-  height = menu_bar.rcBar.bottom - menu_bar.rcBar.top;
-
-  unblock_input ();
-
-  return list4 (make_number (width), make_number (height),
-               make_number (wrapped_height), make_number (single_height));
-}
+`outer-size' is a cons of the outer width and height of FRAME.  The
+  outer size includes the title bar and the external borders as well as
+  any menu and/or tool bar of frame.
 
-DEFUN ("w32-frame-rect", Fw32_frame_rect, Sw32_frame_rect, 0, 2, 0,
-       doc: /* Return boundary rectangle of FRAME in screen coordinates.
-FRAME must be a live frame and defaults to the selected one.
-
-The boundary rectangle is a list of four elements, specifying the left,
-top, right and bottom screen coordinates of FRAME including menu and
-title bar and decorations.  Optional argument CLIENT non-nil means to
-return the boundaries of the client rectangle which excludes menu and
-title bar and decorations.  */)
-  (Lisp_Object frame, Lisp_Object client)
-{
-  struct frame *f = decode_live_frame (frame);
-  RECT rect;
+`external-border-size' is a cons of the horizontal and vertical width of
+  FRAME's external borders as supplied by the window manager.
 
-  if (FRAME_INITIAL_P (f) || !FRAME_W32_P (f))
-    return Qnil;
+`title-bar-size' is a cons of the width and height of the title bar of
+  FRAME as supplied by the window manager.  If both of them are zero,
+  FRAME has no title bar.  If only the width is zero, Emacs was not
+  able to retrieve the width information.
 
-  block_input ();
+`menu-bar-external', if non-nil, means the menu bar is external (never
+  included in the inner edges of FRAME).
 
-  if (!NILP (client))
-    GetClientRect (FRAME_W32_WINDOW (f), &rect);
-  else
-    GetWindowRect (FRAME_W32_WINDOW (f), &rect);
-
-  unblock_input ();
-
-  return list4 (make_number (rect.left), make_number (rect.top),
-               make_number (rect.right), make_number (rect.bottom));
-}
-
-DEFUN ("x-frame-geometry", Fx_frame_geometry, Sx_frame_geometry, 0, 1, 0,
-       doc: /* Return geometric attributes of frame FRAME.
-FRAME must be a live frame and defaults to the selected one.
-
-The return value is an association list containing the following
-elements (all size values are in pixels).
-
-- `frame-outer-size' is a cons of the outer width and height of FRAME.
-  The outer size includes the title bar and the external borders as well
-  as any menu and/or tool bar of frame.
-
-- `border' is a cons of the horizontal and vertical width of FRAME's
-  external borders.
-
-- `title-bar-height' is the height of the title bar of FRAME.
-
-- `menu-bar-external' if t means the menu bar is by default external
-  (not included in the inner size of FRAME).
-
-- `menu-bar-size' is a cons of the width and height of the menu bar of
+`menu-bar-size' is a cons of the width and height of the menu bar of
   FRAME.
 
-- `tool-bar-external' if t means the tool bar is by default external
-  (not included in the inner size of FRAME).
+`tool-bar-external', if non-nil, means the tool bar is external (never
+  included in the inner edges of FRAME).
 
-- `tool-bar-side' tells tells on which side the tool bar on FRAME is by
-  default and can be one of `left', `top', `right' or `bottom'.
+`tool-bar-position' tells on which side the tool bar on FRAME is and can
+  be one of `left', `top', `right' or `bottom'.  If this is nil, FRAME
+  has no tool bar.
 
-`tool-bar-size' is a cons of the width and height of the tool bar of
+`tool-bar-size' is a cons of the width and height of the tool bar of
   FRAME.
 
-- `frame-inner-size' is a cons of the inner width and height of FRAME.
-  This excludes FRAME's title bar and external border as well as any
-  external menu and/or tool bar.  */)
+`internal-border-width' is the width of the internal border of
+  FRAME.  */)
   (Lisp_Object frame)
 {
   struct frame *f = decode_live_frame (frame);
-  Lisp_Object geometry = Qnil;
-  RECT frame_outer_edges, frame_inner_edges;
+
   MENUBARINFO menu_bar;
-  int  border_width, border_height, title_height;
-  int single_bar_height, wrapped_bar_height, menu_bar_height;
-  Lisp_Object fullscreen = Fframe_parameter (frame, Qfullscreen);
+  WINDOWINFO window;
+  int left, top, right, bottom;
+  unsigned int external_border_width, external_border_height;
+  int title_bar_width = 0, title_bar_height = 0;
+  int single_menu_bar_height, wrapped_menu_bar_height, menu_bar_height;
+  int tool_bar_height = FRAME_TOOL_BAR_HEIGHT (f);
+  int internal_border_width = FRAME_INTERNAL_BORDER_WIDTH (f);
 
   if (FRAME_INITIAL_P (f) || !FRAME_W32_P (f))
     return Qnil;
 
   block_input ();
-
-  /* Outer frame rectangle, including outer borders and title bar. */
-  GetWindowRect (FRAME_W32_WINDOW (f), &frame_outer_edges);
-  /* Inner frame rectangle, excluding borders and title bar.  */
-  GetClientRect (FRAME_W32_WINDOW (f), &frame_inner_edges);
-  /* Outer border.  */
-  border_width = GetSystemMetrics (SM_CXFRAME);
-  border_height = GetSystemMetrics (SM_CYFRAME);
+  /* Outer rectangle and borders.  */
+  window.cbSize = sizeof (window);
+  GetWindowInfo (FRAME_W32_WINDOW (f), &window);
+  external_border_width = window.cxWindowBorders;
+  external_border_height = window.cyWindowBorders;
   /* Title bar.  */
-  title_height = GetSystemMetrics (SM_CYCAPTION);
+  if (get_title_bar_info_fn)
+    {
+      TITLEBAR_INFO title_bar;
+
+      title_bar.cbSize = sizeof (title_bar);
+      title_bar.rcTitleBar.left = title_bar.rcTitleBar.right = 0;
+      title_bar.rcTitleBar.top = title_bar.rcTitleBar.bottom = 0;
+      for (int i = 0; i < 6; i++)
+       title_bar.rgstate[i] = 0;
+      if (get_title_bar_info_fn (FRAME_W32_WINDOW (f), &title_bar)
+         && !(title_bar.rgstate[0] & 0x00008001))
+       {
+         title_bar_width
+           = title_bar.rcTitleBar.right - title_bar.rcTitleBar.left;
+         title_bar_height
+           = title_bar.rcTitleBar.bottom - title_bar.rcTitleBar.top;
+       }
+    }
+  else if ((window.dwStyle & WS_CAPTION) == WS_CAPTION)
+    title_bar_height = GetSystemMetrics (SM_CYCAPTION);
   /* Menu bar.  */
   menu_bar.cbSize = sizeof (menu_bar);
   menu_bar.rcBar.right = menu_bar.rcBar.left = 0;
   menu_bar.rcBar.top = menu_bar.rcBar.bottom = 0;
   GetMenuBarInfo (FRAME_W32_WINDOW (f), 0xFFFFFFFD, 0, &menu_bar);
-  single_bar_height = GetSystemMetrics (SM_CYMENU);
-  wrapped_bar_height = GetSystemMetrics (SM_CYMENUSIZE);
+  single_menu_bar_height = GetSystemMetrics (SM_CYMENU);
+  wrapped_menu_bar_height = GetSystemMetrics (SM_CYMENUSIZE);
   unblock_input ();
 
+  left = window.rcWindow.left;
+  top = window.rcWindow.top;
+  right = window.rcWindow.right;
+  bottom = window.rcWindow.bottom;
+
+  /* Menu bar.  */
   menu_bar_height = menu_bar.rcBar.bottom - menu_bar.rcBar.top;
   /* Fix menu bar height reported by GetMenuBarInfo.  */
-  if (menu_bar_height > single_bar_height)
+  if (menu_bar_height > single_menu_bar_height)
     /* A wrapped menu bar.  */
-    menu_bar_height += single_bar_height - wrapped_bar_height;
+    menu_bar_height += single_menu_bar_height - wrapped_menu_bar_height;
   else if (menu_bar_height > 0)
     /* A single line menu bar.  */
-    menu_bar_height = single_bar_height;
-
-  return
-    listn (CONSTYPE_HEAP, 10,
-          Fcons (Qframe_position,
-                 Fcons (make_number (frame_outer_edges.left),
-                        make_number (frame_outer_edges.top))),
-          Fcons (Qframe_outer_size,
-                 Fcons (make_number
-                        (frame_outer_edges.right - frame_outer_edges.left),
-                        make_number
-                        (frame_outer_edges.bottom - frame_outer_edges.top))),
+    menu_bar_height = single_menu_bar_height;
+
+  return listn (CONSTYPE_HEAP, 10,
+               Fcons (Qouter_position,
+                      Fcons (make_number (left), make_number (top))),
+               Fcons (Qouter_size,
+                      Fcons (make_number (right - left),
+                             make_number (bottom - top))),
           Fcons (Qexternal_border_size,
-                 ((EQ (fullscreen, Qfullboth) || EQ (fullscreen, Qfullscreen))
-                  ? Fcons (make_number (0), make_number (0))
-                  : Fcons (make_number (border_width),
-                           make_number (border_height)))),
-          Fcons (Qtitle_height,
-                 ((EQ (fullscreen, Qfullboth) || EQ (fullscreen, Qfullscreen))
-                  ? make_number (0)
-                  : make_number (title_height))),
+                      Fcons (make_number (external_border_width),
+                             make_number (external_border_height))),
+               Fcons (Qtitle_bar_size,
+                      Fcons (make_number (title_bar_width),
+                             make_number (title_bar_height))),
           Fcons (Qmenu_bar_external, Qt),
           Fcons (Qmenu_bar_size,
                  Fcons (make_number
                         (menu_bar.rcBar.right - menu_bar.rcBar.left),
                         make_number (menu_bar_height))),
           Fcons (Qtool_bar_external, Qnil),
-          Fcons (Qtool_bar_position, Qtop),
+               Fcons (Qtool_bar_position, tool_bar_height ? Qtop : Qnil),
           Fcons (Qtool_bar_size,
-                 Fcons (make_number (FRAME_TOOL_BAR_LINES (f)
-                                     ? (FRAME_PIXEL_WIDTH (f)
-                                        - 2 * FRAME_INTERNAL_BORDER_WIDTH (f))
+                      Fcons (make_number
+                             (tool_bar_height
+                              ? right - left - 2 * internal_border_width
                                      : 0),
-                        make_number (FRAME_TOOL_BAR_HEIGHT (f)))),
-          Fcons (Qframe_inner_size,
-                 Fcons (make_number
-                        (frame_inner_edges.right - frame_inner_edges.left),
-                        make_number
-                        (frame_inner_edges.bottom - frame_inner_edges.top))));
+                             make_number (tool_bar_height))),
+               Fcons (Qinternal_border_width,
+                      make_number (internal_border_width)));
+}
+
+DEFUN ("w32-frame-edges", Fw32_frame_edges, Sw32_frame_edges, 0, 2, 0,
+       doc: /* Return edge coordinates of FRAME.
+FRAME must be a live frame and defaults to the selected one.  The return
+value is a list of the form (LEFT, TOP, RIGHT, BOTTOM).  All values are
+in pixels relative to the origin - the position (0, 0) - of FRAME's
+display.
+
+If optional argument TYPE is the symbol `outer-edges', return the outer
+edges of FRAME.  The outer edges comprise the decorations of the window
+manager (like the title bar or external borders) as well as any external
+menu or tool bar of FRAME.  If optional argument TYPE is the symbol
+`native-edges' or nil, return the native edges of FRAME.  The native
+edges exclude the decorations of the window manager and any external
+menu or tool bar of FRAME.  If TYPE is the symbol `inner-edges', return
+the inner edges of FRAME.  These edges exclude title bar, any borders,
+menu bar or tool bar of FRAME.  */)
+  (Lisp_Object frame, Lisp_Object type)
+{
+  struct frame *f = decode_live_frame (frame);
+
+  if (FRAME_INITIAL_P (f) || !FRAME_W32_P (f))
+    return Qnil;
+
+  if (EQ (type, Qouter_edges))
+    {
+      RECT rectangle;
+
+      block_input ();
+      /* Outer frame rectangle, including outer borders and title bar. */
+      GetWindowRect (FRAME_W32_WINDOW (f), &rectangle);
+      unblock_input ();
+
+      return list4 (make_number (rectangle.left),
+                   make_number (rectangle.top),
+                   make_number (rectangle.right),
+                   make_number (rectangle.bottom));
+    }
+  else
+    {
+      RECT rectangle;
+      POINT pt;
+      int left, top, right, bottom;
+
+      block_input ();
+      /* Inner frame rectangle, excluding borders and title bar.  */
+      GetClientRect (FRAME_W32_WINDOW (f), &rectangle);
+      /* Get top-left corner of native rectangle in screen
+        coordinates.  */
+      pt.x = 0;
+      pt.y = 0;
+      ClientToScreen (FRAME_W32_WINDOW (f), &pt);
+      unblock_input ();
+
+      left = pt.x;
+      top = pt.y;
+      right = left + rectangle.right;
+      bottom = top + rectangle.bottom;
+
+      if (EQ (type, Qinner_edges))
+       {
+         int internal_border_width = FRAME_INTERNAL_BORDER_WIDTH (f);
+
+         return list4 (make_number (left + internal_border_width),
+                       make_number (top
+                                    + FRAME_TOOL_BAR_HEIGHT (f)
+                                    + internal_border_width),
+                       make_number (right - internal_border_width),
+                       make_number (bottom - internal_border_width));
+       }
+      else
+       return list4 (make_number (left), make_number (top),
+                     make_number (right), make_number (bottom));
+    }
+}
+
+DEFUN ("w32-mouse-absolute-pixel-position", Fw32_mouse_absolute_pixel_position,
+       Sw32_mouse_absolute_pixel_position, 0, 0, 0,
+       doc: /* Return absolute position of mouse cursor in pixels.
+The position is returned as a cons cell (X . Y) of the coordinates of
+the mouse cursor position in pixels relative to a position (0, 0) of the
+selected frame's display.  */)
+  (void)
+{
+  POINT pt;
+
+  block_input ();
+  GetCursorPos (&pt);
+  unblock_input ();
+
+  return Fcons (make_number (pt.x), make_number (pt.y));
+}
+
+DEFUN ("w32-set-mouse-absolute-pixel-position", Fw32_set_mouse_absolute_pixel_position,
+       Sw32_set_mouse_absolute_pixel_position, 2, 2, 0,
+       doc: /* Move mouse pointer to absolute pixel position (X, Y).
+The coordinates X and Y are interpreted in pixels relative to a position
+\(0, 0) of the selected frame's display.  */)
+  (Lisp_Object x, Lisp_Object y)
+{
+  UINT trail_num = 0;
+  BOOL ret = false;
+
+  CHECK_TYPE_RANGED_INTEGER (int, x);
+  CHECK_TYPE_RANGED_INTEGER (int, y);
+
+  block_input ();
+  /* 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 (XINT (x), XINT (y));
+  if (ret)
+    SystemParametersInfo (SPI_SETMOUSETRAILS, trail_num, NULL, 0);
+  unblock_input ();
+
+  return Qnil;
 }
 
 DEFUN ("w32-battery-status", Fw32_battery_status, Sw32_battery_status, 0, 0, 0,
@@ -8313,7 +8302,7 @@ If the underlying system call fails, value is nil.  */)
     char rootname[MAX_UTF8_PATH];
     wchar_t rootname_w[MAX_PATH];
     char rootname_a[MAX_PATH];
-    char *name = SDATA (encoded);
+    char *name = SSDATA (encoded);
     BOOL result;
 
     /* find the root name of the volume if given */
@@ -8767,7 +8756,7 @@ w32_kbd_patch_key (KEY_EVENT_RECORD *event, int cpId)
 
          event->uChar.UnicodeChar = buf[isdead - 1];
          isdead = WideCharToMultiByte (cpId, 0, buf, isdead,
-                                       ansi_code, 4, NULL, NULL);
+                                       (LPSTR)ansi_code, 4, NULL, NULL);
        }
       else
        isdead = 0;
@@ -8809,6 +8798,457 @@ Internal use only.  */)
   return menubar_in_use ? Qt : Qnil;
 }
 
+#if defined WINDOWSNT && !defined HAVE_DBUS
+
+/***********************************************************************
+                         Tray notifications
+ ***********************************************************************/
+/* A private struct declaration to avoid compile-time limits.  */
+typedef struct MY_NOTIFYICONDATAW {
+  DWORD cbSize;
+  HWND hWnd;
+  UINT uID;
+  UINT uFlags;
+  UINT uCallbackMessage;
+  HICON hIcon;
+  WCHAR szTip[128];
+  DWORD dwState;
+  DWORD dwStateMask;
+  WCHAR szInfo[256];
+  _ANONYMOUS_UNION union {
+    UINT uTimeout;
+    UINT uVersion;
+  } DUMMYUNIONNAME;
+  WCHAR szInfoTitle[64];
+  DWORD dwInfoFlags;
+  GUID guidItem;
+  HICON hBalloonIcon;
+} MY_NOTIFYICONDATAW;
+
+#define MYNOTIFYICONDATAW_V1_SIZE offsetof (MY_NOTIFYICONDATAW, szTip[64])
+#define MYNOTIFYICONDATAW_V2_SIZE offsetof (MY_NOTIFYICONDATAW, guidItem)
+#define MYNOTIFYICONDATAW_V3_SIZE offsetof (MY_NOTIFYICONDATAW, hBalloonIcon)
+#ifndef NIF_INFO
+# define NIF_INFO     0x00000010
+#endif
+#ifndef NIIF_NONE
+# define NIIF_NONE    0x00000000
+#endif
+#ifndef NIIF_INFO
+# define NIIF_INFO    0x00000001
+#endif
+#ifndef NIIF_WARNING
+# define NIIF_WARNING 0x00000002
+#endif
+#ifndef NIIF_ERROR
+# define NIIF_ERROR   0x00000003
+#endif
+
+
+#define EMACS_TRAY_NOTIFICATION_ID  42 /* arbitrary */
+#define EMACS_NOTIFICATION_MSG      (WM_APP + 1)
+
+enum NI_Severity {
+  Ni_None,
+  Ni_Info,
+  Ni_Warn,
+  Ni_Err
+};
+
+/* Report the version of a DLL given by its name.  The return value is
+   constructed using MAKEDLLVERULL.  */
+static ULONGLONG
+get_dll_version (const char *dll_name)
+{
+  ULONGLONG version = 0;
+  HINSTANCE hdll = LoadLibrary (dll_name);
+
+  if (hdll)
+    {
+      DLLGETVERSIONPROC pDllGetVersion
+       = (DLLGETVERSIONPROC) GetProcAddress (hdll, "DllGetVersion");
+
+      if (pDllGetVersion)
+       {
+         DLLVERSIONINFO dvi;
+         HRESULT result;
+
+         memset (&dvi, 0, sizeof(dvi));
+         dvi.cbSize = sizeof(dvi);
+         result = pDllGetVersion (&dvi);
+         if (SUCCEEDED (result))
+           version = MAKEDLLVERULL (dvi.dwMajorVersion, dvi.dwMinorVersion,
+                                    0, 0);
+       }
+      FreeLibrary (hdll);
+    }
+
+  return version;
+}
+
+/* Return the number of bytes in UTF-8 encoded string STR that
+   corresponds to at most LIM characters.  If STR ends before LIM
+   characters, return the number of bytes in STR including the
+   terminating null byte.  */
+static int
+utf8_mbslen_lim (const char *str, int lim)
+{
+  const char *p = str;
+  int mblen = 0, nchars = 0;
+
+  while (*p && nchars < lim)
+    {
+      int nbytes = CHAR_BYTES (*p);
+
+      mblen += nbytes;
+      nchars++;
+      p += nbytes;
+    }
+
+  if (!*p && nchars < lim)
+    mblen++;
+
+  return mblen;
+}
+
+/* Low-level subroutine to show tray notifications.  All strings are
+   supposed to be unibyte UTF-8 encoded by the caller.  */
+static EMACS_INT
+add_tray_notification (struct frame *f, const char *icon, const char *tip,
+                      enum NI_Severity severity, unsigned timeout,
+                      const char *title, const char *msg)
+{
+  EMACS_INT retval = EMACS_TRAY_NOTIFICATION_ID;
+
+  if (FRAME_W32_P (f))
+    {
+      MY_NOTIFYICONDATAW nidw;
+      ULONGLONG shell_dll_version = get_dll_version ("Shell32.dll");
+      wchar_t tipw[128], msgw[256], titlew[64];
+      int tiplen;
+
+      memset (&nidw, 0, sizeof(nidw));
+
+      /* MSDN says the full struct is supported since Vista, whose
+        Shell32.dll version is said to be 6.0.6.  But DllGetVersion
+        cannot report the 3rd field value, it reports "build number"
+        instead, which is something else.  So we use the Windows 7's
+        version 6.1 as cutoff, and Vista loses.  (Actually, the loss
+        is not a real one, since we don't expose the hBalloonIcon
+        member of the struct to Lisp.)  */
+      if (shell_dll_version >= MAKEDLLVERULL (6, 1, 0, 0)) /* >= Windows 7 */
+       nidw.cbSize = sizeof (nidw);
+      else if (shell_dll_version >= MAKEDLLVERULL (6, 0, 0, 0)) /* XP */
+       nidw.cbSize = MYNOTIFYICONDATAW_V3_SIZE;
+      else if (shell_dll_version >= MAKEDLLVERULL (5, 0, 0, 0)) /* W2K */
+       nidw.cbSize = MYNOTIFYICONDATAW_V2_SIZE;
+      else
+       nidw.cbSize = MYNOTIFYICONDATAW_V1_SIZE;                /* < W2K */
+      nidw.hWnd = FRAME_W32_WINDOW (f);
+      nidw.uID = EMACS_TRAY_NOTIFICATION_ID;
+      nidw.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP | NIF_INFO;
+      nidw.uCallbackMessage = EMACS_NOTIFICATION_MSG;
+      if (!*icon)
+       nidw.hIcon = LoadIcon (hinst, EMACS_CLASS);
+      else
+       {
+         if (w32_unicode_filenames)
+           {
+             wchar_t icon_w[MAX_PATH];
+
+             if (filename_to_utf16 (icon, icon_w) != 0)
+               {
+                 errno = ENOENT;
+                 return -1;
+               }
+             nidw.hIcon = LoadImageW (NULL, icon_w, IMAGE_ICON, 0, 0,
+                                      LR_DEFAULTSIZE | LR_LOADFROMFILE);
+           }
+         else
+           {
+             char icon_a[MAX_PATH];
+
+             if (filename_to_ansi (icon, icon_a) != 0)
+               {
+                 errno = ENOENT;
+                 return -1;
+               }
+             nidw.hIcon = LoadImageA (NULL, icon_a, IMAGE_ICON, 0, 0,
+                                      LR_DEFAULTSIZE | LR_LOADFROMFILE);
+           }
+       }
+      if (!nidw.hIcon)
+       {
+         switch (GetLastError ())
+           {
+           case ERROR_FILE_NOT_FOUND:
+             errno = ENOENT;
+             break;
+           default:
+             errno = ENOMEM;
+             break;
+           }
+         return -1;
+       }
+
+      /* Windows 9X and NT4 support only 64 characters in the Tip,
+        later versions support up to 128.  */
+      if (nidw.cbSize == MYNOTIFYICONDATAW_V1_SIZE)
+       {
+         tiplen = pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags,
+                                        tip, utf8_mbslen_lim (tip, 63),
+                                        tipw, 64);
+         if (tiplen >= 63)
+           tipw[63] = 0;
+       }
+      else
+       {
+         tiplen = pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags,
+                                        tip, utf8_mbslen_lim (tip, 127),
+                                        tipw, 128);
+         if (tiplen >= 127)
+           tipw[127] = 0;
+       }
+      if (tiplen == 0)
+       {
+         errno = EINVAL;
+         retval = -1;
+         goto done;
+       }
+      wcscpy (nidw.szTip, tipw);
+
+      /* The rest of the structure is only supported since Windows 2000.  */
+      if (nidw.cbSize > MYNOTIFYICONDATAW_V1_SIZE)
+       {
+         int slen;
+
+         slen = pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags,
+                                            msg, utf8_mbslen_lim (msg, 255),
+                                            msgw, 256);
+         if (slen >= 255)
+           msgw[255] = 0;
+         else if (slen == 0)
+           {
+             errno = EINVAL;
+             retval = -1;
+             goto done;
+           }
+         wcscpy (nidw.szInfo, msgw);
+         nidw.uTimeout = timeout;
+         slen = pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags,
+                                      title, utf8_mbslen_lim (title, 63),
+                                      titlew, 64);
+         if (slen >= 63)
+           titlew[63] = 0;
+         else if (slen == 0)
+           {
+             errno = EINVAL;
+             retval = -1;
+             goto done;
+           }
+         wcscpy (nidw.szInfoTitle, titlew);
+
+         switch (severity)
+           {
+           case Ni_None:
+             nidw.dwInfoFlags = NIIF_NONE;
+             break;
+           case Ni_Info:
+           default:
+             nidw.dwInfoFlags = NIIF_INFO;
+             break;
+           case Ni_Warn:
+             nidw.dwInfoFlags = NIIF_WARNING;
+             break;
+           case Ni_Err:
+             nidw.dwInfoFlags = NIIF_ERROR;
+             break;
+           }
+       }
+
+      if (!Shell_NotifyIconW (NIM_ADD, (PNOTIFYICONDATAW)&nidw))
+       {
+         /* GetLastError returns meaningless results when
+            Shell_NotifyIcon fails.  */
+         DebPrint (("Shell_NotifyIcon ADD failed (err=%d)\n",
+                    GetLastError ()));
+         errno = EINVAL;
+         retval = -1;
+       }
+    done:
+      if (*icon && !DestroyIcon (nidw.hIcon))
+       DebPrint (("DestroyIcon failed (err=%d)\n", GetLastError ()));
+    }
+  return retval;
+}
+
+/* Low-level subroutine to remove a tray notification.  Note: we only
+   pass the minimum data about the notification: its ID and the handle
+   of the window to which it sends messages.  MSDN doesn't say this is
+   enough, but it works in practice.  This allows us to avoid keeping
+   the notification data around after we show the notification.  */
+static void
+delete_tray_notification (struct frame *f, int id)
+{
+  if (FRAME_W32_P (f))
+    {
+      MY_NOTIFYICONDATAW nidw;
+
+      memset (&nidw, 0, sizeof(nidw));
+      nidw.hWnd = FRAME_W32_WINDOW (f);
+      nidw.uID = id;
+
+      if (!Shell_NotifyIconW (NIM_DELETE, (PNOTIFYICONDATAW)&nidw))
+       {
+         /* GetLastError returns meaningless results when
+            Shell_NotifyIcon fails.  */
+         DebPrint (("Shell_NotifyIcon DELETE failed\n"));
+         errno = EINVAL;
+         return;
+       }
+    }
+  return;
+}
+
+DEFUN ("w32-notification-notify",
+       Fw32_notification_notify, Sw32_notification_notify,
+       0, MANY, 0,
+       doc: /* Display an MS-Windows tray notification as specified by PARAMS.
+
+Value is the integer unique ID of the notification that can be used
+to remove the notification using `w32-notification-close', which see.
+If the function fails, the return value is nil.
+
+Tray notifications, a.k.a. \"taskbar messages\", are messages that
+inform the user about events unrelated to the current user activity,
+such as a significant system event, by briefly displaying informative
+text in a balloon from an icon in the notification area of the taskbar.
+
+Parameters in PARAMS are specified as keyword/value pairs.  All the
+parameters are optional, but if no parameters are specified, the
+function will do nothing and return nil.
+
+The following parameters are supported:
+
+:icon ICON       -- Display ICON in the system tray.  If ICON is a string,
+                    it should specify a file name from which to load the
+                    icon; the specified file should be a .ico Windows icon
+                    file.  If ICON is not a string, or if this parameter
+                    is not specified, the standard Emacs icon will be used.
+
+:tip TIP         -- Use TIP as the tooltip for the notification.  If TIP
+                    is a string, this is the text of a tooltip that will
+                    be shown when the mouse pointer hovers over the tray
+                    icon added by the notification.  If TIP is not a
+                    string, or if this parameter is not specified, the
+                    default tooltip text is \"Emacs notification\".  The
+                    tooltip text can be up to 127 characters long (63
+                    on Windows versions before W2K).  Longer strings
+                    will be truncated.
+
+:level LEVEL     -- Notification severity level, one of `info',
+                    `warning', or `error'.  If given, the value
+                    determines the icon displayed to the left of the
+                    notification title, but only if the `:title'
+                    parameter (see below) is also specified and is a
+                    string.
+
+:title TITLE     -- The title of the notification.  If TITLE is a string,
+                    it is displayed in a larger font immediately above
+                    the body text.  The title text can be up to 63
+                    characters long; longer text will be truncated.
+
+:body BODY       -- The body of the notification.  If BODY is a string,
+                    it specifies the text of the notification message.
+                    Use embedded newlines to control how the text is
+                    broken into lines.  The body text can be up to 255
+                    characters long, and will be truncated if it's longer.
+
+Note that versions of Windows before W2K support only `:icon' and `:tip'.
+You can pass the other parameters, but they will be ignored on those
+old systems.
+
+There can be at most one active notification at any given time.  An
+active notification must be removed by calling `w32-notification-close'
+before a new one can be shown.
+
+usage: (w32-notification-notify &rest PARAMS)  */)
+  (ptrdiff_t nargs, Lisp_Object *args)
+{
+  struct frame *f = SELECTED_FRAME ();
+  Lisp_Object arg_plist, lres;
+  EMACS_INT retval;
+  char *icon, *tip, *title, *msg;
+  enum NI_Severity severity;
+  unsigned timeout;
+
+  if (nargs == 0)
+    return Qnil;
+
+  arg_plist = Flist (nargs, args);
+
+  /* Icon.  */
+  lres = Fplist_get (arg_plist, QCicon);
+  if (STRINGP (lres))
+    icon = SSDATA (ENCODE_FILE (Fexpand_file_name (lres, Qnil)));
+  else
+    icon = "";
+
+  /* Tip.  */
+  lres = Fplist_get (arg_plist, QCtip);
+  if (STRINGP (lres))
+    tip = SSDATA (code_convert_string_norecord (lres, Qutf_8, 1));
+  else
+    tip = "Emacs notification";
+
+  /* Severity.  */
+  lres = Fplist_get (arg_plist, QClevel);
+  if (NILP (lres))
+    severity = Ni_None;
+  else if (EQ (lres, Qinfo))
+    severity = Ni_Info;
+  else if (EQ (lres, Qwarning))
+    severity = Ni_Warn;
+  else if (EQ (lres, Qerror))
+    severity = Ni_Err;
+  else
+    severity = Ni_Info;
+
+  /* Title.  */
+  lres = Fplist_get (arg_plist, QCtitle);
+  if (STRINGP (lres))
+    title = SSDATA (code_convert_string_norecord (lres, Qutf_8, 1));
+  else
+    title = "";
+
+  /* Notification body text.  */
+  lres = Fplist_get (arg_plist, QCbody);
+  if (STRINGP (lres))
+    msg = SSDATA (code_convert_string_norecord (lres, Qutf_8, 1));
+  else
+    msg = "";
+
+  /* Do it!  */
+  retval = add_tray_notification (f, icon, tip, severity, timeout, title, msg);
+  return (retval < 0 ? Qnil : make_number (retval));
+}
+
+DEFUN ("w32-notification-close",
+       Fw32_notification_close, Sw32_notification_close,
+       1, 1, 0,
+       doc: /* Remove the MS-Windows tray notification specified by its ID.  */)
+  (Lisp_Object id)
+{
+  struct frame *f = SELECTED_FRAME ();
+
+  if (INTEGERP (id))
+    delete_tray_notification (f, XINT (id));
+
+  return Qnil;
+}
+
+#endif /* WINDOWSNT && !HAVE_DBUS */
+
 \f
 /***********************************************************************
                            Initialization
@@ -8882,6 +9322,15 @@ syms_of_w32fns (void)
   DEFSYM (Qframes, "frames");
   DEFSYM (Qtip_frame, "tip-frame");
   DEFSYM (Qunicode_sip, "unicode-sip");
+#if defined WINDOWSNT && !defined HAVE_DBUS
+  DEFSYM (QCicon, ":icon");
+  DEFSYM (QCtip, ":tip");
+  DEFSYM (QClevel, ":level");
+  DEFSYM (Qinfo, "info");
+  DEFSYM (Qwarning, "warning");
+  DEFSYM (QCtitle, ":title");
+  DEFSYM (QCbody, ":body");
+#endif
 
   /* Symbols used elsewhere, but only in MS-Windows-specific code.  */
   DEFSYM (Qgnutls_dll, "gnutls");
@@ -9158,6 +9607,16 @@ Default is nil.
 This variable has effect only on NT family of systems, not on Windows 9X.  */);
   w32_use_fallback_wm_chars_method = 0;
 
+  DEFVAR_BOOL ("w32-disable-new-uniscribe-apis",
+              w32_disable_new_uniscribe_apis,
+              doc: /* Non-nil means don't use new Uniscribe APIs.
+The new APIs are used to access OTF features supported by fonts.
+This is intended only for debugging of the new Uniscribe-related code.
+Default is nil.
+
+This variable has effect only on Windows Vista and later.  */);
+  w32_disable_new_uniscribe_apis = 0;
+
 #if 0 /* TODO: Port to W32 */
   defsubr (&Sx_change_window_property);
   defsubr (&Sx_delete_window_property);
@@ -9184,7 +9643,10 @@ This variable has effect only on NT family of systems, not on Windows 9X.  */);
   defsubr (&Sx_open_connection);
   defsubr (&Sx_close_connection);
   defsubr (&Sx_display_list);
-  defsubr (&Sx_frame_geometry);
+  defsubr (&Sw32_frame_geometry);
+  defsubr (&Sw32_frame_edges);
+  defsubr (&Sw32_mouse_absolute_pixel_position);
+  defsubr (&Sw32_set_mouse_absolute_pixel_position);
   defsubr (&Sx_synchronize);
 
   /* W32 specific functions */
@@ -9200,10 +9662,12 @@ This variable has effect only on NT family of systems, not on Windows 9X.  */);
   defsubr (&Sw32_reconstruct_hot_key);
   defsubr (&Sw32_toggle_lock_key);
   defsubr (&Sw32_window_exists_p);
-  defsubr (&Sw32_frame_rect);
-  defsubr (&Sw32_frame_menu_bar_size);
   defsubr (&Sw32_battery_status);
   defsubr (&Sw32__menu_bar_in_use);
+#if defined WINDOWSNT && !defined HAVE_DBUS
+  defsubr (&Sw32_notification_notify);
+  defsubr (&Sw32_notification_close);
+#endif
 
 #ifdef WINDOWSNT
   defsubr (&Sfile_system_info);
@@ -9239,18 +9703,79 @@ static DWORD except_code;
 static PVOID except_addr;
 
 #ifndef CYGWIN
+
+/* Stack overflow recovery.  */
+
+/* MinGW headers don't declare this (should be in malloc.h).  Also,
+   the function is not present pre-W2K, so make the call through
+   a function pointer.  */
+typedef int (__cdecl *_resetstkoflw_proc) (void);
+static _resetstkoflw_proc resetstkoflw;
+
+/* Re-establish the guard page at stack limit.  This is needed because
+   when a stack overflow is detected, Windows removes the guard bit
+   from the guard page, so if we don't re-establish that protection,
+   the next stack overflow will cause a crash.  */
+void
+w32_reset_stack_overflow_guard (void)
+{
+  if (resetstkoflw == NULL)
+    resetstkoflw =
+      (_resetstkoflw_proc)GetProcAddress (GetModuleHandle ("msvcrt.dll"),
+                                         "_resetstkoflw");
+  /* We ignore the return value.  If _resetstkoflw fails, the next
+     stack overflow will crash the program.  */
+  if (resetstkoflw != NULL)
+    (void)resetstkoflw ();
+}
+
+static void
+stack_overflow_handler (void)
+{
+  /* Hard GC error may lead to stack overflow caused by
+     too nested calls to mark_object.  No way to survive.  */
+  if (gc_in_progress)
+    terminate_due_to_signal (SIGSEGV, 40);
+#ifdef _WIN64
+  /* See ms-w32.h: MinGW64's longjmp crashes if invoked in this context.  */
+  __builtin_longjmp (return_to_command_loop, 1);
+#else
+  sys_longjmp (return_to_command_loop, 1);
+#endif
+}
+
 /* This handler records the exception code and the address where it
    was triggered so that this info could be included in the backtrace.
    Without that, the backtrace in some cases has no information
    whatsoever about the offending code, and looks as if the top-level
-   exception handler in the MinGW startup code di the one that
-   crashed.  */
+   exception handler in the MinGW startup code was the one that
+   crashed.  We also recover from stack overflow, by calling our stack
+   overflow handler that jumps back to top level.  */
 static LONG CALLBACK
 my_exception_handler (EXCEPTION_POINTERS * exception_data)
 {
   except_code = exception_data->ExceptionRecord->ExceptionCode;
   except_addr = exception_data->ExceptionRecord->ExceptionAddress;
 
+  /* If this is a stack overflow exception, attempt to recover.  */
+  if (exception_data->ExceptionRecord->ExceptionCode == EXCEPTION_STACK_OVERFLOW
+      && exception_data->ExceptionRecord->NumberParameters == 2
+      /* We can only longjmp to top level from the main thread.  */
+      && GetCurrentThreadId () == dwMainThreadId)
+    {
+      /* Call stack_overflow_handler ().  */
+#ifdef _WIN64
+      exception_data->ContextRecord->Rip = (DWORD_PTR) &stack_overflow_handler;
+#else
+      exception_data->ContextRecord->Eip = (DWORD_PTR) &stack_overflow_handler;
+#endif
+      /* Zero this out, so the stale address of the stack overflow
+        exception we handled is not displayed in some future
+        unrelated crash.  */
+      except_addr = 0;
+      return EXCEPTION_CONTINUE_EXECUTION;
+    }
+
   if (prev_exception_handler)
     return prev_exception_handler (exception_data);
   return EXCEPTION_EXECUTE_HANDLER;
@@ -9413,6 +9938,8 @@ globals_of_w32fns (void)
     GetProcAddress (user32_lib, "MonitorFromWindow");
   enum_display_monitors_fn = (EnumDisplayMonitors_Proc)
     GetProcAddress (user32_lib, "EnumDisplayMonitors");
+  get_title_bar_info_fn = (GetTitleBarInfo_Proc)
+    GetProcAddress (user32_lib, "GetTitleBarInfo");
 
   {
     HMODULE imm32_lib = GetModuleHandle ("imm32.dll");
@@ -9430,6 +9957,7 @@ globals_of_w32fns (void)
   except_addr = 0;
 #ifndef CYGWIN
   prev_exception_handler = SetUnhandledExceptionFilter (my_exception_handler);
+  resetstkoflw = NULL;
 #endif
 
   DEFVAR_INT ("w32-ansi-code-page",