#include <limits.h>
#include <errno.h>
#include <math.h>
-#include <setjmp.h>
#include "lisp.h"
#include "w32term.h"
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
#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
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);
}
{
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 ();
}
{
register Lisp_Object ret = Qnil;
- BLOCK_INPUT;
+ block_input ();
if (colorname[0] == '#')
{
pos += 0x8;
if (i == 2)
{
- UNBLOCK_INPUT;
+ unblock_input ();
XSETINT (ret, colorval);
return ret;
}
{
if (*end != '\0')
break;
- UNBLOCK_INPUT;
+ unblock_input ();
XSETINT (ret, colorval);
return ret;
}
{
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
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 (STRING_MULTIBYTE (name))
name = ENCODE_SYSTEM (name);
- BLOCK_INPUT;
+ block_input ();
SetWindowText (FRAME_W32_WINDOW (f), SDATA (name));
- UNBLOCK_INPUT;
+ unblock_input ();
}
}
if (STRING_MULTIBYTE (name))
name = ENCODE_SYSTEM (name);
- BLOCK_INPUT;
+ block_input ();
SetWindowText (FRAME_W32_WINDOW (f), SDATA (name));
- UNBLOCK_INPUT;
+ unblock_input ();
}
}
}
#endif /* EMACSDEBUG */
+/* Here's an overview of how Emacs input works on MS-Windows.
+
+ 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);
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 ();
GC. */
XSETCAR ((Lisp_Object) ((EMACS_INT) msg.lParam), Qnil);
if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
- abort ();
+ emacs_abort ();
break;
case WM_EMACS_TOGGLE_LOCK_KEY:
{
}
if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE,
cur_state, 0))
- abort ();
+ emacs_abort ();
}
break;
#ifdef MSG_DEBUG
{
/* 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;
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
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 ();
}
/* 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
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
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. */
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);
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)
{
int count = SPECPDL_INDEX ();
specbind (Qinhibit_redisplay, Qt);
- BLOCK_INPUT;
+ block_input ();
file_details->lpfnHook = file_dialog_callback;
#ifdef NTGUI_UNICODE
#else /* !NTGUI_UNICODE */
file_opened = GetOpenFileNameA (file_details);
#endif /* NTGUI_UNICODE */
- UNBLOCK_INPUT;
+ unblock_input ();
unbind_to (count, Qnil);
}
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))
check_window_system_func = check_w32;
- hourglass_timer = 0;
hourglass_hwnd = NULL;
defsubr (&Sx_show_tip);
syms_of_w32uniscribe ();
}
-#undef abort
-
void
-w32_abort (void)
+emacs_abort (void)
{
int button;
button = MessageBox (NULL,