/* Keyboard and mouse input; editor command loop.
- Copyright (C) 1985,86,87,88,89,93,94,95 Free Software Foundation, Inc.
+ Copyright (C) 1985,86,87,88,89,93,94,95,96 Free Software Foundation, Inc.
This file is part of GNU Emacs.
You should have received a copy of the GNU General Public License
along with GNU Emacs; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
/* Allow config.h to undefine symbols found here. */
#include <signal.h>
#include "window.h"
#include "commands.h"
#include "buffer.h"
+#include "charset.h"
#include "disptab.h"
#include "dispextern.h"
#include "keyboard.h"
#include "xterm.h"
#endif
+#ifdef HAVE_NTGUI
+#include "w32term.h"
+#endif /* HAVE_NTGUI */
+
/* Include systime.h after xterm.h to avoid double inclusion of time.h. */
#include "systime.h"
/* File descriptor to use for input. */
extern int input_fd;
-#ifdef HAVE_X_WINDOWS
+#ifdef HAVE_WINDOW_SYSTEM
/* Make all keyboard buffers much bigger when using X windows. */
#define KBD_BUFFER_SIZE 4096
#else /* No X-windows, character input */
Lisp_Object this_command_keys;
int this_command_key_count;
+/* Number of elements of this_command_keys
+ that precede this key sequence. */
+int this_single_command_key_start;
+
/* Record values of this_command_key_count and echo_length ()
before this command was read. */
static int before_command_key_count;
/* True while displaying for echoing. Delays C-g throwing. */
static int echoing;
+/* True means we can start echoing at the next input pause
+ even though there is something in the echo area. */
+static char *ok_to_echo_at_next_pause;
+
/* Nonzero means disregard local maps for the menu bar. */
static int inhibit_local_menu_bar_menus;
/* The buffer that was current when the last command was started. */
Lisp_Object last_point_position_buffer;
-#ifdef MULTI_FRAME
/* The frame in which the last input event occurred, or Qmacro if the
last event came from a macro. We use this to determine when to
generate switch-frame events. This may be cleared by functions
like Fselect_frame, to make sure that a switch-frame event is
generated by the next character. */
Lisp_Object internal_last_event_frame;
-#endif
/* A user-visible version of the above, intended to allow users to
figure out where the last event came from, if the event doesn't
Lisp_Object Vlucid_menu_bar_dirty_flag;
Lisp_Object Qrecompute_lucid_menubar, Qactivate_menubar_hook;
+Lisp_Object Qecho_area_clear_hook;
+
/* Hooks to run before and after each command. */
Lisp_Object Qpre_command_hook, Vpre_command_hook;
Lisp_Object Qpost_command_hook, Vpost_command_hook;
/* Symbols to denote kinds of events. */
Lisp_Object Qfunction_key;
Lisp_Object Qmouse_click;
+Lisp_Object Qtimer_event;
/* Lisp_Object Qmouse_movement; - also an event header */
/* Properties of event headers. */
Lisp_Object recursive_edit_unwind (), command_loop ();
Lisp_Object Fthis_command_keys ();
Lisp_Object Qextended_command_history;
+EMACS_TIME timer_check ();
extern char *x_get_keysym_name ();
+static void record_menu_key ();
+
Lisp_Object Qpolling_period;
+/* List of absolute timers. Appears in order of next scheduled event. */
+Lisp_Object Vtimer_list;
+
+/* List of idle time timers. Appears in order of next scheduled event. */
+Lisp_Object Vtimer_idle_list;
+
+/* Incremented whenever a timer is run. */
+int timers_run;
+
extern Lisp_Object Vprint_level, Vprint_length;
/* Address (if not 0) of EMACS_TIME to zero out if a SIGIO interrupt
/* Nonzero while interrupts are temporarily deferred during redisplay. */
int interrupts_deferred;
-/* nonzero means use ^S/^Q for flow control. */
+/* Nonzero means use ^S/^Q for flow control. */
int flow_control;
/* Allow m- file to inhibit use of FIONREAD. */
#endif
#endif
-/* If we support X Windows, turn on the code to poll periodically
+/* If we support a window system, turn on the code to poll periodically
to detect C-g. It isn't actually used when doing interrupt input. */
-#ifdef HAVE_X_WINDOWS
+#ifdef HAVE_WINDOW_SYSTEM
#define POLL_FOR_INPUT
#endif
\f
current_kboard->echo_after_prompt = len;
- echo ();
+ echo_now ();
}
/* Add C to the echo string, if echoing is going on.
*ptr = 0;
current_kboard->echoptr = ptr;
- echo ();
+ echo_now ();
}
}
current_kboard->echoptr[0] = '-';
current_kboard->echoptr[1] = 0;
- echo ();
+ echo_now ();
}
/* Display the current echo string, and begin echoing if not already
doing so. */
-echo ()
+echo_now ()
{
if (!current_kboard->immediate_echo)
{
current_kboard->immediate_echo = 0;
current_kboard->echoptr = current_kboard->echobuf;
current_kboard->echo_after_prompt = -1;
+ ok_to_echo_at_next_pause = 0;
}
/* Return the length of the current echo string. */
if (before_command_restore_flag)
{
this_command_key_count = before_command_key_count_1;
+ if (this_command_key_count < this_single_command_key_start)
+ this_single_command_key_start = this_command_key_count;
echo_truncate (before_command_echo_length_1);
before_command_restore_flag = 0;
}
val = command_loop ();
if (EQ (val, Qt))
Fsignal (Qquit, Qnil);
+ /* Handle throw from read_minibuf when using minibuffer
+ while it's active but we're in another window. */
+ if (STRINGP (val))
+ Fsignal (Qerror, Fcons (val, Qnil));
return unbind_to (count, Qnil);
}
Lisp_Object data;
{
Lisp_Object old_level, old_length;
+ char macroerror[50];
+
+ if (!NILP (executing_macro))
+ {
+ if (executing_macro_iterations == 1)
+ sprintf (macroerror, "After 1 kbd macro iteration: ");
+ else
+ sprintf (macroerror, "After %d kbd macro iterations: ",
+ executing_macro_iterations);
+ }
+ else
+ *macroerror = 0;
Vstandard_output = Qt;
Vstandard_input = Qt;
Vexecuting_macro = Qnil;
+ executing_macro = Qnil;
current_kboard->Vprefix_arg = Qnil;
cancel_echoing ();
/* Avoid unquittable loop if data contains a circular list. */
old_level = Vprint_level;
old_length = Vprint_length;
- XSETFASTINT(Vprint_level, 10);
- XSETFASTINT(Vprint_length, 10);
- cmd_error_internal (data, NULL);
+ XSETFASTINT (Vprint_level, 10);
+ XSETFASTINT (Vprint_length, 10);
+ cmd_error_internal (data, macroerror);
Vprint_level = old_level;
Vprint_length = old_length;
Lisp_Object data;
char *context;
{
- Lisp_Object errmsg, tail, errname, file_error;
Lisp_Object stream;
- struct gcpro gcpro1;
- int i;
Vquit_flag = Qnil;
Vinhibit_quit = Qt;
if (context != 0)
write_string_1 (context, -1, stream);
- errname = Fcar (data);
-
- if (EQ (errname, Qerror))
- {
- data = Fcdr (data);
- if (!CONSP (data)) data = Qnil;
- errmsg = Fcar (data);
- file_error = Qnil;
- }
- else
- {
- errmsg = Fget (errname, Qerror_message);
- file_error = Fmemq (Qfile_error,
- Fget (errname, Qerror_conditions));
- }
-
- /* Print an error message including the data items.
- This is done by printing it into a scratch buffer
- and then making a copy of the text in the buffer. */
-
- if (!CONSP (data)) data = Qnil;
- tail = Fcdr (data);
- GCPRO1 (tail);
-
- /* For file-error, make error message by concatenating
- all the data items. They are all strings. */
- if (!NILP (file_error) && !NILP (tail))
- errmsg = XCONS (tail)->car, tail = XCONS (tail)->cdr;
-
- if (STRINGP (errmsg))
- Fprinc (errmsg, stream);
- else
- write_string_1 ("peculiar error", -1, stream);
-
- for (i = 0; CONSP (tail); tail = Fcdr (tail), i++)
- {
- write_string_1 (i ? ", " : ": ", 2, stream);
- if (!NILP (file_error))
- Fprinc (Fcar (tail), stream);
- else
- Fprin1 (Fcar (tail), stream);
- }
- UNGCPRO;
+ print_error_message (data, stream);
/* If the window system or terminal frame hasn't been initialized
yet, or we're in -batch mode, this error should cause Emacs to exit. */
command_loop_1 ()
{
Lisp_Object cmd, tem;
- int lose;
+ int lose, lose2;
int nonundocount;
Lisp_Object keybuf[30];
int i;
nonundocount = 0;
no_redisplay = 0;
this_command_key_count = 0;
+ this_single_command_key_start = 0;
/* Make sure this hook runs after commands that get errors and
throw to top level. */
/* Note that the value cell will never directly contain nil
if the symbol is a local variable. */
- if (!NILP (XSYMBOL (Qpost_command_hook)->value) && !NILP (Vrun_hooks))
+ if (!NILP (Vpost_command_hook) && !NILP (Vrun_hooks))
safe_run_hooks (Qpost_command_hook);
if (!NILP (Vdeferred_action_list))
call0 (Vdeferred_action_function);
- if (!NILP (XSYMBOL (Qpost_command_idle_hook)->value) && !NILP (Vrun_hooks))
+ if (!NILP (Vpost_command_idle_hook) && !NILP (Vrun_hooks))
{
if (NILP (Vunread_command_events)
&& NILP (Vexecuting_macro)
rather than quitting back to the minibuffer. */
int count = specpdl_ptr - specpdl;
specbind (Qinhibit_quit, Qt);
+
Fsit_for (make_number (2), Qnil, Qnil);
+ /* Clear the echo area. */
+ message2 (0);
+ safe_run_hooks (Qecho_area_clear_hook);
+
unbind_to (count, Qnil);
- echo_area_glyphs = 0;
- no_direct = 1;
+ /* If a C-g came in before, treat it as input now. */
if (!NILP (Vquit_flag))
{
Vquit_flag = Qnil;
#endif /* C_ALLOCA */
#if 0
-#ifdef MULTI_FRAME
/* Select the frame that the last event came from. Usually,
switch-frame events will take care of this, but if some lisp
code swallows a switch-frame event, we'll fix things up here.
if (FRAMEP (internal_last_event_frame)
&& XFRAME (internal_last_event_frame) != selected_frame)
Fselect_frame (internal_last_event_frame, Qnil);
-#endif
#endif
/* If it has changed current-menubar from previous value,
really recompute the menubar from the value. */
i = read_key_sequence (keybuf, sizeof keybuf / sizeof keybuf[0],
Qnil, 0, 1);
+ /* A filter may have run while we were reading the input. */
+ if (XBUFFER (XWINDOW (selected_window)->buffer) != current_buffer)
+ set_buffer_internal (XBUFFER (XWINDOW (selected_window)->buffer));
+
++num_input_keys;
/* Now we have read a key sequence of length I,
{
cancel_echoing ();
this_command_key_count = 0;
+ this_single_command_key_start = 0;
goto finalize;
}
this_command = cmd;
/* Note that the value cell will never directly contain nil
if the symbol is a local variable. */
- if (!NILP (XSYMBOL (Qpre_command_hook)->value) && !NILP (Vrun_hooks))
+ if (!NILP (Vpre_command_hook) && !NILP (Vrun_hooks))
safe_run_hooks (Qpre_command_hook);
if (NILP (this_command))
{
struct Lisp_Char_Table *dp
= window_display_table (XWINDOW (selected_window));
- lose = FETCH_CHAR (PT);
- SET_PT (PT + 1);
+ lose = FETCH_BYTE (PT);
+ SET_PT (forward_point (1));
if ((dp
? (VECTORP (DISP_CHAR_VECTOR (dp, lose))
? XVECTOR (DISP_CHAR_VECTOR (dp, lose))->size == 1
: (NILP (DISP_CHAR_VECTOR (dp, lose))
&& (lose >= 0x20 && lose < 0x7f)))
: (lose >= 0x20 && lose < 0x7f))
+ /* To extract the case of continuation on
+ wide-column characters. */
+ && (WIDTH_BY_CHAR_HEAD (FETCH_BYTE (PT)) == 1)
&& (XFASTINT (XWINDOW (selected_window)->last_modified)
>= MODIFF)
+ && (XFASTINT (XWINDOW (selected_window)->last_overlay_modified)
+ >= OVERLAY_MODIFF)
&& (XFASTINT (XWINDOW (selected_window)->last_point)
== PT - 1)
&& !windows_or_buffers_changed
&& EQ (current_buffer->selective_display, Qnil)
&& !detect_input_pending ()
+ && NILP (XWINDOW (selected_window)->column_number_displayed)
&& NILP (Vexecuting_macro))
no_redisplay = direct_output_forward_char (1);
goto directly_done;
{
struct Lisp_Char_Table *dp
= window_display_table (XWINDOW (selected_window));
- SET_PT (PT - 1);
- lose = FETCH_CHAR (PT);
+ SET_PT (forward_point (-1));
+ lose = FETCH_BYTE (PT);
if ((dp
? (VECTORP (DISP_CHAR_VECTOR (dp, lose))
? XVECTOR (DISP_CHAR_VECTOR (dp, lose))->size == 1
: (lose >= 0x20 && lose < 0x7f))
&& (XFASTINT (XWINDOW (selected_window)->last_modified)
>= MODIFF)
+ && (XFASTINT (XWINDOW (selected_window)->last_overlay_modified)
+ >= OVERLAY_MODIFF)
&& (XFASTINT (XWINDOW (selected_window)->last_point)
== PT + 1)
&& !windows_or_buffers_changed
&& EQ (current_buffer->selective_display, Qnil)
&& !detect_input_pending ()
+ && NILP (XWINDOW (selected_window)->column_number_displayed)
&& NILP (Vexecuting_macro))
no_redisplay = direct_output_forward_char (-1);
goto directly_done;
}
lose = ((XFASTINT (XWINDOW (selected_window)->last_modified)
< MODIFF)
+ || (XFASTINT (XWINDOW (selected_window)->last_overlay_modified)
+ < OVERLAY_MODIFF)
|| (XFASTINT (XWINDOW (selected_window)->last_point)
!= PT)
|| MODIFF <= SAVE_MODIFF
|| windows_or_buffers_changed
|| !EQ (current_buffer->selective_display, Qnil)
|| detect_input_pending ()
+ || !NILP (XWINDOW (selected_window)->column_number_displayed)
|| !NILP (Vexecuting_macro));
value = internal_self_insert (c, 0);
if (value)
nonundocount = 0;
if (!lose
- && (PT == ZV || FETCH_CHAR (PT) == '\n'))
+ && (PT == ZV || FETCH_BYTE (PT) == '\n'))
{
struct Lisp_Char_Table *dp
= window_display_table (XWINDOW (selected_window));
nonundocount = 0;
if (NILP (current_kboard->Vprefix_arg))
Fundo_boundary ();
- Fcommand_execute (this_command, Qnil);
+ Fcommand_execute (this_command, Qnil, Qnil, Qnil);
}
directly_done: ;
- /* Note that the value cell will never directly contain nil
- if the symbol is a local variable. */
- if (!NILP (XSYMBOL (Qpost_command_hook)->value) && !NILP (Vrun_hooks))
- safe_run_hooks (Qpost_command_hook);
-
- if (!NILP (Vdeferred_action_list))
- safe_run_hooks (Qdeferred_action_function);
-
- if (!NILP (XSYMBOL (Qpost_command_idle_hook)->value)
- && !NILP (Vrun_hooks))
- {
- if (NILP (Vunread_command_events)
- && NILP (Vexecuting_macro)
- && !NILP (sit_for (0, post_command_idle_delay, 0, 1)))
- safe_run_hooks (Qpost_command_idle_hook);
- }
-
/* If there is a prefix argument,
1) We don't want Vlast_command to be ``universal-argument''
(that would be dumb), so don't set Vlast_command,
current_kboard->Vlast_command = this_command;
cancel_echoing ();
this_command_key_count = 0;
+ this_single_command_key_start = 0;
+ }
+
+ /* Note that the value cell will never directly contain nil
+ if the symbol is a local variable. */
+ if (!NILP (Vpost_command_hook) && !NILP (Vrun_hooks))
+ safe_run_hooks (Qpost_command_hook);
+
+ if (!NILP (Vdeferred_action_list))
+ safe_run_hooks (Qdeferred_action_function);
+
+ if (!NILP (Vpost_command_idle_hook) && !NILP (Vrun_hooks))
+ {
+ if (NILP (Vunread_command_events)
+ && NILP (Vexecuting_macro)
+ && !NILP (sit_for (0, post_command_idle_delay, 0, 1)))
+ safe_run_hooks (Qpost_command_idle_hook);
}
if (!NILP (current_buffer->mark_active) && !NILP (Vrun_hooks))
int count = specpdl_ptr - specpdl;
specbind (Qinhibit_quit, hook);
- internal_condition_case (safe_run_hooks_1, Qerror, safe_run_hooks_error);
+ internal_condition_case (safe_run_hooks_1, Qt, safe_run_hooks_error);
unbind_to (count, Qnil);
}
input_poll_signal (signalnum) /* If we don't have an argument, */
int signalnum; /* some compilers complain in signal calls. */
{
+ /* This causes the call to start_polling at the end
+ to do its job. It also arranges for a quit or error
+ from within read_avail_input to resume polling. */
+ poll_suppress_count++;
if (interrupt_input_blocked == 0
&& !waiting_for_input)
read_avail_input (0);
- signal (SIGALRM, input_poll_signal);
- alarm (polling_period);
+ /* Turn on the SIGALRM handler and request another alarm. */
+ start_polling ();
}
#endif
c = XCONS (Vunread_command_events)->car;
Vunread_command_events = XCONS (Vunread_command_events)->cdr;
+ /* Undo what read_char_x_menu_prompt did when it unread
+ additional keys returned by Fx_popup_menu. */
+ if (CONSP (c)
+ && (SYMBOLP (XCONS (c)->car) || INTEGERP (XCONS (c)->car))
+ && NILP (XCONS (c)->cdr))
+ c = XCONS (c)->car;
+
if (this_command_key_count == 0)
goto reread_first;
else
if (!NILP (Vexecuting_macro))
{
-#ifdef MULTI_FRAME
/* We set this to Qmacro; since that's not a frame, nobody will
try to switch frames on us, and the selected window will
remain unchanged.
events read from a macro should never cause a new frame to be
selected. */
Vlast_event_frame = internal_last_event_frame = Qmacro;
-#endif
/* Exit the macro if we are at the end.
Also, some things replace the macro with t
goto reread_first;
}
- if (commandflag >= 0 && !input_pending && !detect_input_pending ())
+ if (commandflag >= 0 && !input_pending
+ && !detect_input_pending_run_timers (0))
redisplay ();
/* Message turns off echoing unless more keystrokes turn it on again. */
if (echo_area_glyphs && *echo_area_glyphs
- && echo_area_glyphs != current_kboard->echobuf)
+ && echo_area_glyphs != current_kboard->echobuf
+ && ok_to_echo_at_next_pause != echo_area_glyphs)
cancel_echoing ();
else
/* If already echoing, continue. */
/* Don't bring up a menu if we already have another event. */
&& NILP (Vunread_command_events)
&& unread_command_char < 0
- && !detect_input_pending ())
+ && !detect_input_pending_run_timers (0))
{
c = read_char_minibuf_menu_prompt (commandflag, nmaps, maps);
if (! NILP (c))
if (_setjmp (local_getcjmp))
{
XSETINT (c, quit_char);
-#ifdef MULTI_FRAME
XSETFRAME (internal_last_event_frame, selected_frame);
Vlast_event_frame = internal_last_event_frame;
-#endif
/* If we report the quit char as an event,
don't do so more than once. */
if (!NILP (Vinhibit_quit))
goto non_reread;
}
+ timer_start_idle ();
+
/* If in middle of key sequence and minibuffer not active,
start echoing if enough time elapses. */
&& this_command_key_count > 0
&& ! noninteractive
&& echo_keystrokes > 0
- && (echo_area_glyphs == 0 || *echo_area_glyphs == 0))
+ && (echo_area_glyphs == 0 || *echo_area_glyphs == 0
+ || ok_to_echo_at_next_pause == echo_area_glyphs))
{
Lisp_Object tem0;
This is because we are probably about to display a menu,
and we don't want to delay before doing so. */
if (EVENT_HAS_PARAMETERS (prev_event))
- echo ();
+ echo_now ();
else
{
save_getcjmp (save_jump);
tem0 = sit_for (echo_keystrokes, 0, 1, 1);
restore_getcjmp (save_jump);
if (EQ (tem0, Qt))
- echo ();
+ echo_now ();
}
}
if (commandflag != 0
&& auto_save_interval > 0
&& num_nonmacro_input_chars - last_auto_save > max (auto_save_interval, 20)
- && !detect_input_pending ())
+ && !detect_input_pending_run_timers (0))
{
Fdo_auto_save (Qnil, Qnil);
/* Hooks can actually change some buffers in auto save. */
/* Don't bring up a menu if we already have another event. */
&& NILP (Vunread_command_events)
&& unread_command_char < 0)
- c = read_char_x_menu_prompt (nmaps, maps, prev_event, used_mouse_menu);
+ {
+ c = read_char_x_menu_prompt (nmaps, maps, prev_event, used_mouse_menu);
+
+ /* Now that we have read an event, Emacs is not idle. */
+ timer_stop_idle ();
+
+ return c;
+ }
/* Maybe autosave and/or garbage collect due to idleness. */
&& XINT (Vauto_save_timeout) > 0)
{
Lisp_Object tem0;
- int delay = delay_level * XFASTINT (Vauto_save_timeout) / 4;
save_getcjmp (save_jump);
restore_getcjmp (local_getcjmp);
- tem0 = sit_for (delay, 0, 1, 1);
+ tem0 = sit_for (delay_level * XFASTINT (Vauto_save_timeout) / 4,
+ 0, 1, 1);
restore_getcjmp (save_jump);
if (EQ (tem0, Qt))
/* If we have auto-saved and there is still no input
available, garbage collect if there has been enough
consing going on to make it worthwhile. */
- if (!detect_input_pending ()
+ if (!detect_input_pending_run_timers (0)
&& consing_since_gc > gc_cons_threshold / 2)
Fgarbage_collect ();
= XCONS (current_kboard->kbd_queue)->cdr;
if (NILP (current_kboard->kbd_queue))
current_kboard->kbd_queue_has_data = 0;
- input_pending = readable_events ();
-#ifdef MULTI_FRAME
+ input_pending = readable_events (0);
if (EVENT_HAS_PARAMETERS (c)
&& EQ (EVENT_HEAD_KIND (EVENT_HEAD (c)), Qswitch_frame))
internal_last_event_frame = XCONS (XCONS (c)->cdr)->car;
Vlast_event_frame = internal_last_event_frame;
-#endif
}
}
non_reread:
+ /* Now that we have read an event, Emacs is not idle--
+ unless the event was a timer event (not used now). */
+ if (! (CONSP (c) && EQ (XCONS (c)->car, Qtimer_event)))
+ timer_stop_idle ();
+
start_polling ();
if (NILP (c))
{
if (commandflag >= 0
- && !input_pending && !detect_input_pending ())
+ && !input_pending && !detect_input_pending_run_timers (0))
redisplay ();
goto wrong_kboard;
if (!NILP (tem))
{
+ int was_locked = single_kboard;
+
last_input_char = c;
- Fcommand_execute (tem, Qnil);
+ Fcommand_execute (tem, Qnil, Fvector (1, &last_input_char), Qt);
+
+ /* Resume allowing input from any kboard, if that was true before. */
+ if (!was_locked)
+ any_kboard_state ();
+
goto retry;
}
/* Wipe the echo area. */
+ if (echo_area_glyphs)
+ safe_run_hooks (Qecho_area_clear_hook);
echo_area_glyphs = 0;
/* Handle things that only apply to characters. */
return c;
if (STRINGP (Vkeyboard_translate_table)
- && XSTRING (Vkeyboard_translate_table)->size > XFASTINT (c))
+ && XSTRING (Vkeyboard_translate_table)->size > (unsigned) XFASTINT (c))
XSETINT (c, XSTRING (Vkeyboard_translate_table)->data[XFASTINT (c)]);
else if ((VECTORP (Vkeyboard_translate_table)
- && XVECTOR (Vkeyboard_translate_table)->size > XFASTINT (c))
- || CHAR_TABLE_P (Vkeyboard_translate_table))
+ && XVECTOR (Vkeyboard_translate_table)->size > (unsigned) XFASTINT (c))
+ || (CHAR_TABLE_P (Vkeyboard_translate_table)
+ && CHAR_TABLE_ORDINARY_SLOTS > (unsigned) XFASTINT (c)))
{
Lisp_Object d;
d = Faref (Vkeyboard_translate_table, c);
echo_char (c);
if (! NILP (also_record))
echo_char (also_record);
+ /* Once we reread a character, echoing can happen
+ the next time we pause to read a new one. */
+ ok_to_echo_at_next_pause = echo_area_glyphs;
}
/* Record this character as part of the current key. */
return c;
}
+/* Record a key that came from a mouse menu.
+ Record it for echoing, for this-command-keys, and so on. */
+
+static void
+record_menu_key (c)
+ Lisp_Object c;
+{
+ /* Wipe the echo area. */
+ echo_area_glyphs = 0;
+
+ record_char (c);
+
+ before_command_key_count = this_command_key_count;
+ before_command_echo_length = echo_length ();
+
+ /* Don't echo mouse motion events. */
+ if (echo_keystrokes)
+ {
+ echo_char (c);
+
+ /* Once we reread a character, echoing can happen
+ the next time we pause to read a new one. */
+ ok_to_echo_at_next_pause = 0;
+ }
+
+ /* Record this character as part of the current key. */
+ add_command_key (c);
+
+ /* Re-reading in the middle of a command */
+ last_input_char = c;
+ num_input_chars++;
+}
+
/* Return 1 if should recognize C as "the help character". */
int
input has been processed. If the only input available was
the sort that we have just disabled, then we need to call
redisplay. */
- if (!readable_events ())
+ if (!readable_events (1))
{
redisplay_preserve_echo_area ();
- get_input_pending (&input_pending);
+ get_input_pending (&input_pending, 1);
}
}
}
\f
/* Low level keyboard/mouse input.
kbd_buffer_store_event places events in kbd_buffer, and
- kbd_buffer_get_event retrieves them.
- mouse_moved indicates when the mouse has moved again, and
- *mouse_position_hook provides the mouse position. */
+ kbd_buffer_get_event retrieves them. */
/* Return true iff there are any events in the queue that read-char
would return. If this returns false, a read-char would block. */
static int
-readable_events ()
+readable_events (do_timers_now)
+ int do_timers_now;
{
+ if (do_timers_now)
+ timer_check (do_timers_now);
+
if (kbd_fetch_ptr != kbd_store_ptr)
return 1;
#ifdef HAVE_MOUSE
}
#endif
-#ifdef MULTI_FRAME
/* If this results in a quit_char being returned to Emacs as
input, set Vlast_event_frame properly. If this doesn't
get returned to Emacs as an event, the next event read
internal_last_event_frame = focus;
Vlast_event_frame = focus;
}
-#endif
last_event_timestamp = event->timestamp;
interrupt_signal ();
{
register int c;
Lisp_Object obj;
+ EMACS_TIME next_timer_delay;
if (noninteractive)
{
and process it again. */
copy = *event;
kbd_fetch_ptr = event + 1;
- input_pending = readable_events ();
+ input_pending = readable_events (0);
x_handle_selection_request (©);
#else
/* We're getting selection request events, but we don't have
/* Remove it from the buffer before processing it. */
copy = *event;
kbd_fetch_ptr = event + 1;
- input_pending = readable_events ();
+ input_pending = readable_events (0);
x_handle_selection_clear (©);
#else
/* We're getting selection request events, but we don't have
abort ();
#endif
}
-#ifdef HAVE_X11
+#if defined (HAVE_X11) || defined (HAVE_NTGUI)
else if (event->kind == delete_window_event)
{
/* Make an event (delete-frame (FRAME)). */
else if (event->kind == menu_bar_activate_event)
{
kbd_fetch_ptr = event + 1;
- input_pending = readable_events ();
- x_activate_menubar (XFRAME (event->frame_or_window));
+ input_pending = readable_events (0);
+ if (FRAME_LIVE_P (XFRAME (event->frame_or_window)))
+ x_activate_menubar (XFRAME (event->frame_or_window));
}
#endif
/* Just discard these, by returning nil.
time, and leave the event in the queue for next time. */
else
{
-#ifdef MULTI_FRAME
Lisp_Object frame;
Lisp_Object focus;
&& XFRAME (frame) != selected_frame)
obj = make_lispy_switch_frame (frame);
internal_last_event_frame = frame;
-#endif /* MULTI_FRAME */
/* If we didn't decide to make a switch-frame event, go ahead
and build a real event from the queue entry. */
if (NILP (obj))
{
obj = make_lispy_event (event);
-#ifdef USE_X_TOOLKIT
+#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI)
/* If this was a menu selection, then set the flag to inhibit
writing to last_nonmenu_event. Don't do this if the event
we're returning is (menu-bar), though; that indicates the
obj = Qnil;
-#ifdef MULTI_FRAME
/* Decide if we should generate a switch-frame event. Don't
generate switch-frame events for motion outside of all Emacs
frames. */
obj = make_lispy_switch_frame (frame);
internal_last_event_frame = frame;
}
-#endif
/* If we didn't decide to make a switch-frame event, go ahead and
return a mouse-motion event. */
something for us to read! */
abort ();
- input_pending = readable_events ();
+ input_pending = readable_events (0);
-#ifdef MULTI_FRAME
Vlast_event_frame = internal_last_event_frame;
-#endif
return (obj);
}
then return, without reading any user-visible events. */
void
-swallow_events ()
+swallow_events (do_display)
+ int do_display;
{
+ int old_timers_run;
+
while (kbd_fetch_ptr != kbd_store_ptr)
{
struct input_event *event;
and process it again. */
copy = *event;
kbd_fetch_ptr = event + 1;
- input_pending = readable_events ();
+ input_pending = readable_events (0);
x_handle_selection_request (©);
#else
/* We're getting selection request events, but we don't have
copy = *event;
kbd_fetch_ptr = event + 1;
- input_pending = readable_events ();
+ input_pending = readable_events (0);
x_handle_selection_clear (©);
#else
/* We're getting selection request events, but we don't have
abort ();
#endif
}
+ /* Note that timer_event is currently never used. */
+ else if (event->kind == timer_event)
+ {
+ Lisp_Object tem, lisp_event;
+ int was_locked = single_kboard;
+
+ tem = get_keymap_1 (Vspecial_event_map, 0, 0);
+ tem = get_keyelt (access_keymap (tem, Qtimer_event, 0, 0),
+ 1);
+ lisp_event = Fcons (Qtimer_event,
+ Fcons (Fcdr (event->frame_or_window), Qnil));
+ kbd_fetch_ptr = event + 1;
+ if (kbd_fetch_ptr == kbd_store_ptr)
+ input_pending = 0;
+ Fcommand_execute (tem, Qnil, Fvector (1, &lisp_event), Qt);
+ timers_run++;
+ if (do_display)
+ redisplay_preserve_echo_area ();
+
+ /* Resume allowing input from any kboard, if that was true before. */
+ if (!was_locked)
+ any_kboard_state ();
+ }
else
break;
}
- get_input_pending (&input_pending);
+ old_timers_run = timers_run;
+ get_input_pending (&input_pending, 1);
+
+ if (timers_run != old_timers_run && do_display)
+ redisplay_preserve_echo_area ();
+}
+\f
+static EMACS_TIME timer_idleness_start_time;
+
+/* Record the start of when Emacs is idle,
+ for the sake of running idle-time timers. */
+
+timer_start_idle ()
+{
+ Lisp_Object timers;
+
+ /* If we are already in the idle state, do nothing. */
+ if (! EMACS_TIME_NEG_P (timer_idleness_start_time))
+ return;
+
+ EMACS_GET_TIME (timer_idleness_start_time);
+
+ /* Mark all idle-time timers as once again candidates for running. */
+ for (timers = Vtimer_idle_list; CONSP (timers); timers = XCONS (timers)->cdr)
+ {
+ Lisp_Object timer;
+
+ timer = XCONS (timers)->car;
+
+ if (!VECTORP (timer) || XVECTOR (timer)->size != 8)
+ continue;
+ XVECTOR (timer)->contents[0] = Qnil;
+ }
+}
+
+/* Record that Emacs is no longer idle, so stop running idle-time timers. */
+
+timer_stop_idle ()
+{
+ EMACS_SET_SECS_USECS (timer_idleness_start_time, -1, -1);
+}
+
+/* This is only for debugging. */
+struct input_event last_timer_event;
+
+/* Check whether a timer has fired. To prevent larger problems we simply
+ disregard elements that are not proper timers. Do not make a circular
+ timer list for the time being.
+
+ Returns the number of seconds to wait until the next timer fires. If a
+ timer is triggering now, return zero seconds.
+ If no timer is active, return -1 seconds.
+
+ If a timer is ripe, we run it, with quitting turned off.
+
+ DO_IT_NOW is now ignored. It used to mean that we should
+ run the timer directly instead of queueing a timer-event.
+ Now we always run timers directly. */
+
+EMACS_TIME
+timer_check (do_it_now)
+ int do_it_now;
+{
+ EMACS_TIME nexttime;
+ EMACS_TIME now, idleness_now;
+ Lisp_Object timers, idle_timers, chosen_timer;
+ /* Nonzero if we generate some events. */
+ int events_generated = 0;
+ struct gcpro gcpro1, gcpro2, gcpro3;
+
+ EMACS_SET_SECS (nexttime, -1);
+ EMACS_SET_USECS (nexttime, -1);
+
+ /* Always consider the ordinary timers. */
+ timers = Vtimer_list;
+ /* Consider the idle timers only if Emacs is idle. */
+ if (! EMACS_TIME_NEG_P (timer_idleness_start_time))
+ idle_timers = Vtimer_idle_list;
+ else
+ idle_timers = Qnil;
+ chosen_timer = Qnil;
+ GCPRO3 (timers, idle_timers, chosen_timer);
+
+ if (CONSP (timers) || CONSP (idle_timers))
+ {
+ EMACS_GET_TIME (now);
+ if (! EMACS_TIME_NEG_P (timer_idleness_start_time))
+ EMACS_SUB_TIME (idleness_now, now, timer_idleness_start_time);
+ }
+
+ while (CONSP (timers) || CONSP (idle_timers))
+ {
+ int triggertime = EMACS_SECS (now);
+ Lisp_Object *vector;
+ Lisp_Object timer, idle_timer;
+ EMACS_TIME timer_time, idle_timer_time;
+ EMACS_TIME difference, timer_difference, idle_timer_difference;
+
+ /* Skip past invalid timers and timers already handled. */
+ if (!NILP (timers))
+ {
+ timer = XCONS (timers)->car;
+ if (!VECTORP (timer) || XVECTOR (timer)->size != 8)
+ {
+ timers = XCONS (timers)->cdr;
+ continue;
+ }
+ vector = XVECTOR (timer)->contents;
+
+ if (!INTEGERP (vector[1]) || !INTEGERP (vector[2])
+ || !INTEGERP (vector[3])
+ || ! NILP (vector[0]))
+ {
+ timers = XCONS (timers)->cdr;
+ continue;
+ }
+ }
+ if (!NILP (idle_timers))
+ {
+ timer = XCONS (idle_timers)->car;
+ if (!VECTORP (timer) || XVECTOR (timer)->size != 8)
+ {
+ idle_timers = XCONS (idle_timers)->cdr;
+ continue;
+ }
+ vector = XVECTOR (timer)->contents;
+
+ if (!INTEGERP (vector[1]) || !INTEGERP (vector[2])
+ || !INTEGERP (vector[3])
+ || ! NILP (vector[0]))
+ {
+ idle_timers = XCONS (idle_timers)->cdr;
+ continue;
+ }
+ }
+
+ /* Set TIMER, TIMER_TIME and TIMER_DIFFERENCE
+ based on the next ordinary timer.
+ TIMER_DIFFERENCE is the distance in time from NOW to when
+ this timer becomes ripe (negative if it's already ripe). */
+ if (!NILP (timers))
+ {
+ timer = XCONS (timers)->car;
+ vector = XVECTOR (timer)->contents;
+ EMACS_SET_SECS (timer_time,
+ (XINT (vector[1]) << 16) | (XINT (vector[2])));
+ EMACS_SET_USECS (timer_time, XINT (vector[3]));
+ EMACS_SUB_TIME (timer_difference, timer_time, now);
+ }
+
+ /* Set IDLE_TIMER, IDLE_TIMER_TIME and IDLE_TIMER_DIFFERENCE
+ based on the next idle timer. */
+ if (!NILP (idle_timers))
+ {
+ idle_timer = XCONS (idle_timers)->car;
+ vector = XVECTOR (idle_timer)->contents;
+ EMACS_SET_SECS (idle_timer_time,
+ (XINT (vector[1]) << 16) | (XINT (vector[2])));
+ EMACS_SET_USECS (idle_timer_time, XINT (vector[3]));
+ EMACS_SUB_TIME (idle_timer_difference, idle_timer_time, idleness_now);
+ }
+
+ /* Decide which timer is the next timer,
+ and set CHOSEN_TIMER, VECTOR and DIFFERENCE accordingly.
+ Also step down the list where we found that timer. */
+
+ if (! NILP (timers) && ! NILP (idle_timers))
+ {
+ EMACS_TIME temp;
+ EMACS_SUB_TIME (temp, timer_difference, idle_timer_difference);
+ if (EMACS_TIME_NEG_P (temp))
+ {
+ chosen_timer = timer;
+ timers = XCONS (timers)->cdr;
+ difference = timer_difference;
+ }
+ else
+ {
+ chosen_timer = idle_timer;
+ idle_timers = XCONS (idle_timers)->cdr;
+ difference = idle_timer_difference;
+ }
+ }
+ else if (! NILP (timers))
+ {
+ chosen_timer = timer;
+ timers = XCONS (timers)->cdr;
+ difference = timer_difference;
+ }
+ else
+ {
+ chosen_timer = idle_timer;
+ idle_timers = XCONS (idle_timers)->cdr;
+ difference = idle_timer_difference;
+ }
+ vector = XVECTOR (chosen_timer)->contents;
+
+ /* If timer is rupe, run it if it hasn't been run. */
+ if (EMACS_TIME_NEG_P (difference)
+ || (EMACS_SECS (difference) == 0
+ && EMACS_USECS (difference) == 0))
+ {
+ if (NILP (vector[0]))
+ {
+ /* Mark the timer as triggered to prevent problems if the lisp
+ code fails to reschedule it right. */
+ vector[0] = Qt;
+
+ /* Run the timer or queue a timer event. */
+ if (1)
+ {
+ Lisp_Object tem, event;
+ int was_locked = single_kboard;
+ int count = specpdl_ptr - specpdl;
+
+ specbind (Qinhibit_quit, Qt);
+
+ tem = get_keymap_1 (Vspecial_event_map, 0, 0);
+ tem = get_keyelt (access_keymap (tem, Qtimer_event, 0, 0),
+ 1);
+ event = Fcons (Qtimer_event, Fcons (chosen_timer, Qnil));
+ Fcommand_execute (tem, Qnil, Fvector (1, &event), Qt);
+ timers_run++;
+
+ unbind_to (count, Qnil);
+
+ /* Resume allowing input from any kboard, if that was true before. */
+ if (!was_locked)
+ any_kboard_state ();
+
+ /* Since we have handled the event,
+ we don't need to tell the caller to wake up and do it. */
+ }
+#if 0
+ else
+ {
+ /* Generate a timer event so the caller will handle it. */
+ struct input_event event;
+
+ event.kind = timer_event;
+ event.modifiers = 0;
+ event.x = event.y = Qnil;
+ event.timestamp = triggertime;
+ /* Store the timer in the frame slot. */
+ event.frame_or_window
+ = Fcons (Fselected_frame (), chosen_timer);
+ kbd_buffer_store_event (&event);
+
+ last_timer_event = event;
+
+ /* Tell caller to handle this event right away. */
+ events_generated = 1;
+ EMACS_SET_SECS (nexttime, 0);
+ EMACS_SET_USECS (nexttime, 0);
+
+ /* Don't queue more than one event at once.
+ When Emacs is ready for another, it will
+ queue the next one. */
+ UNGCPRO;
+ return nexttime;
+ }
+#endif /* 0 */
+ }
+ }
+ else
+ /* When we encounter a timer that is still waiting,
+ return the amount of time to wait before it is ripe. */
+ {
+ UNGCPRO;
+ /* But if we generated an event,
+ tell the caller to handle it now. */
+ if (events_generated)
+ return nexttime;
+ return difference;
+ }
+ }
+
+ /* No timers are pending in the future. */
+ /* Return 0 if we generated an event, and -1 if not. */
+ UNGCPRO;
+ return nexttime;
}
\f
/* Caches for modify_event_symbol. */
"dead-abovedot",
};
+#ifdef HAVE_NTGUI
+#define FUNCTION_KEY_OFFSET 0x0
+
+char *lispy_function_keys[] =
+ {
+ 0, /* 0 */
+
+ 0, /* VK_LBUTTON 0x01 */
+ 0, /* VK_RBUTTON 0x02 */
+ "cancel", /* VK_CANCEL 0x03 */
+ 0, /* VK_MBUTTON 0x04 */
+
+ 0, 0, 0, /* 0x05 .. 0x07 */
+
+ "backspace", /* VK_BACK 0x08 */
+ "tab", /* VK_TAB 0x09 */
+
+ 0, 0, /* 0x0A .. 0x0B */
+
+ "clear", /* VK_CLEAR 0x0C */
+ "return", /* VK_RETURN 0x0D */
+
+ 0, 0, /* 0x0E .. 0x0F */
+
+ "shift", /* VK_SHIFT 0x10 */
+ "control", /* VK_CONTROL 0x11 */
+ "menu", /* VK_MENU 0x12 */
+ "pause", /* VK_PAUSE 0x13 */
+ "capital", /* VK_CAPITAL 0x14 */
+
+ 0, 0, 0, 0, 0, 0, /* 0x15 .. 0x1A */
+
+ 0, /* VK_ESCAPE 0x1B */
+
+ 0, 0, 0, 0, /* 0x1C .. 0x1F */
+
+ 0, /* VK_SPACE 0x20 */
+ "prior", /* VK_PRIOR 0x21 */
+ "next", /* VK_NEXT 0x22 */
+ "end", /* VK_END 0x23 */
+ "home", /* VK_HOME 0x24 */
+ "left", /* VK_LEFT 0x25 */
+ "up", /* VK_UP 0x26 */
+ "right", /* VK_RIGHT 0x27 */
+ "down", /* VK_DOWN 0x28 */
+ "select", /* VK_SELECT 0x29 */
+ "print", /* VK_PRINT 0x2A */
+ "execute", /* VK_EXECUTE 0x2B */
+ "snapshot", /* VK_SNAPSHOT 0x2C */
+ "insert", /* VK_INSERT 0x2D */
+ "delete", /* VK_DELETE 0x2E */
+ "help", /* VK_HELP 0x2F */
+
+ /* VK_0 thru VK_9 are the same as ASCII '0' thru '9' (0x30 - 0x39) */
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, /* 0x3A .. 0x40 */
+
+ /* VK_A thru VK_Z are the same as ASCII 'A' thru 'Z' (0x41 - 0x5A) */
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ "lwindow", /* VK_LWIN 0x5B */
+ "rwindow", /* VK_RWIN 0x5C */
+ "apps", /* VK_APPS 0x5D */
+
+ 0, 0, /* 0x5E .. 0x5F */
+
+ "kp-0", /* VK_NUMPAD0 0x60 */
+ "kp-1", /* VK_NUMPAD1 0x61 */
+ "kp-2", /* VK_NUMPAD2 0x62 */
+ "kp-3", /* VK_NUMPAD3 0x63 */
+ "kp-4", /* VK_NUMPAD4 0x64 */
+ "kp-5", /* VK_NUMPAD5 0x65 */
+ "kp-6", /* VK_NUMPAD6 0x66 */
+ "kp-7", /* VK_NUMPAD7 0x67 */
+ "kp-8", /* VK_NUMPAD8 0x68 */
+ "kp-9", /* VK_NUMPAD9 0x69 */
+ "kp-multiply", /* VK_MULTIPLY 0x6A */
+ "kp-add", /* VK_ADD 0x6B */
+ "kp-separator", /* VK_SEPARATOR 0x6C */
+ "kp-subtract", /* VK_SUBTRACT 0x6D */
+ "kp-decimal", /* VK_DECIMAL 0x6E */
+ "kp-divide", /* VK_DIVIDE 0x6F */
+ "f1", /* VK_F1 0x70 */
+ "f2", /* VK_F2 0x71 */
+ "f3", /* VK_F3 0x72 */
+ "f4", /* VK_F4 0x73 */
+ "f5", /* VK_F5 0x74 */
+ "f6", /* VK_F6 0x75 */
+ "f7", /* VK_F7 0x76 */
+ "f8", /* VK_F8 0x77 */
+ "f9", /* VK_F9 0x78 */
+ "f10", /* VK_F10 0x79 */
+ "f11", /* VK_F11 0x7A */
+ "f12", /* VK_F12 0x7B */
+ "f13", /* VK_F13 0x7C */
+ "f14", /* VK_F14 0x7D */
+ "f15", /* VK_F15 0x7E */
+ "f16", /* VK_F16 0x7F */
+ "f17", /* VK_F17 0x80 */
+ "f18", /* VK_F18 0x81 */
+ "f19", /* VK_F19 0x82 */
+ "f20", /* VK_F20 0x83 */
+ "f21", /* VK_F21 0x84 */
+ "f22", /* VK_F22 0x85 */
+ "f23", /* VK_F23 0x86 */
+ "f24", /* VK_F24 0x87 */
+
+ 0, 0, 0, 0, /* 0x88 .. 0x8B */
+ 0, 0, 0, 0, /* 0x8C .. 0x8F */
+
+ "kp-numlock", /* VK_NUMLOCK 0x90 */
+ "scroll", /* VK_SCROLL 0x91 */
+
+ "kp-space", /* VK_NUMPAD_CLEAR 0x92 */
+ "kp-enter", /* VK_NUMPAD_ENTER 0x93 */
+ "kp-prior", /* VK_NUMPAD_PRIOR 0x94 */
+ "kp-next", /* VK_NUMPAD_NEXT 0x95 */
+ "kp-end", /* VK_NUMPAD_END 0x96 */
+ "kp-home", /* VK_NUMPAD_HOME 0x97 */
+ "kp-left", /* VK_NUMPAD_LEFT 0x98 */
+ "kp-up", /* VK_NUMPAD_UP 0x99 */
+ "kp-right", /* VK_NUMPAD_RIGHT 0x9A */
+ "kp-down", /* VK_NUMPAD_DOWN 0x9B */
+ "kp-insert", /* VK_NUMPAD_INSERT 0x9C */
+ "kp-delete", /* VK_NUMPAD_DELETE 0x9D */
+
+ 0, 0, /* 0x9E .. 0x9F */
+
+ /*
+ * VK_L* & VK_R* - left and right Alt, Ctrl and Shift virtual keys.
+ * Used only as parameters to GetAsyncKeyState() and GetKeyState().
+ * No other API or message will distinguish left and right keys this way.
+ */
+ /* 0xA0 .. 0xEF */
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ /* 0xF0 .. 0xF5 */
+
+ 0, 0, 0, 0, 0, 0,
+
+ "attn", /* VK_ATTN 0xF6 */
+ "crsel", /* VK_CRSEL 0xF7 */
+ "exsel", /* VK_EXSEL 0xF8 */
+ "ereof", /* VK_EREOF 0xF9 */
+ "play", /* VK_PLAY 0xFA */
+ "zoom", /* VK_ZOOM 0xFB */
+ "noname", /* VK_NONAME 0xFC */
+ "pa1", /* VK_PA1 0xFD */
+ "oem_clear", /* VK_OEM_CLEAR 0xFE */
+ };
+
+#else
+
+#define FUNCTION_KEY_OFFSET 0xff00
+
+#ifdef XK_kana_A
+static char *lispy_kana_keys[] =
+ {
+ /* X Keysym value */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x400 .. 0x40f */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x410 .. 0x41f */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x420 .. 0x42f */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x430 .. 0x43f */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x440 .. 0x44f */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x450 .. 0x45f */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x460 .. 0x46f */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,"overline",0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x480 .. 0x48f */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x490 .. 0x49f */
+ 0, "kana-fullstop", "kana-openingbracket", "kana-closingbracket",
+ "kana-comma", "kana-conjunctive", "kana-WO", "kana-a",
+ "kana-i", "kana-u", "kana-e", "kana-o",
+ "kana-ya", "kana-yu", "kana-yo", "kana-tsu",
+ "prolongedsound", "kana-A", "kana-I", "kana-U",
+ "kana-E", "kana-O", "kana-KA", "kana-KI",
+ "kana-KU", "kana-KE", "kana-KO", "kana-SA",
+ "kana-SHI", "kana-SU", "kana-SE", "kana-SO",
+ "kana-TA", "kana-CHI", "kana-TSU", "kana-TE",
+ "kana-TO", "kana-NA", "kana-NI", "kana-NU",
+ "kana-NE", "kana-NO", "kana-HA", "kana-HI",
+ "kana-FU", "kana-HE", "kana-HO", "kana-MA",
+ "kana-MI", "kana-MU", "kana-ME", "kana-MO",
+ "kana-YA", "kana-YU", "kana-YO", "kana-RA",
+ "kana-RI", "kana-RU", "kana-RE", "kana-RO",
+ "kana-WA", "kana-N", "voicedsound", "semivoicedsound",
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x4e0 .. 0x4ef */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x4f0 .. 0x4ff */
+ };
+#endif /* XK_kana_A */
+
/* You'll notice that this table is arranged to be conveniently
indexed by X Windows keysym values. */
static char *lispy_function_keys[] =
0, 0, 0, 0, 0, 0, 0,
"escape",
0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xff20...2f */
+ 0, "kanji", "muhenkan",
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xff20...2f */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xff30...3f */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xff40...4f */
0, 0, 0, 0, 0, 0, 0, "delete"
};
+#endif /* HAVE_NTGUI */
+
static char *lispy_mouse_names[] =
{
"mouse-1", "mouse-2", "mouse-3", "mouse-4", "mouse-5"
/* Scroll bar parts. */
Lisp_Object Qabove_handle, Qhandle, Qbelow_handle;
+Lisp_Object Qup, Qdown;
/* An array of scroll bar parts, indexed by an enum scroll_bar_part value. */
Lisp_Object *scroll_bar_parts[] = {
- &Qabove_handle, &Qhandle, &Qbelow_handle
+ &Qabove_handle, &Qhandle, &Qbelow_handle,
+ &Qup, &Qdown,
};
(unsigned)-1);
}
- return modify_event_symbol (event->code - 0xff00,
+#ifdef XK_kana_A
+ if (event->code >= 0x400 && event->code < 0x500)
+ return modify_event_symbol (event->code - 0x400,
+ event->modifiers & ~shift_modifier,
+ Qfunction_key, Qnil,
+ lispy_kana_keys, &func_key_syms,
+ (sizeof (lispy_kana_keys)
+ / sizeof (lispy_kana_keys[0])));
+#endif /* XK_kana_A */
+
+ return modify_event_symbol (event->code - FUNCTION_KEY_OFFSET,
event->modifiers,
Qfunction_key, Qnil,
lispy_function_keys, &func_key_syms,
/ sizeof (lispy_function_keys[0])));
break;
+ /* Note that timer_event is currently never used. */
+ case timer_event:
+ return Fcons (Qtimer_event, Fcons (Fcdr (event->frame_or_window), Qnil));
+
#ifdef HAVE_MOUSE
/* A mouse click. Figure out where it is, decide whether it's
a press, click or drag, and build the appropriate structure. */
item = Qnil;
items = FRAME_MENU_BAR_ITEMS (f);
- for (i = 0; i < XVECTOR (items)->size; i += 3)
+ for (i = 0; i < XVECTOR (items)->size; i += 4)
{
Lisp_Object pos, string;
string = XVECTOR (items)->contents[i + 1];
- pos = XVECTOR (items)->contents[i + 2];
+ pos = XVECTOR (items)->contents[i + 3];
if (NILP (string))
break;
if (column >= XINT (pos)
else
{
int pixcolumn, pixrow;
- column -= XINT (XWINDOW (window)->left);
+ column -= WINDOW_LEFT_MARGIN (XWINDOW (window));
row -= XINT (XWINDOW (window)->top);
glyph_to_pixel_coords (f, column, row, &pixcolumn, &pixrow);
XSETINT (event->x, pixcolumn);
portion_whole = Fcons (event->x, event->y);
part = *scroll_bar_parts[(int) event->part];
- position =
- Fcons (window,
- Fcons (Qvertical_scroll_bar,
- Fcons (portion_whole,
- Fcons (make_number (event->timestamp),
- Fcons (part, Qnil)))));
+ position
+ = Fcons (window,
+ Fcons (Qvertical_scroll_bar,
+ Fcons (portion_whole,
+ Fcons (make_number (event->timestamp),
+ Fcons (part, Qnil)))));
}
start_pos_ptr = &XVECTOR (button_down_location)->contents[button];
Qnil));
}
}
+
+#ifdef WINDOWSNT
+ case w32_scroll_bar_click:
+ {
+ int button = event->code;
+ int is_double;
+ Lisp_Object position;
+ Lisp_Object *start_pos_ptr;
+ Lisp_Object start_pos;
+
+ if (button < 0 || button >= NUM_MOUSE_BUTTONS)
+ abort ();
+
+ {
+ Lisp_Object window;
+ Lisp_Object portion_whole;
+ Lisp_Object part;
+
+ window = event->frame_or_window;
+ portion_whole = Fcons (event->x, event->y);
+ part = *scroll_bar_parts[(int) event->part];
+
+ position =
+ Fcons (window,
+ Fcons (Qvertical_scroll_bar,
+ Fcons (portion_whole,
+ Fcons (make_number (event->timestamp),
+ Fcons (part, Qnil)))));
+ }
+
+ /* Always treat W32 scroll bar events as clicks. */
+ event->modifiers |= click_modifier;
+
+ {
+ /* Get the symbol we should use for the mouse click. */
+ Lisp_Object head;
+
+ head = modify_event_symbol (button,
+ event->modifiers,
+ Qmouse_click, Qnil,
+ lispy_mouse_names, &mouse_syms,
+ (sizeof (lispy_mouse_names)
+ / sizeof (lispy_mouse_names[0])));
+ return Fcons (head,
+ Fcons (position,
+ Qnil));
+ }
+ }
+#endif
+
#endif /* HAVE_MOUSE */
-#ifdef USE_X_TOOLKIT
+#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI)
case menu_bar_event:
/* The event value is in the cdr of the frame_or_window slot. */
if (!CONSP (event->frame_or_window))
Lisp_Object x, y;
unsigned long time;
{
-#ifdef MULTI_FRAME
/* Is it a scroll bar movement? */
if (frame && ! NILP (bar_window))
{
/* Or is it an ordinary mouse movement? */
else
-#endif /* MULTI_FRAME */
{
int area;
Lisp_Object window;
Lisp_Object posn;
int column, row;
-#ifdef MULTI_FRAME
if (frame)
-#else
- if (1)
-#endif
{
/* It's in a frame; which window on that frame? */
pixel_to_glyph_coords (frame, XINT (x), XINT (y), &column, &row,
if (WINDOWP (window))
{
int pixcolumn, pixrow;
- column -= XINT (XWINDOW (window)->left);
+ column -= WINDOW_LEFT_MARGIN (XWINDOW (window));
row -= XINT (XWINDOW (window)->top);
glyph_to_pixel_coords (frame, column, row, &pixcolumn, &pixrow);
XSETINT (x, pixcolumn);
XSETINT (posn,
buffer_posn_from_coords (XWINDOW (window), column, row));
}
-#ifdef MULTI_FRAME
else if (frame != 0)
{
XSETFRAME (window, frame);
posn = Qnil;
}
-#endif
else
{
window = Qnil;
/* No; let's create it. */
if (!NILP (name_alist))
value = Fcdr_safe (Fassq (symbol_int, name_alist));
- else if (name_table[symbol_num])
+ else if (name_table != 0 && name_table[symbol_num])
value = intern (name_table[symbol_num]);
-#ifdef HAVE_X_WINDOWS
+#ifdef HAVE_WINDOW_SYSTEM
if (NILP (value))
{
char *name = x_get_keysym_name (symbol_num);
}
if (CONSP (*symbol_table))
- *symbol_table = Fcons (value, *symbol_table);
+ *symbol_table = Fcons (Fcons (symbol_int, value), *symbol_table);
else
XVECTOR (*symbol_table)->contents[symbol_num] = value;
event type as a number or a symbol. */
DEFUN ("event-convert-list", Fevent_convert_list, Sevent_convert_list, 1, 1, 0,
- "Convert the event description LIST to an event type.\n\
-LIST should contain one base event type (a character or symbol)\n\
+ "Convert the event description list EVENT-DESC to an event type.\n\
+EVENT-DESC should contain one base event type (a character or symbol)\n\
and zero or more modifier names (control, meta, hyper, super, shift, alt,\n\
-drag, down, double or triple).\n\
+drag, down, double or triple). The base must be last.\n\
The return value is an event type (a character or symbol) which\n\
has the same base event type and all the specified modifiers.")
- (event)
- Lisp_Object event;
+ (event_desc)
+ Lisp_Object event_desc;
{
Lisp_Object base;
int modifiers = 0;
Lisp_Object rest;
base = Qnil;
- rest = event;
+ rest = event_desc;
while (CONSP (rest))
{
Lisp_Object elt;
int this = 0;
elt = XCONS (rest)->car;
+ rest = XCONS (rest)->cdr;
/* Given a symbol, see if it is a modifier name. */
- if (SYMBOLP (elt))
+ if (SYMBOLP (elt) && CONSP (rest))
this = parse_solitary_modifier (elt);
if (this != 0)
else
base = elt;
- rest = XCONS (rest)->cdr;
}
/* Let the symbol A refer to the character A. */
/* Store into *addr a value nonzero if terminal input chars are available.
Serves the purpose of ioctl (0, FIONREAD, addr)
but works even if FIONREAD does not exist.
- (In fact, this may actually read some input.) */
+ (In fact, this may actually read some input.)
+
+ If DO_TIMERS_NOW is nonzero, actually run timer events that are ripe. */
static void
-get_input_pending (addr)
+get_input_pending (addr, do_timers_now)
int *addr;
+ int do_timers_now;
{
/* First of all, have we already counted some input? */
- *addr = !NILP (Vquit_flag) || readable_events ();
+ *addr = !NILP (Vquit_flag) || readable_events (do_timers_now);
/* If input is being read as it arrives, and we have none, there is none. */
if (*addr > 0 || (interrupt_input && ! interrupts_deferred))
/* Try to read some input and see how much we get. */
gobble_input (0);
- *addr = !NILP (Vquit_flag) || readable_events ();
+ *addr = !NILP (Vquit_flag) || readable_events (do_timers_now);
}
/* Interface to read_avail_input, blocking SIGIO or SIGALRM if necessary. */
if (interrupt_input)
{
SIGMASKTYPE mask;
- mask = sigblockx (SIGIO);
+ mask = sigblock (sigmask (SIGIO));
read_avail_input (expected);
sigsetmask (mask);
}
if (read_socket_hook && !interrupt_input && poll_suppress_count == 0)
{
SIGMASKTYPE mask;
- mask = sigblockx (SIGALRM);
+ mask = sigblock (sigmask (SIGALRM));
read_avail_input (expected);
sigsetmask (mask);
}
if (interrupt_input)
{
SIGMASKTYPE mask;
- mask = sigblockx (SIGIO);
+ mask = sigblock (sigmask (SIGIO));
kbd_buffer_store_event (&event);
sigsetmask (mask);
}
if (read_socket_hook)
/* No need for FIONREAD or fcntl; just say don't wait. */
- nread = (*read_socket_hook) (input_fd, buf, KBD_BUFFER_SIZE,
- expected, expected);
+ nread = (*read_socket_hook) (input_fd, buf, KBD_BUFFER_SIZE, expected);
else
{
/* Using KBD_BUFFER_SIZE - 1 here avoids reading more than
if (n_to_read > sizeof cbuf)
n_to_read = sizeof cbuf;
#else /* no FIONREAD */
-#if defined(USG) || defined(DGUX)
+#if defined (USG) || defined (DGUX)
/* Read some input if available, but don't wait. */
n_to_read = sizeof cbuf;
fcntl (input_fd, F_SETFL, O_NDELAY);
do
{
#ifdef MSDOS
- cbuf[0] = dos_keyread();
+ cbuf[0] = dos_keyread ();
nread = 1;
#else
nread = read (input_fd, cbuf, n_to_read);
cbuf[i] &= ~0x80;
buf[i].code = cbuf[i];
-#ifdef MULTI_FRAME
XSETFRAME (buf[i].frame_or_window, selected_frame);
-#else
- buf[i].frame_or_window = Qnil;
-#endif
}
}
extern int select_alarmed;
#endif
-#ifdef USG
+#if defined (USG) && !defined (POSIX_SIGNALS)
/* USG systems forget handlers when they are used;
must reestablish each time */
signal (signo, input_available_signal);
reinvoke_input_signal ()
{
#ifdef SIGIO
- kill (0, SIGIO);
+ kill (getpid (), SIGIO);
#endif
}
int i;
int end = menu_bar_items_index;
- for (i = 0; i < end; i += 3)
+ for (i = 0; i < end; i += 4)
if (EQ (XCONS (tail)->car, XVECTOR (menu_bar_items_vector)->contents[i]))
{
- Lisp_Object tem0, tem1, tem2;
+ Lisp_Object tem0, tem1, tem2, tem3;
/* Move the item at index I to the end,
shifting all the others forward. */
tem0 = XVECTOR (menu_bar_items_vector)->contents[i + 0];
tem1 = XVECTOR (menu_bar_items_vector)->contents[i + 1];
tem2 = XVECTOR (menu_bar_items_vector)->contents[i + 2];
- if (end > i + 3)
- bcopy (&XVECTOR (menu_bar_items_vector)->contents[i + 3],
+ tem3 = XVECTOR (menu_bar_items_vector)->contents[i + 3];
+ if (end > i + 4)
+ bcopy (&XVECTOR (menu_bar_items_vector)->contents[i + 4],
&XVECTOR (menu_bar_items_vector)->contents[i],
- (end - i - 3) * sizeof (Lisp_Object));
- XVECTOR (menu_bar_items_vector)->contents[end - 3] = tem0;
- XVECTOR (menu_bar_items_vector)->contents[end - 2] = tem1;
- XVECTOR (menu_bar_items_vector)->contents[end - 1] = tem2;
+ (end - i - 4) * sizeof (Lisp_Object));
+ XVECTOR (menu_bar_items_vector)->contents[end - 4] = tem0;
+ XVECTOR (menu_bar_items_vector)->contents[end - 3] = tem1;
+ XVECTOR (menu_bar_items_vector)->contents[end - 2] = tem2;
+ XVECTOR (menu_bar_items_vector)->contents[end - 1] = tem3;
break;
}
}
- /* Add nil, nil, nil at the end. */
+ /* Add nil, nil, nil, nil at the end. */
i = menu_bar_items_index;
- if (i + 3 > XVECTOR (menu_bar_items_vector)->size)
+ if (i + 4 > XVECTOR (menu_bar_items_vector)->size)
{
Lisp_Object tem;
int newsize = 2 * i;
XVECTOR (menu_bar_items_vector)->contents[i++] = Qnil;
XVECTOR (menu_bar_items_vector)->contents[i++] = Qnil;
XVECTOR (menu_bar_items_vector)->contents[i++] = Qnil;
+ XVECTOR (menu_bar_items_vector)->contents[i++] = Qnil;
menu_bar_items_index = i;
Vinhibit_quit = oquit;
Lisp_Object enabled;
int i;
+ /* Skip menu-bar equiv keys data. */
+ if (CONSP (def) && CONSP (XCONS (def)->car))
+ def = XCONS (def)->cdr;
+
if (EQ (def, Qundefined))
{
/* If a map has an explicit `undefined' as definition,
discard any previously made menu bar item. */
- for (i = 0; i < menu_bar_items_index; i += 3)
+ for (i = 0; i < menu_bar_items_index; i += 4)
if (EQ (key, XVECTOR (menu_bar_items_vector)->contents[i]))
{
- if (menu_bar_items_index > i + 3)
- bcopy (&XVECTOR (menu_bar_items_vector)->contents[i + 3],
+ if (menu_bar_items_index > i + 4)
+ bcopy (&XVECTOR (menu_bar_items_vector)->contents[i + 4],
&XVECTOR (menu_bar_items_vector)->contents[i],
- (menu_bar_items_index - i - 3) * sizeof (Lisp_Object));
- menu_bar_items_index -= 3;
+ (menu_bar_items_index - i - 4) * sizeof (Lisp_Object));
+ menu_bar_items_index -= 4;
return;
}
return;
/* Find any existing item for this KEY. */
- for (i = 0; i < menu_bar_items_index; i += 3)
+ for (i = 0; i < menu_bar_items_index; i += 4)
if (EQ (key, XVECTOR (menu_bar_items_vector)->contents[i]))
break;
if (i == menu_bar_items_index)
{
/* If vector is too small, get a bigger one. */
- if (i + 3 > XVECTOR (menu_bar_items_vector)->size)
+ if (i + 4 > XVECTOR (menu_bar_items_vector)->size)
{
Lisp_Object tem;
int newsize = 2 * i;
XVECTOR (menu_bar_items_vector)->contents[i++] = key;
XVECTOR (menu_bar_items_vector)->contents[i++] = item_string;
XVECTOR (menu_bar_items_vector)->contents[i++] = Fcons (def, Qnil);
+ XVECTOR (menu_bar_items_vector)->contents[i++] = make_number (0);
menu_bar_items_index = i;
}
/* We did find an item for this KEY. Add DEF to its list of maps. */
if (mapno >= nmaps)
return Qnil;
-#if (defined (HAVE_X_WINDOWS) && defined (HAVE_X_MENU)) || defined (MSDOS)
+#ifdef HAVE_MENUS
/* If we got to this point via a mouse click,
use a real menu for mouse selection. */
if (EVENT_HAS_PARAMETERS (prev_event)
{
Lisp_Object tem;
+ record_menu_key (XCONS (value)->car);
+
/* If we got multiple events, unread all but
the first.
There is no way to prevent those unread events
they won't confuse things. */
for (tem = XCONS (value)->cdr; !NILP (tem);
tem = XCONS (tem)->cdr)
- if (SYMBOLP (XCONS (tem)->car)
- || INTEGERP (XCONS (tem)->car))
- XCONS (tem)->car
- = Fcons (XCONS (tem)->car, Qnil);
+ {
+ record_menu_key (XCONS (tem)->car);
+ if (SYMBOLP (XCONS (tem)->car)
+ || INTEGERP (XCONS (tem)->car))
+ XCONS (tem)->car
+ = Fcons (XCONS (tem)->car, Qnil);
+ }
/* If we got more than one event, put all but the first
onto this list to be read later.
*used_mouse_menu = 1;
return value;
}
-#endif /* (HAVE_X_WINDOWS && HAVE_X_MENU) || MSDOS */
+#endif /* HAVE_MENUS */
return Qnil ;
}
+/* Buffer in use so far for the minibuf prompts for menu keymaps.
+ We make this bigger when necessary, and never free it. */
+static char *read_char_minibuf_menu_text;
+/* Size of that buffer. */
+static int read_char_minibuf_menu_width;
+
static Lisp_Object
read_char_minibuf_menu_prompt (commandflag, nmaps, maps)
int commandflag ;
register Lisp_Object name;
int nlength;
int width = FRAME_WIDTH (selected_frame) - 4;
- char *menu = (char *) alloca (width + 4);
int idx = -1;
int nobindings = 1;
Lisp_Object rest, vector;
+ char *menu;
if (! menu_prompting)
return Qnil;
+ /* Make sure we have a big enough buffer for the menu text. */
+ if (read_char_minibuf_menu_text == 0)
+ {
+ read_char_minibuf_menu_width = width + 4;
+ read_char_minibuf_menu_text = (char *) xmalloc (width + 4);
+ }
+ else if (width + 4 > read_char_minibuf_menu_width)
+ {
+ read_char_minibuf_menu_width = width + 4;
+ read_char_minibuf_menu_text
+ = (char *) xrealloc (read_char_minibuf_menu_text, width + 4);
+ }
+ menu = read_char_minibuf_menu_text;
+
/* Get the menu name from the first map that has one (a prompt string). */
for (mapno = 0; mapno < nmaps; mapno++)
{
if (INTERACTIVE)
echo_start = echo_length ();
keys_start = this_command_key_count;
+ this_single_command_key_start = keys_start;
#if defined (GOBBLE_FIRST_EVENT)
/* This doesn't quite work, because some of the things that read_char
if (!used_mouse_menu)
last_nonmenu_event = key;
+ /* Record what part of this_command_keys is the current key sequence. */
+ this_single_command_key_start = this_command_key_count - t;
+
prev_fkey_map = fkey_map;
prev_fkey_start = fkey_start;
prev_fkey_end = fkey_end;
(To ignore it safely, we would need to gcpro a bunch of
other variables.) */
if (! (VECTORP (fkey_next) || STRINGP (fkey_next)))
- error ("Function in function-key-map returns invalid key sequence");
+ error ("Function in key-translation-map returns invalid key sequence");
}
function_key_possible = ! NILP (fkey_next);
original_uppercase = key;
original_uppercase_position = t - 1;
- if (XINT (new_key) & shift_modifier)
+ if (XINT (key) & shift_modifier)
XSETINT (new_key, XINT (key) & ~shift_modifier);
else
XSETINT (new_key, (DOWNCASE (XINT (key) & 0x3ffff)
gcpro1.nvars = (sizeof keybuf/sizeof (keybuf[0]));
if (NILP (continue_echo))
- this_command_key_count = 0;
+ {
+ this_command_key_count = 0;
+ this_single_command_key_start = 0;
+ }
i = read_key_sequence (keybuf, (sizeof keybuf/sizeof (keybuf[0])),
prompt, ! NILP (dont_downcase_last),
return make_event_array (i, keybuf);
}
\f
-DEFUN ("command-execute", Fcommand_execute, Scommand_execute, 1, 2, 0,
+DEFUN ("command-execute", Fcommand_execute, Scommand_execute, 1, 4, 0,
"Execute CMD as an editor command.\n\
CMD must be a symbol that satisfies the `commandp' predicate.\n\
Optional second arg RECORD-FLAG non-nil\n\
means unconditionally put this command in `command-history'.\n\
-Otherwise, that is done only if an arg is read using the minibuffer.")
- (cmd, record)
- Lisp_Object cmd, record;
+Otherwise, that is done only if an arg is read using the minibuffer.\n\
+The argument KEYS specifies the value to use instead of (this-command-keys)\n\
+when reading the arguments; if it is nil, (this-command-keys) is used.\n\
+The argument SPECIAL, if non-nil, means that this command is executing\n\
+a special event, so ignore the prefix argument and don't clear it.")
+ (cmd, record_flag, keys, special)
+ Lisp_Object cmd, record_flag, keys, special;
{
register Lisp_Object final;
register Lisp_Object tem;
struct backtrace backtrace;
extern int debug_on_next_call;
- prefixarg = current_kboard->Vprefix_arg;
- current_kboard->Vprefix_arg = Qnil;
- Vcurrent_prefix_arg = prefixarg;
debug_on_next_call = 0;
+ if (NILP (special))
+ {
+ prefixarg = current_kboard->Vprefix_arg;
+ Vcurrent_prefix_arg = prefixarg;
+ current_kboard->Vprefix_arg = Qnil;
+ }
+ else
+ prefixarg = Qnil;
+
if (SYMBOLP (cmd))
{
tem = Fget (cmd, Qdisabled);
final = Findirect_function (cmd);
if (CONSP (final) && (tem = Fcar (final), EQ (tem, Qautoload)))
- do_autoload (final, cmd);
+ {
+ struct gcpro gcpro1, gcpro2;
+
+ GCPRO2 (cmd, prefixarg);
+ do_autoload (final, cmd);
+ UNGCPRO;
+ }
else
break;
}
/* If requested, place the macro in the command history. For
other sorts of commands, call-interactively takes care of
this. */
- if (!NILP (record))
+ if (!NILP (record_flag))
Vcommand_history
= Fcons (Fcons (Qexecute_kbd_macro,
Fcons (final, Fcons (prefixarg, Qnil))),
backtrace.nargs = 1;
backtrace.evalargs = 0;
- tem = Fcall_interactively (cmd, record);
+ tem = Fcall_interactively (cmd, record_flag, keys);
backtrace_list = backtrace.next;
return tem;
Lisp_Object function;
char buf[40];
Lisp_Object saved_keys;
- struct gcpro gcpro1;
+ Lisp_Object bindings, value;
+ struct gcpro gcpro1, gcpro2;
saved_keys = Fvector (this_command_key_count,
XVECTOR (this_command_keys)->contents);
buf[0] = 0;
- GCPRO1 (saved_keys);
+ GCPRO2 (saved_keys, prefixarg);
if (EQ (prefixarg, Qminus))
strcpy (buf, "- ");
Vobarray, Qcommandp,
Qt, Qnil, Qextended_command_history);
+ if (STRINGP (function) && XSTRING (function)->size == 0)
+ error ("No command name given");
+
/* Set this_command_keys to the concatenation of saved_keys and
function, followed by a RET. */
{
Lisp_Object tem;
this_command_key_count = 0;
+ this_single_command_key_start = 0;
keys = XVECTOR (saved_keys)->contents;
for (i = 0; i < XVECTOR (saved_keys)->size; i++)
/* If enabled, show which key runs this command. */
if (!NILP (Vsuggest_key_bindings)
+ && NILP (Vexecuting_macro)
&& SYMBOLP (function))
- {
- Lisp_Object *maps, bindings;
- int nmaps, i;
-
- bindings = Qnil;
- nmaps = current_active_maps (&maps);
-
- for (i = 0; i < nmaps && NILP (bindings); i++)
- bindings = Fwhere_is_internal (function, maps[i], Qt, Qnil);
+ bindings = Fwhere_is_internal (function, Voverriding_local_map,
+ Qt, Qnil);
+ else
+ bindings = Qnil;
- free (maps);
+ value = Qnil;
+ GCPRO2 (bindings, value);
+ value = Fcommand_execute (function, Qt, Qnil, Qnil);
- if (!NILP (bindings))
+ /* If the command has a key binding, print it now. */
+ if (!NILP (bindings))
+ {
+ /* But first wait, and skip the message if there is input. */
+ if (!NILP (Fsit_for ((NUMBERP (Vsuggest_key_bindings)
+ ? Vsuggest_key_bindings : make_number (2)),
+ Qnil, Qnil)))
{
- message ("You can run the command `%s' by typing %s",
+ Lisp_Object binding;
+ char *newmessage;
+ char *oldmessage = echo_area_glyphs;
+ int oldmessage_len = echo_area_glyphs_length;
+
+ binding = Fkey_description (bindings);
+
+ newmessage
+ = (char *) alloca (XSYMBOL (function)->name->size
+ + XSTRING (binding)->size
+ + 100);
+ sprintf (newmessage, "You can run the command `%s' by typing %s",
XSYMBOL (function)->name->data,
- XSTRING (Fkey_description (bindings))->data);
- Fsit_for ((NUMBERP (Vsuggest_key_bindings)
- ? Vsuggest_key_bindings : make_number (2)),
- Qnil, Qnil);
+ XSTRING (binding)->data);
+ message1_nolog (newmessage);
+ if (!NILP (Fsit_for ((NUMBERP (Vsuggest_key_bindings)
+ ? Vsuggest_key_bindings : make_number (2)),
+ Qnil, Qnil)))
+ message2_nolog (oldmessage, oldmessage_len);
}
}
- return Fcommand_execute (function, Qt);
+ RETURN_UNGCPRO (value);
}
/* Find the set of keymaps now active.
return nmaps;
}
\f
+/* Return nonzero if input events are pending. */
detect_input_pending ()
{
if (!input_pending)
- get_input_pending (&input_pending);
+ get_input_pending (&input_pending, 0);
+
+ return input_pending;
+}
+
+/* Return nonzero if input events are pending, and run any pending timers. */
+
+detect_input_pending_run_timers (do_display)
+ int do_display;
+{
+ int old_timers_run = timers_run;
+
+ if (!input_pending)
+ get_input_pending (&input_pending, 1);
+
+ if (old_timers_run != timers_run && do_display)
+ redisplay_preserve_echo_area ();
return input_pending;
}
input_pending = 0;
}
+/* Return nonzero if there are pending requeued events.
+ This isn't used yet. The hope is to make wait_reading_process_input
+ call it, and return return if it runs Lisp code that unreads something.
+ The problem is, kbd_buffer_get_event needs to be fixed to know what
+ to do in that case. It isn't trivial. */
+
+requeued_events_pending_p ()
+{
+ return (!NILP (Vunread_command_events) || unread_command_char != -1);
+}
+
+
DEFUN ("input-pending-p", Finput_pending_p, Sinput_pending_p, 0, 0, 0,
"T if command input is currently available with no waiting.\n\
Actually, the value is nil only if we can be sure that no input is available.")
if (!NILP (Vunread_command_events) || unread_command_char != -1)
return (Qt);
- return detect_input_pending () ? Qt : Qnil;
+ get_input_pending (&input_pending, 1);
+ return input_pending > 0 ? Qt : Qnil;
}
DEFUN ("recent-keys", Frecent_keys, Srecent_keys, 0, 0, 0,
XVECTOR (this_command_keys)->contents);
}
+DEFUN ("this-single-command-keys", Fthis_single_command_keys,
+ Sthis_single_command_keys, 0, 0, 0,
+ "Return the key sequence that invoked this command.\n\
+Unlike `this-command-keys', this function's value\n\
+does not include prefix arguments.\n\
+The value is a string or a vector.")
+ ()
+{
+ return make_event_array (this_command_key_count
+ - this_single_command_key_start,
+ (XVECTOR (this_command_keys)->contents
+ + this_single_command_key_start));
+}
+
DEFUN ("reset-this-command-lengths", Freset_this_command_lengths,
Sreset_this_command_lengths, 0, 0, 0,
"Used for complicated reasons in `universal-argument-other-key'.\n\
(file)
Lisp_Object file;
{
- if (NILP (file))
+ if (dribble)
{
- if (dribble)
- {
- fclose (dribble);
- dribble = 0;
- }
+ fclose (dribble);
+ dribble = 0;
}
- else
+ if (!NILP (file))
{
file = Fexpand_file_name (file, Qnil);
dribble = fopen (XSTRING (file)->data, "w");
+ if (dribble == 0)
+ report_file_error ("Opening dribble", Fcons (file, Qnil));
}
return Qnil;
}
Lisp_Object stuffstring;
{
/* stuff_char works only in BSD, versions 4.2 and up. */
-#ifdef BSD
+#ifdef BSD_SYSTEM
#ifndef BSD4_1
register unsigned char *p;
}
input_pending = 0;
#endif
-#endif /* BSD and not BSD4_1 */
+#endif /* BSD_SYSTEM and not BSD4_1 */
}
\f
set_waiting_for_input (time_to_clear)
/* Must preserve main program's value of errno. */
int old_errno = errno;
-#ifdef USG
+#if defined (USG) && !defined (POSIX_SIGNALS)
if (!read_socket_hook && NILP (Vwindow_system))
{
/* USG systems forget handlers when they are used;
cancel_echoing ();
- if (!NILP (Vquit_flag) && FRAME_TERMCAP_P (selected_frame))
+ if (!NILP (Vquit_flag)
+ && (FRAME_TERMCAP_P (selected_frame) || FRAME_MSDOS_P (selected_frame)))
{
+ /* If SIGINT isn't blocked, don't let us be interrupted by
+ another SIGINT, it might be harmful due to non-reentrancy
+ in I/O functions. */
+ sigblock (sigmask (SIGINT));
+
fflush (stdout);
reset_sys_modes ();
- sigfree ();
+
#ifdef SIGTSTP /* Support possible in later USG versions */
/*
* On systems which can suspend the current process and return to the original
is used. Note that [Enter] is not echoed by dos. */
cursor_to (0, 0);
#endif
- printf ("Auto-save? (y or n) ");
- fflush (stdout);
- if (((c = getchar ()) & ~040) == 'Y')
+ /* It doesn't work to autosave while GC is in progress;
+ the code used for auto-saving doesn't cope with the mark bit. */
+ if (!gc_in_progress)
{
- Fdo_auto_save (Qt, Qnil);
+ printf ("Auto-save? (y or n) ");
+ fflush (stdout);
+ if (((c = getchar ()) & ~040) == 'Y')
+ {
+ Fdo_auto_save (Qt, Qnil);
#ifdef MSDOS
- printf ("\r\nAuto-save done");
+ printf ("\r\nAuto-save done");
#else /* not MSDOS */
- printf ("Auto-save done\n");
+ printf ("Auto-save done\n");
#endif /* not MSDOS */
+ }
+ while (c != '\n') c = getchar ();
}
- while (c != '\n') c = getchar ();
+ else
+ {
+ /* During GC, it must be safe to reenable quitting again. */
+ Vinhibit_quit = Qnil;
+#ifdef MSDOS
+ printf ("\r\n");
+#endif /* not MSDOS */
+ printf ("Garbage collection in progress; cannot auto-save now\r\n");
+ printf ("but will instead do a real quit after garbage collection ends\r\n");
+ fflush (stdout);
+ }
+
#ifdef MSDOS
printf ("\r\nAbort? (y or n) ");
#else /* not MSDOS */
#endif /* not MSDOS */
fflush (stdout);
init_sys_modes ();
+ sigfree ();
}
else
{
abort ();
#endif
#endif
-#ifdef MULTI_FRAME
if (FRAMEP (internal_last_event_frame)
&& XFRAME (internal_last_event_frame) != selected_frame)
do_switch_frame (make_lispy_switch_frame (internal_last_event_frame),
Qnil, 0);
-#endif
_longjmp (getcjmp, 1);
}
/*
* Destroy the contents of a kboard object, but not the object itself.
- * We use this just before deleteing it, or if we're going to initialize
+ * We use this just before deleting it, or if we're going to initialize
* it a second time.
*/
static void
quit_char = Ctl ('g');
Vunread_command_events = Qnil;
unread_command_char = -1;
+ EMACS_SET_SECS_USECS (timer_idleness_start_time, -1, -1);
total_keys = 0;
recent_keys_index = 0;
kbd_fetch_ptr = kbd_buffer;
#endif
input_pending = 0;
-#ifdef MULTI_FRAME
/* This means that command_loop_1 won't try to select anything the first
time through. */
internal_last_event_frame = Qnil;
Vlast_event_frame = internal_last_event_frame;
-#endif
#ifdef MULTI_KBOARD
current_kboard = initial_kboard;
staticpro (&Qfunction_key);
Qmouse_click = intern ("mouse-click");
staticpro (&Qmouse_click);
+ Qtimer_event = intern ("timer-event");
+ staticpro (&Qtimer_event);
Qmenu_enable = intern ("menu-enable");
staticpro (&Qmenu_enable);
staticpro (&Qhandle);
Qbelow_handle = intern ("below-handle");
staticpro (&Qbelow_handle);
+ Qup = intern ("up");
+ staticpro (&Qup);
+ Qdown = intern ("down");
+ staticpro (&Qdown);
Qevent_kind = intern ("event-kind");
staticpro (&Qevent_kind);
unread_switch_frame = Qnil;
staticpro (&unread_switch_frame);
+ internal_last_event_frame = Qnil;
+ staticpro (&internal_last_event_frame);
+
+ read_key_sequence_cmd = Qnil;
+ staticpro (&read_key_sequence_cmd);
+
defsubr (&Sevent_convert_list);
defsubr (&Sread_key_sequence);
defsubr (&Srecursive_edit);
defsubr (&Scommand_execute);
defsubr (&Srecent_keys);
defsubr (&Sthis_command_keys);
+ defsubr (&Sthis_single_command_keys);
defsubr (&Sreset_this_command_lengths);
defsubr (&Ssuspend_emacs);
defsubr (&Sabort_recursive_edit);
inhibit_local_menu_bar_menus = 0;
DEFVAR_INT ("num-input-keys", &num_input_keys,
- "Number of complete keys read from the keyboard so far.");
+ "Number of complete key sequences read from the keyboard so far.\n\
+This includes key sequences read from keyboard macros.\n\
+The number is effectively the number of interactive command invocations.");
num_input_keys = 0;
DEFVAR_LISP ("last-event-frame", &Vlast_event_frame,
DEFVAR_LISP ("post-command-idle-hook", &Vpost_command_idle_hook,
"Normal hook run after each command is executed, if idle.\n\
-Errors running the hook are caught and ignored.");
+Errors running the hook are caught and ignored.\n\
+This feature is obsolete; use idle timers instead. See `etc/NEWS'.");
Vpost_command_idle_hook = Qnil;
DEFVAR_INT ("post-command-idle-delay", &post_command_idle_delay,
- "Delay time before running `post-command-idle-delay'.\n\
+ "Delay time before running `post-command-idle-hook'.\n\
This is measured in microseconds.");
post_command_idle_delay = 100000;
+#if 0
+ DEFVAR_LISP ("echo-area-clear-hook", ...,
+ "Normal hook run when clearing the echo area.");
+#endif
+ Qecho_area_clear_hook = intern ("echo-area-clear-hook");
+ XSYMBOL (Qecho_area_clear_hook)->value = Qnil;
+
DEFVAR_LISP ("lucid-menu-bar-dirty-flag", &Vlucid_menu_bar_dirty_flag,
"t means menu bar, specified Lucid style, needs to be recomputed.");
Vlucid_menu_bar_dirty_flag = Qnil;
The value can be a length of time to show the message for.\n\
If the value is non-nil and not a number, we wait 2 seconds.");
Vsuggest_key_bindings = Qt;
+
+ DEFVAR_LISP ("timer-list", &Vtimer_list,
+ "List of active absolute time timers in order of increasing time");
+ Vtimer_list = Qnil;
+
+ DEFVAR_LISP ("timer-idle-list", &Vtimer_idle_list,
+ "List of active idle-time timers in order of increasing time");
+ Vtimer_idle_list = Qnil;
}
keys_of_keyboard ()