/* Keyboard and mouse input; editor command loop.
- Copyright (C) 1985,86,87,88,89,93,94,95,96,97,99, 2000
+ Copyright (C) 1985,86,87,88,89,93,94,95,96,97,99, 2000, 2001
Free Software Foundation, Inc.
This file is part of GNU Emacs.
#include "lisp.h"
#include "termhooks.h"
#include "macros.h"
+#include "keyboard.h"
#include "frame.h"
#include "window.h"
#include "commands.h"
#include "charset.h"
#include "disptab.h"
#include "dispextern.h"
-#include "keyboard.h"
#include "syntax.h"
#include "intervals.h"
#include "blockinput.h"
#include "w32term.h"
#endif /* HAVE_NTGUI */
+#ifdef macintosh
+#include "macterm.h"
+#endif
+
/* Include systime.h after xterm.h to avoid double inclusion of time.h. */
#include "systime.h"
+#ifndef USE_CRT_DLL
extern int errno;
+#endif
/* Variables for blockinput.h: */
#ifdef HAVE_WINDOW_SYSTEM
/* Make all keyboard buffers much bigger when using X windows. */
#ifdef macintosh
-/* But not too big (local data > 32K error) if on macintosh */
+/* But not too big (local data > 32K error) if on macintosh. */
#define KBD_BUFFER_SIZE 512
#else
#define KBD_BUFFER_SIZE 4096
/* True while displaying for echoing. Delays C-g throwing. */
-static int echoing;
+int echoing;
/* Non-null means we can start echoing at the next input pause even
though there is something in the echo area. */
/* The buffer used for echoing. Set in echo_now, reset in
cancel_echoing. */
-static Lisp_Object echo_message_buffer;
+Lisp_Object echo_message_buffer;
/* Nonzero means disregard local maps for the menu bar. */
static int inhibit_local_menu_bar_menus;
If the value is non-nil and not a number, we wait 2 seconds. */
Lisp_Object Vsuggest_key_bindings;
+/* How long to display an echo-area message when the minibuffer is active.
+ If the value is not a number, such messages don't time out. */
+Lisp_Object Vminibuffer_message_timeout;
+
/* Character that causes a quit. Normally C-g.
If we are running on an ordinary terminal, this must be an ordinary
int meta_key;
+/* Non-zero means force key bindings update in parse_menu_item. */
+
+int update_menu_bindings;
+
extern char *pending_malloc_warning;
/* Circular buffer for pre-read keyboard input. */
/* If this flag is non-nil, we check mouse_moved to see when the
mouse moves, and motion events will appear in the input stream.
Otherwise, mouse motion is ignored. */
-static Lisp_Object do_mouse_tracking;
+Lisp_Object do_mouse_tracking;
/* Symbols to head events. */
Lisp_Object Qmouse_movement;
Lisp_Object Vglobal_disable_point_adjustment;
+/* The time when Emacs started being idle. */
+
+static EMACS_TIME timer_idleness_start_time;
+
\f
/* Global variable declarations. */
/* Function for init_keyboard to call with no args (if nonzero). */
void (*keyboard_init_hook) ();
-static int read_avail_input ();
-static void get_input_pending ();
-static int readable_events ();
+static int read_avail_input P_ ((int));
+static void get_input_pending P_ ((int *, int));
+static int readable_events P_ ((int));
+static Lisp_Object read_char_x_menu_prompt P_ ((int, Lisp_Object *,
+ Lisp_Object, int *));
static Lisp_Object read_char_x_menu_prompt ();
-static Lisp_Object read_char_minibuf_menu_prompt ();
-static Lisp_Object make_lispy_event ();
+static Lisp_Object read_char_minibuf_menu_prompt P_ ((int, int,
+ Lisp_Object *));
+static Lisp_Object make_lispy_event P_ ((struct input_event *));
#ifdef HAVE_MOUSE
-static Lisp_Object make_lispy_movement ();
+static Lisp_Object make_lispy_movement P_ ((struct frame *, Lisp_Object,
+ enum scroll_bar_part,
+ Lisp_Object, Lisp_Object,
+ unsigned long));
#endif
-static Lisp_Object modify_event_symbol ();
-static Lisp_Object make_lispy_switch_frame ();
+static Lisp_Object modify_event_symbol P_ ((int, unsigned, Lisp_Object,
+ Lisp_Object, char **,
+ Lisp_Object *, unsigned));
+static Lisp_Object make_lispy_switch_frame P_ ((Lisp_Object));
+static int parse_solitary_modifier P_ ((Lisp_Object));
static int parse_solitary_modifier ();
+static void save_getcjmp P_ ((jmp_buf));
static void save_getcjmp ();
-static void restore_getcjmp ();
+static void restore_getcjmp P_ ((jmp_buf));
static Lisp_Object apply_modifiers P_ ((int, Lisp_Object));
+static void clear_event P_ ((struct input_event *));
/* Nonzero means don't try to suspend even if the operating system seems
to support it. */
void
echo_prompt (str)
- char *str;
+ Lisp_Object str;
{
- int len = strlen (str);
+ int nbytes = STRING_BYTES (XSTRING (str));
+ int multibyte_p = STRING_MULTIBYTE (str);
- if (len > ECHOBUFSIZE - 4)
- len = ECHOBUFSIZE - 4;
- bcopy (str, current_kboard->echobuf, len);
- current_kboard->echoptr = current_kboard->echobuf + len;
- *current_kboard->echoptr = '\0';
+ if (nbytes > ECHOBUFSIZE - 4)
+ {
+ if (multibyte_p)
+ {
+ /* Have to find the last character that fit's into the
+ echo buffer. */
+ unsigned char *p = XSTRING (str)->data;
+ unsigned char *pend = p + ECHOBUFSIZE - 4;
+ int char_len;
+
+ do
+ {
+ PARSE_MULTIBYTE_SEQ (p, pend - p, char_len);
+ p += char_len;
+ }
+ while (p < pend);
- current_kboard->echo_after_prompt = len;
+ nbytes = p - XSTRING (str)->data - char_len;
+ }
+ else
+ nbytes = ECHOBUFSIZE - 4;
+ }
+
+ nbytes = copy_text (XSTRING (str)->data, current_kboard->echobuf, nbytes,
+ STRING_MULTIBYTE (str), 1);
+ current_kboard->echoptr = current_kboard->echobuf + nbytes;
+ *current_kboard->echoptr = '\0';
+ current_kboard->echo_after_prompt = nbytes;
echo_now ();
}
echo_char (c)
Lisp_Object c;
{
- extern char *push_key_description ();
-
if (current_kboard->immediate_echo)
{
char *ptr = current_kboard->echoptr;
if (INTEGERP (c))
{
+ int ch = XINT (c);
+
if (ptr - current_kboard->echobuf
> ECHOBUFSIZE - KEY_DESCRIPTION_SIZE)
return;
- ptr = push_key_description (XINT (c), ptr);
+ ptr = push_key_description (ch, ptr, 1);
}
else if (SYMBOLP (c))
{
if ((ptr - current_kboard->echobuf) + STRING_BYTES (name) + 4
> ECHOBUFSIZE)
return;
- bcopy (name->data, ptr, STRING_BYTES (name));
- ptr += STRING_BYTES (name);
+ ptr += copy_text (name->data, ptr, STRING_BYTES (name),
+ name->size_byte >= 0, 1);
}
if (current_kboard->echoptr == current_kboard->echobuf
echoing = 1;
message2_nolog (current_kboard->echobuf, strlen (current_kboard->echobuf),
- ! NILP (current_buffer->enable_multibyte_characters));
+ 1);
echoing = 0;
/* Record in what buffer we echoed, and from which kboard. */
}
#ifdef HAVE_X_WINDOWS
- /* The command loop has started a busy-cursor timer, so we have to
+ /* The command loop has started an hourglass timer, so we have to
cancel it here, otherwise it will fire because the recursive edit
can take some time. */
- if (display_busy_cursor_p)
- cancel_busy_cursor ();
+ if (display_hourglass_p)
+ cancel_hourglass ();
#endif
+ /* This function may have been called from a debugger called from
+ within redisplay, for instance by Edebugging a function called
+ from fontification-functions. We want to allow redisplay in
+ the debugging session.
+
+ The recursive edit is left with a `(throw exit ...)'. The `exit'
+ tag is not caught anywhere in redisplay, i.e. when we leave the
+ recursive edit, the original redisplay leading to the recursive
+ edit will be unwound. The outcome should therefore be safe. */
+ specbind (Qinhibit_redisplay, Qnil);
+ redisplaying_p = 0;
+
val = command_loop ();
if (EQ (val, Qt))
Fsignal (Qquit, Qnil);
()
{
#ifdef HAVE_X_WINDOWS
- if (display_busy_cursor_p)
- cancel_busy_cursor ();
+ if (display_hourglass_p)
+ cancel_hourglass ();
#endif
- Fthrow (Qtop_level, Qnil);
+ return Fthrow (Qtop_level, Qnil);
}
DEFUN ("exit-recursive-edit", Fexit_recursive_edit, Sexit_recursive_edit, 0, 0, "",
Fthrow (Qexit, Qnil);
error ("No recursive edit is in progress");
+ return Qnil;
}
DEFUN ("abort-recursive-edit", Fabort_recursive_edit, Sabort_recursive_edit, 0, 0, "",
Fthrow (Qexit, Qt);
error ("No recursive edit is in progress");
+ return Qnil;
}
\f
/* This is the actual command reading loop,
sans error-handling encapsulation. */
-Lisp_Object Fcommand_execute ();
-static int read_key_sequence ();
-void safe_run_hooks ();
-static void adjust_point_for_property ();
+EXFUN (Fcommand_execute, 4);
+static int read_key_sequence P_ ((Lisp_Object *, int, Lisp_Object,
+ int, int, int));
+void safe_run_hooks P_ ((Lisp_Object));
+static void adjust_point_for_property P_ ((int));
Lisp_Object
command_loop_1 ()
int i;
int no_direct;
int prev_modiff;
- struct buffer *prev_buffer;
+ struct buffer *prev_buffer = NULL;
#ifdef MULTI_KBOARD
int was_locked = single_kboard;
#endif
Vdeactivate_mark = Qnil;
/* If minibuffer on and echo area in use,
- wait 2 sec and redraw minibuffer. */
+ wait a short time and redraw minibuffer. */
if (minibuf_level
&& !NILP (echo_area_buffer[0])
- && EQ (minibuf_window, echo_area_window))
+ && EQ (minibuf_window, echo_area_window)
+ && NUMBERP (Vminibuffer_message_timeout))
{
/* Bind inhibit-quit to t so that C-g gets read in
rather than quitting back to the minibuffer. */
int count = specpdl_ptr - specpdl;
specbind (Qinhibit_quit, Qt);
- Fsit_for (make_number (2), Qnil, Qnil);
+ Fsit_for (Vminibuffer_message_timeout, Qnil, Qnil);
/* Clear the echo area. */
message2 (0, 0, 0);
safe_run_hooks (Qecho_area_clear_hook);
this variable differently. */
Vdisable_point_adjustment = Qnil;
+ /* Process filters and timers may have messed with deactivate-mark.
+ reset it before we execute the command. */
+ Vdeactivate_mark = Qnil;
+
/* Execute the command. */
Vthis_command = cmd;
/* Here for a command that isn't executed directly */
#ifdef HAVE_X_WINDOWS
- if (display_busy_cursor_p)
- start_busy_cursor ();
+ if (display_hourglass_p)
+ start_hourglass ();
#endif
nonundocount = 0;
Fcommand_execute (Vthis_command, Qnil, Qnil, Qnil);
#ifdef HAVE_X_WINDOWS
- if (display_busy_cursor_p)
- cancel_busy_cursor ();
+ if (display_hourglass_p)
+ cancel_hourglass ();
#endif
}
directly_done: ;
/* Display help echo in the echo area.
- MSG a string means display that string, MSG nil means clear the
- help echo. If MSG is neither a string nor nil, it is evaluated
- to obtain a string.
+ HELP a string means display that string, HELP nil means clear the
+ help echo. If HELP is a function, call it with OBJECT and POS as
+ arguments; the function should return a help string or nil for
+ none. For all other types of HELP evaluate it to obtain a string.
+
+ WINDOW is the window in which the help was generated, if any.
+ It is nil if not in a window.
+
+ If OBJECT is a buffer, POS is the position in the buffer where the
+ `help-echo' text property was found.
+
+ If OBJECT is an overlay, that overlay has a `help-echo' property,
+ and POS is the position in the overlay's buffer under the mouse.
+
+ If OBJECT is a string (an overlay string or a string displayed with
+ the `display' property). POS is the position in that string under
+ the mouse.
OK_TO_IVERWRITE_KEYSTROKE_ECHO non-zero means it's okay if the help
echo overwrites a keystroke echo currently displayed in the echo
area.
- Note: this function may only be called with MSG being nil or
- a string from X code running asynchronously. */
+ Note: this function may only be called with HELP nil or a string
+ from X code running asynchronously. */
void
-show_help_echo (msg, ok_to_overwrite_keystroke_echo)
- Lisp_Object msg;
+show_help_echo (help, window, object, pos, ok_to_overwrite_keystroke_echo)
+ Lisp_Object help, window, object, pos;
int ok_to_overwrite_keystroke_echo;
{
- if (!NILP (msg) && !STRINGP (msg))
+ if (!NILP (help) && !STRINGP (help))
{
- msg = eval_form (msg);
- if (!STRINGP (msg))
+ if (FUNCTIONP (help))
+ {
+ Lisp_Object args[4];
+ args[0] = help;
+ args[1] = window;
+ args[2] = object;
+ args[3] = pos;
+ help = safe_call (4, args);
+ }
+ else
+ help = safe_eval (help);
+
+ if (!STRINGP (help))
return;
}
- if (STRINGP (msg) || NILP (msg))
+ if (STRINGP (help) || NILP (help))
{
if (!NILP (Vshow_help_function))
- call1 (Vshow_help_function, msg);
+ call1 (Vshow_help_function, help);
else if (/* Don't overwrite minibuffer contents. */
!MINI_WINDOW_P (XWINDOW (selected_window))
/* Don't overwrite a keystroke echo. */
- && (NILP (echo_message_buffer) || ok_to_overwrite_keystroke_echo)
+ && (NILP (echo_message_buffer)
+ || ok_to_overwrite_keystroke_echo)
/* Don't overwrite a prompt. */
&& !cursor_in_echo_area)
{
- if (STRINGP (msg))
+ if (STRINGP (help))
{
int count = specpdl_ptr - specpdl;
specbind (Qmessage_truncate_lines, Qt);
- message3_nolog (msg, XSTRING (msg)->size, STRING_MULTIBYTE (msg));
+ message3_nolog (help, STRING_BYTES (XSTRING (help)),
+ STRING_MULTIBYTE (help));
unbind_to (count, Qnil);
}
else
- message (0);
+ message (0);
}
+
+ help_echo_showing_p = STRINGP (help);
}
}
Lisp_Object prev_event;
int *used_mouse_menu;
{
- Lisp_Object c;
+ volatile Lisp_Object c;
int count;
jmp_buf local_getcjmp;
jmp_buf save_jump;
- int key_already_recorded = 0;
+ volatile int key_already_recorded = 0;
Lisp_Object tem, save;
- Lisp_Object previous_echo_area_message;
- Lisp_Object also_record;
- int reread;
+ volatile Lisp_Object previous_echo_area_message;
+ volatile Lisp_Object also_record;
+ volatile int reread;
struct gcpro gcpro1, gcpro2;
+ EMACS_TIME last_idle_start;
also_record = Qnil;
&& NILP (XCDR (c)))
c = XCAR (c);
+ /* If the queued event is something that used the mouse,
+ set used_mouse_menu accordingly. */
+ if (used_mouse_menu
+ && (EQ (c, Qtool_bar) || EQ (c, Qmenu_bar)))
+ *used_mouse_menu = 1;
+
reread = 1;
goto reread_for_input_method;
}
/* Redisplay if no pending input. */
while (!input_pending)
{
- redisplay ();
+ if (help_echo_showing_p && !EQ (selected_window, minibuf_window))
+ redisplay_preserve_echo_area (5);
+ else
+ redisplay ();
if (!input_pending)
/* Normal case: no input arrived during redisplay. */
/* Actually read a character, waiting if necessary. */
save_getcjmp (save_jump);
restore_getcjmp (local_getcjmp);
+ timer_start_idle ();
c = kbd_buffer_get_event (&kb, used_mouse_menu);
restore_getcjmp (save_jump);
non_reread:
+ /* Record the last idle start time so that we can reset it
+ should the next event read be a help-echo. */
+ last_idle_start = timer_idleness_start_time;
timer_stop_idle ();
-
start_polling ();
if (NILP (c))
and loop around to read another event. */
save = Vquit_flag;
Vquit_flag = Qnil;
- tem = get_keyelt (access_keymap (get_keymap_1 (Vspecial_event_map, 0, 0),
- c, 0, 0), 1);
+ tem = access_keymap (get_keymap (Vspecial_event_map, 0, 1), c, 0, 0, 1);
Vquit_flag = save;
if (!NILP (tem))
/* Display help if not echoing. */
if (CONSP (c) && EQ (XCAR (c), Qhelp_echo))
{
- show_help_echo (XCDR (XCDR (c)), 0);
+ /* (help-echo FRAME HELP WINDOW OBJECT POS). */
+ Lisp_Object help, object, position, window;
+ help = Fnth (make_number (2), c);
+ window = Fnth (make_number (3), c);
+ object = Fnth (make_number (4), c);
+ position = Fnth (make_number (5), c);
+ show_help_echo (help, window, object, position, 0);
+
+ /* We stopped being idle for this event; undo that. */
+ timer_idleness_start_time = last_idle_start;
goto retry;
}
record_char (c)
Lisp_Object c;
{
- total_keys++;
- XVECTOR (recent_keys)->contents[recent_keys_index] = c;
- if (++recent_keys_index >= NUM_RECENT_KEYS)
- recent_keys_index = 0;
+ /* Don't record `help-echo' in recent_keys unless it shows some help
+ message, and a different help than the previoiusly recorded
+ event. */
+ if (CONSP (c) && EQ (XCAR (c), Qhelp_echo))
+ {
+ Lisp_Object help;
+ help = Fnth (make_number (2), c);
+ if (STRINGP (help))
+ {
+ int last_idx;
+ Lisp_Object last_c, last_help;
+
+ last_idx = recent_keys_index - 1;
+ if (last_idx < 0)
+ last_idx = NUM_RECENT_KEYS - 1;
+ last_c = AREF (recent_keys, last_idx);
+
+ if (!CONSP (last_c)
+ || !EQ (XCAR (last_c), Qhelp_echo)
+ || (last_help = Fnth (make_number (2), last_c),
+ !EQ (last_help, help)))
+ {
+ total_keys++;
+ ASET (recent_keys, recent_keys_index, c);
+ if (++recent_keys_index >= NUM_RECENT_KEYS)
+ recent_keys_index = 0;
+ }
+ }
+ }
+ else
+ {
+ total_keys++;
+ ASET (recent_keys, recent_keys_index, c);
+ if (++recent_keys_index >= NUM_RECENT_KEYS)
+ recent_keys_index = 0;
+ }
+
/* Write c to the dribble file. If c is a lispy event, write
the event's symbol to the dribble file, in <brackets>. Bleaugh.
If you, dear reader, have a better idea, you've got the source. :-) */
fflush (dribble);
}
- store_kbd_macro_char (c);
+ if (!CONSP (c) || !EQ (Qhelp_echo, XCAR (c)))
+ store_kbd_macro_char (c);
num_nonmacro_input_events++;
}
redisplay. */
if (!readable_events (1))
{
- redisplay_preserve_echo_area ();
+ redisplay_preserve_echo_area (6);
get_input_pending (&input_pending, 1);
}
}
++kbd_store_ptr;
}
}
+
+
+/* Generate HELP_EVENT input_events in BUFP which has room for
+ SIZE events. If there's not enough room in BUFP, ignore this
+ event.
+
+ HELP is the help form.
+
+ FRAME is the frame on which the help is generated. OBJECT is the
+ Lisp object where the help was found (a buffer, a string, an
+ overlay, or nil if neither from a string nor from a buffer. POS is
+ the position within OBJECT where the help was found.
+
+ Value is the number of input_events generated. */
+
+int
+gen_help_event (bufp, size, help, frame, window, object, pos)
+ struct input_event *bufp;
+ int size;
+ Lisp_Object help, frame, object, window;
+ int pos;
+{
+ int nevents_stored = 0;
+
+ if (size >= 2)
+ {
+ bufp->kind = HELP_EVENT;
+ bufp->frame_or_window = frame;
+ bufp->arg = object;
+ bufp->x = make_number (pos);
+ bufp->code = 0;
+
+ ++bufp;
+ bufp->kind = HELP_EVENT;
+ bufp->frame_or_window = WINDOWP (window) ? window : frame;
+ bufp->arg = help;
+ bufp->code = 1;
+ nevents_stored = 2;
+ }
+
+ return nevents_stored;
+}
+
+
+/* Store HELP_EVENTs for HELP on FRAME in the input queue. */
+
+void
+kbd_buffer_store_help_event (frame, help)
+ Lisp_Object frame, help;
+{
+ struct input_event event;
+
+ event.kind = HELP_EVENT;
+ event.frame_or_window = frame;
+ event.arg = Qnil;
+ event.x = make_number (0);
+ event.code = 0;
+ kbd_buffer_store_event (&event);
+
+ event.kind = HELP_EVENT;
+ event.frame_or_window = frame;
+ event.arg = help;
+ event.x = make_number (0);
+ event.code = 1;
+ kbd_buffer_store_event (&event);
+}
+
\f
/* Discard any mouse events in the event buffer by setting them to
no_event. */
}
}
}
+
+
+/* Return non-zero if there are any real events waiting in the event
+ buffer, not counting `no_event's.
+
+ If DISCARD is non-zero, discard no_event events at the front of
+ the input queue, possibly leaving the input queue empty if there
+ are no real input events. */
+
+int
+kbd_buffer_events_waiting (discard)
+ int discard;
+{
+ struct input_event *sp;
+
+ for (sp = kbd_fetch_ptr;
+ sp != kbd_store_ptr && sp->kind == no_event;
+ ++sp)
+ {
+ if (sp == kbd_buffer + KBD_BUFFER_SIZE)
+ sp = kbd_buffer;
+ }
+
+ if (discard)
+ kbd_fetch_ptr = sp;
+
+ return sp != kbd_store_ptr && sp->kind != no_event;
+}
+
\f
+/* Clear input event EVENT. */
+
+static INLINE void
+clear_event (event)
+ struct input_event *event;
+{
+ int idx = 2 * (event - kbd_buffer);
+ ASET (kbd_buffer_gcpro, idx, Qnil);
+ ASET (kbd_buffer_gcpro, idx + 1, Qnil);
+ event->kind = no_event;
+}
+
+
/* Read one event from the event buffer, waiting if necessary.
The value is a Lisp object representing the event.
The value is nil for an event that should be ignored,
abort ();
#endif
}
-#if defined (HAVE_X11) || defined (HAVE_NTGUI)
+#if defined (HAVE_X11) || defined (HAVE_NTGUI) || defined (macintosh)
else if (event->kind == delete_window_event)
{
/* Make an event (delete-frame (FRAME)). */
obj = Fcons (Qdelete_frame, Fcons (obj, Qnil));
kbd_fetch_ptr = event + 1;
}
+#endif
+#if defined (HAVE_X11) || defined (HAVE_NTGUI)
else if (event->kind == iconify_event)
{
/* Make an event (iconify-frame (FRAME)). */
XSETBUFFER (obj, current_buffer);
kbd_fetch_ptr = event + 1;
}
-#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI)
+#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (macintosh)
else if (event->kind == menu_bar_activate_event)
{
kbd_fetch_ptr = event + 1;
kbd_fetch_ptr = event + 1;
else if (event->kind == HELP_EVENT)
{
- /* Event->frame_or_window is a frame, event->arg is the
- help to display. */
+ /* There are always two HELP_EVENTs in the input queue. */
+ Lisp_Object object, position, help, frame, window;
+
+ xassert (event->code == 0);
+ frame = event->frame_or_window;
+ object = event->arg;
+ position = event->x;
+ clear_event (event);
+
+ kbd_fetch_ptr = event + 1;
+ event = ((kbd_fetch_ptr < kbd_buffer + KBD_BUFFER_SIZE)
+ ? kbd_fetch_ptr
+ : kbd_buffer);
+ xassert (event->code == 1);
+ help = event->arg;
+ window = event->frame_or_window;
+ if (!WINDOWP (window))
+ window = Qnil;
obj = Fcons (Qhelp_echo,
- Fcons (event->frame_or_window,
- event->arg));
+ list5 (frame, help, window, object, position));
+ clear_event (event);
kbd_fetch_ptr = event + 1;
}
else if (event->kind == FOCUS_IN_EVENT)
if (NILP (obj))
{
- int idx;
-
obj = make_lispy_event (event);
#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI)
#endif
/* Wipe out this event, to catch bugs. */
- event->kind = no_event;
- idx = 2 * (event - kbd_buffer);
- ASET (kbd_buffer_gcpro, idx, Qnil);
- ASET (kbd_buffer_gcpro, idx + 1, Qnil);
-
+ clear_event (event);
kbd_fetch_ptr = event + 1;
}
}
get_input_pending (&input_pending, 1);
if (timers_run != old_timers_run && do_display)
- redisplay_preserve_echo_area ();
+ redisplay_preserve_echo_area (7);
}
\f
-static EMACS_TIME timer_idleness_start_time;
-
/* Record the start of when Emacs is idle,
for the sake of running idle-time timers. */
while (CONSP (timers) || CONSP (idle_timers))
{
Lisp_Object *vector;
- Lisp_Object timer, idle_timer;
+ Lisp_Object timer = Qnil, idle_timer = Qnil;
EMACS_TIME timer_time, idle_timer_time;
EMACS_TIME difference, timer_difference, idle_timer_difference;
if (NILP (vector[0]))
{
int was_locked = single_kboard;
- int count = specpdl_ptr - specpdl;
+ int count = BINDING_STACK_SIZE ();
+ Lisp_Object old_deactivate_mark = Vdeactivate_mark;
/* Mark the timer as triggered to prevent problems if the lisp
code fails to reschedule it right. */
vector[0] = Qt;
specbind (Qinhibit_quit, Qt);
-
+
call1 (Qtimer_event_handler, chosen_timer);
+ Vdeactivate_mark = old_deactivate_mark;
timers_run++;
-
unbind_to (count, Qnil);
/* Resume allowing input from any kboard, if that was true before. */
return lispy_c;
}
+ case multibyte_char_keystroke:
+ {
+ Lisp_Object lispy_c;
+
+ XSETFASTINT (lispy_c, event->code);
+ return lispy_c;
+ }
+
/* A function key. The symbol may need to have modifier prefixes
tacked onto it. */
case non_ascii_keystroke:
Lisp_Object *start_pos_ptr;
Lisp_Object start_pos;
+ position = Qnil;
+
/* Build the position as appropriate for this mouse click. */
if (event->kind == mouse_click)
{
for (i = 0; i < XVECTOR (items)->size; i += 4)
{
Lisp_Object pos, string;
- string = XVECTOR (items)->contents[i + 1];
- pos = XVECTOR (items)->contents[i + 3];
+ string = AREF (items, i + 1);
+ pos = AREF (items, i + 3);
if (NILP (string))
break;
if (column >= XINT (pos)
&& column < XINT (pos) + XSTRING (string)->size)
{
- item = XVECTOR (items)->contents[i];
+ item = AREF (items, i);
break;
}
}
if (part == 1 || part == 3)
{
- /* Mode line or top line. Look for a string under
+ /* Mode line or header line. Look for a string under
the mouse that may have a `local-map' property. */
Lisp_Object string;
int charpos;
else if (part == 2)
posn = Qvertical_line;
else
- XSETINT (posn, buffer_posn_from_coords (w, &wx, &wy));
+ {
+ Lisp_Object object;
+ struct display_pos p;
+ buffer_posn_from_coords (w, &wx, &wy, &object, &p);
+ posn = make_number (CHARPOS (p.pos));
+ if (STRINGP (object))
+ string_info
+ = Fcons (object,
+ make_number (CHARPOS (p.string_pos)));
+ }
}
position
}
#endif /* not USE_TOOLKIT_SCROLL_BARS */
- if (button >= XVECTOR (button_down_location)->size)
+ if (button >= ASIZE (button_down_location))
{
button_down_location = larger_vector (button_down_location,
button + 1, Qnil);
mouse_syms = larger_vector (mouse_syms, button + 1, Qnil);
}
- start_pos_ptr = &XVECTOR (button_down_location)->contents[button];
-
+ start_pos_ptr = &AREF (button_down_location, button);
start_pos = *start_pos_ptr;
*start_pos_ptr = Qnil;
see if this was a click or a drag. */
else if (event->modifiers & up_modifier)
{
- /* If we did not see a down before this up,
- ignore the up. Probably this happened because
- the down event chose a menu item.
- It would be an annoyance to treat the release
- of the button that chose the menu item
- as a separate event. */
+ /* If we did not see a down before this up, ignore the up.
+ Probably this happened because the down event chose a
+ menu item. It would be an annoyance to treat the
+ release of the button that chose the menu item as a
+ separate event. */
if (!CONSP (start_pos))
return Qnil;
Lisp_Object down;
down = Fnth (make_number (2), start_pos);
- if (EQ (event->x, XCAR (down))
- && EQ (event->y, XCDR (down)))
- {
- event->modifiers |= click_modifier;
- }
+ if (EQ (event->x, XCAR (down)) && EQ (event->y, XCDR (down)))
+ /* Mouse hasn't moved. */
+ event->modifiers |= click_modifier;
else
{
- button_down_time = 0;
- event->modifiers |= drag_modifier;
+ Lisp_Object window1, window2, posn1, posn2;
+
+ /* Avoid generating a drag event if the mouse
+ hasn't actually moved off the buffer position. */
+ window1 = Fnth (make_number (0), position);
+ posn1 = Fnth (make_number (1), position);
+ window2 = Fnth (make_number (0), start_pos);
+ posn2 = Fnth (make_number (1), start_pos);
+
+ if (EQ (window1, window2) && EQ (posn1, posn2))
+ event->modifiers |= click_modifier;
+ else
+ {
+ button_down_time = 0;
+ event->modifiers |= drag_modifier;
+ }
}
+
/* Don't check is_double; treat this as multiple
if the down-event was multiple. */
if (double_click_count > 1)
return Qnil;
pixel_to_glyph_coords (f, XINT (event->x), XINT (event->y),
&column, &row, NULL, 1);
- window = window_from_coordinates (f, column, row, &part, 0);
+ window = window_from_coordinates (f, XINT (event->x),
+ XINT (event->y), &part, 0);
if (!WINDOWP (window))
{
else if (part == 3)
posn = Qheader_line;
else
- XSETINT (posn,
- buffer_posn_from_coords (XWINDOW (window),
- &column, &row));
+ {
+ Lisp_Object object;
+ struct display_pos p;
+ buffer_posn_from_coords (XWINDOW (window), &column, &row,
+ &object, &p);
+ posn = make_number (CHARPOS (p.pos));
+ }
}
{
Lisp_Object window;
Lisp_Object posn;
Lisp_Object files;
- int row, column;
/* The frame_or_window field should be a cons of the frame in
which the event occurred and a list of the filenames
have been deleted. */
if (! FRAME_LIVE_P (f))
return Qnil;
- pixel_to_glyph_coords (f, XINT (event->x), XINT (event->y),
- &column, &row, NULL, 1);
- window = window_from_coordinates (f, column, row, &part, 0);
+
+ window = window_from_coordinates (f, XINT (event->x),
+ XINT (event->y), &part, 0);
if (!WINDOWP (window))
{
else if (part == 3)
posn = Qheader_line;
else
- XSETINT (posn, buffer_posn_from_coords (w, &wx, &wy));
+ {
+ Lisp_Object object;
+ struct display_pos p;
+ buffer_posn_from_coords (w, &wx, &wy, &object, &p);
+ posn = make_number (CHARPOS (p.pos));
+ }
}
{
}
#endif /* HAVE_MOUSE */
-#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI)
+#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (macintosh)
case MENU_BAR_EVENT:
if (EQ (event->arg, event->frame_or_window))
/* This is the prefix key. We translate this to
else if (area == 3)
posn = Qheader_line;
else
- XSETINT (posn, buffer_posn_from_coords (w, &wx, &wy));
+ {
+ Lisp_Object object;
+ struct display_pos p;
+ buffer_posn_from_coords (w, &wx, &wy, &object, &p);
+ posn = make_number (CHARPOS (p.pos));
+ }
}
else if (frame != 0)
{
Alternatively, NAME_ALIST_OR_STEM is either an alist mapping codes
into symbol names, or a string specifying a name stem used to
- contruct a symbol name or the form `STEM-N', where N is the decimal
+ construct a symbol name or the form `STEM-N', where N is the decimal
representation of SYMBOL_NUM. NAME_ALIST_OR_STEM is used if it is
non-nil; otherwise NAME_TABLE is used.
else if (SYMBOLP (base))
return apply_modifiers (modifiers, base);
else
- error ("Invalid base event");
+ {
+ error ("Invalid base event");
+ return Qnil;
+ }
}
/* Try to recognize SYMBOL as a modifier name.
if (! CONSP (object))
return 0;
+ if (EQ (XCAR (object), Qhelp_echo)
+ || EQ (XCAR (object), Qvertical_line)
+ || EQ (XCAR (object), Qmode_line)
+ || EQ (XCAR (object), Qheader_line))
+ return 0;
+
for (tail = object; CONSP (tail); tail = XCDR (tail))
{
Lisp_Object elt;
return Qnil;
}
-static void menu_bar_item ();
-static void menu_bar_one_keymap ();
+static void menu_bar_item P_ ((Lisp_Object, Lisp_Object));
+static void menu_bar_one_keymap P_ ((Lisp_Object));
/* These variables hold the vector under construction within
menu_bar_items and its subroutines, and the current index
in the current keymaps, or nil where it is not a prefix. */
Lisp_Object *maps;
- Lisp_Object def, tem, tail;
+ Lisp_Object def, tail;
Lisp_Object result;
{
/* No, so use major and minor mode keymaps and keymap property. */
int extra_maps = 2;
- Lisp_Object map = get_local_map (PT, current_buffer, keymap);
+ Lisp_Object map = get_local_map (PT, current_buffer, Qkeymap);
if (!NILP (map))
extra_maps = 3;
nmaps = current_minor_maps (NULL, &tmaps);
* sizeof (maps[0]));
bcopy (tmaps, maps, nmaps * sizeof (maps[0]));
if (!NILP (map))
- maps[nmaps++] = get_local_map (PT, current_buffer, keymap);
- maps[nmaps++] = get_local_map (PT, current_buffer, local_map);
+ maps[nmaps++] = map;
+ maps[nmaps++] = get_local_map (PT, current_buffer, Qlocal_map);
}
maps[nmaps++] = current_global_map;
}
result = Qnil;
for (mapno = nmaps - 1; mapno >= 0; mapno--)
- {
- if (! NILP (maps[mapno]))
- def = get_keyelt (access_keymap (maps[mapno], Qmenu_bar, 1, 0), 0);
- else
- def = Qnil;
-
- tem = Fkeymapp (def);
- if (!NILP (tem))
- menu_bar_one_keymap (def);
- }
+ if (!NILP (maps[mapno]))
+ {
+ def = get_keymap (access_keymap (maps[mapno], Qmenu_bar, 1, 0, 1),
+ 0, 1);
+ if (CONSP (def))
+ menu_bar_one_keymap (def);
+ }
/* Move to the end those items that should be at the end. */
&XVECTOR (menu_bar_items_vector)->contents[i],
(menu_bar_items_index - i - 4) * sizeof (Lisp_Object));
menu_bar_items_index -= 4;
- return;
}
-
- /* If there's no definition for this key yet,
- just ignore `undefined'. */
- return;
}
- GCPRO1 (key); /* Is this necessary? */
- i = parse_menu_item (item, 0, 1);
- UNGCPRO;
- if (!i)
- return;
-
/* If this keymap has already contributed to this KEY,
don't contribute to it a second time. */
tem = Fmemq (key, menu_bar_one_keymap_changed_items);
- if (!NILP (tem))
+ if (!NILP (tem) || NILP (item))
return;
menu_bar_one_keymap_changed_items
= Fcons (key, menu_bar_one_keymap_changed_items);
+ /* We add to menu_bar_one_keymap_changed_items before doing the
+ parse_menu_item, so that if it turns out it wasn't a menu item,
+ it still correctly hides any further menu item. */
+ GCPRO1 (key);
+ i = parse_menu_item (item, 0, 1);
+ UNGCPRO;
+ if (!i)
+ return;
+
item = XVECTOR (item_properties)->contents[ITEM_PROPERTY_DEF];
/* Find any existing item for this KEY. */
/* Initialize optional entries. */
for (i = ITEM_PROPERTY_DEF; i < ITEM_PROPERTY_ENABLE; i++)
- XVECTOR (item_properties)->contents[i] = Qnil;
- XVECTOR (item_properties)->contents[ITEM_PROPERTY_ENABLE] = Qt;
+ AREF (item_properties, i) = Qnil;
+ AREF (item_properties, ITEM_PROPERTY_ENABLE) = Qt;
/* Save the item here to protect it from GC. */
- XVECTOR (item_properties)->contents[ITEM_PROPERTY_ITEM] = item;
+ AREF (item_properties, ITEM_PROPERTY_ITEM) = item;
item_string = XCAR (item);
if (STRINGP (item_string))
{
/* Old format menu item. */
- XVECTOR (item_properties)->contents[ITEM_PROPERTY_NAME] = item_string;
+ AREF (item_properties, ITEM_PROPERTY_NAME) = item_string;
/* Maybe help string. */
if (CONSP (item) && STRINGP (XCAR (item)))
{
- XVECTOR (item_properties)->contents[ITEM_PROPERTY_HELP]
- = XCAR (item);
+ AREF (item_properties, ITEM_PROPERTY_HELP) = XCAR (item);
start = item;
item = XCDR (item);
}
}
/* This is the real definition--the function to run. */
- XVECTOR (item_properties)->contents[ITEM_PROPERTY_DEF] = item;
+ AREF (item_properties, ITEM_PROPERTY_DEF) = item;
/* Get enable property, if any. */
if (SYMBOLP (item))
{
tem = Fget (item, Qmenu_enable);
if (!NILP (tem))
- XVECTOR (item_properties)->contents[ITEM_PROPERTY_ENABLE] = tem;
+ AREF (item_properties, ITEM_PROPERTY_ENABLE) = tem;
}
}
else if (EQ (item_string, Qmenu_item) && CONSP (item))
{
/* New format menu item. */
- XVECTOR (item_properties)->contents[ITEM_PROPERTY_NAME]
- = XCAR (item);
+ AREF (item_properties, ITEM_PROPERTY_NAME) = XCAR (item);
start = XCDR (item);
if (CONSP (start))
{
/* We have a real binding. */
- XVECTOR (item_properties)->contents[ITEM_PROPERTY_DEF]
- = XCAR (start);
+ AREF (item_properties, ITEM_PROPERTY_DEF) = XCAR (start);
item = XCDR (start);
/* Is there a cache list with key equivalences. */
item = XCDR (item);
if (EQ (tem, QCenable))
- XVECTOR (item_properties)->contents[ITEM_PROPERTY_ENABLE]
- = XCAR (item);
+ AREF (item_properties, ITEM_PROPERTY_ENABLE) = XCAR (item);
else if (EQ (tem, QCvisible) && !notreal)
{
/* If got a visible property and that evaluates to nil
return 0;
}
else if (EQ (tem, QChelp))
- XVECTOR (item_properties)->contents[ITEM_PROPERTY_HELP]
- = XCAR (item);
+ AREF (item_properties, ITEM_PROPERTY_HELP) = XCAR (item);
else if (EQ (tem, QCfilter))
filter = item;
else if (EQ (tem, QCkey_sequence))
{
tem = XCAR (item);
if (CONSP (tem) || (STRINGP (tem) && NILP (cachelist)))
- XVECTOR (item_properties)->contents[ITEM_PROPERTY_KEYEQ]
- = tem;
+ AREF (item_properties, ITEM_PROPERTY_KEYEQ) = tem;
}
else if (EQ (tem, QCbutton) && CONSP (XCAR (item)))
{
type = XCAR (tem);
if (EQ (type, QCtoggle) || EQ (type, QCradio))
{
- XVECTOR (item_properties)->contents[ITEM_PROPERTY_SELECTED]
+ AREF (item_properties, ITEM_PROPERTY_SELECTED)
= XCDR (tem);
- XVECTOR (item_properties)->contents[ITEM_PROPERTY_TYPE]
+ AREF (item_properties, ITEM_PROPERTY_TYPE)
= type;
}
}
/* If item string is not a string, evaluate it to get string.
If we don't get a string, skip this item. */
- item_string = XVECTOR (item_properties)->contents[ITEM_PROPERTY_NAME];
+ item_string = AREF (item_properties, ITEM_PROPERTY_NAME);
if (!(STRINGP (item_string) || notreal))
{
item_string = menu_item_eval_property (item_string);
if (!STRINGP (item_string))
return 0;
- XVECTOR (item_properties)->contents[ITEM_PROPERTY_NAME] = item_string;
+ AREF (item_properties, ITEM_PROPERTY_NAME) = item_string;
}
/* If got a filter apply it on definition. */
- def = XVECTOR (item_properties)->contents[ITEM_PROPERTY_DEF];
+ def = AREF (item_properties, ITEM_PROPERTY_DEF);
if (!NILP (filter))
{
def = menu_item_eval_property (list2 (XCAR (filter),
list2 (Qquote, def)));
- XVECTOR (item_properties)->contents[ITEM_PROPERTY_DEF] = def;
+ AREF (item_properties, ITEM_PROPERTY_DEF) = def;
}
/* If we got no definition, this item is just unselectable text which
return (inmenubar ? 0 : 1);
/* Enable or disable selection of item. */
- tem = XVECTOR (item_properties)->contents[ITEM_PROPERTY_ENABLE];
+ tem = AREF (item_properties, ITEM_PROPERTY_ENABLE);
if (!EQ (tem, Qt))
{
if (notreal)
tem = menu_item_eval_property (tem);
if (inmenubar && NILP (tem))
return 0; /* Ignore disabled items in menu bar. */
- XVECTOR (item_properties)->contents[ITEM_PROPERTY_ENABLE] = tem;
+ AREF (item_properties, ITEM_PROPERTY_ENABLE) = tem;
}
/* See if this is a separate pane or a submenu. */
- def = XVECTOR (item_properties)->contents[ITEM_PROPERTY_DEF];
- tem = get_keymap_1 (def, 0, 1);
+ def = AREF (item_properties, ITEM_PROPERTY_DEF);
+ tem = get_keymap (def, 0, 1);
/* For a subkeymap, just record its details and exit. */
- if (!NILP (tem))
+ if (CONSP (tem))
{
- XVECTOR (item_properties)->contents[ITEM_PROPERTY_MAP] = tem;
- XVECTOR (item_properties)->contents[ITEM_PROPERTY_DEF] = tem;
+ AREF (item_properties, ITEM_PROPERTY_MAP) = tem;
+ AREF (item_properties, ITEM_PROPERTY_DEF) = tem;
return 1;
}
+
/* At the top level in the menu bar, do likewise for commands also.
The menu bar does not display equivalent key bindings anyway.
ITEM_PROPERTY_DEF is already set up properly. */
XCDR (start) = Fcons (Fcons (Qnil, Qnil), XCDR (start));
cachelist = XCAR (XCDR (start));
newcache = 1;
- tem = XVECTOR (item_properties)->contents[ITEM_PROPERTY_KEYEQ];
+ tem = AREF (item_properties, ITEM_PROPERTY_KEYEQ);
if (!NILP (keyhint))
{
XCAR (cachelist) = XCAR (keyhint);
XCAR (cachelist) = Qt;
}
}
+
tem = XCAR (cachelist);
if (!EQ (tem, Qt))
{
if (!NILP (tem))
tem = Fkey_binding (tem, Qnil);
- prefix = XVECTOR (item_properties)->contents[ITEM_PROPERTY_KEYEQ];
+ prefix = AREF (item_properties, ITEM_PROPERTY_KEYEQ);
if (CONSP (prefix))
{
def = XCAR (prefix);
prefix = XCDR (prefix);
}
else
- def = XVECTOR (item_properties)->contents[ITEM_PROPERTY_DEF];
+ def = AREF (item_properties, ITEM_PROPERTY_DEF);
- if (NILP (XCAR (cachelist))) /* Have no saved key. */
+ if (!update_menu_bindings)
+ chkcache = 0;
+ else if (NILP (XCAR (cachelist))) /* Have no saved key. */
{
if (newcache /* Always check first time. */
/* Should we check everything when precomputing key
bindings? */
- /* || notreal */
/* If something had no key binding before, don't recheck it
because that is too slow--except if we have a list of
rebound commands in Vdefine_key_rebound_commands, do
command name has equivalent keys. Otherwise look up the
specified command itself. We don't try both, because that
makes lmenu menus slow. */
- if (SYMBOLP (def) && SYMBOLP (XSYMBOL (def)->function)
+ if (SYMBOLP (def)
+ && SYMBOLP (XSYMBOL (def)->function)
&& ! NILP (Fget (def, Qmenu_alias)))
def = XSYMBOL (def)->function;
tem = Fwhere_is_internal (def, Qnil, Qt, Qnil);
return 1;
/* If we have an equivalent key binding, use that. */
- XVECTOR (item_properties)->contents[ITEM_PROPERTY_KEYEQ] = tem;
+ AREF (item_properties, ITEM_PROPERTY_KEYEQ) = tem;
/* Include this when menu help is implemented.
tem = XVECTOR (item_properties)->contents[ITEM_PROPERTY_HELP];
*/
/* Handle radio buttons or toggle boxes. */
- tem = XVECTOR (item_properties)->contents[ITEM_PROPERTY_SELECTED];
+ tem = AREF (item_properties, ITEM_PROPERTY_SELECTED);
if (!NILP (tem))
- XVECTOR (item_properties)->contents[ITEM_PROPERTY_SELECTED]
+ AREF (item_properties, ITEM_PROPERTY_SELECTED)
= menu_item_eval_property (tem);
return 1;
{
/* No, so use major and minor mode keymaps and keymap property. */
int extra_maps = 2;
- Lisp_Object map = get_local_map (PT, current_buffer, keymap);
+ Lisp_Object map = get_local_map (PT, current_buffer, Qkeymap);
if (!NILP (map))
extra_maps = 3;
nmaps = current_minor_maps (NULL, &tmaps);
* sizeof (maps[0]));
bcopy (tmaps, maps, nmaps * sizeof (maps[0]));
if (!NILP (map))
- maps[nmaps++] = get_local_map (PT, current_buffer, keymap);
- maps[nmaps++] = get_local_map (PT, current_buffer, local_map);
+ maps[nmaps++] = map;
+ maps[nmaps++] = get_local_map (PT, current_buffer, Qlocal_map);
}
/* Add global keymap at the end. */
if (!NILP (maps[i]))
{
Lisp_Object keymap;
-
- keymap = get_keyelt (access_keymap (maps[i], Qtool_bar, 1, 1), 0);
- if (!NILP (Fkeymapp (keymap)))
+
+ keymap = get_keymap (access_keymap (maps[i], Qtool_bar, 1, 0, 1), 0, 1);
+ if (CONSP (keymap))
{
Lisp_Object tail;
extern Lisp_Object QCbutton, QCtoggle, QCradio;
int i;
- /* Defininition looks like `(tool-bar-item CAPTION BINDING
- PROPS...)'. Rule out items that aren't lists, don't start with
- `tool-bar-item' or whose rest following `tool-bar-item' is not a
+ /* Defininition looks like `(menu-item CAPTION BINDING PROPS...)'.
+ Rule out items that aren't lists, don't start with
+ `menu-item' or whose rest following `tool-bar-item' is not a
list. */
if (!CONSP (item)
|| !EQ (XCAR (item), Qmenu_item)
PROP (TOOL_BAR_ITEM_BINDING) = XCAR (item);
item = XCDR (item);
+ /* Ignore cached key binding, if any. */
+ if (CONSP (item) && CONSP (XCAR (item)))
+ item = XCDR (item);
+
/* Process the rest of the properties. */
for (; CONSP (item) && CONSP (XCDR (item)); item = XCDR (XCDR (item)))
{
PROP (TOOL_BAR_ITEM_BINDING))));
/* See if the binding is a keymap. Give up if it is. */
- if (!NILP (get_keymap_1 (PROP (TOOL_BAR_ITEM_BINDING), 0, 1)))
+ if (CONSP (get_keymap (PROP (TOOL_BAR_ITEM_BINDING), 0, 1)))
return 0;
/* Enable or disable selection of item. */
Lisp_Object rest, vector;
char *menu;
+ vector = Qnil;
+
if (! menu_prompting)
return Qnil;
/* 1 if the char to type matches the string. */
int char_matches;
Lisp_Object upcased_event, downcased_event;
- Lisp_Object desc;
+ Lisp_Object desc = Qnil;
Lisp_Object s
= XVECTOR (item_properties)->contents[ITEM_PROPERTY_NAME];
char_matches = (XINT (upcased_event) == XSTRING (s)->data[0]
|| XINT (downcased_event) == XSTRING (s)->data[0]);
if (! char_matches)
- desc = Fsingle_key_description (event);
+ desc = Fsingle_key_description (event, Qnil);
tem
= XVECTOR (item_properties)->contents[ITEM_PROPERTY_KEYEQ];
orig_defn_macro = current_kboard->defining_kbd_macro;
current_kboard->defining_kbd_macro = Qnil;
do
- obj = read_char (commandflag, 0, 0, Qnil, 0);
+ obj = read_char (commandflag, 0, 0, Qt, 0);
while (BUFFERP (obj));
current_kboard->defining_kbd_macro = orig_defn_macro;
int i, first_binding;
int did_meta = 0;
- /* If KEY is a meta ASCII character, treat it like meta-prefix-char
- followed by the corresponding non-meta character.
- Put the results into DEFS, since we are going to alter that anyway.
- Do not alter CURRENT or NEXT. */
- if (INTEGERP (key) && (XUINT (key) & CHAR_META))
- {
- for (i = 0; i < nmaps; i++)
- if (! NILP (current[i]))
- {
- Lisp_Object def;
- def = get_keyelt (access_keymap (current[i],
- meta_prefix_char, 1, 0), 0);
-
- /* Note that since we pass the resulting bindings through
- get_keymap_1, non-prefix bindings for meta-prefix-char
- disappear. */
- defs[i] = get_keymap_1 (def, 0, 1);
- }
- else
- defs[i] = Qnil;
-
- did_meta = 1;
- XSETINT (key, XFASTINT (key) & ~CHAR_META);
- }
-
first_binding = nmaps;
for (i = nmaps - 1; i >= 0; i--)
{
else
map = current[i];
- defs[i] = get_keyelt (access_keymap (map, key, 1, 0), 1);
+ defs[i] = access_keymap (map, key, 1, 0, 1);
if (! NILP (defs[i]))
first_binding = i;
}
/* Given the set of bindings we've found, produce the next set of maps. */
if (first_binding < nmaps)
for (i = 0; i < nmaps; i++)
- next[i] = NILP (defs[i]) ? Qnil : get_keymap_1 (defs[i], 0, 1);
+ next[i] = NILP (defs[i]) ? Qnil : get_keymap (defs[i], 0, 1);
return first_binding;
}
int can_return_switch_frame;
int fix_current_buffer;
{
- int count = specpdl_ptr - specpdl;
+ volatile Lisp_Object from_string;
+ volatile int count = specpdl_ptr - specpdl;
/* How many keys there are in the current key sequence. */
- int t;
+ volatile int t;
/* The length of the echo buffer when we started reading, and
the length of this_command_keys when we started reading. */
- int echo_start;
- int keys_start;
+ volatile int echo_start;
+ volatile int keys_start;
/* The number of keymaps we're scanning right now, and the number of
keymaps we have allocated space for. */
- int nmaps;
- int nmaps_allocated = 0;
+ volatile int nmaps;
+ volatile int nmaps_allocated = 0;
/* defs[0..nmaps-1] are the definitions of KEYBUF[0..t-1] in
the current keymaps. */
- Lisp_Object *defs;
+ Lisp_Object *volatile defs = NULL;
/* submaps[0..nmaps-1] are the prefix definitions of KEYBUF[0..t-1]
in the current keymaps, or nil where it is not a prefix. */
- Lisp_Object *submaps;
+ Lisp_Object *volatile submaps = NULL;
/* The local map to start out with at start of key sequence. */
- Lisp_Object orig_local_map;
+ volatile Lisp_Object orig_local_map;
/* The map from the `keymap' property to start out with at start of
key sequence. */
- Lisp_Object orig_keymap;
+ volatile Lisp_Object orig_keymap;
/* 1 if we have already considered switching to the local-map property
of the place where a mouse click occurred. */
- int localized_local_map = 0;
+ volatile int localized_local_map = 0;
/* The index in defs[] of the first keymap that has a binding for
this key sequence. In other words, the lowest i such that
defs[i] is non-nil. */
- int first_binding;
+ volatile int first_binding;
/* If t < mock_input, then KEYBUF[t] should be read as the next
input key.
restart_sequence; the loop will read keys from keybuf up until
mock_input, thus rebuilding the state; and then it will resume
reading characters from the keyboard. */
- int mock_input = 0;
+ volatile int mock_input = 0;
/* If the sequence is unbound in submaps[], then
keybuf[fkey_start..fkey_end-1] is a prefix in Vfunction_key_map,
should hold off until t reaches them. We do this when we've just
recognized a function key, to avoid searching for the function
key's again in Vfunction_key_map. */
- int fkey_start = 0, fkey_end = 0;
- Lisp_Object fkey_map;
+ volatile int fkey_start = 0, fkey_end = 0;
+ volatile Lisp_Object fkey_map;
/* Likewise, for key_translation_map. */
- int keytran_start = 0, keytran_end = 0;
- Lisp_Object keytran_map;
+ volatile int keytran_start = 0, keytran_end = 0;
+ volatile Lisp_Object keytran_map;
/* If we receive a ``switch-frame'' event in the middle of a key sequence,
we put it off for later. While we're reading, we keep the event here. */
- Lisp_Object delayed_switch_frame;
+ volatile Lisp_Object delayed_switch_frame;
/* See the comment below... */
#if defined (GOBBLE_FIRST_EVENT)
Lisp_Object first_event;
#endif
- Lisp_Object original_uppercase;
- int original_uppercase_position = -1;
+ volatile Lisp_Object original_uppercase;
+ volatile int original_uppercase_position = -1;
/* Gets around Microsoft compiler limitations. */
int dummyflag = 0;
/* Nonzero if we seem to have got the beginning of a binding
in function_key_map. */
- int function_key_possible = 0;
- int key_translation_possible = 0;
+ volatile int function_key_possible = 0;
+ volatile int key_translation_possible = 0;
+
+ /* List of events for which a fake prefix key has been generated. */
+ volatile Lisp_Object fake_prefixed_keys = Qnil;
/* Save the status of key translation before each step,
so that we can restore this after downcasing. */
int junk;
#endif
+ struct gcpro gcpro1;
+
+ GCPRO1 (fake_prefixed_keys);
raw_keybuf_count = 0;
last_nonmenu_event = Qnil;
keytran_map = Vkey_translation_map;
/* If there is no function-key-map, turn off function key scanning. */
- if (NILP (Fkeymapp (Vfunction_key_map)))
+ if (!KEYMAPP (Vfunction_key_map))
fkey_start = fkey_end = bufsize + 1;
/* If there is no key-translation-map, turn off scanning. */
- if (NILP (Fkeymapp (Vkey_translation_map)))
+ if (!KEYMAPP (Vkey_translation_map))
keytran_start = keytran_end = bufsize + 1;
if (INTERACTIVE)
{
if (!NILP (prompt))
- echo_prompt (XSTRING (prompt)->data);
+ echo_prompt (prompt);
else if (cursor_in_echo_area
&& (FLOATP (Vecho_keystrokes) || INTEGERP (Vecho_keystrokes))
&& NILP (Fzerop (Vecho_keystrokes)))
&junk);
#endif /* GOBBLE_FIRST_EVENT */
- orig_local_map = get_local_map (PT, current_buffer, local_map);
- orig_keymap = get_local_map (PT, current_buffer, keymap);
+ orig_local_map = get_local_map (PT, current_buffer, Qlocal_map);
+ orig_keymap = get_local_map (PT, current_buffer, Qkeymap);
+ from_string = Qnil;
/* We jump here when the key sequence has been thoroughly changed, and
we need to rescan it starting from the beginning. When we jump here,
* sizeof (defs[0]));
nmaps_allocated = nmaps + extra_maps;
}
- bcopy (maps, submaps, nmaps * sizeof (submaps[0]));
+ bcopy (maps, (void *) submaps, nmaps * sizeof (submaps[0]));
if (!NILP (orig_keymap))
submaps[nmaps++] = orig_keymap;
submaps[nmaps++] = orig_local_map;
(say, a mouse click on the mode line which is being treated
as [mode-line (mouse-...)], then we backtrack to this point
of keybuf. */
- int last_real_key_start;
+ volatile int last_real_key_start;
/* These variables are analogous to echo_start and keys_start;
while those allow us to restart the entire key sequence,
echo_local_start and keys_local_start allow us to throw away
just one key. */
- int echo_local_start, keys_local_start, local_first_binding;
+ volatile int echo_local_start, keys_local_start, local_first_binding;
if (t >= bufsize)
error ("Key sequence too long");
interrupted_kboard->kbd_queue);
}
mock_input = 0;
- orig_local_map = get_local_map (PT, current_buffer, local_map);
- orig_keymap = get_local_map (PT, current_buffer, keymap);
+ orig_local_map = get_local_map (PT, current_buffer, Qlocal_map);
+ orig_keymap = get_local_map (PT, current_buffer, Qkeymap);
goto replay_sequence;
}
#endif
- key = read_char (NILP (prompt), nmaps, submaps, last_nonmenu_event,
+ key = read_char (NILP (prompt), nmaps,
+ (Lisp_Object *) submaps, last_nonmenu_event,
&used_mouse_menu);
}
if (EQ (key, Qt))
{
unbind_to (count, Qnil);
+ UNGCPRO;
return -1;
}
Fset_buffer (XWINDOW (selected_window)->buffer);
}
- orig_local_map = get_local_map (PT, current_buffer, local_map);
- orig_keymap = get_local_map (PT, current_buffer, keymap);
+ orig_local_map = get_local_map (PT, current_buffer, Qlocal_map);
+ orig_keymap = get_local_map (PT, current_buffer, Qkeymap);
goto replay_sequence;
}
keybuf[t++] = key;
mock_input = t;
Vquit_flag = Qnil;
- orig_local_map = get_local_map (PT, current_buffer, local_map);
- orig_keymap = get_local_map (PT, current_buffer, keymap);
+ orig_local_map = get_local_map (PT, current_buffer, Qlocal_map);
+ orig_keymap = get_local_map (PT, current_buffer, Qkeymap);
goto replay_sequence;
}
window = POSN_WINDOW (EVENT_START (key));
posn = POSN_BUFFER_POSN (EVENT_START (key));
- if (CONSP (posn))
+ if (CONSP (posn)
+ || (!NILP (fake_prefixed_keys)
+ && !NILP (Fmemq (key, fake_prefixed_keys))))
{
- /* We're looking at the second event of a
- sequence which we expanded before. Set
+ /* We're looking a second time at an event for which
+ we generated a fake prefix key. Set
last_real_key_start appropriately. */
if (t > 0)
last_real_key_start = t - 1;
if (! FRAME_LIVE_P (XFRAME (selected_frame)))
Fkill_emacs (Qnil);
- set_buffer_internal (XBUFFER (XWINDOW
- (window)->buffer)
-);
+ set_buffer_internal (XBUFFER (XWINDOW (window)->buffer));
orig_local_map = get_local_map (PT, current_buffer,
- local_map);
- orig_keymap = get_local_map (PT, current_buffer, keymap);
+ Qlocal_map);
+ orig_keymap = get_local_map (PT, current_buffer, Qkeymap);
goto replay_sequence;
}
&& XINT (pos) >= BEG && XINT (pos) <= Z)
{
map_here = get_local_map (XINT (pos),
- current_buffer, local_map);
+ current_buffer, Qlocal_map);
if (!EQ (map_here, orig_local_map))
{
orig_local_map = map_here;
goto replay_sequence;
}
map_here = get_local_map (XINT (pos),
- current_buffer, keymap);
+ current_buffer, Qkeymap);
if (!EQ (map_here, orig_keymap))
{
orig_keymap = map_here;
/* Expand mode-line and scroll-bar events into two events:
use posn as a fake prefix key. */
- if (SYMBOLP (posn))
+ if (SYMBOLP (posn)
+ && (NILP (fake_prefixed_keys)
+ || NILP (Fmemq (key, fake_prefixed_keys))))
{
if (t + 1 >= bufsize)
error ("Key sequence too long");
- keybuf[t] = posn;
- keybuf[t+1] = key;
- mock_input = t + 2;
- /* Zap the position in key, so we know that we've
- expanded it, and don't try to do so again. */
- POSN_BUFFER_POSN (EVENT_START (key))
- = Fcons (posn, Qnil);
+ keybuf[t] = posn;
+ keybuf[t + 1] = key;
+ mock_input = t + 2;
+
+ /* Record that a fake prefix key has been generated
+ for KEY. Don't modify the event; this would
+ prevent proper action when the event is pushed
+ back tino unread-command-events. */
+ fake_prefixed_keys = Fcons (key, fake_prefixed_keys);
/* If on a mode line string with a local keymap,
reconsider the key sequence with that keymap. */
goto replay_key;
}
+ else if (CONSP (POSN_STRING (EVENT_START (key)))
+ && NILP (from_string))
+ {
+ /* For a click on a string, i.e. overlay string or a
+ string displayed via the `display' property,
+ consider `local-map' and `keymap' properties of
+ that string. */
+ Lisp_Object string, pos, map, map2;
+
+ string = POSN_STRING (EVENT_START (key));
+ pos = XCDR (string);
+ string = XCAR (string);
+ if (XINT (pos) >= 0
+ && XINT (pos) < XSTRING (string)->size)
+ {
+ map = Fget_text_property (pos, Qlocal_map, string);
+ if (!NILP (map))
+ orig_local_map = map;
+ map2 = Fget_text_property (pos, Qkeymap, string);
+ if (!NILP (map2))
+ orig_keymap = map2;
+
+ if (!NILP (map) || !NILP (map2))
+ {
+ from_string = string;
+ goto replay_sequence;
+ }
+ }
+ }
}
else if (CONSP (XCDR (key))
&& CONSP (EVENT_START (key))
Lisp_Object key;
key = keybuf[fkey_end++];
- /* Look up meta-characters by prefixing them
- with meta_prefix_char. I hate this. */
- if (INTEGERP (key) && XUINT (key) & meta_modifier)
- {
- fkey_next
- = get_keymap_1
- (get_keyelt
- (access_keymap (fkey_map, meta_prefix_char, 1, 0), 0),
- 0, 1);
- XSETFASTINT (key, XFASTINT (key) & ~meta_modifier);
- }
- else
- fkey_next = fkey_map;
-
fkey_next
- = get_keyelt (access_keymap (fkey_next, key, 1, 0), 1);
+ = access_keymap (fkey_map, key, 1, 0, 1);
/* Handle symbol with autoload definition. */
if (SYMBOLP (fkey_next) && ! NILP (Ffboundp (fkey_next))
or an array. */
if (SYMBOLP (fkey_next) && ! NILP (Ffboundp (fkey_next))
&& (!NILP (Farrayp (XSYMBOL (fkey_next)->function))
- || !NILP (Fkeymapp (XSYMBOL (fkey_next)->function))))
+ || KEYMAPP (XSYMBOL (fkey_next)->function)))
fkey_next = XSYMBOL (fkey_next)->function;
#if 0 /* I didn't turn this on, because it might cause trouble
goto replay_sequence;
}
- fkey_map = get_keymap_1 (fkey_next, 0, 1);
+ fkey_map = get_keymap (fkey_next, 0, 1);
/* If we no longer have a bound suffix, try a new positions for
fkey_start. */
- if (NILP (fkey_map))
+ if (!CONSP (fkey_map))
{
fkey_end = ++fkey_start;
fkey_map = Vfunction_key_map;
Lisp_Object key;
key = keybuf[keytran_end++];
- /* Look up meta-characters by prefixing them
- with meta_prefix_char. I hate this. */
- if (INTEGERP (key) && XUINT (key) & meta_modifier)
- {
- keytran_next
- = get_keymap_1
- (get_keyelt
- (access_keymap (keytran_map, meta_prefix_char, 1, 0), 0),
- 0, 1);
- XSETFASTINT (key, XFASTINT (key) & ~meta_modifier);
- }
- else
- keytran_next = keytran_map;
-
keytran_next
- = get_keyelt (access_keymap (keytran_next, key, 1, 0), 1);
+ = access_keymap (keytran_map, key, 1, 0, 1);
/* Handle symbol with autoload definition. */
if (SYMBOLP (keytran_next) && ! NILP (Ffboundp (keytran_next))
or an array. */
if (SYMBOLP (keytran_next) && ! NILP (Ffboundp (keytran_next))
&& (!NILP (Farrayp (XSYMBOL (keytran_next)->function))
- || !NILP (Fkeymapp (XSYMBOL (keytran_next)->function))))
+ || KEYMAPP (XSYMBOL (keytran_next)->function)))
keytran_next = XSYMBOL (keytran_next)->function;
/* If the key translation map gives a function, not an
goto replay_sequence;
}
- keytran_map = get_keymap_1 (keytran_next, 0, 1);
+ keytran_map = get_keymap (keytran_next, 0, 1);
/* If we no longer have a bound suffix, try a new positions for
keytran_start. */
- if (NILP (keytran_map))
+ if (!CONSP (keytran_map))
{
keytran_end = ++keytran_start;
keytran_map = Vkey_translation_map;
+ UNGCPRO;
return t;
}
}
#ifdef HAVE_X_WINDOWS
- if (display_busy_cursor_p)
- cancel_busy_cursor ();
+ if (display_hourglass_p)
+ cancel_hourglass ();
#endif
i = read_key_sequence (keybuf, (sizeof keybuf/sizeof (keybuf[0])),
prompt, ! NILP (dont_downcase_last),
! NILP (can_return_switch_frame), 0);
+#if 0 /* The following is fine for code reading a key sequence and
+ then proceeding with a lenghty compuation, but it's not good
+ for code reading keys in a loop, like an input method. */
#ifdef HAVE_X_WINDOWS
- if (display_busy_cursor_p)
- start_busy_cursor ();
+ if (display_hourglass_p)
+ start_hourglass ();
+#endif
#endif
if (i == -1)
}
#ifdef HAVE_X_WINDOWS
- if (display_busy_cursor_p)
- cancel_busy_cursor ();
+ if (display_hourglass_p)
+ cancel_hourglass ();
#endif
i = read_key_sequence (keybuf, (sizeof keybuf/sizeof (keybuf[0])),
! NILP (can_return_switch_frame), 0);
#ifdef HAVE_X_WINDOWS
- if (display_busy_cursor_p)
- start_busy_cursor ();
+ if (display_hourglass_p)
+ start_hourglass ();
#endif
if (i == -1)
}
return Qnil;
}
+
+
\f
DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_command,
1, 1, "P",
Lisp_Object binding;
char *newmessage;
int message_p = push_message ();
+ int count = BINDING_STACK_SIZE ();
+ record_unwind_protect (push_message_unwind, Qnil);
binding = Fkey_description (bindings);
newmessage
&& message_p)
restore_message ();
- pop_message ();
+ unbind_to (count, Qnil);
}
}
{
/* No, so use major and minor mode keymaps and keymap property. */
int extra_maps = 2;
- Lisp_Object map = get_local_map (PT, current_buffer, keymap);
+ Lisp_Object map = get_local_map (PT, current_buffer, Qkeymap);
if (!NILP (map))
extra_maps = 3;
nmaps = current_minor_maps (NULL, &tmaps);
* sizeof (maps[0]));
bcopy (tmaps, maps, nmaps * sizeof (maps[0]));
if (!NILP (map))
- maps[nmaps++] = get_local_map (PT, current_buffer, keymap);
- maps[nmaps++] = get_local_map (PT, current_buffer, local_map);
+ maps[nmaps++] = map;
+ maps[nmaps++] = get_local_map (PT, current_buffer, Qlocal_map);
}
maps[nmaps++] = current_global_map;
if (old_timers_run != timers_run && do_display)
{
- redisplay_preserve_echo_area ();
+ redisplay_preserve_echo_area (8);
/* The following fixes a bug when using lazy-lock with
lazy-lock-defer-on-the-fly set to t, i.e. when fontifying
from an idle timer function. The symptom of the bug is that
if (FRAMEP (internal_last_event_frame)
&& !EQ (internal_last_event_frame, selected_frame))
do_switch_frame (make_lispy_switch_frame (internal_last_event_frame),
- Qnil, 0);
+ 0, 0);
_longjmp (getcjmp, 1);
}
}
#ifdef MULTI_KBOARD
+
+/* Free KB and memory referenced from it. */
+
void
delete_kboard (kb)
- KBOARD *kb;
+ KBOARD *kb;
{
KBOARD **kbp;
+
for (kbp = &all_kboards; *kbp != kb; kbp = &(*kbp)->next_kboard)
if (*kbp == NULL)
abort ();
*kbp = kb->next_kboard;
+
+ /* Prevent a dangling reference to KB. */
+ if (kb == current_kboard
+ && FRAMEP (selected_frame)
+ && FRAME_LIVE_P (XFRAME (selected_frame)))
+ {
+ current_kboard = XFRAME (selected_frame)->kboard;
+ if (current_kboard == kb)
+ abort ();
+ }
+
wipe_kboard (kb);
xfree (kb);
}
-#endif
+
+#endif /* MULTI_KBOARD */
void
init_keyboard ()
wipe_kboard (current_kboard);
init_kboard (current_kboard);
- if (initialized)
- Ffillarray (kbd_buffer_gcpro, Qnil);
-
- kbd_buffer_gcpro = Fmake_vector (make_number (2 * KBD_BUFFER_SIZE), Qnil);
if (!noninteractive && !read_socket_hook && NILP (Vwindow_system))
{
signal (SIGINT, interrupt_signal);
Fset (Qinput_method_exit_on_first_char, Qnil);
Fset (Qinput_method_use_echo_area, Qnil);
+ last_point_position_buffer = Qnil;
+
{
struct event_head *p;
"Per-terminal keymap that overrides all other local keymaps.\n\
If this variable is non-nil, it is used as a keymap instead of the\n\
buffer's local map, and the minor mode keymaps and text property keymaps.\n\
-This variable is intended to let commands such as `universal-argumemnt'\n\
+This variable is intended to let commands such as `universal-argument'\n\
set up a different keymap for reading the next command.");
DEFVAR_LISP ("overriding-local-map", &Voverriding_local_map,
suppressed only after special commands that set\n\
`disable-point-adjustment' (which see) to non-nil.");
Vglobal_disable_point_adjustment = Qnil;
+
+ DEFVAR_BOOL ("update-menu-bindings", &update_menu_bindings,
+ "Non-nil means updating menu bindings is allowed.\n\
+A value of nil means menu bindings should not be updated.\n\
+Used during Emacs' startup.");
+ update_menu_bindings = 1;
+
+ DEFVAR_LISP ("minibuffer-message-timeout", &Vminibuffer_message_timeout,
+ "*How long to display an echo-area message when the minibuffer is active.\n\
+If the value is not a number, such messages don't time out.");
+ Vminibuffer_message_timeout = make_number (2);
}
void