/* Graphical user interface functions for the Microsoft Windows API.
-Copyright (C) 1989, 1992-2012 Free Software Foundation, Inc.
+Copyright (C) 1989, 1992-2013 Free Software Foundation, Inc.
This file is part of GNU Emacs.
#include <limits.h>
#include <errno.h>
#include <math.h>
+#include <fcntl.h>
+#include <unistd.h>
#include "lisp.h"
#include "w32term.h"
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);
static void w32_hide_hourglass (void);
#ifdef WINDOWSNT
-/* From w32inevet.c */
+/* From w32inevt.c */
extern int faked_key;
#endif /* WINDOWSNT */
/* 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;
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;
/* 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;
static BOOL
w32_init_class (HINSTANCE hinst)
{
-
if (w32_unicode_gui)
{
WNDCLASSW uwc;
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);
thread-safe. The next line is okay because the cons
cell is never made into garbage and is not relocated by
GC. */
- XSETCAR ((Lisp_Object) ((EMACS_INT) msg.lParam), Qnil);
+ XSETCAR (XIL ((EMACS_INT) msg.lParam), Qnil);
if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
emacs_abort ();
break;
{
int vk_code = (int) msg.wParam;
int cur_state = (GetKeyState (vk_code) & 1);
- Lisp_Object new_state = (Lisp_Object) ((EMACS_INT) msg.lParam);
+ Lisp_Object new_state = XIL ((EMACS_INT) msg.lParam);
/* NB: This code must be thread-safe. It is safe to
call NILP because symbols are not relocated by GC,
versions, there is no way of telling when the mouse leaves the
frame, so we just have to put up with help-echo and mouse
highlighting remaining while the frame is not active. */
- if (track_mouse_event_fn && !track_mouse_window)
+ if (track_mouse_event_fn && !track_mouse_window
+ /* If the menu bar is active, turning on tracking of mouse
+ movement events might send these events to the tooltip
+ frame, if the user happens to move the mouse pointer over
+ the tooltip. But since we don't process events for
+ tooltip frames, this causes Windows to present a
+ hourglass cursor, which is ugly and unexpected. So don't
+ enable tracking mouse events in this case; they will be
+ restarted when the menu pops down. (Confusingly, the
+ menubar_active member of f->output_data.w32, tested
+ above, is only set when a menu was popped up _not_ from
+ the frame's menu bar, but via x-popup-menu.) */
+ && !menubar_in_use)
{
TRACKMOUSEEVENT tme;
tme.cbSize = sizeof (tme);
return retval;
}
+ case WM_EMACS_FILENOTIFY:
+ my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
+ return 1;
default:
/* Check for messages registered at runtime. */
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);
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)
{
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
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);
}
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)
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);
/* 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
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);
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;
/* 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);
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)
{
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.)"
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;
+ }
}
}
-