X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/0c9071cd60b6e1d5207d5c858b1737846e2de821..17cea80917206c92bd0029bd620bd718926eae9c:/src/keyboard.c diff --git a/src/keyboard.c b/src/keyboard.c index aa9138a4ba..a3dd95e0f7 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -1,5 +1,5 @@ /* Keyboard and mouse input; editor command loop. - Copyright (C) 1985,86,87,88,89,93,94,95,96 Free Software Foundation, Inc. + Copyright (C) 1985,86,87,88,89,93,94,95,96,97 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -32,11 +32,14 @@ Boston, MA 02111-1307, USA. */ #include "window.h" #include "commands.h" #include "buffer.h" +#include "charset.h" #include "disptab.h" #include "dispextern.h" #include "keyboard.h" +#include "syntax.h" #include "intervals.h" #include "blockinput.h" +#include "puresize.h" #include #include @@ -143,6 +146,8 @@ static int before_command_restore_flag; extern int minbuf_level; +extern int message_enable_multibyte; + extern struct backtrace *backtrace_list; /* Nonzero means do menu prompting. */ @@ -170,6 +175,9 @@ static int inhibit_local_menu_bar_menus; /* Nonzero means C-g should cause immediate error-signal. */ int immediate_quit; +/* The user's ERASE setting. */ +Lisp_Object Vtty_erase_char; + /* Character to recognize as the help char. */ Lisp_Object Vhelp_char; @@ -268,17 +276,17 @@ static int last_non_minibuf_size; static Lisp_Object Vauto_save_timeout; /* Total number of times read_char has returned. */ -int num_input_chars; +int num_input_events; /* Total number of times read_char has returned, outside of macros. */ -int num_nonmacro_input_chars; +int num_nonmacro_input_events; /* Auto-save automatically when this many characters have been typed since the last time. */ static int auto_save_interval; -/* Value of num_nonmacro_input_chars as of last auto save. */ +/* Value of num_nonmacro_input_events as of last auto save. */ int last_auto_save; @@ -293,14 +301,12 @@ int last_point_position; /* 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 @@ -315,6 +321,7 @@ Lisp_Object Qself_insert_command; Lisp_Object Qforward_char; Lisp_Object Qbackward_char; Lisp_Object Qundefined; +Lisp_Object Qtimer_event_handler; /* read_key_sequence stores here the command definition of the key sequence that it reads. */ @@ -341,6 +348,8 @@ Lisp_Object Vdeactivate_mark; 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; @@ -439,14 +448,23 @@ Lisp_Object Qmake_frame_visible; /* Symbols to denote kinds of events. */ Lisp_Object Qfunction_key; Lisp_Object Qmouse_click; -Lisp_Object Qtimer_event; +#ifdef WINDOWSNT +Lisp_Object Qmouse_wheel; +#endif +Lisp_Object Qdrag_n_drop; /* Lisp_Object Qmouse_movement; - also an event header */ /* Properties of event headers. */ Lisp_Object Qevent_kind; Lisp_Object Qevent_symbol_elements; +/* menu item parts */ +Lisp_Object Qmenu_alias; Lisp_Object Qmenu_enable; +Lisp_Object QCenable, QCvisible, QChelp, QCfilter, QCkeys, QCkey_sequence; +Lisp_Object QCbutton, QCtoggle, QCradio; +extern Lisp_Object Vdefine_key_rebound_commands; +extern Lisp_Object Qmenu_item; /* An event header symbol HEAD may have a property named Qevent_symbol_element_mask, which is of the form (BASE MODIFIERS); @@ -467,15 +485,17 @@ Lisp_Object Qvertical_line; Lisp_Object Qvertical_scroll_bar; Lisp_Object Qmenu_bar; -extern Lisp_Object Qmenu_enable; - Lisp_Object recursive_edit_unwind (), command_loop (); Lisp_Object Fthis_command_keys (); Lisp_Object Qextended_command_history; EMACS_TIME timer_check (); +extern Lisp_Object Vhistory_length; + 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. */ @@ -521,9 +541,6 @@ int flow_control; #ifdef HAVE_WINDOW_SYSTEM #define POLL_FOR_INPUT #endif - -/* Non-nil enables Column Number mode. */ -Lisp_Object Vcolumn_number_mode; /* Global variable declarations. */ @@ -542,6 +559,8 @@ static Lisp_Object make_lispy_movement (); static Lisp_Object modify_event_symbol (); static Lisp_Object make_lispy_switch_frame (); static int parse_solitary_modifier (); +static void save_getcjmp (); +static void restore_getcjmp (); /* > 0 if we are to echo keystrokes. */ static int echo_keystrokes; @@ -557,6 +576,7 @@ static int cannot_suspend; so that it serves as a prompt for the next character. Also start echoing. */ +void echo_prompt (str) char *str; { @@ -577,6 +597,7 @@ echo_prompt (str) C can be a character, which is printed prettily ("M-C-x" and all that jazz), or a symbol, whose name is printed. */ +void echo_char (c) Lisp_Object c; { @@ -602,10 +623,11 @@ echo_char (c) else if (SYMBOLP (c)) { struct Lisp_String *name = XSYMBOL (c)->name; - if ((ptr - current_kboard->echobuf) + name->size + 4 > ECHOBUFSIZE) + if ((ptr - current_kboard->echobuf) + STRING_BYTES (name) + 4 + > ECHOBUFSIZE) return; - bcopy (name->data, ptr, name->size); - ptr += name->size; + bcopy (name->data, ptr, STRING_BYTES (name)); + ptr += STRING_BYTES (name); } if (current_kboard->echoptr == current_kboard->echobuf @@ -625,6 +647,7 @@ echo_char (c) /* Temporarily add a dash to the end of the echo string if it's not empty, so that it serves as a mini-prompt for the very next character. */ +void echo_dash () { if (!current_kboard->immediate_echo @@ -649,6 +672,7 @@ echo_dash () /* Display the current echo string, and begin echoing if not already doing so. */ +void echo_now () { if (!current_kboard->immediate_echo) @@ -668,7 +692,9 @@ echo_now () } echoing = 1; - message1_nolog (current_kboard->echobuf); + message2_nolog (current_kboard->echobuf, strlen (current_kboard->echobuf), + ! NILP (current_buffer->enable_multibyte_characters)); + echoing = 0; if (waiting_for_input && !NILP (Vquit_flag)) @@ -677,6 +703,7 @@ echo_now () /* Turn off echoing, for the start of a new command. */ +void cancel_echoing () { current_kboard->immediate_echo = 0; @@ -755,19 +782,25 @@ recursive_edit_1 () 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); } /* When an auto-save happens, record the "time", and don't do again soon. */ +void record_auto_save () { - last_auto_save = num_nonmacro_input_chars; + last_auto_save = num_nonmacro_input_events; } /* Make an auto save happen as soon as possible at command level. */ +void force_auto_save_soon () { last_auto_save = - auto_save_interval - 1; @@ -888,10 +921,23 @@ cmd_error (data) 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 (); @@ -900,7 +946,7 @@ cmd_error (data) old_length = Vprint_length; XSETFASTINT (Vprint_level, 10); XSETFASTINT (Vprint_length, 10); - cmd_error_internal (data, NULL); + cmd_error_internal (data, macroerror); Vprint_level = old_level; Vprint_length = old_length; @@ -914,6 +960,15 @@ cmd_error (data) return make_number (0); } +/* Take actions on handling an error. DATA is the data that describes + the error. + + CONTEXT is a C-string containing ASCII characters only which + describes the context in which the error happened. If we need to + generalize CONTEXT to allow multibyte characters, make it a Lisp + string. */ + +void cmd_error_internal (data, context) Lisp_Object data; char *context; @@ -1054,7 +1109,7 @@ Lisp_Object command_loop_1 () { Lisp_Object cmd, tem; - int lose; + int lose, lose2; int nonundocount; Lisp_Object keybuf[30]; int i; @@ -1090,7 +1145,7 @@ command_loop_1 () { if (NILP (Vunread_command_events) && NILP (Vexecuting_macro) - && !NILP (sit_for (0, post_command_idle_delay, 0, 1))) + && !NILP (sit_for (0, post_command_idle_delay, 0, 1, 1))) safe_run_hooks (Qpost_command_idle_hook); } @@ -1126,7 +1181,8 @@ command_loop_1 () Fsit_for (make_number (2), Qnil, Qnil); /* Clear the echo area. */ - message2 (0); + message2 (0, 0, 0); + safe_run_hooks (Qecho_area_clear_hook); unbind_to (count, Qnil); @@ -1144,7 +1200,6 @@ command_loop_1 () #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. @@ -1152,7 +1207,6 @@ command_loop_1 () 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. */ @@ -1167,7 +1221,11 @@ command_loop_1 () /* Read next key sequence; i gets its length. */ i = read_key_sequence (keybuf, sizeof keybuf / sizeof keybuf[0], - Qnil, 0, 1); + Qnil, 0, 1, 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; @@ -1248,7 +1306,7 @@ command_loop_1 () { struct Lisp_Char_Table *dp = window_display_table (XWINDOW (selected_window)); - lose = FETCH_CHAR (PT); + lose = FETCH_CHAR (PT_BYTE); SET_PT (PT + 1); if ((dp ? (VECTORP (DISP_CHAR_VECTOR (dp, lose)) @@ -1256,14 +1314,19 @@ command_loop_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_BYTE)) == 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 (Vcolumn_number_mode) + && NILP (XWINDOW (selected_window)->column_number_displayed) && NILP (Vexecuting_macro)) no_redisplay = direct_output_forward_char (1); goto directly_done; @@ -1273,7 +1336,7 @@ command_loop_1 () struct Lisp_Char_Table *dp = window_display_table (XWINDOW (selected_window)); SET_PT (PT - 1); - lose = FETCH_CHAR (PT); + lose = FETCH_CHAR (PT_BYTE); if ((dp ? (VECTORP (DISP_CHAR_VECTOR (dp, lose)) ? XVECTOR (DISP_CHAR_VECTOR (dp, lose))->size == 1 @@ -1282,12 +1345,14 @@ command_loop_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 (Vcolumn_number_mode) + && NILP (XWINDOW (selected_window)->column_number_displayed) && NILP (Vexecuting_macro)) no_redisplay = direct_output_forward_char (-1); goto directly_done; @@ -1296,7 +1361,7 @@ command_loop_1 () /* Try this optimization only on ascii keystrokes. */ && INTEGERP (last_command_char)) { - unsigned char c = XINT (last_command_char); + unsigned int c = XINT (last_command_char); int value; if (NILP (Vexecuting_macro) @@ -1311,13 +1376,15 @@ command_loop_1 () } 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 (Vcolumn_number_mode) + || !NILP (XWINDOW (selected_window)->column_number_displayed) || !NILP (Vexecuting_macro)); value = internal_self_insert (c, 0); if (value) @@ -1326,12 +1393,18 @@ command_loop_1 () nonundocount = 0; if (!lose - && (PT == ZV || FETCH_CHAR (PT) == '\n')) + && (PT == ZV || FETCH_BYTE (PT_BYTE) == '\n')) { struct Lisp_Char_Table *dp = window_display_table (XWINDOW (selected_window)); int lose = c; + /* Add the offset to the character, for Finsert_char. + We pass internal_self_insert the unmodified character + because it itself does this offsetting. */ + if (! NILP (current_buffer->enable_multibyte_characters)) + lose = unibyte_char_to_multibyte (lose); + if (dp) { Lisp_Object obj; @@ -1385,7 +1458,7 @@ command_loop_1 () { if (NILP (Vunread_command_events) && NILP (Vexecuting_macro) - && !NILP (sit_for (0, post_command_idle_delay, 0, 1))) + && !NILP (sit_for (0, post_command_idle_delay, 0, 1, 1))) safe_run_hooks (Qpost_command_idle_hook); } @@ -1504,6 +1577,7 @@ input_poll_signal (signalnum) /* If we don't have an argument, */ /* Begin signals to poll for input, if they are appropriate. This function is called unconditionally from various places. */ +void start_polling () { #ifdef POLL_FOR_INPUT @@ -1534,6 +1608,7 @@ input_polling_used () /* Turn off polling. */ +void stop_polling () { #ifdef POLL_FOR_INPUT @@ -1573,6 +1648,7 @@ set_poll_suppress_count (count) /* Bind polling_period to a value at least N. But don't decrease it. */ +void bind_polling_period (n) int n; { @@ -1664,17 +1740,22 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu) Lisp_Object prev_event; int *used_mouse_menu; { - register Lisp_Object c; + Lisp_Object c; int count; jmp_buf local_getcjmp; jmp_buf save_jump; int key_already_recorded = 0; Lisp_Object tem, save; Lisp_Object also_record; + struct gcpro gcpro1; + also_record = Qnil; before_command_key_count = this_command_key_count; before_command_echo_length = echo_length (); + c = Qnil; + + GCPRO1 (c); retry: @@ -1713,7 +1794,6 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu) 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. @@ -1725,7 +1805,6 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu) 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 @@ -1734,7 +1813,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu) || executing_macro_index >= XFASTINT (Flength (Vexecuting_macro))) { XSETINT (c, -1); - return c; + RETURN_UNGCPRO (c); } c = Faref (Vexecuting_macro, make_number (executing_macro_index)); @@ -1757,9 +1836,30 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu) goto reread_first; } - if (commandflag >= 0 && !input_pending - && !detect_input_pending_run_timers (0)) - redisplay (); + /* if redisplay was requested */ + if (commandflag >= 0) + { + /* If there is pending input, process any events which are not + user-visible, such as X selection_request events. */ + if (input_pending + || detect_input_pending_run_timers (0)) + swallow_events (0); /* may clear input_pending */ + + /* Redisplay if no pending input. */ + while (!input_pending) + { + redisplay (); + + if (!input_pending) + /* Normal case: no input arrived during redisplay. */ + break; + + /* Input arrived and pre-empted redisplay. + Process any events which are not user-visible. */ + swallow_events (0); + /* If that cleared input_pending, try again to redisplay. */ + } + } /* Message turns off echoing unless more keystrokes turn it on again. */ if (echo_area_glyphs && *echo_area_glyphs @@ -1800,10 +1900,8 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu) 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)) @@ -1825,6 +1923,9 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu) *tailp = Fcons (c, Qnil); kb->kbd_queue_has_data = 1; current_kboard = kb; + /* This is going to exit from read_char + so we had better get rid of this frame's stuff. */ + UNGCPRO; longjmp (wrong_kboard_jmpbuf, 1); } } @@ -1855,9 +1956,10 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu) { save_getcjmp (save_jump); restore_getcjmp (local_getcjmp); - tem0 = sit_for (echo_keystrokes, 0, 1, 1); + tem0 = sit_for (echo_keystrokes, 0, 1, 1, 0); restore_getcjmp (save_jump); - if (EQ (tem0, Qt)) + if (EQ (tem0, Qt) + && ! CONSP (Vunread_command_events)) echo_now (); } } @@ -1866,7 +1968,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu) if (commandflag != 0 && auto_save_interval > 0 - && num_nonmacro_input_chars - last_auto_save > max (auto_save_interval, 20) + && num_nonmacro_input_events - last_auto_save > max (auto_save_interval, 20) && !detect_input_pending_run_timers (0)) { Fdo_auto_save (Qnil, Qnil); @@ -1886,7 +1988,14 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu) /* 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_UNGCPRO (c); + } /* Maybe autosave and/or garbage collect due to idleness. */ @@ -1908,7 +2017,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu) /* Auto save if enough time goes by without input. */ if (commandflag != 0 - && num_nonmacro_input_chars > last_auto_save + && num_nonmacro_input_events > last_auto_save && INTEGERP (Vauto_save_timeout) && XINT (Vauto_save_timeout) > 0) { @@ -1917,10 +2026,11 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu) save_getcjmp (save_jump); restore_getcjmp (local_getcjmp); tem0 = sit_for (delay_level * XFASTINT (Vauto_save_timeout) / 4, - 0, 1, 1); + 0, 1, 1, 0); restore_getcjmp (save_jump); - if (EQ (tem0, Qt)) + if (EQ (tem0, Qt) + && ! CONSP (Vunread_command_events)) { Fdo_auto_save (Qnil, Qnil); @@ -1936,6 +2046,14 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu) } } + /* If this has become non-nil here, it has been set by a timer + or sentinel or filter. */ + if (CONSP (Vunread_command_events)) + { + c = XCONS (Vunread_command_events)->car; + Vunread_command_events = XCONS (Vunread_command_events)->cdr; + } + /* Read something from current KBOARD's side queue, if possible. */ if (NILP (c)) @@ -1950,12 +2068,10 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu) if (NILP (current_kboard->kbd_queue)) current_kboard->kbd_queue_has_data = 0; input_pending = readable_events (0); -#ifdef MULTI_FRAME 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 } } @@ -1975,6 +2091,9 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu) if (kb->kbd_queue_has_data) { current_kboard = kb; + /* This is going to exit from read_char + so we had better get rid of this frame's stuff. */ + UNGCPRO; longjmp (wrong_kboard_jmpbuf, 1); } } @@ -2012,6 +2131,9 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu) if (single_kboard) goto wrong_kboard; current_kboard = kb; + /* This is going to exit from read_char + so we had better get rid of this frame's stuff. */ + UNGCPRO; longjmp (wrong_kboard_jmpbuf, 1); } #endif @@ -2037,10 +2159,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu) 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 (); + timer_stop_idle (); start_polling (); @@ -2056,12 +2175,10 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu) non_reread_1: /* Buffer switch events are only for internal wakeups - so don't show them to the user. */ - if (BUFFERP (c)) - return c; - - if (key_already_recorded) - return c; + so don't show them to the user. + Also, don't record a key if we already did. */ + if (BUFFERP (c) || key_already_recorded) + RETURN_UNGCPRO (c); /* Process special events within read_char and loop around to read another event. */ @@ -2086,6 +2203,8 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu) } /* 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. */ @@ -2093,14 +2212,14 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu) { /* If kbd_buffer_get_event gave us an EOF, return that. */ if (XINT (c) == -1) - return c; - - if (STRINGP (Vkeyboard_translate_table) - && XSTRING (Vkeyboard_translate_table)->size > 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)) + RETURN_UNGCPRO (c); + + if ((STRINGP (Vkeyboard_translate_table) + && XSTRING (Vkeyboard_translate_table)->size > (unsigned) XFASTINT (c)) + || (VECTORP (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); @@ -2140,6 +2259,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu) from_macro: reread_first: + before_command_key_count = this_command_key_count; before_command_echo_length = echo_length (); @@ -2164,7 +2284,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu) /* Re-reading in the middle of a command */ reread: last_input_char = c; - num_input_chars++; + num_input_events++; /* Process the help character specially if enabled */ if (!NILP (Vhelp_form) && help_char_p (c)) @@ -2196,7 +2316,40 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu) } } - return c; + RETURN_UNGCPRO (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_events++; } /* Return 1 if should recognize C as "the help character". */ @@ -2249,7 +2402,7 @@ record_char (c) { putc ('<', dribble); fwrite (XSYMBOL (dribblee)->name->data, sizeof (char), - XSYMBOL (dribblee)->name->size, + STRING_BYTES (XSYMBOL (dribblee)->name), dribble); putc ('>', dribble); } @@ -2260,7 +2413,7 @@ record_char (c) store_kbd_macro_char (c); - num_nonmacro_input_chars++; + num_nonmacro_input_events++; } Lisp_Object @@ -2280,12 +2433,14 @@ print_help (object) in case get_char is called recursively. See read_process_output. */ +static void save_getcjmp (temp) jmp_buf temp; { bcopy (getcjmp, temp, sizeof getcjmp); } +static void restore_getcjmp (temp) jmp_buf temp; { @@ -2464,7 +2619,6 @@ kbd_buffer_store_event (event) } #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 @@ -2478,7 +2632,6 @@ kbd_buffer_store_event (event) internal_last_event_frame = focus; Vlast_event_frame = focus; } -#endif last_event_timestamp = event->timestamp; interrupt_signal (); @@ -2534,6 +2687,28 @@ kbd_buffer_store_event (event) } } +/* Discard any mouse events in the event buffer by setting them to + no_event. */ +void +discard_mouse_events () +{ + struct input_event *sp; + for (sp = kbd_fetch_ptr; sp != kbd_store_ptr; sp++) + { + if (sp == kbd_buffer + KBD_BUFFER_SIZE) + sp = kbd_buffer; + + if (sp->kind == mouse_click +#ifdef WINDOWSNT + || sp->kind == w32_scroll_bar_click +#endif + || sp->kind == scroll_bar_click) + { + sp->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, @@ -2601,6 +2776,15 @@ kbd_buffer_get_event (kbp, used_mouse_menu) #endif /* not VMS */ } + if (CONSP (Vunread_command_events)) + { + Lisp_Object first; + first = XCONS (Vunread_command_events)->car; + Vunread_command_events = XCONS (Vunread_command_events)->cdr; + *kbp = current_kboard; + return first; + } + /* At this point, we know that there is a readable event available somewhere. If the event queue is empty, then there must be a mouse movement enabled and available. */ @@ -2691,12 +2875,13 @@ kbd_buffer_get_event (kbp, used_mouse_menu) XSETBUFFER (obj, current_buffer); kbd_fetch_ptr = event + 1; } -#ifdef USE_X_TOOLKIT +#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) else if (event->kind == menu_bar_activate_event) { kbd_fetch_ptr = event + 1; input_pending = readable_events (0); - x_activate_menubar (XFRAME (event->frame_or_window)); + if (FRAME_LIVE_P (XFRAME (event->frame_or_window))) + x_activate_menubar (XFRAME (event->frame_or_window)); } #endif /* Just discard these, by returning nil. @@ -2705,6 +2890,8 @@ kbd_buffer_get_event (kbp, used_mouse_menu) (They shouldn't otherwise be found in the buffer, but on some machines it appears they do show up even without MULTI_KBOARD.) */ + /* On Windows NT/9X, no_event is used to delete extraneous + mouse events during a popup-menu call. */ else if (event->kind == no_event) kbd_fetch_ptr = event + 1; @@ -2712,7 +2899,6 @@ kbd_buffer_get_event (kbp, used_mouse_menu) time, and leave the event in the queue for next time. */ else { -#ifdef MULTI_FRAME Lisp_Object frame; Lisp_Object focus; @@ -2730,7 +2916,6 @@ kbd_buffer_get_event (kbp, used_mouse_menu) && 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. */ @@ -2777,7 +2962,6 @@ kbd_buffer_get_event (kbp, used_mouse_menu) 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. */ @@ -2794,7 +2978,6 @@ kbd_buffer_get_event (kbp, used_mouse_menu) 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. */ @@ -2809,9 +2992,7 @@ kbd_buffer_get_event (kbp, used_mouse_menu) input_pending = readable_events (0); -#ifdef MULTI_FRAME Vlast_event_frame = internal_last_event_frame; -#endif return (obj); } @@ -2873,29 +3054,6 @@ swallow_events (do_display) 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; } @@ -2912,6 +3070,7 @@ static EMACS_TIME timer_idleness_start_time; /* Record the start of when Emacs is idle, for the sake of running idle-time timers. */ +void timer_start_idle () { Lisp_Object timers; @@ -2937,6 +3096,7 @@ timer_start_idle () /* Record that Emacs is no longer idle, so stop running idle-time timers. */ +void timer_stop_idle () { EMACS_SET_SECS_USECS (timer_idleness_start_time, -1, -1); @@ -2966,8 +3126,6 @@ timer_check (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); @@ -3104,64 +3262,27 @@ timer_check (do_it_now) { if (NILP (vector[0])) { + Lisp_Object tem; + int was_locked = single_kboard; + int count = specpdl_ptr - specpdl; + /* 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); + 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++; + call1 (Qtimer_event_handler, chosen_timer); + timers_run++; - unbind_to (count, Qnil); + unbind_to (count, Qnil); - /* Resume allowing input from any kboard, if that was true before. */ - if (!was_locked) - any_kboard_state (); + /* 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 */ + /* Since we have handled the event, + we don't need to tell the caller to wake up and do it. */ } } else @@ -3169,10 +3290,6 @@ timer_check (do_it_now) 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; } } @@ -3187,6 +3304,10 @@ timer_check (do_it_now) static Lisp_Object accent_key_syms; static Lisp_Object func_key_syms; static Lisp_Object mouse_syms; +#ifdef WINDOWSNT +static Lisp_Object mouse_wheel_syms; +#endif +static Lisp_Object drag_n_drop_syms; /* This is a list of keysym codes for special "accent" characters. It parallels lispy_accent_keys. */ @@ -3415,7 +3536,7 @@ char *lispy_function_keys[] = /* * VK_L* & VK_R* - left and right Alt, Ctrl and Shift virtual keys. - * Used only as parameters to GetAsyncKeyState() and GetKeyState(). + * Used only as parameters to GetAsyncKeyState and GetKeyState. * No other API or message will distinguish left and right keys this way. */ /* 0xA0 .. 0xEF */ @@ -3441,7 +3562,42 @@ char *lispy_function_keys[] = "oem_clear", /* VK_OEM_CLEAR 0xFE */ }; -#else +#else /* not HAVE_NTGUI */ + +#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 */ #define FUNCTION_KEY_OFFSET 0xff00 @@ -3464,7 +3620,8 @@ 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 */ @@ -3539,15 +3696,59 @@ static char *lispy_function_keys[] = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xfff0 */ 0, 0, 0, 0, 0, 0, 0, "delete" - }; + }; -#endif /* HAVE_NTGUI */ +/* ISO 9995 Function and Modifier Keys; the first byte is 0xFE. */ +#define ISO_FUNCTION_KEY_OFFSET 0xfe00 + +static char *iso_lispy_function_keys[] = + { + 0, 0, 0, 0, 0, 0, 0, 0, /* 0xfe00 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0xfe08 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0xfe10 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0xfe18 */ + "iso-lefttab", /* 0xfe20 */ + "iso-move-line-up", "iso-move-line-down", + "iso-partial-line-up", "iso-partial-line-down", + "iso-partial-space-left", "iso-partial-space-right", + "iso-set-margin-left", "iso-set-margin-right", /* 0xffe27, 28 */ + "iso-release-margin-left", "iso-release-margin-right", + "iso-release-both-margins", + "iso-fast-cursor-left", "iso-fast-cursor-right", + "iso-fast-cursor-up", "iso-fast-cursor-down", + "iso-continuous-underline", "iso-discontinuous-underline", /* 0xfe30, 31 */ + "iso-emphasize", "iso-center-object", "iso-enter", /* ... 0xfe34 */ + }; + +#endif /* not HAVE_NTGUI */ static char *lispy_mouse_names[] = { "mouse-1", "mouse-2", "mouse-3", "mouse-4", "mouse-5" }; +#ifdef WINDOWSNT +/* mouse-wheel events are generated by the wheel on devices such as + the MS Intellimouse. The wheel sits in between the left and right + mouse buttons, and is typically used to scroll or zoom the window + underneath the pointer. mouse-wheel events specify the object on + which they operate, and a delta corresponding to the amount and + direction that the wheel is rotated. Clicking the mouse-wheel + generates a mouse-2 event. */ +static char *lispy_mouse_wheel_names[] = +{ + "mouse-wheel" +}; + +#endif /* WINDOWSNT */ + +/* drag-n-drop events are generated when a set of selected files are + dragged from another application and dropped onto an Emacs window. */ +static char *lispy_drag_n_drop_names[] = +{ + "drag-n-drop" +}; + /* Scroll bar parts. */ Lisp_Object Qabove_handle, Qhandle, Qbelow_handle; Lisp_Object Qup, Qdown; @@ -3621,6 +3822,10 @@ make_lispy_event (event) c |= (event->modifiers & (meta_modifier | alt_modifier | hyper_modifier | super_modifier)); + /* Distinguish Shift-SPC from SPC. */ + if ((event->code & 0377) == 040 + && event->modifiers & shift_modifier) + c |= shift_modifier; button_down_time = 0; XSETFASTINT (lispy_c, c); return lispy_c; @@ -3655,17 +3860,33 @@ make_lispy_event (event) (unsigned)-1); } - return modify_event_symbol (event->code - FUNCTION_KEY_OFFSET, - event->modifiers, - Qfunction_key, Qnil, - lispy_function_keys, &func_key_syms, - (sizeof (lispy_function_keys) - / 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 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 */ + +#ifdef ISO_FUNCTION_KEY_OFFSET + if (event->code < FUNCTION_KEY_OFFSET + && event->code >= ISO_FUNCTION_KEY_OFFSET) + return modify_event_symbol (event->code - ISO_FUNCTION_KEY_OFFSET, + event->modifiers, + Qfunction_key, Qnil, + iso_lispy_function_keys, &func_key_syms, + (sizeof (iso_lispy_function_keys) + / sizeof (iso_lispy_function_keys[0]))); + else +#endif + return modify_event_symbol (event->code - FUNCTION_KEY_OFFSET, + event->modifiers, + Qfunction_key, Qnil, + lispy_function_keys, &func_key_syms, + (sizeof (lispy_function_keys) + / sizeof (lispy_function_keys[0]))); #ifdef HAVE_MOUSE /* A mouse click. Figure out where it is, decide whether it's @@ -3760,7 +3981,7 @@ make_lispy_event (event) 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); @@ -3912,7 +4133,7 @@ make_lispy_event (event) } #ifdef WINDOWSNT - case win32_scroll_bar_click: + case w32_scroll_bar_click: { int button = event->code; int is_double; @@ -3932,15 +4153,15 @@ make_lispy_event (event) 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))))); } - /* Always treat Win32 scroll bar events as clicks. */ + /* Always treat W32 scroll bar events as clicks. */ event->modifiers |= click_modifier; { @@ -3958,8 +4179,140 @@ make_lispy_event (event) Qnil)); } } -#endif + case mouse_wheel: + { + int part; + FRAME_PTR f = XFRAME (event->frame_or_window); + Lisp_Object window; + Lisp_Object posn; + Lisp_Object head, position; + int row, column; + + /* Ignore mouse events that were made on frame that + 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); + + if (!WINDOWP (window)) + { + window = event->frame_or_window; + posn = Qnil; + } + else + { + int pixcolumn, pixrow; + column -= XINT (XWINDOW (window)->left); + row -= XINT (XWINDOW (window)->top); + glyph_to_pixel_coords (f, column, row, &pixcolumn, &pixrow); + XSETINT (event->x, pixcolumn); + XSETINT (event->y, pixrow); + + if (part == 1) + posn = Qmode_line; + else if (part == 2) + posn = Qvertical_line; + else + XSETINT (posn, + buffer_posn_from_coords (XWINDOW (window), + column, row)); + } + + { + Lisp_Object head, position; + + position + = Fcons (window, + Fcons (posn, + Fcons (Fcons (event->x, event->y), + Fcons (make_number (event->timestamp), + Qnil)))); + + head = modify_event_symbol (0, event->modifiers, + Qmouse_wheel, Qnil, + lispy_mouse_wheel_names, + &mouse_wheel_syms, 1); + return Fcons (head, + Fcons (position, + Fcons (make_number (event->code), + Qnil))); + } + } +#endif /* WINDOWSNT */ + + case drag_n_drop: + { + int part; + FRAME_PTR f; + Lisp_Object window; + Lisp_Object posn; + Lisp_Object head, position; + 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 + dropped. */ + if (! CONSP (event->frame_or_window)) + abort (); + + f = XFRAME (XCONS (event->frame_or_window)->car); + files = XCONS (event->frame_or_window)->cdr; + + /* Ignore mouse events that were made on frames that + 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); + + if (!WINDOWP (window)) + { + window = XCONS (event->frame_or_window)->car; + posn = Qnil; + } + else + { + int pixcolumn, pixrow; + column -= XINT (XWINDOW (window)->left); + row -= XINT (XWINDOW (window)->top); + glyph_to_pixel_coords (f, column, row, &pixcolumn, &pixrow); + XSETINT (event->x, pixcolumn); + XSETINT (event->y, pixrow); + + if (part == 1) + posn = Qmode_line; + else if (part == 2) + posn = Qvertical_line; + else + XSETINT (posn, + buffer_posn_from_coords (XWINDOW (window), + column, row)); + } + { + Lisp_Object head, position; + + position + = Fcons (window, + Fcons (posn, + Fcons (Fcons (event->x, event->y), + Fcons (make_number (event->timestamp), + Qnil)))); + + head = modify_event_symbol (0, event->modifiers, + Qdrag_n_drop, Qnil, + lispy_drag_n_drop_names, + &drag_n_drop_syms, 1); + return Fcons (head, + Fcons (position, + Fcons (files, + Qnil))); + } + } #endif /* HAVE_MOUSE */ #if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) @@ -3986,7 +4339,6 @@ make_lispy_movement (frame, bar_window, part, x, y, time) Lisp_Object x, y; unsigned long time; { -#ifdef MULTI_FRAME /* Is it a scroll bar movement? */ if (frame && ! NILP (bar_window)) { @@ -4005,18 +4357,13 @@ make_lispy_movement (frame, bar_window, part, x, y, time) /* 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, @@ -4029,7 +4376,7 @@ make_lispy_movement (frame, bar_window, part, x, y, time) 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); @@ -4043,13 +4390,11 @@ make_lispy_movement (frame, bar_window, part, x, y, time) 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; @@ -4102,7 +4447,7 @@ parse_modifiers_uncached (symbol, modifier_end) modifiers = 0; name = XSYMBOL (symbol)->name; - for (i = 0; i+2 <= name->size; ) + for (i = 0; i+2 <= STRING_BYTES (name); ) { int this_mod_end = 0; int this_mod = 0; @@ -4149,7 +4494,8 @@ parse_modifiers_uncached (symbol, modifier_end) /* Check there is a dash after the modifier, so that it really is a modifier. */ - if (this_mod_end >= name->size || name->data[this_mod_end] != '-') + if (this_mod_end >= STRING_BYTES (name) + || name->data[this_mod_end] != '-') break; /* This modifier is real; look for another. */ @@ -4160,7 +4506,7 @@ parse_modifiers_uncached (symbol, modifier_end) /* Should we include the `click' modifier? */ if (! (modifiers & (down_modifier | drag_modifier | double_modifier | triple_modifier)) - && i + 7 == name->size + && i + 7 == STRING_BYTES (name) && strncmp (name->data + i, "mouse-", 6) == 0 && ('0' <= name->data[i + 6] && name->data[i + 6] <= '9')) modifiers |= click_modifier; @@ -4175,16 +4521,16 @@ parse_modifiers_uncached (symbol, modifier_end) prepended to the string BASE[0..BASE_LEN-1]. This doesn't use any caches. */ static Lisp_Object -apply_modifiers_uncached (modifiers, base, base_len) +apply_modifiers_uncached (modifiers, base, base_len, base_len_byte) int modifiers; char *base; - int base_len; + int base_len, base_len_byte; { /* Since BASE could contain nulls, we can't use intern here; we have to use Fintern, which expects a genuine Lisp_String, and keeps a reference to it. */ - char *new_mods = - (char *) alloca (sizeof ("A-C-H-M-S-s-down-drag-double-triple-")); + char *new_mods + = (char *) alloca (sizeof ("A-C-H-M-S-s-down-drag-double-triple-")); int mod_len; { @@ -4215,9 +4561,10 @@ apply_modifiers_uncached (modifiers, base, base_len) { Lisp_Object new_name; - new_name = make_uninit_string (mod_len + base_len); + new_name = make_uninit_multibyte_string (mod_len + base_len, + mod_len + base_len_byte); bcopy (new_mods, XSTRING (new_name)->data, mod_len); - bcopy (base, XSTRING (new_name)->data + mod_len, base_len); + bcopy (base, XSTRING (new_name)->data + mod_len, base_len_byte); return Fintern (new_name, Qnil); } @@ -4276,7 +4623,7 @@ parse_modifiers (symbol) Lisp_Object mask; unmodified = Fintern (make_string (XSYMBOL (symbol)->name->data + end, - XSYMBOL (symbol)->name->size - end), + STRING_BYTES (XSYMBOL (symbol)->name) - end), Qnil); if (modifiers & ~(((EMACS_INT)1 << VALBITS) - 1)) @@ -4330,7 +4677,8 @@ apply_modifiers (modifiers, base) /* We have to create the symbol ourselves. */ new_symbol = apply_modifiers_uncached (modifiers, XSYMBOL (base)->name->data, - XSYMBOL (base)->name->size); + XSYMBOL (base)->name->size, + STRING_BYTES (XSYMBOL (base)->name)); /* Add the new symbol to the base's cache. */ entry = Fcons (index, new_symbol); @@ -4463,7 +4811,7 @@ modify_event_symbol (symbol_num, modifiers, symbol_kind, name_alist, /* 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_WINDOW_SYSTEM @@ -4483,7 +4831,7 @@ modify_event_symbol (symbol_num, modifiers, symbol_kind, name_alist, } 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; @@ -4578,11 +4926,11 @@ parse_solitary_modifier (symbol) switch (name->data[0]) { #define SINGLE_LETTER_MOD(BIT) \ - if (name->size == 1) \ + if (STRING_BYTES (name) == 1) \ return BIT; #define MULTI_LETTER_MOD(BIT, NAME, LEN) \ - if (LEN == name->size \ + if (LEN == STRING_BYTES (name) \ && ! strncmp (name->data, NAME, LEN)) \ return BIT; @@ -4696,7 +5044,7 @@ get_input_pending (addr, do_timers_now) /* Interface to read_avail_input, blocking SIGIO or SIGALRM if necessary. */ -int +void gobble_input (expected) int expected; { @@ -4705,7 +5053,7 @@ gobble_input (expected) if (interrupt_input) { SIGMASKTYPE mask; - mask = sigblockx (SIGIO); + mask = sigblock (sigmask (SIGIO)); read_avail_input (expected); sigsetmask (mask); } @@ -4714,7 +5062,7 @@ gobble_input (expected) 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); } @@ -4728,6 +5076,7 @@ gobble_input (expected) /* Put a buffer_switch_event in the buffer so that read_key_sequence will notice the new current buffer. */ +void record_asynch_buffer_change () { struct input_event event; @@ -4754,7 +5103,7 @@ record_asynch_buffer_change () if (interrupt_input) { SIGMASKTYPE mask; - mask = sigblockx (SIGIO); + mask = sigblock (sigmask (SIGIO)); kbd_buffer_store_event (&event); sigsetmask (mask); } @@ -4791,8 +5140,7 @@ read_avail_input (expected) 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 @@ -4846,6 +5194,13 @@ read_avail_input (expected) #else nread = read (input_fd, cbuf, n_to_read); #endif + /* POSIX infers that processes which are not in the session leader's + process group won't get SIGHUP's at logout time. BSDI adheres to + this part standard and returns -1 from read (0) with errno==EIO + when the control tty is taken away. + Jeffrey Honig says this is generally safe. */ + if (nread == -1 && errno == EIO) + kill (0, SIGHUP); #if defined (AIX) && (! defined (aix386) && defined (_BSD)) /* The kernel sometimes fails to deliver SIGHUP for ptys. This looks incorrect, but it isn't, because _BSD causes @@ -4889,11 +5244,7 @@ read_avail_input (expected) 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 } } @@ -4925,7 +5276,7 @@ input_available_signal (signo) 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); @@ -5091,7 +5442,7 @@ menu_bar_items (old) for (mapno = nmaps - 1; mapno >= 0; mapno--) { if (! NILP (maps[mapno])) - def = get_keyelt (access_keymap (maps[mapno], Qmenu_bar, 1, 0)); + def = get_keyelt (access_keymap (maps[mapno], Qmenu_bar, 1, 0), 0); else def = Qnil; @@ -5159,25 +5510,14 @@ static void menu_bar_one_keymap (keymap) Lisp_Object keymap; { - Lisp_Object tail, item, key, binding, item_string, table; + Lisp_Object tail, item, table; /* Loop over all keymap entries that have menu strings. */ for (tail = keymap; CONSP (tail); tail = XCONS (tail)->cdr) { item = XCONS (tail)->car; if (CONSP (item)) - { - key = XCONS (item)->car; - binding = XCONS (item)->cdr; - if (CONSP (binding)) - { - item_string = XCONS (binding)->car; - if (STRINGP (item_string)) - menu_bar_item (key, item_string, Fcdr (binding)); - } - else if (EQ (binding, Qundefined)) - menu_bar_item (key, Qnil, binding); - } + menu_bar_item (XCONS (item)->car, XCONS (item)->cdr); else if (VECTORP (item)) { /* Loop over the char values represented in the vector. */ @@ -5187,41 +5527,25 @@ menu_bar_one_keymap (keymap) { Lisp_Object character; XSETFASTINT (character, c); - binding = XVECTOR (item)->contents[c]; - if (CONSP (binding)) - { - item_string = XCONS (binding)->car; - if (STRINGP (item_string)) - menu_bar_item (key, item_string, Fcdr (binding)); - } - else if (EQ (binding, Qundefined)) - menu_bar_item (key, Qnil, binding); + menu_bar_item (character, XVECTOR (item)->contents[c]); } } } } -/* This is used as the handler when calling internal_condition_case_1. */ - -static Lisp_Object -menu_bar_item_1 (arg) - Lisp_Object arg; -{ - return Qnil; -} - /* Add one item to menu_bar_items_vector, for KEY, ITEM_STRING and DEF. If there's already an item for KEY, add this DEF to it. */ +Lisp_Object item_properties; + static void -menu_bar_item (key, item_string, def) - Lisp_Object key, item_string, def; +menu_bar_item (key, item) + Lisp_Object key, item; { - Lisp_Object tem; - Lisp_Object enabled; + struct gcpro gcpro1; int i; - if (EQ (def, Qundefined)) + if (EQ (item, Qundefined)) { /* If a map has an explicit `undefined' as definition, discard any previously made menu bar item. */ @@ -5242,25 +5566,14 @@ menu_bar_item (key, item_string, def) return; } - /* See if this entry is enabled. */ - enabled = Qt; - - if (SYMBOLP (def)) - { - /* No property, or nil, means enable. - Otherwise, enable if value is not nil. */ - tem = Fget (def, Qmenu_enable); - if (!NILP (tem)) - /* (condition-case nil (eval tem) - (error nil)) */ - enabled = internal_condition_case_1 (Feval, tem, Qerror, - menu_bar_item_1); - } - - /* Ignore this item if it's not enabled. */ - if (NILP (enabled)) + GCPRO1 (key); /* Is this necessary? */ + 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. */ for (i = 0; i < menu_bar_items_index; i += 4) if (EQ (key, XVECTOR (menu_bar_items_vector)->contents[i])) @@ -5279,20 +5592,387 @@ menu_bar_item (key, item_string, def) XVECTOR (tem)->contents, i * sizeof (Lisp_Object)); menu_bar_items_vector = tem; } + /* Add this item. */ 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++] + = XVECTOR (item_properties)->contents[ITEM_PROPERTY_NAME]; + XVECTOR (menu_bar_items_vector)->contents[i++] = Fcons (item, 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. */ + /* We did find an item for this KEY. Add ITEM to its list of maps. */ else { Lisp_Object old; old = XVECTOR (menu_bar_items_vector)->contents[i + 2]; - XVECTOR (menu_bar_items_vector)->contents[i + 2] = Fcons (def, old); + XVECTOR (menu_bar_items_vector)->contents[i + 2] = Fcons (item, old); + } +} + + /* This is used as the handler when calling menu_item_eval_property. */ +static Lisp_Object +menu_item_eval_property_1 (arg) + Lisp_Object arg; +{ + /* If we got a quit from within the menu computation, + quit all the way out of it. This takes care of C-] in the debugger. */ + if (CONSP (arg) && EQ (XCONS (arg)->car, Qquit)) + Fsignal (Qquit, Qnil); + + return Qnil; +} + +/* Evaluate an expression and return the result (or nil if something + went wrong). Used to evaluate dynamic parts of menu items. */ +static Lisp_Object +menu_item_eval_property (sexpr) + Lisp_Object sexpr; +{ + Lisp_Object val; + val = internal_condition_case_1 (Feval, sexpr, Qerror, + menu_item_eval_property_1); + return val; +} + +/* This function parses a menu item and leaves the result in the + vector item_properties. + ITEM is a key binding, a possible menu item. + If NOTREAL is nonzero, only check for equivalent key bindings, don't + evaluate dynamic expressions in the menu item. + INMENUBAR is > 0 when this is considered for an entry in a menu bar + top level. + INMENUBAR is < 0 when this is considered for an entry in a keyboard menu. + parse_menu_item returns true if the item is a menu item and false + otherwise. */ + +int +parse_menu_item (item, notreal, inmenubar) + Lisp_Object item; + int notreal, inmenubar; +{ + Lisp_Object def, tem, item_string, start; + Lisp_Object cachelist = Qnil; + Lisp_Object filter = Qnil; + Lisp_Object keyhint = Qnil; + int i; + int newcache = 0; + + if (!CONSP (item)) + return 0; + + /* Create item_properties vector if necessary. */ + if (NILP (item_properties)) + item_properties + = Fmake_vector (make_number (ITEM_PROPERTY_ENABLE + 1), Qnil); + + /* 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; + + /* Save the item here to protect it from GC. */ + XVECTOR (item_properties)->contents[ITEM_PROPERTY_ITEM] = item; + + item_string = XCONS (item)->car; + + start = item; + item = XCONS (item)->cdr; + if (STRINGP (item_string)) + { + /* Old format menu item. */ + XVECTOR (item_properties)->contents[ITEM_PROPERTY_NAME] = item_string; + + /* Maybe help string. */ + if (CONSP (item) && STRINGP (XCONS (item)->car)) + { + XVECTOR (item_properties)->contents[ITEM_PROPERTY_HELP] + = XCONS (item)->car; + start = item; + item = XCONS (item)->cdr; + } + + /* Maybee key binding cache. */ + if (CONSP (item) && CONSP (XCONS (item)->car) + && (NILP (XCONS (XCONS (item)->car)->car) + || VECTORP (XCONS (XCONS (item)->car)->car))) + { + cachelist = XCONS (item)->car; + item = XCONS (item)->cdr; + } + + /* This is the real definition--the function to run. */ + XVECTOR (item_properties)->contents[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; + } + } + else if (EQ (item_string, Qmenu_item) && CONSP (item)) + { + /* New format menu item. */ + XVECTOR (item_properties)->contents[ITEM_PROPERTY_NAME] + = XCONS (item)->car; + start = XCONS (item)->cdr; + if (CONSP (start)) + { + /* We have a real binding. */ + XVECTOR (item_properties)->contents[ITEM_PROPERTY_DEF] + = XCONS (start)->car; + + item = XCONS (start)->cdr; + /* Is there a cache list with key equivalences. */ + if (CONSP (item) && CONSP (XCONS (item)->car)) + { + cachelist = XCONS (item)->car; + item = XCONS (item)->cdr; + } + + /* Parse properties. */ + while (CONSP (item) && CONSP (XCONS (item)->cdr)) + { + tem = XCONS (item)->car; + item = XCONS (item)->cdr; + + if (EQ (tem, QCenable)) + XVECTOR (item_properties)->contents[ITEM_PROPERTY_ENABLE] + = XCONS (item)->car; + else if (EQ (tem, QCvisible) && !notreal) + { + /* If got a visible property and that evaluates to nil + then ignore this item. */ + tem = menu_item_eval_property (XCONS (item)->car); + if (NILP (tem)) + return 0; + } + else if (EQ (tem, QChelp)) + XVECTOR (item_properties)->contents[ITEM_PROPERTY_HELP] + = XCONS (item)->car; + else if (EQ (tem, QCfilter)) + filter = item; + else if (EQ (tem, QCkey_sequence)) + { + tem = XCONS (item)->car; + if (NILP (cachelist) + && (SYMBOLP (tem) || STRINGP (tem) || VECTORP (tem))) + /* Be GC protected. Set keyhint to item instead of tem. */ + keyhint = item; + } + else if (EQ (tem, QCkeys)) + { + tem = XCONS (item)->car; + if (CONSP (tem) || STRINGP (tem) && NILP (cachelist)) + XVECTOR (item_properties)->contents[ITEM_PROPERTY_KEYEQ] + = tem; + } + else if (EQ (tem, QCbutton) && CONSP (XCONS (item)->car)) + { + Lisp_Object type; + tem = XCONS (item)->car; + type = XCONS (tem)->car; + if (EQ (type, QCtoggle) || EQ (type, QCradio)) + { + XVECTOR (item_properties)->contents[ITEM_PROPERTY_SELECTED] + = XCONS (tem)->cdr; + XVECTOR (item_properties)->contents[ITEM_PROPERTY_TYPE] + = type; + } + } + item = XCONS (item)->cdr; + } + } + else if (inmenubar || !NILP (start)) + return 0; + } + else + return 0; /* not a menu item */ + + /* 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]; + 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; + } + + /* If got a filter apply it on definition. */ + def = XVECTOR (item_properties)->contents[ITEM_PROPERTY_DEF]; + if (!NILP (filter)) + { + def = menu_item_eval_property (Fcons (XCONS (filter)->car, + Fcons (def, Qnil))); + XVECTOR (item_properties)->contents[ITEM_PROPERTY_DEF] = def; + } + + /* If we got no definition, this item is just unselectable text which + is OK in a submenu but not in the menubar. */ + if (NILP (def)) + return (inmenubar ? 0 : 1); + + /* Enable or disable selection of item. */ + tem = XVECTOR (item_properties)->contents[ITEM_PROPERTY_ENABLE]; + if (!EQ (tem, Qt)) + { + if (notreal) + tem = Qt; + else + 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; + } + + /* 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); + if (!NILP (tem)) + { + XVECTOR (item_properties)->contents[ITEM_PROPERTY_MAP] = tem; + XVECTOR (item_properties)->contents[ITEM_PROPERTY_DEF] = tem; + return 1; + } + else if (inmenubar > 0) + return 0; /* Entries in menu bar must be submenus. */ + + /* This is a command. See if there is an equivalent key binding. */ + if (NILP (cachelist)) + { + /* We have to create a cachelist. */ + CHECK_IMPURE (start); + XCONS (start)->cdr = Fcons (Fcons (Qnil, Qnil), XCONS (start)->cdr); + cachelist = XCONS (XCONS (start)->cdr)->car; + newcache = 1; + tem = XVECTOR (item_properties)->contents[ITEM_PROPERTY_KEYEQ]; + if (!NILP (keyhint)) + { + XCONS (cachelist)->car = XCONS (keyhint)->car; + newcache = 0; + } + else if (STRINGP (tem)) + { + XCONS (cachelist)->cdr = Fsubstitute_command_keys (tem); + XCONS (cachelist)->car = Qt; + } } + tem = XCONS (cachelist)->car; + if (!EQ (tem, Qt)) + { + int chkcache = 0; + Lisp_Object prefix; + + if (!NILP (tem)) + tem = Fkey_binding (tem, Qnil); + + prefix = XVECTOR (item_properties)->contents[ITEM_PROPERTY_KEYEQ]; + if (CONSP (prefix)) + { + def = XCONS (prefix)->car; + prefix = XCONS (prefix)->cdr; + } + else + def = XVECTOR (item_properties)->contents[ITEM_PROPERTY_DEF]; + + if (NILP (XCONS (cachelist)->car)) /* 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 + recheck any command that appears in that list. */ + || (CONSP (Vdefine_key_rebound_commands) + && !NILP (Fmemq (def, Vdefine_key_rebound_commands)))) + chkcache = 1; + } + /* We had a saved key. Is it still bound to the command? */ + else if (NILP (tem) + || !EQ (tem, def) + /* If the command is an alias for another + (such as lmenu.el set it up), check if the + original command matches the cached command. */ + && !(SYMBOLP (def) && EQ (tem, XSYMBOL (def)->function))) + chkcache = 1; /* Need to recompute key binding. */ + + if (chkcache) + { + /* Recompute equivalent key binding. If the command is an alias + for another (such as lmenu.el set it up), see if the original + 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) + && ! NILP (Fget (def, Qmenu_alias))) + def = XSYMBOL (def)->function; + tem = Fwhere_is_internal (def, Qnil, Qt, Qnil); + XCONS (cachelist)->car = tem; + if (NILP (tem)) + { + XCONS (cachelist)->cdr = Qnil; + chkcache = 0; + } + } + else if (!NILP (keyhint) && !NILP (XCONS (cachelist)->car)) + { + tem = XCONS (cachelist)->car; + chkcache = 1; + } + + newcache = chkcache; + if (chkcache) + { + tem = Fkey_description (tem); + if (CONSP (prefix)) + { + if (STRINGP (XCONS (prefix)->car)) + tem = concat2 (XCONS (prefix)->car, tem); + if (STRINGP (XCONS (prefix)->cdr)) + tem = concat2 (tem, XCONS (prefix)->cdr); + } + XCONS (cachelist)->cdr = tem; + } + } + + tem = XCONS (cachelist)->cdr; + if (newcache && !NILP (tem)) + { + tem = concat3 (build_string (" ("), tem, build_string (")")); + XCONS (cachelist)->cdr = tem; + } + + /* If we only want to precompute equivalent key bindings, stop here. */ + if (notreal) + return 1; + + /* If we have an equivalent key binding, use that. */ + XVECTOR (item_properties)->contents[ITEM_PROPERTY_KEYEQ] = tem; + + /* Include this when menu help is implemented. + tem = XVECTOR (item_properties)->contents[ITEM_PROPERTY_HELP]; + if (!(NILP (tem) || STRINGP (tem))) + { + tem = menu_item_eval_property (tem); + if (!STRINGP (tem)) + tem = Qnil; + XVECTOR (item_properties)->contents[ITEM_PROPERTY_HELP] = tem; + } + */ + + /* Handle radio buttons or toggle boxes. */ + tem = XVECTOR (item_properties)->contents[ITEM_PROPERTY_SELECTED]; + if (!NILP (tem)) + XVECTOR (item_properties)->contents[ITEM_PROPERTY_SELECTED] + = menu_item_eval_property (tem); + + return 1; } /* Read a character using menus based on maps in the array MAPS. @@ -5375,6 +6055,8 @@ read_char_x_menu_prompt (nmaps, maps, prev_event, used_mouse_menu) { 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 @@ -5385,10 +6067,13 @@ read_char_x_menu_prompt (nmaps, maps, prev_event, used_mouse_menu) 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. @@ -5459,7 +6144,7 @@ read_char_minibuf_menu_prompt (commandflag, nmaps, maps) /* Prompt string always starts with map's prompt, and a space. */ strcpy (menu, XSTRING (name)->data); - nlength = XSTRING (name)->size; + nlength = STRING_BYTES (XSTRING (name)); menu[nlength++] = ':'; menu[nlength++] = ' '; menu[nlength] = 0; @@ -5480,7 +6165,7 @@ read_char_minibuf_menu_prompt (commandflag, nmaps, maps) /* Loop over elements of map. */ while (i < width) { - Lisp_Object s, elt; + Lisp_Object elt; /* If reached end of map, start at beginning of next map. */ if (NILP (rest)) @@ -5513,26 +6198,27 @@ read_char_minibuf_menu_prompt (commandflag, nmaps, maps) else { /* An ordinary element. */ - Lisp_Object event; + Lisp_Object event, tem; if (idx < 0) { - s = Fcar_safe (Fcdr_safe (elt)); /* alist */ - event = Fcar_safe (elt); + event = Fcar_safe (elt); /* alist */ + elt = Fcdr_safe (elt); } else { - s = Fcar_safe (elt); /* vector */ - XSETINT (event, idx); + XSETINT (event, idx); /* vector */ } /* Ignore the element if it has no prompt string. */ - if (STRINGP (s) && INTEGERP (event)) + if (INTEGERP (event) && parse_menu_item (elt, 0, -1)) { /* 1 if the char to type matches the string. */ int char_matches; Lisp_Object upcased_event, downcased_event; Lisp_Object desc; + Lisp_Object s + = XVECTOR (item_properties)->contents[ITEM_PROPERTY_NAME]; upcased_event = Fupcase (event); downcased_event = Fdowncase (event); @@ -5541,6 +6227,27 @@ read_char_minibuf_menu_prompt (commandflag, nmaps, maps) if (! char_matches) desc = Fsingle_key_description (event); + tem + = XVECTOR (item_properties)->contents[ITEM_PROPERTY_KEYEQ]; + if (!NILP (tem)) + /* Insert equivalent keybinding. */ + s = concat2 (s, tem); + + tem + = XVECTOR (item_properties)->contents[ITEM_PROPERTY_TYPE]; + if (EQ (tem, QCradio) || EQ (tem, QCtoggle)) + { + /* Insert button prefix. */ + Lisp_Object selected + = XVECTOR (item_properties)->contents[ITEM_PROPERTY_SELECTED]; + if (EQ (tem, QCradio)) + tem = build_string (NILP (selected) ? "(*) " : "( ) "); + else + tem = build_string (NILP (selected) ? "[X] " : "[ ] "); + s = concat2 (tem, s); + } + + /* If we have room for the prompt string, add it to this line. If this is the first on the line, always add it. */ if ((XSTRING (s)->size + i + 2 @@ -5602,7 +6309,8 @@ read_char_minibuf_menu_prompt (commandflag, nmaps, maps) } /* Prompt with that and read response. */ - message1 (menu); + message2_nolog (menu, strlen (menu), + ! NILP (current_buffer->enable_multibyte_characters)); /* Make believe its not a keyboard macro in case the help char is pressed. Help characters are not recorded because menu prompting @@ -5669,7 +6377,7 @@ follow_key (key, nmaps, current, defs, next) { Lisp_Object def; def = get_keyelt (access_keymap (current[i], - meta_prefix_char, 1, 0)); + 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 @@ -5694,7 +6402,7 @@ follow_key (key, nmaps, current, defs, next) else map = current[i]; - defs[i] = get_keyelt (access_keymap (map, key, 1, 0)); + defs[i] = get_keyelt (access_keymap (map, key, 1, 0), 0); if (! NILP (defs[i])) first_binding = i; } @@ -5742,16 +6450,20 @@ follow_key (key, nmaps, current, defs, next) If the user switches frames in the midst of a key sequence, we put off the switch-frame event until later; the next call to - read_char will return it. */ + read_char will return it. + + If FIX_CURRENT_BUFFER is nonzero, we restore current_buffer + from the selected window's buffer. */ static int read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last, - can_return_switch_frame) + can_return_switch_frame, fix_current_buffer) Lisp_Object *keybuf; int bufsize; Lisp_Object prompt; int dont_downcase_last; int can_return_switch_frame; + int fix_current_buffer; { int count = specpdl_ptr - specpdl; @@ -5843,12 +6555,12 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last, /* Save the status of key translation before each step, so that we can restore this after downcasing. */ Lisp_Object prev_fkey_map; - Lisp_Object prev_fkey_start; - Lisp_Object prev_fkey_end; + int prev_fkey_start; + int prev_fkey_end; Lisp_Object prev_keytran_map; - Lisp_Object prev_keytran_start; - Lisp_Object prev_keytran_end; + int prev_keytran_start; + int prev_keytran_end; int junk; @@ -6091,6 +6803,14 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last, if (BUFFERP (key)) { mock_input = t; + /* Reset the current buffer from the selected window + in case something changed the former and not the latter. + This is to be more consistent with the behavior + of the command_loop_1. */ + if (fix_current_buffer) + if (XBUFFER (XWINDOW (selected_window)->buffer) != current_buffer) + Fset_buffer (XWINDOW (selected_window)->buffer); + orig_local_map = get_local_map (PT, current_buffer); goto replay_sequence; } @@ -6434,7 +7154,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last, fkey_next = get_keymap_1 (get_keyelt - (access_keymap (fkey_map, meta_prefix_char, 1, 0)), + (access_keymap (fkey_map, meta_prefix_char, 1, 0), 0), 0, 1); XSETFASTINT (key, XFASTINT (key) & ~meta_modifier); } @@ -6442,7 +7162,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last, fkey_next = fkey_map; fkey_next - = get_keyelt (access_keymap (fkey_next, key, 1, 0)); + = get_keyelt (access_keymap (fkey_next, key, 1, 0), 0); #if 0 /* I didn't turn this on, because it might cause trouble for the mapping of return into C-m and tab into C-i. */ @@ -6542,7 +7262,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last, keytran_next = get_keymap_1 (get_keyelt - (access_keymap (keytran_map, meta_prefix_char, 1, 0)), + (access_keymap (keytran_map, meta_prefix_char, 1, 0), 0), 0, 1); XSETFASTINT (key, XFASTINT (key) & ~meta_modifier); } @@ -6550,7 +7270,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last, keytran_next = keytran_map; keytran_next - = get_keyelt (access_keymap (keytran_next, key, 1, 0)); + = get_keyelt (access_keymap (keytran_next, key, 1, 0), 0); /* If the key translation map gives a function, not an array, then call the function with no args and use @@ -6634,7 +7354,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last, && ! key_translation_possible && INTEGERP (key) && ((((XINT (key) & 0x3ffff) - < XSTRING (current_buffer->downcase_table)->size) + < XCHAR_TABLE (current_buffer->downcase_table)->size) && UPPERCASEP (XINT (key) & 0x3ffff)) || (XINT (key) & shift_modifier))) { @@ -6811,7 +7531,7 @@ DEFUN ("read-key-sequence", Fread_key_sequence, Sread_key_sequence, 1, 4, 0, i = read_key_sequence (keybuf, (sizeof keybuf/sizeof (keybuf[0])), prompt, ! NILP (dont_downcase_last), - ! NILP (can_return_switch_frame)); + ! NILP (can_return_switch_frame), 0); if (i == -1) { @@ -6821,6 +7541,44 @@ DEFUN ("read-key-sequence", Fread_key_sequence, Sread_key_sequence, 1, 4, 0, UNGCPRO; return make_event_array (i, keybuf); } + +DEFUN ("read-key-sequence-vector", Fread_key_sequence_vector, + Sread_key_sequence_vector, 1, 4, 0, + "Like `read-key-sequence' but always return a vector.") + (prompt, continue_echo, dont_downcase_last, can_return_switch_frame) + Lisp_Object prompt, continue_echo, dont_downcase_last; + Lisp_Object can_return_switch_frame; +{ + Lisp_Object keybuf[30]; + register int i; + struct gcpro gcpro1, gcpro2; + + if (!NILP (prompt)) + CHECK_STRING (prompt, 0); + QUIT; + + bzero (keybuf, sizeof keybuf); + GCPRO1 (keybuf[0]); + gcpro1.nvars = (sizeof keybuf/sizeof (keybuf[0])); + + if (NILP (continue_echo)) + { + 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), + ! NILP (can_return_switch_frame), 0); + + if (i == -1) + { + Vquit_flag = Qt; + QUIT; + } + UNGCPRO; + return Fvector (i, keybuf); +} DEFUN ("command-execute", Fcommand_execute, Scommand_execute, 1, 4, 0, "Execute CMD as an editor command.\n\ @@ -6868,7 +7626,13 @@ a special event, so ignore the prefix argument and don't clear it.") 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; } @@ -6879,13 +7643,24 @@ a special event, so ignore the prefix argument and don't clear it.") other sorts of commands, call-interactively takes care of this. */ if (!NILP (record_flag)) - Vcommand_history - = Fcons (Fcons (Qexecute_kbd_macro, - Fcons (final, Fcons (prefixarg, Qnil))), - Vcommand_history); + { + Vcommand_history + = Fcons (Fcons (Qexecute_kbd_macro, + Fcons (final, Fcons (prefixarg, Qnil))), + Vcommand_history); + + /* Don't keep command history around forever. */ + if (NUMBERP (Vhistory_length) && XINT (Vhistory_length) > 0) + { + tem = Fnthcdr (Vhistory_length, Vcommand_history); + if (CONSP (tem)) + XCONS (tem)->cdr = Qnil; + } + } return Fexecute_kbd_macro (final, prefixarg); } + if (CONSP (final) || SUBRP (final) || COMPILEDP (final)) { backtrace.next = backtrace_list; @@ -6912,12 +7687,13 @@ DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_ 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, "- "); @@ -6953,7 +7729,8 @@ DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_ history list. */ function = Fcompleting_read (build_string (buf), Vobarray, Qcommandp, - Qt, Qnil, Qextended_command_history); + Qt, Qnil, Qextended_command_history, Qnil, + Qnil); if (STRINGP (function) && XSTRING (function)->size == 0) error ("No command name given"); @@ -6964,7 +7741,6 @@ DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_ struct Lisp_String *str; Lisp_Object *keys; int i; - Lisp_Object tem; this_command_key_count = 0; this_single_command_key_start = 0; @@ -6975,13 +7751,9 @@ DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_ str = XSTRING (function); for (i = 0; i < str->size; i++) - { - XSETFASTINT (tem, str->data[i]); - add_command_key (tem); - } + add_command_key (Faref (function, make_number (i))); - XSETFASTINT (tem, '\015'); - add_command_key (tem); + add_command_key (make_number ('\015')); } UNGCPRO; @@ -6994,24 +7766,52 @@ DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_ if (!NILP (Vsuggest_key_bindings) && NILP (Vexecuting_macro) && SYMBOLP (function)) - { - Lisp_Object bindings; + bindings = Fwhere_is_internal (function, Voverriding_local_map, + Qt, Qnil); + else + bindings = Qnil; - bindings = Fwhere_is_internal (function, Voverriding_local_map, - Qt, Qnil); + 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) + && ! (VECTORP (bindings) && EQ (Faref (bindings, make_number (0)), + Qmouse_movement))) + { + /* 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)) + && ! CONSP (Vunread_command_events)) { - 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; + int oldmultibyte = message_enable_multibyte; + + binding = Fkey_description (bindings); + + newmessage + = (char *) alloca (XSYMBOL (function)->name->size + + STRING_BYTES (XSTRING (binding)) + + 100); + sprintf (newmessage, "You can run the command `%s' with %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); + message2_nolog (newmessage, + strlen (newmessage), + STRING_MULTIBYTE (binding)); + if (!NILP (Fsit_for ((NUMBERP (Vsuggest_key_bindings) + ? Vsuggest_key_bindings : make_number (2)), + Qnil, Qnil))) + message2_nolog (oldmessage, oldmessage_len, oldmultibyte); } } - return Fcommand_execute (function, Qt, Qnil, Qnil); + RETURN_UNGCPRO (value); } /* Find the set of keymaps now active. @@ -7057,6 +7857,7 @@ current_active_maps (maps_p) /* Return nonzero if input events are pending. */ +int detect_input_pending () { if (!input_pending) @@ -7065,9 +7866,9 @@ detect_input_pending () return input_pending; } -/* Return nonzero if input events are pending. - Execute timers immediately; don't make events for them. */ +/* Return nonzero if input events are pending, and run any pending timers. */ +int detect_input_pending_run_timers (do_display) int do_display; { @@ -7085,11 +7886,26 @@ detect_input_pending_run_timers (do_display) /* This is called in some cases before a possible quit. It cases the next call to detect_input_pending to recompute input_pending. So calling this function unnecessarily can't do any harm. */ + +void clear_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. */ + +int +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.") @@ -7133,18 +7949,26 @@ The value is a string or a vector.") XVECTOR (this_command_keys)->contents); } +DEFUN ("this-command-keys-vector", Fthis_command_keys_vector, Sthis_command_keys_vector, 0, 0, 0, + "Return the key sequence that invoked this command, as a vector.") + () +{ + return Fvector (this_command_key_count, + 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.") +The value is always 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)); + return Fvector (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, @@ -7241,7 +8065,6 @@ On such systems, Emacs starts a subshell instead of suspending.") int old_height, old_width; int width, height; struct gcpro gcpro1, gcpro2; - extern init_sys_modes (); if (!NILP (stuffstring)) CHECK_STRING (stuffstring, 0); @@ -7255,7 +8078,8 @@ On such systems, Emacs starts a subshell instead of suspending.") reset_sys_modes (); /* sys_suspend can get an error if it tries to fork a subshell and the system resources aren't available for that. */ - record_unwind_protect (init_sys_modes, 0); + record_unwind_protect ((Lisp_Object (*) P_ ((Lisp_Object))) init_sys_modes, + Qnil); stuff_buffered_input (stuffstring); if (cannot_suspend) sys_subshell (); @@ -7281,11 +8105,12 @@ On such systems, Emacs starts a subshell instead of suspending.") /* If STUFFSTRING is a string, stuff its contents as pending terminal input. Then in any case stuff anything Emacs has read ahead and not used. */ +void stuff_buffered_input (stuffstring) 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; @@ -7294,7 +8119,7 @@ stuff_buffered_input (stuffstring) register int count; p = XSTRING (stuffstring)->data; - count = XSTRING (stuffstring)->size; + count = STRING_BYTES (XSTRING (stuffstring)); while (count-- > 0) stuff_char (*p++); stuff_char ('\n'); @@ -7315,9 +8140,10 @@ stuff_buffered_input (stuffstring) } input_pending = 0; #endif -#endif /* BSD and not BSD4_1 */ +#endif /* BSD_SYSTEM and not BSD4_1 */ } +void set_waiting_for_input (time_to_clear) EMACS_TIME *time_to_clear; { @@ -7332,6 +8158,7 @@ set_waiting_for_input (time_to_clear) quit_throw_to_read_char (); } +void clear_waiting_for_input () { /* Tell interrupt_signal not to throw back to read_char, */ @@ -7359,7 +8186,7 @@ interrupt_signal (signalnum) /* If we don't have an argument, */ /* 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; @@ -7371,11 +8198,17 @@ interrupt_signal (signalnum) /* If we don't have an argument, */ 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 @@ -7454,6 +8287,7 @@ interrupt_signal (signalnum) /* If we don't have an argument, */ #endif /* not MSDOS */ fflush (stdout); init_sys_modes (); + sigfree (); } else { @@ -7462,9 +8296,17 @@ interrupt_signal (signalnum) /* If we don't have an argument, */ then quit right away. */ if (immediate_quit && NILP (Vinhibit_quit)) { + struct gl_state_s saved; + struct gcpro gcpro1, gcpro2, gcpro3, gcpro4; + immediate_quit = 0; sigfree (); + saved = gl_state; + GCPRO4 (saved.object, saved.global_code, + saved.current_syntax_table, saved.old_prop); Fsignal (Qquit, Qnil); + gl_state = saved; + UNGCPRO; } else /* Else request quit when it's safe */ @@ -7479,6 +8321,7 @@ interrupt_signal (signalnum) /* If we don't have an argument, */ /* Handle a C-g by making read_char return C-g. */ +void quit_throw_to_read_char () { quit_error_check (); @@ -7499,12 +8342,10 @@ quit_throw_to_read_char () 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); } @@ -7531,7 +8372,7 @@ See also `current-input-mode'.") stop_polling (); #endif -#ifndef MSDOS +#ifndef DOS_NT /* this causes startup screen to be restored and messes with the mouse */ reset_sys_modes (); #endif @@ -7570,7 +8411,7 @@ See also `current-input-mode'.") /* Don't let this value be out of range. */ quit_char = XINT (quit) & (meta_key ? 0377 : 0177); -#ifndef MSDOS +#ifndef DOS_NT init_sys_modes (); #endif @@ -7661,6 +8502,7 @@ delete_kboard (kb) } #endif +void init_keyboard () { /* This is correct before outermost invocation of the editor loop */ @@ -7681,12 +8523,10 @@ init_keyboard () #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; @@ -7757,8 +8597,15 @@ struct event_head head_table[] = { &Qmake_frame_visible, "make-frame-visible", &Qmake_frame_visible, }; +void syms_of_keyboard () { + staticpro (&item_properties); + item_properties = Qnil; + + Qtimer_event_handler = intern ("timer-event-handler"); + staticpro (&Qtimer_event_handler); + Qdisabled_command_hook = intern ("disabled-command-hook"); staticpro (&Qdisabled_command_hook); @@ -7796,11 +8643,33 @@ syms_of_keyboard () staticpro (&Qfunction_key); Qmouse_click = intern ("mouse-click"); staticpro (&Qmouse_click); - Qtimer_event = intern ("timer-event"); - staticpro (&Qtimer_event); +#ifdef WINDOWSNT + Qmouse_wheel = intern ("mouse-wheel"); + staticpro (&Qmouse_wheel); +#endif + Qdrag_n_drop = intern ("drag-n-drop"); + staticpro (&Qdrag_n_drop); Qmenu_enable = intern ("menu-enable"); staticpro (&Qmenu_enable); + Qmenu_alias = intern ("menu-alias"); + staticpro (&Qmenu_alias); + QCenable = intern (":enable"); + staticpro (&QCenable); + QCvisible = intern (":visible"); + staticpro (&QCvisible); + QCfilter = intern (":filter"); + staticpro (&QCfilter); + QCbutton = intern (":button"); + staticpro (&QCbutton); + QCkeys = intern (":keys"); + staticpro (&QCkeys); + QCkey_sequence = intern (":key-sequence"); + staticpro (&QCkey_sequence); + QCtoggle = intern (":toggle"); + staticpro (&QCtoggle); + QCradio = intern (":radio"); + staticpro (&QCradio); Qmode_line = intern ("mode-line"); staticpro (&Qmode_line); @@ -7890,11 +8759,26 @@ syms_of_keyboard () mouse_syms = Qnil; staticpro (&mouse_syms); +#ifdef WINDOWSNT + mouse_wheel_syms = Qnil; + staticpro (&mouse_wheel_syms); + + drag_n_drop_syms = Qnil; + staticpro (&drag_n_drop_syms); +#endif + 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 (&Sread_key_sequence_vector); defsubr (&Srecursive_edit); #ifdef HAVE_MOUSE defsubr (&Strack_mouse); @@ -7903,6 +8787,7 @@ syms_of_keyboard () defsubr (&Scommand_execute); defsubr (&Srecent_keys); defsubr (&Sthis_command_keys); + defsubr (&Sthis_command_keys_vector); defsubr (&Sthis_single_command_keys); defsubr (&Sreset_this_command_lengths); defsubr (&Ssuspend_emacs); @@ -7999,14 +8884,25 @@ by position only."); 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 as input 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_INT ("num-nonmacro-input-events", &num_nonmacro_input_events, + "Number of input events read from the keyboard so far.\n\ +This does not include events generated by keyboard macros."); + num_nonmacro_input_events = 0; + DEFVAR_LISP ("last-event-frame", &Vlast_event_frame, "The frame in which the most recently read event occurred.\n\ If the last event came from a keyboard macro, this is set to `macro'."); Vlast_event_frame = Qnil; + /* This variable is set up in sysdep.c. */ + DEFVAR_LISP ("tty-erase-char", &Vtty_erase_char, + "The ERASE character as set by the user with stty."); + DEFVAR_LISP ("help-char", &Vhelp_char, "Character to recognize as meaning Help.\n\ When it is read, do `(eval help-form)', and display result if it's a string.\n\ @@ -8109,6 +9005,13 @@ This feature is obsolete; use idle timers instead. See `etc/NEWS'."); 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; @@ -8120,9 +9023,11 @@ The elements of the list are event types that may have menu bar bindings."); DEFVAR_KBOARD ("overriding-terminal-local-map", Voverriding_terminal_local_map, - "Keymap that overrides all other local keymaps.\n\ + "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."); +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\ +set up a different keymap for reading the next command."); DEFVAR_LISP ("overriding-local-map", &Voverriding_local_map, "Keymap that overrides all other local keymaps.\n\ @@ -8166,10 +9071,6 @@ 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 ("column-number-mode", &Vcolumn_number_mode, - "Non-nil enables display of the current column number in the mode line."); - Vcolumn_number_mode = Qnil; - DEFVAR_LISP ("timer-list", &Vtimer_list, "List of active absolute time timers in order of increasing time"); Vtimer_list = Qnil; @@ -8179,6 +9080,7 @@ If the value is non-nil and not a number, we wait 2 seconds."); Vtimer_idle_list = Qnil; } +void keys_of_keyboard () { initial_define_key (global_map, Ctl ('Z'), "suspend-emacs");