]> code.delx.au - gnu-emacs/blobdiff - src/w32fns.c
Ibuffer change marks
[gnu-emacs] / src / w32fns.c
index 10c8af7107389c3f96069bec92230c57d85a4b7a..20e09d8a4630134e62605abd70c83b52d5f9ca97 100644 (file)
@@ -6,8 +6,8 @@ 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
@@ -74,15 +74,10 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #define FOF_NO_CONNECTED_ELEMENTS 0x2000
 #endif
 
-void syms_of_w32fns (void);
-void globals_of_w32fns (void);
-
-extern void free_frame_menubar (struct frame *);
 extern int w32_console_toggle_lock_key (int, Lisp_Object);
 extern void w32_menu_display_help (HWND, HMENU, UINT, UINT);
 extern void w32_free_menu_strings (HWND);
 extern const char *map_w32_filename (const char *, const char **);
-extern char * w32_strerror (int error_no);
 
 #ifndef IDC_HAND
 #define IDC_HAND MAKEINTRESOURCE(32649)
@@ -191,11 +186,7 @@ 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
-#else /* !NTGUI_UNICODE */
 extern AppendMenuW_Proc unicode_append_menu;
-#endif /* NTGUI_UNICODE */
 
 /* Flag to selectively ignore WM_IME_CHAR messages.  */
 static int ignore_ime_char = 0;
@@ -222,7 +213,6 @@ static HWND w32_visible_system_caret_hwnd;
 static int w32_unicode_gui;
 
 /* From w32menu.c  */
-extern HMENU current_popup_menu;
 int menubar_in_use = 0;
 
 /* From w32uniscribe.c  */
@@ -365,10 +355,7 @@ void x_set_cursor_type (struct frame *, Lisp_Object, Lisp_Object);
 void x_set_icon_type (struct frame *, Lisp_Object, Lisp_Object);
 void x_set_icon_name (struct frame *, Lisp_Object, Lisp_Object);
 void x_explicitly_set_name (struct frame *, Lisp_Object, Lisp_Object);
-void x_set_menu_bar_lines (struct frame *, Lisp_Object, Lisp_Object);
 void x_set_title (struct frame *, Lisp_Object, Lisp_Object);
-void x_set_tool_bar_lines (struct frame *, Lisp_Object, Lisp_Object);
-void x_set_internal_border_width (struct frame *f, Lisp_Object, Lisp_Object);
 \f
 
 /* Store the screen positions of frame F into XPTR and YPTR.
@@ -491,7 +478,7 @@ if the entry is new.  */)
 /* The default colors for the w32 color map */
 typedef struct colormap_t
 {
-  char *name;
+  const char *name;
   COLORREF colorref;
 } colormap_t;
 
