/* 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 <setjmp.h>
#include "lisp.h"
#include "w32term.h"
#include "fontset.h"
#include "systime.h"
#include "termhooks.h"
+
+#include "w32common.h"
+
+#ifdef WINDOWSNT
#include "w32heap.h"
+#endif /* WINDOWSNT */
+
+#if CYGWIN
+#include "cygw32.h"
+#else
#include "w32.h"
+#endif
#include "bitmaps/gray.xbm"
#include <dlgs.h>
#include <imm.h>
-#define FILE_NAME_TEXT_FIELD edt1
-#define FILE_NAME_COMBO_BOX cmb13
-#define FILE_NAME_LIST lst1
#include "font.h"
#include "w32font.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);
extern const char *map_w32_filename (const char *, const char **);
+extern char * w32_strerror (int error_no);
-/* If non-zero, a w32 timer that, when it expires, displays an
- hourglass cursor on all frames. */
-static unsigned hourglass_timer = 0;
+/* If non-NULL, a handle to a frame where to display the hourglass cursor. */
static HWND hourglass_hwnd = NULL;
#ifndef IDC_HAND
};
/* Reportedly, MSVC does not have this in its headers. */
-#ifdef _MSC_VER
+#if defined (_MSC_VER) && _WIN32_WINNT < 0x0500
DECLARE_HANDLE(HMONITOR);
#endif
MonitorFromPoint_Proc monitor_from_point_fn = NULL;
GetMonitorInfo_Proc get_monitor_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;
#define MOUSE_BUTTON_ID 1
#define MOUSE_MOVE_ID 2
#define MENU_FREE_ID 3
-#define HOURGLASS_ID 4
/* The delay (milliseconds) before a menu is freed after WM_EXITMENULOOP
is received. */
#define MENU_FREE_DELAY 1000
static void w32_show_hourglass (struct frame *);
static void w32_hide_hourglass (void);
+#ifdef WINDOWSNT
+/* From w32inevt.c */
+extern int faked_key;
+#endif /* WINDOWSNT */
+
+/* This gives us the page size and the size of the allocation unit on NT. */
+SYSTEM_INFO sysinfo_cache;
+
+/* This gives us version, build, and platform identification. */
+OSVERSIONINFO osinfo_cache;
+
+DWORD_PTR syspage_mask = 0;
+
+/* The major and minor versions of NT. */
+int w32_major_version;
+int w32_minor_version;
+int w32_build_number;
+
+/* Distinguish between Windows NT and Windows 95. */
+int os_subtype;
+
+#ifdef HAVE_NTGUI
+HINSTANCE hinst = NULL;
+#endif
+
+static unsigned int sound_type = 0xFFFFFFFF;
+#define MB_EMACS_SILENT (0xFFFFFFFF - 1)
\f
/* Error if we are not connected to MS-Windows. */
XSETINT (rgb, RGB (XUINT (red), XUINT (green), XUINT (blue)));
- BLOCK_INPUT;
+ block_input ();
/* replace existing entry in w32-color-map or add new entry. */
entry = Fassoc (name, Vw32_color_map);
Fsetcdr (entry, rgb);
}
- UNBLOCK_INPUT;
+ unblock_input ();
return (oldrgb);
}
colormap_t *pc = w32_color_map;
Lisp_Object cmap;
- BLOCK_INPUT;
+ block_input ();
cmap = Qnil;
make_number (pc->colorref)),
cmap);
- UNBLOCK_INPUT;
+ unblock_input ();
return (cmap);
}
}
static Lisp_Object
-w32_color_map_lookup (char *colorname)
+w32_color_map_lookup (const char *colorname)
{
Lisp_Object tail, ret = Qnil;
- BLOCK_INPUT;
+ block_input ();
for (tail = Vw32_color_map; CONSP (tail); tail = XCDR (tail))
{
QUIT;
}
- UNBLOCK_INPUT;
+ unblock_input ();
return ret;
}
HKEY colors_key;
/* Other registry operations are done with input blocked. */
- BLOCK_INPUT;
+ block_input ();
/* Look for "Control Panel/Colors" under User and Machine registry
settings. */
RegCloseKey (colors_key);
}
- UNBLOCK_INPUT;
+ unblock_input ();
}
static Lisp_Object
-x_to_w32_color (char * colorname)
+x_to_w32_color (const char * colorname)
{
register Lisp_Object ret = Qnil;
- BLOCK_INPUT;
+ block_input ();
if (colorname[0] == '#')
{
/* Could be an old-style RGB Device specification. */
- char *color;
- int size;
- color = colorname + 1;
+ int size = strlen (colorname + 1);
+ char *color = alloca (size + 1);
- size = strlen (color);
+ strcpy (color, colorname + 1);
if (size == 3 || size == 6 || size == 9 || size == 12)
{
UINT colorval;
pos += 0x8;
if (i == 2)
{
- UNBLOCK_INPUT;
+ unblock_input ();
XSETINT (ret, colorval);
return ret;
}
}
else if (strnicmp (colorname, "rgb:", 4) == 0)
{
- char *color;
+ const char *color;
UINT colorval;
int i, pos;
pos = 0;
{
if (*end != '\0')
break;
- UNBLOCK_INPUT;
+ unblock_input ();
XSETINT (ret, colorval);
return ret;
}
else if (strnicmp (colorname, "rgbi:", 5) == 0)
{
/* This is an RGB Intensity specification. */
- char *color;
+ const char *color;
UINT colorval;
int i, pos;
pos = 0;
{
if (*end != '\0')
break;
- UNBLOCK_INPUT;
+ unblock_input ();
XSETINT (ret, colorval);
return ret;
}
}
}
- UNBLOCK_INPUT;
+ unblock_input ();
return ret;
}
If ALLOC is nonzero, allocate a new colormap cell. */
int
-w32_defined_color (FRAME_PTR f, char *color, XColor *color_def, int alloc)
+w32_defined_color (FRAME_PTR f, const char *color, XColor *color_def, int alloc)
{
register Lisp_Object tem;
COLORREF w32_color_ref;
f->output_data.w32->mouse_pixel = FRAME_FOREGROUND_PIXEL (f);
#if 0 /* TODO : Mouse cursor customization. */
- BLOCK_INPUT;
+ block_input ();
/* It's not okay to crash if the user selects a screwy cursor. */
count = x_catch_errors (FRAME_W32_DISPLAY (f));
f->output_data.w32->hand_cursor = hand_cursor;
XFlush (FRAME_W32_DISPLAY (f));
- UNBLOCK_INPUT;
+ unblock_input ();
update_face_from_frame_parameter (f, Qmouse_color, arg);
#endif /* TODO */
if (FRAME_W32_WINDOW (f) != 0)
{
- BLOCK_INPUT;
+ block_input ();
/* Update frame's cursor_gc. */
f->output_data.w32->cursor_gc->foreground = fore_pixel;
f->output_data.w32->cursor_gc->background = pixel;
- UNBLOCK_INPUT;
+ unblock_input ();
if (FRAME_VISIBLE_P (f))
{
if (SYMBOLP (arg) && SYMBOLP (oldval) && EQ (arg, oldval))
return;
- BLOCK_INPUT;
+ block_input ();
result = x_bitmap_icon (f, arg);
if (result)
{
- UNBLOCK_INPUT;
+ unblock_input ();
error ("No icon window available");
}
- UNBLOCK_INPUT;
+ unblock_input ();
}
void
else if (!NILP (arg) || NILP (oldval))
return;
- FSET (f, icon_name, arg);
+ fset_icon_name (f, arg);
#if 0
if (f->output_data.w32->icon_bitmap != 0)
return;
- BLOCK_INPUT;
+ block_input ();
result = x_text_icon (f,
SSDATA ((!NILP (f->icon_name)
if (result)
{
- UNBLOCK_INPUT;
+ unblock_input ();
error ("No icon window available");
}
}
XFlush (FRAME_W32_DISPLAY (f));
- UNBLOCK_INPUT;
+ unblock_input ();
#endif
}
int width = FRAME_PIXEL_WIDTH (f);
int y = nlines * FRAME_LINE_HEIGHT (f);
- BLOCK_INPUT;
+ block_input ();
{
HDC hdc = get_frame_dc (f);
w32_clear_area (f, hdc, 0, y, width, height);
release_frame_dc (f, hdc);
}
- UNBLOCK_INPUT;
+ unblock_input ();
if (WINDOWP (f->tool_bar_window))
clear_glyph_matrix (XWINDOW (f->tool_bar_window)->current_matrix);
if (! NILP (Fstring_equal (name, f->name)))
return;
- FSET (f, name, name);
+ fset_name (f, name);
/* For setting the frame title, the title parameter should override
the name parameter. */
if (STRING_MULTIBYTE (name))
name = ENCODE_SYSTEM (name);
- BLOCK_INPUT;
+ block_input ();
SetWindowText (FRAME_W32_WINDOW (f), SDATA (name));
- UNBLOCK_INPUT;
+ unblock_input ();
}
}
update_mode_lines = 1;
- FSET (f, title, name);
+ fset_title (f, name);
if (NILP (name))
name = f->name;
if (STRING_MULTIBYTE (name))
name = ENCODE_SYSTEM (name);
- BLOCK_INPUT;
+ block_input ();
SetWindowText (FRAME_W32_WINDOW (f), SDATA (name));
- UNBLOCK_INPUT;
+ unblock_input ();
}
}
/* Do first time app init */
- if (!hprevinst)
- {
- w32_init_class (hinst);
- }
+ w32_init_class (hinst);
if (f->size_hint_flags & USPosition || f->size_hint_flags & PPosition)
{
}
}
+#if EMACSDEBUG
+const char*
+w32_name_of_message (UINT msg)
+{
+ unsigned i;
+ static char buf[64];
+ static const struct {
+ UINT msg;
+ const char* name;
+ } msgnames[] = {
+#define M(msg) { msg, # msg }
+ M (WM_PAINT),
+ M (WM_TIMER),
+ M (WM_USER),
+ M (WM_MOUSEMOVE),
+ M (WM_LBUTTONUP),
+ M (WM_KEYDOWN),
+ M (WM_EMACS_KILL),
+ M (WM_EMACS_CREATEWINDOW),
+ M (WM_EMACS_DONE),
+ M (WM_EMACS_CREATESCROLLBAR),
+ M (WM_EMACS_SHOWWINDOW),
+ M (WM_EMACS_SETWINDOWPOS),
+ M (WM_EMACS_DESTROYWINDOW),
+ M (WM_EMACS_TRACKPOPUPMENU),
+ M (WM_EMACS_SETFOCUS),
+ M (WM_EMACS_SETFOREGROUND),
+ M (WM_EMACS_SETLOCALE),
+ M (WM_EMACS_SETKEYBOARDLAYOUT),
+ M (WM_EMACS_REGISTER_HOT_KEY),
+ M (WM_EMACS_UNREGISTER_HOT_KEY),
+ M (WM_EMACS_TOGGLE_LOCK_KEY),
+ M (WM_EMACS_TRACK_CARET),
+ M (WM_EMACS_DESTROY_CARET),
+ M (WM_EMACS_SHOW_CARET),
+ M (WM_EMACS_HIDE_CARET),
+ M (WM_EMACS_SETCURSOR),
+ M (WM_EMACS_PAINT),
+ M (WM_CHAR),
+#undef M
+ { 0, 0 }
+ };
+
+ for (i = 0; msgnames[i].name; ++i)
+ if (msgnames[i].msg == msg)
+ return msgnames[i].name;
+
+ sprintf (buf, "message 0x%04x", (unsigned)msg);
+ return buf;
+}
+#endif /* EMACSDEBUG */
+
+/* Here's an overview of how Emacs input works in GUI sessions on
+ MS-Windows. (For description of non-GUI input, see the commentary
+ before w32_console_read_socket in w32inevt.c.)
+
+ System messages are read and processed by w32_msg_pump below. This
+ function runs in a separate thread. It handles a small number of
+ custom WM_EMACS_* messages (posted by the main thread, look for
+ PostMessage calls), and dispatches the rest to w32_wnd_proc, which
+ is the main window procedure for the entire Emacs application.
+
+ w32_wnd_proc also runs in the same separate input thread. It
+ handles some messages, mostly those that need GDI calls, by itself.
+ For the others, it calls my_post_msg, which inserts the messages
+ into the input queue serviced by w32_read_socket.
+
+ w32_read_socket runs in the main (a.k.a. "Lisp") thread, and is
+ called synchronously from keyboard.c when it is known or suspected
+ that some input is available. w32_read_socket either handles
+ messages immediately, or converts them into Emacs input events and
+ stuffs them into kbd_buffer, where kbd_buffer_get_event can get at
+ them and process them when read_char and its callers require
+ input.
+
+ Under Cygwin with the W32 toolkit, the use of /dev/windows with
+ select(2) takes the place of w32_read_socket.
+
+ */
+
/* Main message dispatch loop. */
static void
w32_msg_pump (deferred_msg * msg_buf)
{
MSG msg;
- int result;
+ WPARAM result;
HWND focus_window;
msh_mousewheel = RegisterWindowMessage (MSH_MOUSEWHEEL);
while ((w32_unicode_gui ? GetMessageW : GetMessageA) (&msg, NULL, 0, 0))
{
+
+ /* DebPrint (("w32_msg_pump: %s time:%u\n", */
+ /* w32_name_of_message (msg.message), msg.time)); */
+
if (msg.hwnd == NULL)
{
switch (msg.message)
CoInitialize (NULL);
w32_createwindow ((struct frame *) msg.wParam);
if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
- abort ();
+ emacs_abort ();
break;
case WM_EMACS_SETLOCALE:
SetThreadLocale (msg.wParam);
/* Reply is not expected. */
break;
case WM_EMACS_SETKEYBOARDLAYOUT:
- result = (int) ActivateKeyboardLayout ((HKL) msg.wParam, 0);
+ result = (WPARAM) ActivateKeyboardLayout ((HKL) msg.wParam, 0);
if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE,
result, 0))
- abort ();
+ emacs_abort ();
break;
case WM_EMACS_REGISTER_HOT_KEY:
focus_window = GetFocus ();
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))
- abort ();
+ emacs_abort ();
break;
case WM_EMACS_TOGGLE_LOCK_KEY:
{
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,
}
if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE,
cur_state, 0))
- abort ();
+ emacs_abort ();
}
break;
#ifdef MSG_DEBUG
/* Broadcast messages make it here, so you need to be looking
for something in particular for this to be useful. */
default:
- DebPrint (("msg %x not expected by w32_msg_pump\n", msg.message));
+ DebPrint (("msg %x not expected by w32_msg_pump\n", msg.message));
#endif
}
}
{
/* Only input thread can send deferred messages. */
if (GetCurrentThreadId () != dwWindowsThreadId)
- abort ();
+ emacs_abort ();
/* It is an error to send a message that is already deferred. */
if (find_deferred_msg (hwnd, msg) != NULL)
- abort ();
+ emacs_abort ();
/* Enforced synchronization is not needed because this is the only
function that alters deferred_msg_head, and the following critical
PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE);
if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
- abort ();
+ emacs_abort ();
memset (&dummy_buf, 0, sizeof (dummy_buf));
dummy_buf.w32msg.msg.hwnd = NULL;
msg = WM_MBUTTONUP;
button_state &= ~MMOUSE;
- if (button_state) abort ();
+ if (button_state) emacs_abort ();
}
else
return 0;
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);
menubar_in_use = 0;
}
}
- else if (wParam == hourglass_timer)
- {
- KillTimer (hwnd, hourglass_timer);
- hourglass_timer = 0;
- w32_show_hourglass (x_window_to_frame (dpyinfo, hwnd));
- }
return 0;
case WM_NCACTIVATE:
/* Detect if message has already been deferred; in this case
we cannot return any sensible value to ignore this. */
if (find_deferred_msg (hwnd, msg) != NULL)
- abort ();
+ emacs_abort ();
menubar_in_use = 1;
MSG msg;
if (!PostThreadMessage (dwWindowsThreadId, WM_EMACS_CREATEWINDOW, (WPARAM)f, 0))
- abort ();
+ emacs_abort ();
GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
}
static void
w32_window (struct frame *f, long window_prompting, int minibuffer_only)
{
- BLOCK_INPUT;
+ block_input ();
/* Use the resource name as the top-level window name
for looking up resources. Make a non-Lisp copy
f->explicit_name = 0;
name = f->name;
- FSET (f, name, Qnil);
+ fset_name (f, Qnil);
x_set_name (f, name, explicit);
}
- UNBLOCK_INPUT;
+ unblock_input ();
if (!minibuffer_only && FRAME_EXTERNAL_MENU_BAR (f))
initialize_frame_menubar (f);
else if (!EQ (icon_x, Qunbound) || !EQ (icon_y, Qunbound))
error ("Both left and top icon corners of icon must be specified");
- BLOCK_INPUT;
+ block_input ();
if (! EQ (icon_x, Qunbound))
x_wm_set_icon_position (f, XINT (icon_x), XINT (icon_y));
: f->name)));
#endif
- UNBLOCK_INPUT;
+ unblock_input ();
}
{
XGCValues gc_values;
- BLOCK_INPUT;
+ block_input ();
/* Create the GC's of this frame.
Note that many default values are used. */
f->output_data.w32->white_relief.gc = 0;
f->output_data.w32->black_relief.gc = 0;
- UNBLOCK_INPUT;
+ unblock_input ();
}
f->output_data.w32 = xzalloc (sizeof (struct w32_output));
FRAME_FONTSET (f) = -1;
- FSET (f, icon_name,
- x_get_arg (dpyinfo, parameters, Qicon_name, "iconName", "Title",
+ fset_icon_name
+ (f, x_get_arg (dpyinfo, parameters, Qicon_name, "iconName", "Title",
RES_TYPE_STRING));
if (! STRINGP (f->icon_name))
- FSET (f, icon_name, Qnil);
+ fset_icon_name (f, Qnil);
/* FRAME_W32_DISPLAY_INFO (f) = dpyinfo; */
be set. */
if (EQ (name, Qunbound) || NILP (name))
{
- FSET (f, name, build_string (dpyinfo->w32_id_name));
+ fset_name (f, build_string (dpyinfo->w32_id_name));
f->explicit_name = 0;
}
else
{
- FSET (f, name, name);
+ fset_name (f, name);
f->explicit_name = 1;
/* use the frame's title when getting resources for this frame. */
specbind (Qx_resource_name, name);
/* 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
bar so that its size can be taken into account. */
- BLOCK_INPUT;
+ block_input ();
x_wm_set_size_hint (f, window_prompting, 0);
- UNBLOCK_INPUT;
+ unblock_input ();
/* Make the window appear on the frame and enable display, unless
the caller says not to. However, with explicit parent, Emacs
if (FRAME_HAS_MINIBUF_P (f)
&& (!FRAMEP (KVAR (kb, Vdefault_minibuffer_frame))
|| !FRAME_LIVE_P (XFRAME (KVAR (kb, Vdefault_minibuffer_frame)))))
- KVAR (kb, Vdefault_minibuffer_frame) = frame;
+ kset_default_minibuffer_frame (kb, frame);
/* All remaining specified parameters, which have not been "used"
by x_get_arg and friends, now go in the misc. alist of the frame. */
for (tem = parameters; CONSP (tem); tem = XCDR (tem))
if (CONSP (XCAR (tem)) && !NILP (XCAR (XCAR (tem))))
- FSET (f, param_alist, Fcons (XCAR (tem), f->param_alist));
+ fset_param_alist (f, Fcons (XCAR (tem), f->param_alist));
UNGCPRO;
(Lisp_Object display)
{
struct w32_display_info *dpyinfo = check_x_display_info (display);
- HDC hdc;
int cap;
- hdc = GetDC (dpyinfo->root_window);
- if (dpyinfo->has_palette)
- cap = GetDeviceCaps (hdc, SIZEPALETTE);
- else
- cap = GetDeviceCaps (hdc, NUMCOLORS);
-
- /* We force 24+ bit depths to 24-bit, both to prevent an overflow
- and because probably is more meaningful on Windows anyway */
- if (cap < 0)
- cap = 1 << min (dpyinfo->n_planes * dpyinfo->n_cbits, 24);
-
- ReleaseDC (dpyinfo->root_window, hdc);
+ /* Don't use NCOLORS: it returns incorrect results under remote
+ * desktop. We force 24+ bit depths to 24-bit, both to prevent an
+ * overflow and because probably is more meaningful on Windows
+ * anyway. */
+ cap = 1 << min (dpyinfo->n_planes * dpyinfo->n_cbits, 24);
return make_number (cap);
}
{
return Qnil;
}
+
+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
+prevents Emacs from making any sound at all.
+SOUND is nil to use the normal beep. */)
+ (Lisp_Object sound)
+{
+ CHECK_SYMBOL (sound);
+
+ if (NILP (sound))
+ sound_type = 0xFFFFFFFF;
+ else if (EQ (sound, intern ("asterisk")))
+ sound_type = MB_ICONASTERISK;
+ else if (EQ (sound, intern ("exclamation")))
+ sound_type = MB_ICONEXCLAMATION;
+ else if (EQ (sound, intern ("hand")))
+ sound_type = MB_ICONHAND;
+ else if (EQ (sound, intern ("question")))
+ sound_type = MB_ICONQUESTION;
+ else if (EQ (sound, intern ("ok")))
+ sound_type = MB_OK;
+ else if (EQ (sound, intern ("silent")))
+ sound_type = MB_EMACS_SILENT;
+ else
+ sound_type = 0xFFFFFFFF;
+
+ return sound;
+}
+
\f
int
x_pixel_width (register struct frame *f)
CHECK_STRING (name);
for (dpyinfo = &one_w32_display_info, names = w32_display_name_list;
- dpyinfo;
+ dpyinfo && !NILP (w32_display_name_list);
dpyinfo = dpyinfo->next, names = XCDR (names))
{
Lisp_Object tem;
unsigned char *xrm_option;
struct w32_display_info *dpyinfo;
+ CHECK_STRING (display);
+
+ /* Signal an error in order to encourage correct use from callers.
+ * If we ever support multiple window systems in the same Emacs,
+ * we'll need callers to be precise about what window system they
+ * want. */
+
+ if (strcmp (SSDATA (display), "w32") != 0)
+ error ("The name of the display in this Emacs must be \"w32\"");
+
/* If initialization has already been done, return now to avoid
overwriting critical parts of one_w32_display_info. */
if (w32_in_use)
return Qnil;
- CHECK_STRING (display);
if (! NILP (xrm_string))
CHECK_STRING (xrm_string);
if (dpyinfo->reference_count > 0)
error ("Display still has frames on it");
- BLOCK_INPUT;
+ block_input ();
x_destroy_all_bitmaps (dpyinfo);
x_delete_display (dpyinfo);
- UNBLOCK_INPUT;
+ unblock_input ();
return Qnil;
}
CHECK_STRING (prop);
CHECK_STRING (value);
- BLOCK_INPUT;
+ block_input ();
prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), SDATA (prop), False);
XChangeProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
prop_atom, XA_STRING, 8, PropModeReplace,
/* Make sure the property is set when we return. */
XFlush (FRAME_W32_DISPLAY (f));
- UNBLOCK_INPUT;
+ unblock_input ();
return value;
}
Atom prop_atom;
CHECK_STRING (prop);
- BLOCK_INPUT;
+ block_input ();
prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), SDATA (prop), False);
XDeleteProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), prop_atom);
/* Make sure the property is removed when we return. */
XFlush (FRAME_W32_DISPLAY (f));
- UNBLOCK_INPUT;
+ unblock_input ();
return prop;
}
unsigned long actual_size, bytes_remaining;
CHECK_STRING (prop);
- BLOCK_INPUT;
+ block_input ();
prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), SDATA (prop), False);
rc = XGetWindowProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
prop_atom, 0, 0, False, XA_STRING,
XFree (tmp_data);
}
- UNBLOCK_INPUT;
+ unblock_input ();
return prop_value;
Busy cursor
***********************************************************************/
-/* Default number of seconds to wait before displaying an hourglass
- cursor. Duplicated from xdisp.c, but cannot use the version there
- due to lack of atimers on w32. */
-#define DEFAULT_HOURGLASS_DELAY 1
-
-/* Cancel a currently active hourglass timer, and start a new one. */
-
void
-start_hourglass (void)
+w32_note_current_window (void)
{
- DWORD delay;
- int secs, msecs = 0;
struct frame * f = SELECTED_FRAME ();
- /* No cursors on non GUI frames. */
if (!FRAME_W32_P (f))
return;
- cancel_hourglass ();
-
- if (INTEGERP (Vhourglass_delay)
- && XINT (Vhourglass_delay) > 0)
- secs = XFASTINT (Vhourglass_delay);
- else if (FLOATP (Vhourglass_delay)
- && XFLOAT_DATA (Vhourglass_delay) > 0)
- {
- Lisp_Object tem;
- tem = Ftruncate (Vhourglass_delay, Qnil);
- secs = XFASTINT (tem);
- msecs = (XFLOAT_DATA (Vhourglass_delay) - secs) * 1000;
- }
- else
- secs = DEFAULT_HOURGLASS_DELAY;
-
- delay = secs * 1000 + msecs;
hourglass_hwnd = FRAME_W32_WINDOW (f);
- hourglass_timer = SetTimer (hourglass_hwnd, HOURGLASS_ID, delay, NULL);
}
-
-/* Cancel the hourglass cursor timer if active, hide an hourglass
- cursor if shown. */
-
void
-cancel_hourglass (void)
+show_hourglass (struct atimer *timer)
{
- if (hourglass_timer)
- {
- KillTimer (hourglass_hwnd, hourglass_timer);
- hourglass_timer = 0;
- }
+ struct frame *f;
- if (hourglass_shown_p)
- w32_hide_hourglass ();
+ hourglass_atimer = NULL;
+
+ block_input ();
+ f = x_window_to_frame (&one_w32_display_info,
+ hourglass_hwnd);
+
+ if (f)
+ f->output_data.w32->hourglass_p = 0;
+ else
+ f = SELECTED_FRAME ();
+
+ if (!FRAME_W32_P (f))
+ return;
+
+ w32_show_hourglass (f);
+ unblock_input ();
}
+void
+hide_hourglass (void)
+{
+ block_input ();
+ w32_hide_hourglass ();
+ unblock_input ();
+}
-/* Timer function of hourglass_timer.
- Display an hourglass cursor. Set the hourglass_p flag in display info
+/* Display an hourglass cursor. Set the hourglass_p flag in display info
to indicate that an hourglass cursor is shown. */
static void
XSETFRAME (frame, f);
buffer = Fget_buffer_create (build_string (" *tip*"));
- Fset_window_buffer (FRAME_ROOT_WINDOW (f), buffer, Qnil);
+ /* 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, 0, 0);
old_buffer = current_buffer;
set_buffer_internal_1 (XBUFFER (buffer));
- BVAR (current_buffer, truncate_lines) = Qnil;
+ bset_truncate_lines (current_buffer, Qnil);
specbind (Qinhibit_read_only, Qt);
specbind (Qinhibit_modification_hooks, Qt);
Ferase_buffer ();
f->output_data.w32 = xzalloc (sizeof (struct w32_output));
FRAME_FONTSET (f) = -1;
- FSET (f, icon_name, Qnil);
+ fset_icon_name (f, Qnil);
#ifdef GLYPH_DEBUG
image_cache_refcount =
be set. */
if (EQ (name, Qunbound) || NILP (name))
{
- FSET (f, name, build_string (dpyinfo->w32_id_name));
+ fset_name (f, build_string (dpyinfo->w32_id_name));
f->explicit_name = 0;
}
else
{
- FSET (f, name, name);
+ fset_name (f, name);
f->explicit_name = 1;
/* use the frame's title when getting resources for this frame. */
specbind (Qx_resource_name, name);
f->left_fringe_width = 0;
f->right_fringe_width = 0;
- BLOCK_INPUT;
+ block_input ();
my_create_tip_window (f);
- UNBLOCK_INPUT;
+ unblock_input ();
x_make_gc (f);
max_x = x_display_pixel_width (FRAME_W32_DISPLAY_INFO (f));
max_y = x_display_pixel_height (FRAME_W32_DISPLAY_INFO (f));
- BLOCK_INPUT;
+ block_input ();
GetCursorPos (&pt);
*root_x = pt.x;
*root_y = pt.y;
- UNBLOCK_INPUT;
+ unblock_input ();
/* If multiple monitor support is available, constrain the tip onto
the current monitor. This improves the above by allowing negative
call1 (Qcancel_timer, timer);
}
- BLOCK_INPUT;
+ block_input ();
compute_tip_xy (f, parms, dx, dy, FRAME_PIXEL_WIDTH (f),
FRAME_PIXEL_HEIGHT (f), &root_x, &root_y);
0, 0, 0, 0,
SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
- UNBLOCK_INPUT;
+ unblock_input ();
goto start_timer;
}
}
/* Block input until the tip has been fully drawn, to avoid crashes
when drawing tips in menus. */
- BLOCK_INPUT;
+ block_input ();
/* Create a frame for the tooltip, and record it in the global
variable tip_frame. */
/* Set up the frame's root window. */
w = XWINDOW (FRAME_ROOT_WINDOW (f));
- WSET (w, left_col, make_number (0));
- WSET (w, top_line, make_number (0));
+ wset_left_col (w, make_number (0));
+ wset_top_line (w, make_number (0));
if (CONSP (Vx_max_tooltip_size)
&& INTEGERP (XCAR (Vx_max_tooltip_size))
&& INTEGERP (XCDR (Vx_max_tooltip_size))
&& XINT (XCDR (Vx_max_tooltip_size)) > 0)
{
- WSET (w, total_cols, XCAR (Vx_max_tooltip_size));
- WSET (w, total_lines, XCDR (Vx_max_tooltip_size));
+ wset_total_cols (w, XCAR (Vx_max_tooltip_size));
+ wset_total_lines (w, XCDR (Vx_max_tooltip_size));
}
else
{
- WSET (w, total_cols, make_number (80));
- WSET (w, total_lines, make_number (40));
+ wset_total_cols (w, make_number (80));
+ wset_total_lines (w, make_number (40));
}
FRAME_TOTAL_COLS (f) = XINT (w->total_cols);
/* Display the tooltip text in a temporary buffer. */
old_buffer = current_buffer;
set_buffer_internal_1 (XBUFFER (XWINDOW (FRAME_ROOT_WINDOW (f))->buffer));
- BVAR (current_buffer, truncate_lines) = Qnil;
+ bset_truncate_lines (current_buffer, Qnil);
clear_glyph_matrix (w->desired_matrix);
clear_glyph_matrix (w->current_matrix);
SET_TEXT_POS (pos, BEGV, BEGV_BYTE);
/* w->total_cols and FRAME_TOTAL_COLS want the width in columns,
not in pixels. */
width /= WINDOW_FRAME_COLUMN_WIDTH (w);
- WSET (w, total_cols, make_number (width));
+ wset_total_cols (w, make_number (width));
FRAME_TOTAL_COLS (f) = width;
adjust_glyphs (f);
w->pseudo_window_p = 1;
w->must_be_updated_p = 1;
update_single_window (w, 1);
- UNBLOCK_INPUT;
+ unblock_input ();
/* Restore original current buffer. */
set_buffer_internal_1 (old_buffer);
File selection dialog
***********************************************************************/
+#define FILE_NAME_TEXT_FIELD edt1
+#define FILE_NAME_COMBO_BOX cmb13
+#define FILE_NAME_LIST lst1
+
+#ifdef NTGUI_UNICODE
+#define GUISTR(x) (L ## x)
+typedef wchar_t guichar_t;
+#else /* !NTGUI_UNICODE */
+#define GUISTR(x) x
+typedef char guichar_t;
+#endif /* NTGUI_UNICODE */
+
/* Callback for altering the behavior of the Open File dialog.
Makes the Filename text field contain "Current Directory" and be
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)
{
- OFNOTIFY * notify = (OFNOTIFY *)lParam;
+#ifdef NTGUI_UNICODE
+ OFNOTIFYW * notify = (OFNOTIFYW *)lParam;
+#else /* !NTGUI_UNICODE */
+ OFNOTIFYA * notify = (OFNOTIFYA *)lParam;
+#endif /* NTGUI_UNICODE */
/* Detect when the Filter dropdown is changed. */
if (notify->hdr.code == CDN_TYPECHANGE
|| notify->hdr.code == CDN_INITDONE)
if (notify->lpOFN->nFilterIndex == 2)
{
CommDlg_OpenSave_SetControlText (dialog, FILE_NAME_TEXT_FIELD,
- "Current Directory");
+ GUISTR ("Current Directory"));
EnableWindow (edit_control, FALSE);
/* Note that at least on Windows 7, the above call to EnableWindow
disables the window that would ordinarily have focus. If we
/* Don't override default filename on init done. */
if (notify->hdr.code == CDN_TYPECHANGE)
CommDlg_OpenSave_SetControlText (dialog,
- FILE_NAME_TEXT_FIELD, "");
+ FILE_NAME_TEXT_FIELD,
+ GUISTR (""));
EnableWindow (edit_control, TRUE);
}
}
return 0;
}
-/* Since we compile with _WIN32_WINNT set to 0x0400 (for NT4 compatibility)
- we end up with the old file dialogs. Define a big enough struct for the
- new dialog to trick GetOpenFileName into giving us the new dialogs on
- Windows 2000 and XP. */
-typedef struct
-{
- OPENFILENAME real_details;
- void * pReserved;
- DWORD dwReserved;
- DWORD FlagsEx;
-} NEWOPENFILENAME;
-
-
DEFUN ("x-file-dialog", Fx_file_dialog, Sx_file_dialog, 2, 5, 0,
doc: /* Read file name, prompting with PROMPT in directory DIR.
Use a file selection dialog. Select DEFAULT-FILENAME in the dialog's file
selection box, if specified. If MUSTMATCH is non-nil, the returned file
or directory must exist.
-This function is only defined on MS Windows, and X Windows with the
+This function is only defined on NS, MS Windows, and X Windows with the
Motif or Gtk toolkits. With the Motif toolkit, ONLY-DIR-P is ignored.
Otherwise, if ONLY-DIR-P is non-nil, the user can only select directories. */)
(Lisp_Object prompt, Lisp_Object dir, Lisp_Object default_filename, Lisp_Object mustmatch, Lisp_Object only_dir_p)
{
+ /* Filter index: 1: All Files, 2: Directories only */
+ static const guichar_t filter[] =
+ GUISTR ("All Files (*.*)\0*.*\0Directories\0*|*\0");
+
+ Lisp_Object filename = default_filename;
struct frame *f = SELECTED_FRAME ();
- Lisp_Object file = Qnil;
- ptrdiff_t count = SPECPDL_INDEX ();
+ BOOL file_opened = FALSE;
+ Lisp_Object orig_dir = dir;
+ Lisp_Object orig_prompt = prompt;
+
+ /* If we compile with _WIN32_WINNT set to 0x0400 (for NT4
+ compatibility) we end up with the old file dialogs. Define a big
+ enough struct for the new dialog to trick GetOpenFileName into
+ giving us the new dialogs on newer versions of Windows. */
+ struct {
+#ifdef NTGUI_UNICODE
+ OPENFILENAMEW details;
+#else /* !NTGUI_UNICODE */
+ OPENFILENAMEA details;
+#endif /* NTGUI_UNICODE */
+
+#if _WIN32_WINNT < 0x500 /* < win2k */
+ PVOID pvReserved;
+ DWORD dwReserved;
+ DWORD FlagsEx;
+#endif /* < win2k */
+ } new_file_details;
+
+#ifdef NTGUI_UNICODE
+ wchar_t filename_buf[32*1024 + 1]; // NT kernel maximum
+ OPENFILENAMEW * file_details = &new_file_details.details;
+#else /* not NTGUI_UNICODE */
+ char filename_buf[MAX_PATH + 1];
+ OPENFILENAMEA * file_details = &new_file_details.details;
+#endif /* NTGUI_UNICODE */
+
struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5, gcpro6;
- char filename[MAX_PATH + 1];
- char init_dir[MAX_PATH + 1];
- int default_filter_index = 1; /* 1: All Files, 2: Directories only */
-
- GCPRO6 (prompt, dir, default_filename, mustmatch, only_dir_p, file);
- CHECK_STRING (prompt);
- CHECK_STRING (dir);
-
- /* Create the dialog with PROMPT as title, using DIR as initial
- directory and using "*" as pattern. */
- dir = Fexpand_file_name (dir, Qnil);
- strncpy (init_dir, SDATA (ENCODE_FILE (dir)), MAX_PATH);
- init_dir[MAX_PATH] = '\0';
- unixtodos_filename (init_dir);
-
- if (STRINGP (default_filename))
- {
- char *file_name_only;
- char *full_path_name = SDATA (ENCODE_FILE (default_filename));
+ GCPRO6 (prompt, dir, default_filename, mustmatch, only_dir_p, filename);
- unixtodos_filename (full_path_name);
+ {
+ struct gcpro gcpro1, gcpro2;
+ GCPRO2 (orig_dir, orig_prompt); /* There is no GCPRON, N>6. */
- file_name_only = strrchr (full_path_name, '\\');
- if (!file_name_only)
- file_name_only = full_path_name;
- else
- file_name_only++;
+ /* 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
+ by the Windows "ANSI" APIs! */
- strncpy (filename, file_name_only, MAX_PATH);
- filename[MAX_PATH] = '\0';
- }
- else
- filename[0] = '\0';
+ CHECK_STRING (prompt);
+ CHECK_STRING (dir);
- /* The code in file_dialog_callback that attempts to set the text
- of the file name edit window when handling the CDN_INITDONE
- WM_NOTIFY message does not work. Setting filename to "Current
- Directory" in the only_dir_p case here does work however. */
- if (filename[0] == 0 && ! NILP (only_dir_p))
- strcpy (filename, "Current Directory");
+ dir = Fexpand_file_name (dir, Qnil);
- {
- NEWOPENFILENAME new_file_details;
- BOOL file_opened = FALSE;
- OPENFILENAME * file_details = &new_file_details.real_details;
+ if (STRINGP (filename))
+ filename = Ffile_name_nondirectory (filename);
+ else
+ filename = empty_unibyte_string;
- /* Prevent redisplay. */
- specbind (Qinhibit_redisplay, Qt);
- BLOCK_INPUT;
+#ifdef CYGWIN
+ dir = Fcygwin_convert_file_name_to_windows (dir, Qt);
+ if (SCHARS (filename) > 0)
+ filename = Fcygwin_convert_file_name_to_windows (filename, Qnil);
+#endif
+ CHECK_STRING (dir);
+ CHECK_STRING (filename);
+
+ /* The code in file_dialog_callback that attempts to set the text
+ of the file name edit window when handling the CDN_INITDONE
+ WM_NOTIFY message does not work. Setting filename to "Current
+ Directory" in the only_dir_p case here does work however. */
+ if (SCHARS (filename) == 0 && ! NILP (only_dir_p))
+ filename = build_string ("Current Directory");
+
+ /* Convert the values we've computed so far to system form. */
+#ifdef NTGUI_UNICODE
+ to_unicode (prompt, &prompt);
+ to_unicode (dir, &dir);
+ to_unicode (filename, &filename);
+#else /* !NTGUI_UNICODE */
+ prompt = ENCODE_FILE (prompt);
+ dir = ENCODE_FILE (dir);
+ filename = ENCODE_FILE (filename);
+
+ /* We modify these in-place, so make copies for safety. */
+ dir = Fcopy_sequence (dir);
+ unixtodos_filename (SDATA (dir));
+ filename = Fcopy_sequence (filename);
+ unixtodos_filename (SDATA (filename));
+#endif /* NTGUI_UNICODE */
+
+ /* Fill in the structure for the call to GetOpenFileName below.
+ For NTGUI_UNICODE builds (which run only on NT), we just use
+ the actual size of the structure. For non-NTGUI_UNICODE
+ builds, we tell the OS we're using an old version of the
+ structure if the OS isn't new enough to support the newer
+ version. */
memset (&new_file_details, 0, sizeof (new_file_details));
- /* Apparently NT4 crashes if you give it an unexpected size.
- I'm not sure about Windows 9x, so play it safe. */
+
if (w32_major_version > 4 && w32_major_version < 95)
- file_details->lStructSize = sizeof (NEWOPENFILENAME);
+ file_details->lStructSize = sizeof (new_file_details);
else
- file_details->lStructSize = sizeof (OPENFILENAME);
+ file_details->lStructSize = sizeof (*file_details);
+
+ /* Set up the inout parameter for the selected file name. */
+ if (SBYTES (filename) + 1 > sizeof (filename_buf))
+ report_file_error ("filename too long", default_filename);
+
+ memcpy (filename_buf, SDATA (filename), SBYTES (filename) + 1);
+ file_details->lpstrFile = filename_buf;
+ file_details->nMaxFile = sizeof (filename_buf) / sizeof (*filename_buf);
file_details->hwndOwner = FRAME_W32_WINDOW (f);
/* Undocumented Bug in Common File Dialog:
If a filter is not specified, shell links are not resolved. */
- file_details->lpstrFilter = "All Files (*.*)\0*.*\0Directories\0*|*\0\0";
- file_details->lpstrFile = filename;
- file_details->nMaxFile = sizeof (filename);
- file_details->lpstrInitialDir = init_dir;
- file_details->lpstrTitle = SDATA (prompt);
-
- if (! NILP (only_dir_p))
- default_filter_index = 2;
-
- file_details->nFilterIndex = default_filter_index;
-
+ file_details->lpstrFilter = filter;
+ file_details->lpstrInitialDir = (guichar_t*) SDATA (dir);
+ file_details->lpstrTitle = (guichar_t*) SDATA (prompt);
+ file_details->nFilterIndex = NILP (only_dir_p) ? 1 : 2;
file_details->Flags = (OFN_HIDEREADONLY | OFN_NOCHANGEDIR
- | OFN_EXPLORER | OFN_ENABLEHOOK);
+ | OFN_EXPLORER | OFN_ENABLEHOOK);
+
if (!NILP (mustmatch))
{
- /* Require that the path to the parent directory exists. */
- file_details->Flags |= OFN_PATHMUSTEXIST;
- /* If we are looking for a file, require that it exists. */
- if (NILP (only_dir_p))
- file_details->Flags |= OFN_FILEMUSTEXIST;
+ /* Require that the path to the parent directory exists. */
+ file_details->Flags |= OFN_PATHMUSTEXIST;
+ /* If we are looking for a file, require that it exists. */
+ if (NILP (only_dir_p))
+ file_details->Flags |= OFN_FILEMUSTEXIST;
}
- file_details->lpfnHook = (LPOFNHOOKPROC) file_dialog_callback;
-
- file_opened = GetOpenFileName (file_details);
-
- UNBLOCK_INPUT;
+ {
+ int count = SPECPDL_INDEX ();
+ /* Prevent redisplay. */
+ specbind (Qinhibit_redisplay, Qt);
+ block_input ();
+ file_details->lpfnHook = file_dialog_callback;
+
+#ifdef NTGUI_UNICODE
+ file_opened = GetOpenFileNameW (file_details);
+#else /* !NTGUI_UNICODE */
+ file_opened = GetOpenFileNameA (file_details);
+#endif /* NTGUI_UNICODE */
+ unblock_input ();
+ unbind_to (count, Qnil);
+ }
if (file_opened)
{
- dostounix_filename (filename);
-
- if (file_details->nFilterIndex == 2)
- {
- /* "Directories" selected - strip dummy file name. */
- char * last = strrchr (filename, '/');
- *last = '\0';
- }
-
- file = DECODE_FILE (build_string (filename));
+ /* Get an Emacs string from the value Windows gave us. */
+#ifdef NTGUI_UNICODE
+ filename = from_unicode (
+ make_unibyte_string (
+ (char*) filename_buf,
+ /* 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);
+ filename = DECODE_FILE (build_string (filename_buf));
+#endif /* NTGUI_UNICODE */
+
+#ifdef CYGWIN
+ filename = Fcygwin_convert_file_name_from_windows (filename, Qt);
+#endif /* CYGWIN */
+
+ /* Strip the dummy filename off the end of the string if we
+ added it to select a directory. */
+ if (file_details->nFilterIndex == 2)
+ {
+ filename = Ffile_name_directory (filename);
+ }
}
/* User canceled the dialog without making a selection. */
else if (!CommDlgExtendedError ())
- file = Qnil;
+ filename = Qnil;
/* An error occurred, fallback on reading from the mini-buffer. */
else
- file = Fcompleting_read (prompt, intern ("read-file-name-internal"),
- dir, mustmatch, dir, Qfile_name_history,
- default_filename, Qnil);
+ filename = Fcompleting_read (
+ orig_prompt,
+ intern ("read-file-name-internal"),
+ orig_dir,
+ mustmatch,
+ orig_dir,
+ Qfile_name_history,
+ default_filename,
+ Qnil);
- file = unbind_to (count, file);
+ UNGCPRO;
}
- UNGCPRO;
-
/* Make "Cancel" equivalent to C-g. */
- if (NILP (file))
+ if (NILP (filename))
Fsignal (Qquit, Qnil);
- return unbind_to (count, file);
+ RETURN_UNGCPRO (filename);
}
-
+\f
+#ifdef WINDOWSNT
/* Moving files to the system recycle bin.
Used by `move-file-to-trash' instead of the default moving to ~/.Trash */
DEFUN ("system-move-file-to-trash", Fsystem_move_file_to_trash,
return Qnil;
}
+#endif /* WINDOWSNT */
+
\f
/***********************************************************************
w32 specialized functions
lisp_modifiers = XINT (Fcar (Fcdr (c)));
c = Fcar (c);
if (!SYMBOLP (c))
- abort ();
+ emacs_abort ();
vk_code = lookup_vk_code (SDATA (SYMBOL_NAME (c)));
}
else if (INTEGERP (c))
else
{
char buffer[16];
- _snprintf (buffer, 16, "%d", system_status.BatteryLifePercent);
+ snprintf (buffer, 16, "%d", system_status.BatteryLifePercent);
load_percentage = build_string (buffer);
}
long m;
float h;
char buffer[16];
- _snprintf (buffer, 16, "%ld", seconds_left);
+ snprintf (buffer, 16, "%ld", seconds_left);
seconds = build_string (buffer);
m = seconds_left / 60;
- _snprintf (buffer, 16, "%ld", m);
+ snprintf (buffer, 16, "%ld", m);
minutes = build_string (buffer);
h = seconds_left / 3600.0;
- _snprintf (buffer, 16, "%3.1f", h);
+ snprintf (buffer, 16, "%3.1f", h);
hours = build_string (buffer);
- _snprintf (buffer, 16, "%ld:%02ld", m / 60, m % 60);
+ snprintf (buffer, 16, "%ld:%02ld", m / 60, m % 60);
remain = build_string (buffer);
}
{
/* a remote printer */
if (*ppi2->pServerName == '\\')
- _snprintf (pname_buf, sizeof (pname_buf), "%s\\%s", ppi2->pServerName,
+ snprintf (pname_buf, sizeof (pname_buf), "%s\\%s", ppi2->pServerName,
ppi2->pShareName);
else
- _snprintf (pname_buf, sizeof (pname_buf), "\\\\%s\\%s", ppi2->pServerName,
+ snprintf (pname_buf, sizeof (pname_buf), "\\\\%s\\%s", ppi2->pServerName,
ppi2->pShareName);
pname_buf[sizeof (pname_buf) - 1] = '\0';
}
return build_string (pname_buf);
}
+\f
+
+/* Equivalent of strerror for W32 error codes. */
+char *
+w32_strerror (int error_no)
+{
+ static char buf[500];
+ DWORD ret;
+
+ if (error_no == 0)
+ error_no = GetLastError ();
+
+ ret = FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ error_no,
+ 0, /* choose most suitable language */
+ buf, sizeof (buf), NULL);
+
+ while (ret > 0 && (buf[ret - 1] == '\n' ||
+ buf[ret - 1] == '\r' ))
+ --ret;
+ buf[ret] = '\0';
+ if (!ret)
+ sprintf (buf, "w32 error %u", error_no);
+
+ return buf;
+}
+
+/* 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)
+{
+ return GetLastError ();
+}
+
+/* Cache information describing the NT system for later use. */
+void
+cache_system_info (void)
+{
+ union
+ {
+ struct info
+ {
+ char major;
+ char minor;
+ short platform;
+ } info;
+ DWORD data;
+ } version;
+
+ /* Cache the version of the operating system. */
+ version.data = GetVersion ();
+ w32_major_version = version.info.major;
+ w32_minor_version = version.info.minor;
+
+ if (version.info.platform & 0x8000)
+ os_subtype = OS_9X;
+ else
+ os_subtype = OS_NT;
+
+ /* Cache page size, allocation unit, processor type, etc. */
+ GetSystemInfo (&sysinfo_cache);
+ syspage_mask = (DWORD_PTR)sysinfo_cache.dwPageSize - 1;
+
+ /* Cache os info. */
+ osinfo_cache.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
+ GetVersionEx (&osinfo_cache);
+
+ w32_build_number = osinfo_cache.dwBuildNumber;
+ if (os_subtype == OS_9X)
+ w32_build_number &= 0xffff;
+
+ w32_num_mouse_buttons = GetSystemMetrics (SM_CMOUSEBUTTONS);
+}
+
+#ifdef EMACSDEBUG
+void
+_DebPrint (const char *fmt, ...)
+{
+ char buf[1024];
+ va_list args;
+
+ va_start (args, fmt);
+ vsprintf (buf, fmt, args);
+ va_end (args);
+#if CYGWIN
+ fprintf (stderr, "%s", buf);
+#endif
+ OutputDebugString (buf);
+}
+#endif
+
+int
+w32_console_toggle_lock_key (int vk_code, Lisp_Object new_state)
+{
+ int cur_state = (GetKeyState (vk_code) & 1);
+
+ if (NILP (new_state)
+ || (NUMBERP (new_state)
+ && ((XUINT (new_state)) & 1) != cur_state))
+ {
+#ifdef WINDOWSNT
+ faked_key = vk_code;
+#endif /* WINDOWSNT */
+
+ keybd_event ((BYTE) vk_code,
+ (BYTE) MapVirtualKey (vk_code, 0),
+ KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
+ keybd_event ((BYTE) vk_code,
+ (BYTE) MapVirtualKey (vk_code, 0),
+ KEYEVENTF_EXTENDEDKEY | 0, 0);
+ keybd_event ((BYTE) vk_code,
+ (BYTE) MapVirtualKey (vk_code, 0),
+ KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
+ cur_state = !cur_state;
+ }
+
+ return cur_state;
+}
+
+/* Translate console modifiers to emacs modifiers.
+ German keyboard support (Kai Morgan Zeise 2/18/95). */
+int
+w32_kbd_mods_to_emacs (DWORD mods, WORD key)
+{
+ int retval = 0;
+
+ /* If we recognize right-alt and left-ctrl as AltGr, and it has been
+ pressed, first remove those modifiers. */
+ if (!NILP (Vw32_recognize_altgr)
+ && (mods & (RIGHT_ALT_PRESSED | LEFT_CTRL_PRESSED))
+ == (RIGHT_ALT_PRESSED | LEFT_CTRL_PRESSED))
+ mods &= ~ (RIGHT_ALT_PRESSED | LEFT_CTRL_PRESSED);
+
+ if (mods & (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED))
+ retval = ((NILP (Vw32_alt_is_meta)) ? alt_modifier : meta_modifier);
+
+ if (mods & (RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED))
+ {
+ retval |= ctrl_modifier;
+ if ((mods & (RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED))
+ == (RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED))
+ retval |= meta_modifier;
+ }
+
+ if (mods & LEFT_WIN_PRESSED)
+ retval |= w32_key_to_modifier (VK_LWIN);
+ if (mods & RIGHT_WIN_PRESSED)
+ retval |= w32_key_to_modifier (VK_RWIN);
+ if (mods & APPS_PRESSED)
+ retval |= w32_key_to_modifier (VK_APPS);
+ if (mods & SCROLLLOCK_ON)
+ retval |= w32_key_to_modifier (VK_SCROLL);
+
+ /* Just in case someone wanted the original behavior, make it
+ optional by setting w32-capslock-is-shiftlock to t. */
+ if (NILP (Vw32_capslock_is_shiftlock)
+ /* Keys that should _not_ be affected by CapsLock. */
+ && ( (key == VK_BACK)
+ || (key == VK_TAB)
+ || (key == VK_CLEAR)
+ || (key == VK_RETURN)
+ || (key == VK_ESCAPE)
+ || ((key >= VK_SPACE) && (key <= VK_HELP))
+ || ((key >= VK_NUMPAD0) && (key <= VK_F24))
+ || ((key >= VK_NUMPAD_CLEAR) && (key <= VK_NUMPAD_DELETE))
+ ))
+ {
+ /* Only consider shift state. */
+ if ((mods & SHIFT_PRESSED) != 0)
+ retval |= shift_modifier;
+ }
+ else
+ {
+ /* Ignore CapsLock state if not enabled. */
+ if (NILP (Vw32_enable_caps_lock))
+ mods &= ~CAPSLOCK_ON;
+ if ((mods & (SHIFT_PRESSED | CAPSLOCK_ON)) != 0)
+ retval |= shift_modifier;
+ }
+
+ return retval;
+}
+
+/* The return code indicates key code size. cpID is the codepage to
+ use for translation to Unicode; -1 means use the current console
+ input codepage. */
+int
+w32_kbd_patch_key (KEY_EVENT_RECORD *event, int cpId)
+{
+ unsigned int key_code = event->wVirtualKeyCode;
+ unsigned int mods = event->dwControlKeyState;
+ BYTE keystate[256];
+ static BYTE ansi_code[4];
+ static int isdead = 0;
+
+ if (isdead == 2)
+ {
+ event->uChar.AsciiChar = ansi_code[2];
+ isdead = 0;
+ return 1;
+ }
+ if (event->uChar.AsciiChar != 0)
+ return 1;
+
+ memset (keystate, 0, sizeof (keystate));
+ keystate[key_code] = 0x80;
+ if (mods & SHIFT_PRESSED)
+ keystate[VK_SHIFT] = 0x80;
+ if (mods & CAPSLOCK_ON)
+ keystate[VK_CAPITAL] = 1;
+ /* If we recognize right-alt and left-ctrl as AltGr, set the key
+ states accordingly before invoking ToAscii. */
+ if (!NILP (Vw32_recognize_altgr)
+ && (mods & LEFT_CTRL_PRESSED) && (mods & RIGHT_ALT_PRESSED))
+ {
+ keystate[VK_CONTROL] = 0x80;
+ keystate[VK_LCONTROL] = 0x80;
+ keystate[VK_MENU] = 0x80;
+ keystate[VK_RMENU] = 0x80;
+ }
+
+#if 0
+ /* Because of an OS bug, ToAscii corrupts the stack when called to
+ convert a dead key in console mode on NT4. Unfortunately, trying
+ to check for dead keys using MapVirtualKey doesn't work either -
+ these functions apparently use internal information about keyboard
+ layout which doesn't get properly updated in console programs when
+ changing layout (though apparently it gets partly updated,
+ otherwise ToAscii wouldn't crash). */
+ if (is_dead_key (event->wVirtualKeyCode))
+ return 0;
+#endif
+
+ /* On NT, call ToUnicode instead and then convert to the current
+ console input codepage. */
+ if (os_subtype == OS_NT)
+ {
+ WCHAR buf[128];
+
+ isdead = ToUnicode (event->wVirtualKeyCode, event->wVirtualScanCode,
+ keystate, buf, 128, 0);
+ if (isdead > 0)
+ {
+ /* When we are called from the GUI message processing code,
+ we are passed the current keyboard codepage, a positive
+ number, to use below. */
+ if (cpId == -1)
+ cpId = GetConsoleCP ();
+
+ event->uChar.UnicodeChar = buf[isdead - 1];
+ isdead = WideCharToMultiByte (cpId, 0, buf, isdead,
+ ansi_code, 4, NULL, NULL);
+ }
+ else
+ isdead = 0;
+ }
+ else
+ {
+ isdead = ToAscii (event->wVirtualKeyCode, event->wVirtualScanCode,
+ keystate, (LPWORD) ansi_code, 0);
+ }
+
+ if (isdead == 0)
+ return 0;
+ event->uChar.AsciiChar = ansi_code[0];
+ return isdead;
+}
+
+
+void
+w32_sys_ring_bell (struct frame *f)
+{
+ if (sound_type == 0xFFFFFFFF)
+ {
+ Beep (666, 100);
+ }
+ else if (sound_type == MB_EMACS_SILENT)
+ {
+ /* Do nothing. */
+ }
+ else
+ MessageBeep (sound_type);
+}
+
\f
/***********************************************************************
Initialization
defsubr (&Sfile_system_info);
defsubr (&Sdefault_printer_name);
+ defsubr (&Sset_message_beep);
check_window_system_func = check_w32;
-
- hourglass_timer = 0;
hourglass_hwnd = NULL;
defsubr (&Sx_show_tip);
staticpro (&last_show_tip_args);
defsubr (&Sx_file_dialog);
+#ifdef WINDOWSNT
defsubr (&Ssystem_move_file_to_trash);
+#endif
}
syms_of_w32uniscribe ();
}
-#undef abort
-
void
-w32_abort (void)
+emacs_abort (void)
{
int button;
button = MessageBox (NULL,
break;
}
}
-
-/* For convenience when debugging. */
-int
-w32_last_error (void)
-{
- return GetLastError ();
-}