Merge from emacs-24; up to 2012-12-23T02:41:17Z!rgm@gnu.org
[bpt/emacs.git] / src / w32fns.c
index 210eaf1..5fab2c9 100644 (file)
@@ -1,6 +1,6 @@
 /* Graphical user interface functions for the Microsoft Windows API.
 
-Copyright (C) 1989, 1992-201 Free Software Foundation, Inc.
+Copyright (C) 1989, 1992-2013 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -26,6 +26,8 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include <limits.h>
 #include <errno.h>
 #include <math.h>
+#include <fcntl.h>
+#include <unistd.h>
 
 #include "lisp.h"
 #include "w32term.h"
@@ -80,7 +82,6 @@ void syms_of_w32fns (void);
 void globals_of_w32fns (void);
 
 extern void free_frame_menubar (struct frame *);
-extern double atof (const char *);
 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);
@@ -221,7 +222,7 @@ SYSTEM_INFO sysinfo_cache;
 /* This gives us version, build, and platform identification.  */
 OSVERSIONINFO osinfo_cache;
 
-unsigned long syspage_mask = 0;
+DWORD_PTR syspage_mask = 0;
 
 /* The major and minor versions of NT.  */
 int w32_major_version;
@@ -262,12 +263,8 @@ have_menus_p (void)
 FRAME_PTR
 check_x_frame (Lisp_Object frame)
 {
-  FRAME_PTR f;
+  struct frame *f = decode_live_frame (frame);
 
-  if (NILP (frame))
-    frame = selected_frame;
-  CHECK_LIVE_FRAME (frame);
-  f = XFRAME (frame);
   if (! FRAME_W32_P (f))
     error ("Non-W32 frame used");
   return f;
@@ -306,19 +303,14 @@ check_x_display_info (Lisp_Object frame)
 /* Return the Emacs frame-object corresponding to an w32 window.
    It could be the frame's main window or an icon window.  */
 
-/* This function can be called during GC, so use GC_xxx type test macros.  */
-
 struct frame *
 x_window_to_frame (struct w32_display_info *dpyinfo, HWND wdesc)
 {
   Lisp_Object tail, frame;
   struct frame *f;
 
-  for (tail = Vframe_list; CONSP (tail); tail = XCDR (tail))
+  FOR_EACH_FRAME (tail, frame)
     {
-      frame = XCAR (tail);
-      if (!FRAMEP (frame))
-        continue;
       f = XFRAME (frame);
       if (!FRAME_W32_P (f) || FRAME_W32_DISPLAY_INFO (f) != dpyinfo)
        continue;
@@ -1829,7 +1821,6 @@ static LRESULT CALLBACK w32_wnd_proc (HWND, UINT, WPARAM, LPARAM);
 static BOOL
 w32_init_class (HINSTANCE hinst)
 {
-
   if (w32_unicode_gui)
     {
       WNDCLASSW  uwc;
@@ -2087,8 +2078,35 @@ sync_modifiers (void)
 static int
 modifier_set (int vkey)
 {
-  if (vkey == VK_CAPITAL || vkey == VK_SCROLL)
-    return (GetKeyState (vkey) & 0x1);
+  /* Warning: The fact that VK_NUMLOCK is not treated as the other 2
+     toggle keys is not an omission!  If you want to add it, you will
+     have to make changes in the default sub-case of the WM_KEYDOWN
+     switch, because if the NUMLOCK modifier is set, the code there
+     will directly convert any key that looks like an ASCII letter,
+     and also downcase those that look like upper-case ASCII.  */
+  if (vkey == VK_CAPITAL)
+    {
+      if (NILP (Vw32_enable_caps_lock))
+       return 0;
+      else
+       return (GetKeyState (vkey) & 0x1);
+    }
+  if (vkey == VK_SCROLL)
+    {
+      if (NILP (Vw32_scroll_lock_modifier)
+         /* w32-scroll-lock-modifier can be any non-nil value that is
+            not one of the modifiers, in which case it shall be ignored.  */
+         || !(   EQ (Vw32_scroll_lock_modifier, Qhyper)
+              || EQ (Vw32_scroll_lock_modifier, Qsuper)
+              || EQ (Vw32_scroll_lock_modifier, Qmeta)
+              || EQ (Vw32_scroll_lock_modifier, Qalt)
+              || EQ (Vw32_scroll_lock_modifier, Qcontrol)
+              || EQ (Vw32_scroll_lock_modifier, Qshift)))
+       return 0;
+      else
+       return (GetKeyState (vkey) & 0x1);
+    }
+
   if (!modifiers_recorded)
     return (GetKeyState (vkey) & 0x8000);
 
@@ -4286,9 +4304,6 @@ This function is an internal primitive--use `make-frame' instead.  */)
 
   XSETFRAME (frame, f);
 
-  /* Note that Windows does support scroll bars.  */
-  FRAME_CAN_HAVE_SCROLL_BARS (f) = 1;
-
   /* By default, make scrollbars the system standard width. */
   FRAME_CONFIG_SCROLL_BAR_WIDTH (f) = GetSystemMetrics (SM_CXVSCROLL);
 
@@ -4852,18 +4867,6 @@ x_pixel_height (register struct frame *f)
   return FRAME_PIXEL_HEIGHT (f);
 }
 
-int
-x_char_width (register struct frame *f)
-{
-  return FRAME_COLUMN_WIDTH (f);
-}
-
-int
-x_char_height (register struct frame *f)
-{
-  return FRAME_LINE_HEIGHT (f);
-}
-
 int
 x_screen_planes (register struct frame *f)
 {
@@ -5389,7 +5392,6 @@ x_create_tip_frame (struct w32_display_info *dpyinfo,
   Finsert (1, &text);
   set_buffer_internal_1 (old_buffer);
 
-  FRAME_CAN_HAVE_SCROLL_BARS (f) = 0;
   record_unwind_protect (unwind_create_tip_frame, frame);
 
   /* By setting the output method, we're essentially saying that
@@ -5941,7 +5943,7 @@ Text larger than the specified size is clipped.  */)
                  SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
 
     /* Let redisplay know that we have made the frame visible already.  */
-    f->async_visible = 1;
+    SET_FRAME_VISIBLE (f, 1);
 
     ShowWindow (FRAME_W32_WINDOW (f), SW_SHOWNOACTIVATE);
   }
@@ -6022,7 +6024,7 @@ typedef char guichar_t;
    read-only when "Directories" is selected in the filter.  This
    allows us to work around the fact that the standard Open File
    dialog does not support directories.  */
-static UINT CALLBACK
+static UINT_PTR CALLBACK
 file_dialog_callback (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
 {
   if (msg == WM_NOTIFY)
@@ -6154,9 +6156,9 @@ Otherwise, if ONLY-DIR-P is non-nil, the user can only select directories.  */)
       filename = empty_unibyte_string;
 
 #ifdef CYGWIN
-    dir = Fcygwin_convert_path_to_windows (dir, Qt);
+    dir = Fcygwin_convert_file_name_to_windows (dir, Qt);
     if (SCHARS (filename) > 0)
-      filename = Fcygwin_convert_path_to_windows (filename, Qnil);
+      filename = Fcygwin_convert_file_name_to_windows (filename, Qnil);
 #endif
 
     CHECK_STRING (dir);
@@ -6252,12 +6254,12 @@ Otherwise, if ONLY-DIR-P is non-nil, the user can only select directories.  */)
             /* we get one of the two final 0 bytes for free. */
             1 + sizeof (wchar_t) * wcslen (filename_buf)));
 #else /* !NTGUI_UNICODE */
-        dostounix_filename (filename_buf);
+        dostounix_filename (filename_buf, 0);
         filename = DECODE_FILE (build_string (filename_buf));
 #endif /* NTGUI_UNICODE */
 
 #ifdef CYGWIN
-        filename = Fcygwin_convert_path_from_windows (filename, Qt);
+        filename = Fcygwin_convert_file_name_from_windows (filename, Qt);
 #endif /* CYGWIN */
 
         /* Strip the dummy filename off the end of the string if we
@@ -6482,12 +6484,12 @@ w32_parse_hot_key (Lisp_Object key)
 
   CHECK_VECTOR (key);
 
-  if (XFASTINT (Flength (key)) != 1)
+  if (ASIZE (key) != 1)
     return Qnil;
 
   GCPRO1 (key);
 
-  c = Faref (key, make_number (0));
+  c = AREF (key, 0);
 
   if (CONSP (c) && lucid_event_type_list_p (c))
     c = Fevent_convert_list (c);
@@ -7024,6 +7026,9 @@ cache_system_info (void)
       DWORD data;
     } version;
 
+  /* Cache the module handle of Emacs itself.  */
+  hinst = GetModuleHandle (NULL);
+
   /* Cache the version of the operating system.  */
   version.data = GetVersion ();
   w32_major_version = version.info.major;
@@ -7036,7 +7041,7 @@ cache_system_info (void)
 
   /* Cache page size, allocation unit, processor type, etc.  */
   GetSystemInfo (&sysinfo_cache);
-  syspage_mask = sysinfo_cache.dwPageSize - 1;
+  syspage_mask = (DWORD_PTR)sysinfo_cache.dwPageSize - 1;
 
   /* Cache os info.  */
   osinfo_cache.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
@@ -7700,6 +7705,30 @@ globals_of_w32fns (void)
   syms_of_w32uniscribe ();
 }
 
+typedef USHORT (WINAPI * CaptureStackBackTrace_proc) (ULONG, ULONG, PVOID *,
+                                                     PULONG);
+
+#define BACKTRACE_LIMIT_MAX 62
+
+int
+w32_backtrace (void **buffer, int limit)
+{
+  static CaptureStackBackTrace_proc s_pfn_CaptureStackBackTrace = NULL;
+  HMODULE hm_kernel32 = NULL;
+
+  if (!s_pfn_CaptureStackBackTrace)
+    {
+      hm_kernel32 = LoadLibrary ("Kernel32.dll");
+      s_pfn_CaptureStackBackTrace =
+       (CaptureStackBackTrace_proc) GetProcAddress (hm_kernel32,
+                                                    "RtlCaptureStackBackTrace");
+    }
+  if (s_pfn_CaptureStackBackTrace)
+    return s_pfn_CaptureStackBackTrace (0, min (BACKTRACE_LIMIT_MAX, limit),
+                                       buffer, NULL);
+  return 0;
+}
+
 void
 emacs_abort (void)
 {
@@ -7707,7 +7736,10 @@ emacs_abort (void)
   button = MessageBox (NULL,
                       "A fatal error has occurred!\n\n"
                       "Would you like to attach a debugger?\n\n"
-                      "Select YES to debug, NO to abort Emacs"
+                      "Select:\n"
+                      "YES -- to debug Emacs, or\n"
+                      "NO  -- to abort Emacs and produce a backtrace\n"
+                      "       (emacs_backtrace.txt in current directory)."
 #if __GNUC__
                       "\n\n(type \"gdb -p <emacs-PID>\" and\n"
                       "\"continue\" inside GDB before clicking YES.)"
@@ -7722,7 +7754,59 @@ emacs_abort (void)
       exit (2);        /* tell the compiler we will never return */
     case IDNO:
     default:
-      abort ();
-      break;
+      {
+       void *stack[BACKTRACE_LIMIT_MAX + 1];
+       int i = w32_backtrace (stack, BACKTRACE_LIMIT_MAX + 1);
+
+       if (i)
+         {
+#ifdef CYGWIN
+           int stderr_fd = 2;
+#else
+           HANDLE errout = GetStdHandle (STD_ERROR_HANDLE);
+           int stderr_fd = -1;
+#endif
+           int errfile_fd = -1;
+           int j;
+
+#ifndef CYGWIN
+           if (errout && errout != INVALID_HANDLE_VALUE)
+             stderr_fd = _open_osfhandle ((intptr_t)errout, O_APPEND | O_BINARY);
+#endif
+           if (stderr_fd >= 0)
+             write (stderr_fd, "\r\nBacktrace:\r\n", 14);
+           errfile_fd = _open ("emacs_backtrace.txt", O_RDWR | O_CREAT | O_BINARY, S_IREAD | S_IWRITE);
+           if (errfile_fd >= 0)
+             {
+               lseek (errfile_fd, 0L, SEEK_END);
+               write (errfile_fd, "\r\nBacktrace:\r\n", 14);
+             }
+
+           for (j = 0; j < i; j++)
+             {
+               char buf[INT_BUFSIZE_BOUND (void *)];
+
+               /* stack[] gives the return addresses, whereas we want
+                  the address of the call, so decrease each address
+                  by approximate size of 1 CALL instruction.  */
+               sprintf (buf, "0x%p\r\n", (char *)stack[j] - sizeof(void *));
+               if (stderr_fd >= 0)
+                 write (stderr_fd, buf, strlen (buf));
+               if (errfile_fd >= 0)
+                 write (errfile_fd, buf, strlen (buf));
+             }
+           if (i == BACKTRACE_LIMIT_MAX)
+             {
+               if (stderr_fd >= 0)
+                 write (stderr_fd, "...\r\n", 5);
+               if (errfile_fd >= 0)
+                 write (errfile_fd, "...\r\n", 5);
+             }
+           if (errfile_fd >= 0)
+             close (errfile_fd);
+         }
+       abort ();
+       break;
+      }
     }
 }