@@ -829,7 +816,7 @@ add_system_logical_colors_to_map (Lisp_Object *system_colors)
                            NULL, NULL, (LPBYTE)color_buffer, &color_size)
             == ERROR_SUCCESS)
        {
-         int r, g, b;
+         unsigned r, g, b;
          if (sscanf (color_buffer, " %u %u %u", &r, &g, &b) == 3)
            *system_colors = Fcons (Fcons (build_string (full_name_buffer),
                                           make_number (RGB (r, g, b))),
@@ -1244,7 +1231,7 @@ w32_defined_color (struct frame *f, const char *color, XColor *color_def,
    If F is not a color screen, return DEF (default) regardless of what
    ARG says.  */
 
-int
+static int
 x_decode_color (struct frame *f, Lisp_Object arg, int def)
 {
   XColor cdef;
@@ -1527,7 +1514,7 @@ x_set_cursor_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
    Note that this does not fully take effect if done before
    F has a window.  */
 
-void
+static void
 x_set_border_pixel (struct frame *f, int pix)
 {
 
@@ -1638,7 +1625,7 @@ x_set_icon_name (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
 #endif
 }
 \f
-void
+static void
 x_clear_under_internal_border (struct frame *f)
 {
   int border = FRAME_INTERNAL_BORDER_WIDTH (f);
@@ -1671,7 +1658,7 @@ x_set_internal_border_width (struct frame *f, Lisp_Object arg, Lisp_Object oldva
 
   if (border != FRAME_INTERNAL_BORDER_WIDTH (f))
     {
-      FRAME_INTERNAL_BORDER_WIDTH (f) = border;
+      f->internal_border_width = border;
 
       if (FRAME_X_WINDOW (f) != 0)
        {
@@ -1864,7 +1851,7 @@ w32_set_title_bar_text (struct frame *f, Lisp_Object name)
        suggesting a new name, which lisp code should override; if
        F->explicit_name is set, ignore the new name; otherwise, set it.  */
 
-void
+static void
 x_set_name (struct frame *f, Lisp_Object name, bool explicit)
 {
   /* Make sure that requests from lisp code override requests from
@@ -1969,6 +1956,8 @@ x_set_scroll_bar_default_height (struct frame *f)
 \f
 /* Subroutines for creating a frame.  */
 
+Cursor w32_load_cursor (LPCTSTR);
+
 Cursor
 w32_load_cursor (LPCTSTR name)
 {
@@ -2112,6 +2101,7 @@ my_post_msg (W32Msg * wmsg, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
   post_msg (wmsg);
 }
 
+#ifdef WINDOWSNT
 /* The Windows keyboard hook callback.  */
 static LRESULT CALLBACK
 funhook (int code, WPARAM w, LPARAM l)
@@ -2188,8 +2178,8 @@ funhook (int code, WPARAM w, LPARAM l)
                     can prevent this by setting the
                     w32-pass-[lr]window-to-system variable to
                     NIL.  */
-                 if (hs->vkCode == VK_LWIN && !NILP (Vw32_pass_lwindow_to_system) ||
-                     hs->vkCode == VK_RWIN && !NILP (Vw32_pass_rwindow_to_system))
+                 if ((hs->vkCode == VK_LWIN && !NILP (Vw32_pass_lwindow_to_system)) ||
+                     (hs->vkCode == VK_RWIN && !NILP (Vw32_pass_rwindow_to_system)))
                    {
                      /* Not prevented - Simulate the keypress to the system.  */
                      memset (inputs, 0, sizeof (inputs));
@@ -2235,8 +2225,8 @@ funhook (int code, WPARAM w, LPARAM l)
       /* Some other key was pressed while a captured Win key is down.
         This is either an Emacs registered hotkey combination, or a
         system hotkey.  */
-      if (kbdhook.lwindown && kbdhook.lwin_hooked[hs->vkCode] ||
-         kbdhook.rwindown && kbdhook.rwin_hooked[hs->vkCode])
+      if ((kbdhook.lwindown && kbdhook.lwin_hooked[hs->vkCode]) ||
+         (kbdhook.rwindown && kbdhook.rwin_hooked[hs->vkCode]))
        {
          /* Hooked Win-x combination, do not pass the keypress to Windows.  */
          kbdhook.suppress_lone = 1;
@@ -2370,10 +2360,11 @@ remove_w32_kbdhook (void)
       kbdhook.hook = NULL;
     }
 }
+#endif /* WINDOWSNT */
 
 /* Mark a specific key combination as hooked, preventing it to be
    handled by the system.  */
-void
+static void
 hook_w32_key (int hook, int modifier, int vkey)
 {
   char *tbl = NULL;
@@ -2411,6 +2402,7 @@ hook_w32_key (int hook, int modifier, int vkey)
     }
 }
 
+#ifdef WINDOWSNT
 /* Check the current Win key pressed state.  */
 int
 check_w32_winkey_state (int vkey)
@@ -2438,12 +2430,13 @@ check_w32_winkey_state (int vkey)
     }
   return 0;
 }
+#endif /* WINDOWSNT */
 
 /* Reset the keyboard hook state.  Locking the workstation with Win-L
    leaves the Win key(s) "down" from the hook's point of view - the
    keyup event is never seen.  Thus, this function must be called when
    the system is locked.  */
-void
+static void
 reset_w32_kbdhook_state (void)
 {
   kbdhook.lwindown = 0;
@@ -2628,8 +2621,10 @@ modifier_set (int vkey)
       else
        return (GetKeyState (vkey) & 0x1);
     }
+#ifdef WINDOWSNT
   if (w32_kbdhook_active && (vkey == VK_LWIN || vkey == VK_RWIN))
     return check_w32_winkey_state (vkey);
+#endif
 
   if (!modifiers_recorded)
     return (GetKeyState (vkey) & 0x8000);
@@ -2650,6 +2645,7 @@ modifier_set (int vkey)
 
 /* Convert between the modifier bits W32 uses and the modifier bits
    Emacs uses.  */
+unsigned int w32_key_to_modifier (int);
 
 unsigned int
 w32_key_to_modifier (int key)
@@ -2748,6 +2744,8 @@ w32_get_key_modifiers (unsigned int wparam, unsigned int lparam)
   return mods;
 }
 
+unsigned int map_keypad_keys (unsigned int, unsigned int);
+
 unsigned int
 map_keypad_keys (unsigned int virt_key, unsigned int extended)
 {
@@ -3120,6 +3118,8 @@ cancel_all_deferred_msgs (void)
   PostThreadMessage (dwWindowsThreadId, WM_NULL, 0, 0);
 }
 
+DWORD WINAPI w32_msg_worker (void *);
+
 DWORD WINAPI
 w32_msg_worker (void *arg)
 {
@@ -3338,7 +3338,7 @@ get_wm_chars (HWND aWnd, int *buf, int buflen, int ignore_ctrl, int ctrl,
    Be ready to treat the case when this delivers WM_(SYS)DEADCHAR. */
 static int after_deadkey = -1;
 
-int
+static int
 deliver_wm_chars (int do_translate, HWND hwnd, UINT msg, UINT wParam,
                  UINT lParam, int legacy_alt_meta)
 {
@@ -3382,7 +3382,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_ExtraMods = 1, hairy = 0;
-      char *type_CtrlAlt = NULL;
+      const char *type_CtrlAlt = NULL;
 
       /*  XXXX In fact, there may be another case when we need to do the same:
               What happens if the string defined in the LIGATURES has length
@@ -3538,9 +3538,45 @@ deliver_wm_chars (int do_translate, HWND hwnd, UINT msg, UINT wParam,
              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 */
@@ -4734,12 +4770,16 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
       my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
       goto dflt;
 
+#ifdef WINDOWSNT
     case WM_CREATE:
       setup_w32_kbdhook ();
       goto dflt;
+#endif
 
     case WM_DESTROY:
+#ifdef WINDOWSNT
       remove_w32_kbdhook ();
+#endif
       CoUninitialize ();
       return 0;
 
@@ -4753,6 +4793,11 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
       my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
       return 0;
 
+    case WM_ENDSESSION:
+      my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
+      /* If we return, the process will be terminated immediately.  */
+      sleep (1000);
+
     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.  */
@@ -5220,7 +5265,7 @@ x_default_font_parameter (struct frame *f, Lisp_Object parms)
   if (!STRINGP (font))
     {
       int i;
-      static char *names[]
+      static const char *names[]
        = { "Courier New-10",
            "-*-Courier-normal-r-*-*-13-*-*-*-c-*-iso8859-1",
            "-*-Fixedsys-normal-r-*-*-12-*-*-*-c-*-iso8859-1",
@@ -5240,7 +5285,8 @@ x_default_font_parameter (struct frame *f, Lisp_Object parms)
     {
       /* Remember the explicit font parameter, so we can re-apply it after
         we've applied the `default' face settings.  */
-      x_set_frame_parameters (f, Fcons (Fcons (Qfont_param, font_param), Qnil));
+      x_set_frame_parameters (f, Fcons (Fcons (Qfont_parameter, font_param),
+                                       Qnil));
     }
   x_default_parameter (f, parms, Qfont, font, "font", "Font", RES_TYPE_STRING);
 }
@@ -5562,8 +5608,10 @@ This function is an internal primitive--use `make-frame' instead.  */)
       else if (! NILP (visibility))
        x_make_frame_visible (f);
       else
-       /* Must have been Qnil.  */
-       ;
+       {
+         /* Must have been Qnil.  */
+         ;
+       }
     }
 
   /* Initialize `default-minibuffer-frame' in case this is the first
@@ -5603,7 +5651,7 @@ x_get_focus_frame (struct frame *frame)
 
 DEFUN ("xw-color-defined-p", Fxw_color_defined_p, Sxw_color_defined_p, 1, 2, 0,
        doc: /* Internal function called by `color-defined-p', which see.
-(Note that the Nextstep version of this function ignores FRAME.)  */)
+\(Note that the Nextstep version of this function ignores FRAME.)  */)
   (Lisp_Object color, Lisp_Object frame)
 {
   XColor foo;
@@ -5745,7 +5793,7 @@ If omitted or nil, that stands for the selected frame's display.  */)
 DEFUN ("x-server-vendor", Fx_server_vendor, Sx_server_vendor, 0, 1, 0,
        doc: /* Return the "vendor ID" string of the GUI software on TERMINAL.
 
-(Labeling every distributor as a "vendor" embodies the false assumption
+\(Labeling every distributor as a "vendor" embodies the false assumption
 that operating systems cannot be developed and distributed noncommercially.)
 
 For GNU and Unix systems, this queries the X server software; for
@@ -6106,11 +6154,13 @@ SOUND is nil to use the normal beep.  */)
   return sound;
 }
 
+#if 0  /* unused */
 int
 x_screen_planes (register struct frame *f)
 {
   return FRAME_DISPLAY_INFO (f)->n_planes;
 }
+#endif
 \f
 /* Return the display structure for the display named NAME.
    Open a new connection if necessary.  */
@@ -6147,7 +6197,7 @@ DISPLAY is the name of the display to connect to.
 Optional second arg XRM-STRING is a string of resources in xrdb format.
 If the optional third arg MUST-SUCCEED is non-nil,
 terminate Emacs if we can't open the connection.
-(In the Nextstep version, the last two arguments are currently ignored.)  */)
+\(In the Nextstep version, the last two arguments are currently ignored.)  */)
   (Lisp_Object display, Lisp_Object xrm_string, Lisp_Object must_succeed)
 {
   char *xrm_option;
@@ -6416,8 +6466,6 @@ no value of TYPE (always string in the MS Windows case).  */)
                                Tool tips
  ***********************************************************************/
 
-static Lisp_Object x_create_tip_frame (struct w32_display_info *,
-                                      Lisp_Object, Lisp_Object);
 static void compute_tip_xy (struct frame *, Lisp_Object, Lisp_Object,
                            Lisp_Object, int, int, int *, int *);
 
@@ -6452,8 +6500,7 @@ unwind_create_tip_frame (Lisp_Object frame)
 
 
 /* Create a frame for a tooltip on the display described by DPYINFO.
-   PARMS is a list of frame parameters.  TEXT is the string to
-   display in the tip frame.  Value is the frame.
+   PARMS is a list of frame parameters.  Value is the frame.
 
    Note that functions called here, esp. x_default_parameter can
    signal errors, for instance when a specified color name is
@@ -6461,8 +6508,7 @@ unwind_create_tip_frame (Lisp_Object frame)
    when this happens.  */
 
 static Lisp_Object
-x_create_tip_frame (struct w32_display_info *dpyinfo,
-                   Lisp_Object parms, Lisp_Object text)
+x_create_tip_frame (struct w32_display_info *dpyinfo, Lisp_Object parms)
 {
   struct frame *f;
   Lisp_Object frame;
@@ -6471,8 +6517,6 @@ x_create_tip_frame (struct w32_display_info *dpyinfo,
   ptrdiff_t count = SPECPDL_INDEX ();
   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
@@ -6496,23 +6540,9 @@ x_create_tip_frame (struct w32_display_info *dpyinfo,
   frame = Qnil;
   /* Make a frame without minibuffer nor mode-line.  */
   f = make_frame (false);
-  f->wants_modeline = 0;
+  f->wants_modeline = false;
   XSETFRAME (frame, f);
 
-  AUTO_STRING (tip, " *tip*");
-  buffer = Fget_buffer_create (tip);
-  /* Use set_window_buffer instead of Fset_window_buffer (see
-     discussion of bug#11984, bug#12025, bug#12026).  */
-  set_window_buffer (FRAME_ROOT_WINDOW (f), buffer, false, false);
-  old_buffer = current_buffer;
-  set_buffer_internal_1 (XBUFFER (buffer));
-  bset_truncate_lines (current_buffer, Qnil);
-  specbind (Qinhibit_read_only, Qt);
-  specbind (Qinhibit_modification_hooks, Qt);
-  Ferase_buffer ();
-  Finsert (1, &text);
-  set_buffer_internal_1 (old_buffer);
-
   record_unwind_protect (unwind_create_tip_frame, frame);
 
   /* By setting the output method, we're essentially saying that
@@ -6546,7 +6576,7 @@ x_create_tip_frame (struct w32_display_info *dpyinfo,
     {
       fset_name (f, name);
       f->explicit_name = true;
-      /* use the frame's title when getting resources for this frame.  */
+      /* Use the frame's title when getting resources for this frame.  */
       specbind (Qx_resource_name, name);
     }
 
@@ -6576,14 +6606,10 @@ x_create_tip_frame (struct w32_display_info *dpyinfo,
        parms = Fcons (Fcons (Qinternal_border_width, value),
                       parms);
     }
+
   x_default_parameter (f, parms, Qinternal_border_width, make_number (1),
                       "internalBorderWidth", "internalBorderWidth",
                       RES_TYPE_NUMBER);
-  x_default_parameter (f, parms, Qright_divider_width, make_number (0),
-                      NULL, NULL, RES_TYPE_NUMBER);
-  x_default_parameter (f, parms, Qbottom_divider_width, make_number (0),
-                      NULL, NULL, RES_TYPE_NUMBER);
-
   /* Also do the stuff which must be set before the window exists.  */
   x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
                       "foreground", "Foreground", RES_TYPE_STRING);
@@ -6610,6 +6636,9 @@ x_create_tip_frame (struct w32_display_info *dpyinfo,
   f->fringe_cols = 0;
   f->left_fringe_width = 0;
   f->right_fringe_width = 0;
+  /* No dividers on tip frame.  */
+  f->right_divider_width = 0;
+  f->bottom_divider_width = 0;
 
   block_input ();
   my_create_tip_window (f);
@@ -6636,7 +6665,6 @@ x_create_tip_frame (struct w32_display_info *dpyinfo,
   SET_FRAME_LINES (f, 0);
   adjust_frame_size (f, width * FRAME_COLUMN_WIDTH (f),
                     height * FRAME_LINE_HEIGHT (f), 0, true, Qtip_frame);
-
   /* Add `tooltip' frame parameter's default value. */
   if (NILP (Fframe_parameter (frame, Qtooltip)))
     Fmodify_frame_parameters (frame, Fcons (Fcons (Qtooltip, Qt), Qnil));
@@ -6654,8 +6682,6 @@ x_create_tip_frame (struct w32_display_info *dpyinfo,
     Lisp_Object fg = Fframe_parameter (frame, Qforeground_color);
     Lisp_Object colors = Qnil;
 
-    /* Set tip_frame here, so that */
-    tip_frame = frame;
     call2 (Qface_set_after_frame_default, frame, Qnil);
 
     if (!EQ (bg, Fframe_parameter (frame, Qbackground_color)))
@@ -6787,6 +6813,48 @@ compute_tip_xy (struct frame *f,
     *root_x = min_x;
 }
 
+/* Hide tooltip.  Delete its frame if DELETE is true.  */
+static Lisp_Object
+x_hide_tip (bool delete)
+{
+  if (!NILP (tip_timer))
+    {
+      call1 (Qcancel_timer, tip_timer);
+      tip_timer = Qnil;
+    }
+
+  if (NILP (tip_frame)
+      || (!delete && FRAMEP (tip_frame)
+         && !FRAME_VISIBLE_P (XFRAME (tip_frame))))
+    return Qnil;
+  else
+    {
+      ptrdiff_t count;
+      Lisp_Object was_open = Qnil;
+
+      count = SPECPDL_INDEX ();
+      specbind (Qinhibit_redisplay, Qt);
+      specbind (Qinhibit_quit, Qt);
+
+      if (FRAMEP (tip_frame))
+       {
+         if (delete)
+           {
+             delete_frame (tip_frame, Qnil);
+             tip_frame = Qnil;
+           }
+         else
+           x_make_frame_invisible (XFRAME (tip_frame));
+
+         was_open = Qt;
+       }
+      else
+       tip_frame = Qnil;
+
+      return unbind_to (count, was_open);
+    }
+}
+
 
 DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
        doc: /* Show STRING in a \"tooltip\" window on frame FRAME.
@@ -6820,20 +6888,22 @@ A tooltip's maximum size is specified by `x-max-tooltip-size'.
 Text larger than the specified size is clipped.  */)
   (Lisp_Object string, Lisp_Object frame, Lisp_Object parms, Lisp_Object timeout, Lisp_Object dx, Lisp_Object dy)
 {
-  struct frame *f;
+  struct frame *tip_f;
   struct window *w;
   int root_x, root_y;
   struct buffer *old_buffer;
   struct text_pos pos;
-  int i, width, height;
-  bool seen_reversed_p;
+  int width, height;
   int old_windows_or_buffers_changed = windows_or_buffers_changed;
   ptrdiff_t count = SPECPDL_INDEX ();
+  ptrdiff_t count_1;
+  Lisp_Object window, size;
+  AUTO_STRING (tip, " *tip*");
 
   specbind (Qinhibit_redisplay, Qt);
 
   CHECK_STRING (string);
-  f = decode_window_system_frame (frame);
+  decode_window_system_frame (frame);
   if (NILP (timeout))
     timeout = make_number (5);
   else
@@ -6852,91 +6922,155 @@ Text larger than the specified size is clipped.  */)
   if (NILP (last_show_tip_args))
     last_show_tip_args = Fmake_vector (make_number (3), Qnil);
 
-  if (!NILP (tip_frame))
+  if (FRAMEP (tip_frame) && FRAME_LIVE_P (XFRAME (tip_frame)))
     {
       Lisp_Object last_string = AREF (last_show_tip_args, 0);
       Lisp_Object last_frame = AREF (last_show_tip_args, 1);
       Lisp_Object last_parms = AREF (last_show_tip_args, 2);
 
-      if (EQ (frame, last_frame)
-         && !NILP (Fequal (last_string, string))
+      if (FRAME_VISIBLE_P (XFRAME (tip_frame))
+         && EQ (frame, last_frame)
+         && !NILP (Fequal_including_properties (last_string, string))
          && !NILP (Fequal (last_parms, parms)))
        {
-         struct frame *f = XFRAME (tip_frame);
-
          /* Only DX and DY have changed.  */
+         tip_f = XFRAME (tip_frame);
          if (!NILP (tip_timer))
            {
              Lisp_Object timer = tip_timer;
+
              tip_timer = Qnil;
              call1 (Qcancel_timer, timer);
            }
 
          block_input ();
-         compute_tip_xy (f, parms, dx, dy, FRAME_PIXEL_WIDTH (f),
-                         FRAME_PIXEL_HEIGHT (f), &root_x, &root_y);
+         compute_tip_xy (tip_f, parms, dx, dy, FRAME_PIXEL_WIDTH (tip_f),
+                         FRAME_PIXEL_HEIGHT (tip_f), &root_x, &root_y);
 
          /* Put tooltip in topmost group and in position.  */
-         SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOPMOST,
+         SetWindowPos (FRAME_W32_WINDOW (tip_f), HWND_TOPMOST,
                        root_x, root_y, 0, 0,
                        SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOOWNERZORDER);
 
          /* Ensure tooltip is on top of other topmost windows (eg menus).  */
-         SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOP,
+         SetWindowPos (FRAME_W32_WINDOW (tip_f), HWND_TOP,
                        0, 0, 0, 0,
                        SWP_NOMOVE | SWP_NOSIZE
                        | SWP_NOACTIVATE | SWP_NOOWNERZORDER);
 
+         /* Let redisplay know that we have made the frame visible already.  */
+         SET_FRAME_VISIBLE (tip_f, 1);
+         ShowWindow (FRAME_W32_WINDOW (tip_f), SW_SHOWNOACTIVATE);
          unblock_input ();
+
          goto start_timer;
        }
-    }
+      else if (tooltip_reuse_hidden_frame && EQ (frame, last_frame))
+       {
+         bool delete = false;
+         Lisp_Object tail, elt, parm, last;
+
+         /* Check if every parameter in PARMS has the same value in
+            last_parms.  This may destruct last_parms which, however,
+            will be recreated below.  */
+         for (tail = parms; CONSP (tail); tail = XCDR (tail))
+           {
+             elt = XCAR (tail);
+             parm = Fcar (elt);
+             /* The left, top, right and bottom parameters are handled
+                by compute_tip_xy so they can be ignored here.  */
+             if (!EQ (parm, Qleft) && !EQ (parm, Qtop)
+                 && !EQ (parm, Qright) && !EQ (parm, Qbottom))
+               {
+                 last = Fassq (parm, last_parms);
+                 if (NILP (Fequal (Fcdr (elt), Fcdr (last))))
+                   {
+                     /* We lost, delete the old tooltip.  */
+                     delete = true;
+                     break;
+                   }
+                 else
+                   last_parms = call2 (Qassq_delete_all, parm, last_parms);
+               }
+             else
+               last_parms = call2 (Qassq_delete_all, parm, last_parms);
+           }
+
+         /* Now check if there's a parameter left in last_parms with a
+            non-nil value.  */
+         for (tail = last_parms; CONSP (tail); tail = XCDR (tail))
+           {
+             elt = XCAR (tail);
+             parm = Fcar (elt);
+             if (!EQ (parm, Qleft) && !EQ (parm, Qtop) && !EQ (parm, Qright)
+                 && !EQ (parm, Qbottom) && !NILP (Fcdr (elt)))
+               {
+                 /* We lost, delete the old tooltip.  */
+                 delete = true;
+                 break;
+               }
+           }
 
-  /* Hide a previous tip, if any.  */
-  Fx_hide_tip ();
+         x_hide_tip (delete);
+       }
+      else
+       x_hide_tip (true);
+    }
+  else
+    x_hide_tip (true);
 
   ASET (last_show_tip_args, 0, string);
   ASET (last_show_tip_args, 1, frame);
   ASET (last_show_tip_args, 2, parms);
 
-  /* Add default values to frame parameters.  */
-  if (NILP (Fassq (Qname, parms)))
-    parms = Fcons (Fcons (Qname, build_string ("tooltip")), parms);
-  if (NILP (Fassq (Qinternal_border_width, parms)))
-    parms = Fcons (Fcons (Qinternal_border_width, make_number (3)), parms);
-  if (NILP (Fassq (Qright_divider_width, parms)))
-    parms = Fcons (Fcons (Qright_divider_width, make_number (0)), parms);
-  if (NILP (Fassq (Qbottom_divider_width, parms)))
-    parms = Fcons (Fcons (Qbottom_divider_width, make_number (0)), parms);
-  if (NILP (Fassq (Qborder_width, parms)))
-    parms = Fcons (Fcons (Qborder_width, make_number (1)), parms);
-  if (NILP (Fassq (Qborder_color, parms)))
-    parms = Fcons (Fcons (Qborder_color, build_string ("lightyellow")), parms);
-  if (NILP (Fassq (Qbackground_color, parms)))
-    parms = Fcons (Fcons (Qbackground_color, build_string ("lightyellow")),
-                  parms);
-
   /* Block input until the tip has been fully drawn, to avoid crashes
      when drawing tips in menus.  */
   block_input ();
 
-  /* Create a frame for the tooltip, and record it in the global
-     variable tip_frame.  */
-  frame = x_create_tip_frame (FRAME_DISPLAY_INFO (f), parms, string);
-  f = XFRAME (frame);
+  if (!FRAMEP (tip_frame) || !FRAME_LIVE_P (XFRAME (tip_frame)))
+    {
+      /* Add default values to frame parameters.  */
+      if (NILP (Fassq (Qname, parms)))
+       parms = Fcons (Fcons (Qname, build_string ("tooltip")), parms);
+      if (NILP (Fassq (Qinternal_border_width, parms)))
+       parms = Fcons (Fcons (Qinternal_border_width, make_number (3)), parms);
+      if (NILP (Fassq (Qborder_width, parms)))
+       parms = Fcons (Fcons (Qborder_width, make_number (1)), parms);
+      if (NILP (Fassq (Qborder_color, parms)))
+       parms = Fcons (Fcons (Qborder_color, build_string ("lightyellow")), parms);
+      if (NILP (Fassq (Qbackground_color, parms)))
+       parms = Fcons (Fcons (Qbackground_color, build_string ("lightyellow")),
+                      parms);
 
-  /* Set up the frame's root window.  */
-  w = XWINDOW (FRAME_ROOT_WINDOW (f));
+      /* Create a frame for the tooltip, and record it in the global
+        variable tip_frame.  */
+      struct frame *f;         /* The value is unused.  */
+      if (NILP (tip_frame = x_create_tip_frame (FRAME_DISPLAY_INFO (f), parms)))
+       {
+         /* Creating the tip frame failed.  */
+         unblock_input ();
+         return unbind_to (count, Qnil);
+       }
+    }
+
+  tip_f = XFRAME (tip_frame);
+  window = FRAME_ROOT_WINDOW (tip_f);
+  set_window_buffer (window, Fget_buffer_create (tip), false, false);
+  w = XWINDOW (window);
+  w->pseudo_window_p = true;
+
+  /* Set up the frame's root window.  Note: The following code does not
+     try to size the window or its frame correctly.  Its only purpose is
+     to make the subsequent text size calculations work.  The right
+     sizes should get installed when the toolkit gets back to us.  */
   w->left_col = 0;
   w->top_line = 0;
   w->pixel_left = 0;
   w->pixel_top = 0;
 
   if (CONSP (Vx_max_tooltip_size)
-      && INTEGERP (XCAR (Vx_max_tooltip_size))
-      && XINT (XCAR (Vx_max_tooltip_size)) > 0
-      && INTEGERP (XCDR (Vx_max_tooltip_size))
-      && XINT (XCDR (Vx_max_tooltip_size)) > 0)
+      && RANGED_INTEGERP (1, XCAR (Vx_max_tooltip_size), INT_MAX)
+      && RANGED_INTEGERP (1, XCDR (Vx_max_tooltip_size), INT_MAX))
     {
       w->total_cols = XFASTINT (XCAR (Vx_max_tooltip_size));
       w->total_lines = XFASTINT (XCDR (Vx_max_tooltip_size));
@@ -6947,164 +7081,71 @@ Text larger than the specified size is clipped.  */)
       w->total_lines = 40;
     }
 
-  w->pixel_width = w->total_cols * FRAME_COLUMN_WIDTH (f);
-  w->pixel_height = w->total_lines * FRAME_LINE_HEIGHT (f);
+  w->pixel_width = w->total_cols * FRAME_COLUMN_WIDTH (tip_f);
+  w->pixel_height = w->total_lines * FRAME_LINE_HEIGHT (tip_f);
+  FRAME_TOTAL_COLS (tip_f) = WINDOW_TOTAL_COLS (w);
+  adjust_frame_glyphs (tip_f);
 
-  FRAME_TOTAL_COLS (f) = WINDOW_TOTAL_COLS (w);
-  adjust_frame_glyphs (f);
-  w->pseudo_window_p = true;
-
-  /* Display the tooltip text in a temporary buffer.  */
+  /* Insert STRING into the root window's buffer and fit the frame to
+     the buffer.  */
+  count_1 = SPECPDL_INDEX ();
   old_buffer = current_buffer;
-  set_buffer_internal_1 (XBUFFER (XWINDOW (FRAME_ROOT_WINDOW (f))->contents));
+  set_buffer_internal_1 (XBUFFER (w->contents));
   bset_truncate_lines (current_buffer, Qnil);
+  specbind (Qinhibit_read_only, Qt);
+  specbind (Qinhibit_modification_hooks, Qt);
+  specbind (Qinhibit_point_motion_hooks, Qt);
+  Ferase_buffer ();
+  Finsert (1, &string);
   clear_glyph_matrix (w->desired_matrix);
   clear_glyph_matrix (w->current_matrix);
   SET_TEXT_POS (pos, BEGV, BEGV_BYTE);
-  try_window (FRAME_ROOT_WINDOW (f), pos, TRY_WINDOW_IGNORE_FONTS_CHANGE);
-
-  /* Compute width and height of the tooltip.  */
-  width = height = 0;
-  seen_reversed_p = false;
-  for (i = 0; i < w->desired_matrix->nrows; ++i)
-    {
-      struct glyph_row *row = &w->desired_matrix->rows[i];
-      struct glyph *last;
-      int row_width;
-
-      /* Stop at the first empty row at the end.  */
-      if (!row->enabled_p || !MATRIX_ROW_DISPLAYS_TEXT_P (row))
-       break;
-
-      /* Let the row go over the full width of the frame.  */
-      row->full_width_p = true;
-
-      row_width = row->pixel_width;
-      if (row->used[TEXT_AREA])
-       {
-         if (!row->reversed_p)
-           {
-             /* There's a glyph at the end of rows that is used to
-                place the cursor there.  Don't include the width of
-                this glyph.  */
-             last = &row->glyphs[TEXT_AREA][row->used[TEXT_AREA] - 1];
-             if (NILP (last->object))
-               row_width -= last->pixel_width;
-           }
-         else
-           {
-             /* There could be a stretch glyph at the beginning of R2L
-                rows that is produced by extend_face_to_end_of_line.
-                Don't count that glyph.  */
-             struct glyph *g = row->glyphs[TEXT_AREA];
-
-             if (g->type == STRETCH_GLYPH && NILP (g->object))
-               {
-                 row_width -= g->pixel_width;
-                 seen_reversed_p = true;
-               }
-           }
-       }
-
-      height += row->height;
-      width = max (width, row_width);
-    }
-
-  /* If we've seen partial-length R2L rows, we need to re-adjust the
-     tool-tip frame width and redisplay it again, to avoid over-wide
-     tips due to the stretch glyph that extends R2L lines to full
-     width of the frame.  */
-  if (seen_reversed_p)
-    {
-      /* PXW: Why do we do the pixel-to-cols conversion only if
-        seen_reversed_p holds?  Don't we have to set other fields of
-        the window/frame structure?
-
-        w->total_cols and FRAME_TOTAL_COLS want the width in columns,
-        not in pixels.  */
-      w->pixel_width = width;
-      width /= WINDOW_FRAME_COLUMN_WIDTH (w);
-      w->total_cols = width;
-      FRAME_TOTAL_COLS (f) = width;
-      SET_FRAME_WIDTH (f, width);
-      adjust_frame_glyphs (f);
-      w->pseudo_window_p = 1;
-      clear_glyph_matrix (w->desired_matrix);
-      clear_glyph_matrix (w->current_matrix);
-      try_window (FRAME_ROOT_WINDOW (f), pos, TRY_WINDOW_IGNORE_FONTS_CHANGE);
-      width = height = 0;
-      /* Recompute width and height of the tooltip.  */
-      for (i = 0; i < w->desired_matrix->nrows; ++i)
-       {
-         struct glyph_row *row = &w->desired_matrix->rows[i];
-         struct glyph *last;
-         int row_width;
-
-         if (!row->enabled_p || !MATRIX_ROW_DISPLAYS_TEXT_P (row))
-           break;
-         row->full_width_p = true;
-         row_width = row->pixel_width;
-         if (row->used[TEXT_AREA] && !row->reversed_p)
-           {
-             last = &row->glyphs[TEXT_AREA][row->used[TEXT_AREA] - 1];
-             if (NILP (last->object))
-               row_width -= last->pixel_width;
-           }
-
-         height += row->height;
-         width = max (width, row_width);
-       }
-    }
-
-  /* Add the frame's internal border to the width and height the w32
-     window should have.  */
-  height += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
-  width += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
-
-  /* Move the tooltip window where the mouse pointer is.  Resize and
-     show it.
-
-     PXW: This should use the frame's pixel coordinates.  */
-  compute_tip_xy (f, parms, dx, dy, width, height, &root_x, &root_y);
-
+  try_window (window, pos, TRY_WINDOW_IGNORE_FONTS_CHANGE);
+  /* Calculate size of tooltip window.  */
+  size = Fwindow_text_pixel_size (window, Qnil, Qnil, Qnil,
+                                 make_number (w->pixel_height), Qnil);
+  /* Add the frame's internal border to calculated size.  */
+  width = XINT (Fcar (size)) + 2 * FRAME_INTERNAL_BORDER_WIDTH (tip_f);
+  height = XINT (Fcdr (size)) + 2 * FRAME_INTERNAL_BORDER_WIDTH (tip_f);
+  /* Calculate position of tooltip frame.  */
+  compute_tip_xy (tip_f, parms, dx, dy, width, height, &root_x, &root_y);
+
+  /* Show tooltip frame.  */
   {
-    /* Adjust Window size to take border into account.  */
     RECT rect;
+    int pad = (NUMBERP (Vw32_tooltip_extra_pixels)
+              ? max (0, XINT (Vw32_tooltip_extra_pixels))
+              : FRAME_COLUMN_WIDTH (tip_f));
+
     rect.left = rect.top = 0;
     rect.right = width;
     rect.bottom = height;
-    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
-       peculiarity of w32 display: without it, some fonts cause the
-       last character of the tip to be truncated or wrapped around to
-       the next line.  */
-    SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOPMOST,
+    AdjustWindowRect (&rect, tip_f->output_data.w32->dwStyle,
+                     FRAME_EXTERNAL_MENU_BAR (tip_f));
+
+    /* Position and size tooltip and put it in the topmost group.  */
+    SetWindowPos (FRAME_W32_WINDOW (tip_f), HWND_TOPMOST,
                  root_x, root_y,
-                 rect.right - rect.left + FRAME_COLUMN_WIDTH (f),
+                 rect.right - rect.left + pad,
                  rect.bottom - rect.top, SWP_NOACTIVATE | SWP_NOOWNERZORDER);
 
     /* Ensure tooltip is on top of other topmost windows (eg menus).  */
-    SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOP,
+    SetWindowPos (FRAME_W32_WINDOW (tip_f), HWND_TOP,
                  0, 0, 0, 0,
                  SWP_NOMOVE | SWP_NOSIZE
                  | SWP_NOACTIVATE | SWP_NOOWNERZORDER);
 
     /* Let redisplay know that we have made the frame visible already.  */
-    SET_FRAME_VISIBLE (f, 1);
+    SET_FRAME_VISIBLE (tip_f, 1);
 
-    ShowWindow (FRAME_W32_WINDOW (f), SW_SHOWNOACTIVATE);
+    ShowWindow (FRAME_W32_WINDOW (tip_f), SW_SHOWNOACTIVATE);
   }
 
-  /* Draw into the window.  */
   w->must_be_updated_p = true;
   update_single_window (w);
-
-  unblock_input ();
-
-  /* Restore original current buffer.  */
   set_buffer_internal_1 (old_buffer);
+  unbind_to (count_1, Qnil);
+  unblock_input ();
   windows_or_buffers_changed = old_windows_or_buffers_changed;
 
  start_timer:
@@ -7121,31 +7162,7 @@ DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0,
 Value is t if tooltip was open, nil otherwise.  */)
   (void)
 {
-  ptrdiff_t count;
-  Lisp_Object deleted, frame, timer;
-
-  /* Return quickly if nothing to do.  */
-  if (NILP (tip_timer) && NILP (tip_frame))
-    return Qnil;
-
-  frame = tip_frame;
-  timer = tip_timer;
-  tip_frame = tip_timer = deleted = Qnil;
-
-  count = SPECPDL_INDEX ();
-  specbind (Qinhibit_redisplay, Qt);
-  specbind (Qinhibit_quit, Qt);
-
-  if (!NILP (timer))
-    call1 (Qcancel_timer, timer);
-
-  if (FRAMEP (frame))
-    {
-      delete_frame (frame, Qnil);
-      deleted = Qt;
-    }
-
-  return unbind_to (count, deleted);
+  return x_hide_tip (!tooltip_reuse_hidden_frame);
 }
 \f
 /***********************************************************************
@@ -7272,7 +7289,9 @@ value of DIR as in previous invocations; this is standard Windows behavior.  */)
 {
   /* Filter index: 1: All Files, 2: Directories only  */
   static const wchar_t filter_w[] = L"All Files (*.*)\0*.*\0Directories\0*|*\0";
+#ifndef NTGUI_UNICODE
   static const char filter_a[] = "All Files (*.*)\0*.*\0Directories\0*|*\0";
+#endif
 
   Lisp_Object filename = default_filename;
   struct frame *f = SELECTED_FRAME ();
@@ -8018,8 +8037,8 @@ lookup_vk_code (char *key)
       /* Alphanumerics map to themselves.  */
       if (key[1] == 0)
       {
-       if (key[0] >= 'A' && key[0] <= 'Z' ||
-           key[0] >= '0' && key[0] <= '9')
+       if ((key[0] >= 'A' && key[0] <= 'Z')
+           || (key[0] >= '0' && key[0] <= '9'))
          return key[0];
        if (key[0] >= 'a' && key[0] <= 'z')
          return toupper(key[0]);
@@ -8550,7 +8569,7 @@ DEFUN ("w32-set-mouse-absolute-pixel-position", Fw32_set_mouse_absolute_pixel_po
        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.  */)
+\(0, 0) of the selected frame's display.  */)
   (Lisp_Object x, Lisp_Object y)
 {
   UINT trail_num = 0;
@@ -8653,7 +8672,7 @@ The following %-sequences are provided:
       else
        {
          long m;
-         float h;
+         double h;
          char buffer[16];
          snprintf (buffer, 16, "%ld", seconds_left);
          seconds = build_string (buffer);
@@ -8946,7 +8965,7 @@ w32_strerror (int error_no)
       --ret;
   buf[ret] = '\0';
   if (!ret)
-    sprintf (buf, "w32 error %u", error_no);
+    sprintf (buf, "w32 error %d", error_no);
 
   return buf;
 }
@@ -8954,6 +8973,8 @@ w32_strerror (int error_no)
 /* For convenience when debugging.  (You cannot call GetLastError
    directly from GDB: it will crash, because it uses the __stdcall
    calling convention, not the _cdecl convention assumed by GDB.)  */
+DWORD w32_last_error (void);
+
 DWORD
 w32_last_error (void)
 {
@@ -9604,7 +9625,7 @@ usage: (w32-notification-notify &rest PARAMS)  */)
   EMACS_INT retval;
   char *icon, *tip, *title, *msg;
   enum NI_Severity severity;
-  unsigned timeout;
+  unsigned timeout = 0;
 
   if (nargs == 0)
     return Qnil;
@@ -9616,14 +9637,14 @@ usage: (w32-notification-notify &rest PARAMS)  */)
   if (STRINGP (lres))
     icon = SSDATA (ENCODE_FILE (Fexpand_file_name (lres, Qnil)));
   else
-    icon = "";
+    icon = (char *)"";
 
   /* Tip.  */
   lres = Fplist_get (arg_plist, QCtip);
   if (STRINGP (lres))
     tip = SSDATA (code_convert_string_norecord (lres, Qutf_8, 1));
   else
-    tip = "Emacs notification";
+    tip = (char *)"Emacs notification";
 
   /* Severity.  */
   lres = Fplist_get (arg_plist, QClevel);
@@ -9643,14 +9664,14 @@ usage: (w32-notification-notify &rest PARAMS)  */)
   if (STRINGP (lres))
     title = SSDATA (code_convert_string_norecord (lres, Qutf_8, 1));
   else
-    title = "";
+    title = (char *)"";
 
   /* Notification body text.  */
   lres = Fplist_get (arg_plist, QCbody);
   if (STRINGP (lres))
     msg = SSDATA (code_convert_string_norecord (lres, Qutf_8, 1));
   else
-    msg = "";
+    msg = (char *)"";
 
   /* Do it!  */
   retval = add_tray_notification (f, icon, tip, severity, timeout, title, msg);
@@ -9739,12 +9760,13 @@ syms_of_w32fns (void)
   DEFSYM (Qctrl, "ctrl");
   DEFSYM (Qcontrol, "control");
   DEFSYM (Qshift, "shift");
-  DEFSYM (Qfont_param, "font-parameter");
+  DEFSYM (Qfont_parameter, "font-parameter");
   DEFSYM (Qgeometry, "geometry");
   DEFSYM (Qworkarea, "workarea");
   DEFSYM (Qmm_size, "mm-size");
   DEFSYM (Qframes, "frames");
   DEFSYM (Qtip_frame, "tip-frame");
+  DEFSYM (Qassq_delete_all, "assq-delete-all");
   DEFSYM (Qunicode_sip, "unicode-sip");
 #if defined WINDOWSNT && !defined HAVE_DBUS
   DEFSYM (QCicon, ":icon");
@@ -9757,10 +9779,10 @@ syms_of_w32fns (void)
 #endif
 
   /* Symbols used elsewhere, but only in MS-Windows-specific code.  */
-  DEFSYM (Qgnutls_dll, "gnutls");
-  DEFSYM (Qlibxml2_dll, "libxml2");
+  DEFSYM (Qgnutls, "gnutls");
+  DEFSYM (Qlibxml2, "libxml2");
   DEFSYM (Qserif, "serif");
-  DEFSYM (Qzlib_dll, "zlib");
+  DEFSYM (Qzlib, "zlib");
 
   Fput (Qundefined_color, Qerror_conditions,
        listn (CONSTYPE_PURE, 2, Qundefined_color, Qerror));
@@ -10057,6 +10079,18 @@ Default is nil.
 This variable has effect only on Windows Vista and later.  */);
   w32_disable_new_uniscribe_apis = 0;
 
+  DEFVAR_LISP ("w32-tooltip-extra-pixels",
+              Vw32_tooltip_extra_pixels,
+              doc: /* Number of pixels added after tooltip text.
+On Windows some fonts may cause the last character of a tooltip be
+truncated or wrapped around to the next line.  Adding some extra space
+at the end of the toooltip works around this problem.
+
+This variable specifies the number of pixels that shall be added.  The
+default value t means to add the width of one canonical character of the
+tip frame.  */);
+  Vw32_tooltip_extra_pixels = Qt;
+
 #if 0 /* TODO: Port to W32 */
   defsubr (&Sx_change_window_property);
   defsubr (&Sx_delete_window_property);
@@ -10227,7 +10261,7 @@ typedef USHORT (WINAPI * CaptureStackBackTrace_proc) (ULONG, ULONG, PVOID *,
 
 #define BACKTRACE_LIMIT_MAX 62
 
-int
+static int
 w32_backtrace (void **buffer, int limit)
 {
   static CaptureStackBackTrace_proc s_pfn_CaptureStackBackTrace = NULL;
@@ -10300,8 +10334,8 @@ emacs_abort (void)
               but not on Windows 7.  addr2line doesn't mind a missing
               "0x", but will be confused by an extra one.  */
            if (except_addr)
-             sprintf (buf, "\r\nException 0x%lx at this address:\r\n%p\r\n",
-                      except_code, except_addr);
+             sprintf (buf, "\r\nException 0x%x at this address:\r\n%p\r\n",
+                      (unsigned int) except_code, except_addr);
            if (stderr_fd >= 0)
              {
                if (except_addr)