X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/2a84c6da58ee6b4519a0b7167d0cc978dc51c4b2..f0ed0a6c895c49f50c9cbcafe36b1a86a25a8620:/src/keyboard.c diff --git a/src/keyboard.c b/src/keyboard.c index b1f8a55507..74f8d7d51e 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -1,6 +1,7 @@ /* Keyboard and mouse input; editor command loop. - Copyright (C) 1985,86,87,88,89,93,94,95,96,97,99,2000,01,02,03,04 - Free Software Foundation, Inc. + Copyright (C) 1985, 1986, 1987, 1988, 1989, 1993, 1994, 1995, + 1996, 1997, 1999, 2000, 2001, 2002, 2003, 2004, + 2005 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -16,19 +17,19 @@ GNU General Public License for more details. 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, Inc., 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ +the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ #include #include #include +#include "lisp.h" #include "termchar.h" #include "termopts.h" -#include "lisp.h" +#include "frame.h" #include "termhooks.h" #include "macros.h" #include "keyboard.h" -#include "frame.h" #include "window.h" #include "commands.h" #include "buffer.h" @@ -58,13 +59,16 @@ Boston, MA 02111-1307, USA. */ #endif /* not MSDOS */ #include "syssignal.h" -#include "systty.h" #include #ifdef HAVE_UNISTD_H #include #endif +#ifdef HAVE_FCNTL_H +#include +#endif + /* This is to get the definitions of the XK_ symbols. */ #ifdef HAVE_X_WINDOWS #include "xterm.h" @@ -92,9 +96,6 @@ int interrupt_input_blocked; int interrupt_input_pending; -/* File descriptor to use for input. */ -extern int input_fd; - #ifdef HAVE_WINDOW_SYSTEM /* Make all keyboard buffers much bigger when using X windows. */ #ifdef MAC_OS8 @@ -417,13 +418,6 @@ Lisp_Object Vtop_level; /* User-supplied table to translate input characters. */ Lisp_Object Vkeyboard_translate_table; -/* Keymap mapping ASCII function key sequences onto their preferred forms. */ -extern Lisp_Object Vfunction_key_map; - -/* Another keymap that maps key sequences into key sequences. - This one takes precedence over ordinary definitions. */ -extern Lisp_Object Vkey_translation_map; - /* If non-nil, this implements the current input method. */ Lisp_Object Vinput_method_function; Lisp_Object Qinput_method_function; @@ -446,11 +440,12 @@ Lisp_Object Qecho_area_clear_hook; Lisp_Object Qpre_command_hook, Vpre_command_hook; Lisp_Object Qpost_command_hook, Vpost_command_hook; Lisp_Object Qcommand_hook_internal, Vcommand_hook_internal; -/* Hook run after a command if there's no more input soon. */ -Lisp_Object Qpost_command_idle_hook, Vpost_command_idle_hook; -/* Delay time in microseconds before running post-command-idle-hook. */ -EMACS_INT post_command_idle_delay; +/* Parent keymap of terminal-local function-key-map instances. */ +Lisp_Object Vfunction_key_map; + +/* Parent keymap of terminal-local key-translation-map instances. */ +Lisp_Object Vkey_translation_map; /* List of deferred actions to be performed at a later time. The precise format isn't relevant here; we just check whether it is nil. */ @@ -469,11 +464,6 @@ FILE *dribble; /* Nonzero if input is available. */ int input_pending; -/* 1 if should obey 0200 bit in input chars as "Meta", 2 if should - keep 0200 bit in input chars. 0 to ignore the 0200 bit. */ - -int meta_key; - /* Non-zero means force key bindings update in parse_menu_item. */ int update_menu_bindings; @@ -519,10 +509,14 @@ Lisp_Object Qmake_frame_visible; Lisp_Object Qselect_window; Lisp_Object Qhelp_echo; +#ifdef HAVE_MOUSE +Lisp_Object Qmouse_fixup_help_message; +#endif + /* Symbols to denote kinds of events. */ Lisp_Object Qfunction_key; Lisp_Object Qmouse_click; -#ifdef WINDOWSNT +#if defined (WINDOWSNT) || defined (MAC_OS) Lisp_Object Qlanguage_change; #endif Lisp_Object Qdrag_n_drop; @@ -600,9 +594,6 @@ int interrupt_input; /* Nonzero while interrupts are temporarily deferred during redisplay. */ int interrupts_deferred; -/* Nonzero means use ^S/^Q for flow control. */ -int flow_control; - /* Allow m- file to inhibit use of FIONREAD. */ #ifdef BROKEN_FIONREAD #undef FIONREAD @@ -646,14 +637,17 @@ static EMACS_TIME timer_last_idleness_start_time; /* Global variable declarations. */ +/* Flags for readable_events. */ +#define READABLE_EVENTS_DO_TIMERS_NOW (1 << 0) +#define READABLE_EVENTS_FILTER_EVENTS (1 << 1) +#define READABLE_EVENTS_IGNORE_SQUEEZABLES (1 << 2) + /* Function for init_keyboard to call with no args (if nonzero). */ void (*keyboard_init_hook) (); static int read_avail_input P_ ((int)); static void get_input_pending P_ ((int *, int)); -static void get_filtered_input_pending P_ ((int *, int, int)); static int readable_events P_ ((int)); -static int readable_filtered_events P_ ((int, int)); static Lisp_Object read_char_x_menu_prompt P_ ((int, Lisp_Object *, Lisp_Object, int *)); static Lisp_Object read_char_x_menu_prompt (); @@ -679,6 +673,7 @@ static Lisp_Object apply_modifiers P_ ((int, Lisp_Object)); static void clear_event P_ ((struct input_event *)); static void any_kboard_state P_ ((void)); static SIGTYPE interrupt_signal P_ ((int signalnum)); +static void handle_interrupt P_ ((void)); static void timer_start_idle P_ ((void)); static void timer_stop_idle P_ ((void)); static void timer_resume_idle P_ ((void)); @@ -1014,7 +1009,7 @@ DEFUN ("recursive-edit", Frecursive_edit, Srecursive_edit, 0, 0, "", doc: /* Invoke the editor command loop recursively. To get out of the recursive edit, a command can do `(throw 'exit nil)'; that tells this function to return. -Alternately, `(throw 'exit t)' makes this function signal an error. +Alternatively, `(throw 'exit t)' makes this function signal an error. This function is called by the editor initialization to begin editing. */) () { @@ -1120,6 +1115,22 @@ struct kboard_stack static struct kboard_stack *kboard_stack; +void +push_device_kboard (d) + struct device *d; +{ +#ifdef MULTI_KBOARD + struct kboard_stack *p + = (struct kboard_stack *) xmalloc (sizeof (struct kboard_stack)); + + p->next = kboard_stack; + p->kboard = current_kboard; + kboard_stack = p; + + current_kboard = d->kboard; +#endif +} + void push_frame_kboard (f) FRAME_PTR f; @@ -1162,21 +1173,21 @@ cmd_error (data) cancel_hourglass (); #endif - if (!NILP (executing_macro)) + if (!NILP (executing_kbd_macro)) { - if (executing_macro_iterations == 1) + if (executing_kbd_macro_iterations == 1) sprintf (macroerror, "After 1 kbd macro iteration: "); else sprintf (macroerror, "After %d kbd macro iterations: ", - executing_macro_iterations); + executing_kbd_macro_iterations); } else *macroerror = 0; Vstandard_output = Qt; Vstandard_input = Qt; - Vexecuting_macro = Qnil; - executing_macro = Qnil; + Vexecuting_kbd_macro = Qnil; + executing_kbd_macro = Qnil; current_kboard->Vprefix_arg = Qnil; current_kboard->Vlast_prefix_arg = Qnil; cancel_echoing (); @@ -1226,11 +1237,7 @@ cmd_error_internal (data, context) yet, or we're not interactive, it's best to dump this message out to stderr and exit. */ if (!sf->glyphs_initialized_p - /* This is the case of the frame dumped with Emacs, when we're - running under a window system. */ - || (!NILP (Vwindow_system) - && !inhibit_window_system - && FRAME_TERMCAP_P (sf)) + || FRAME_INITIAL_P (sf) || noninteractive) { stream = Qexternal_debugging_output; @@ -1277,19 +1284,19 @@ command_loop () { Lisp_Object val; val = internal_catch (Qexit, command_loop_2, Qnil); - executing_macro = Qnil; + executing_kbd_macro = Qnil; return val; } else while (1) { internal_catch (Qtop_level, top_level_1, Qnil); - /* Reset single_kboard in case top-level set it while - evaluating an -f option, or we are stuck there for some - other reason. */ - any_kboard_state (); + /* Reset single_kboard in case top-level set it while + evaluating an -f option, or we are stuck there for some + other reason. */ + any_kboard_state (); internal_catch (Qtop_level, command_loop_2, Qnil); - executing_macro = Qnil; + executing_kbd_macro = Qnil; /* End of file in -batch run causes exit here. */ if (noninteractive) @@ -1402,12 +1409,12 @@ command_loop_1 () Lisp_Object keybuf[30]; int i; int no_direct; - int prev_modiff; + int prev_modiff = 0; struct buffer *prev_buffer = NULL; #ifdef MULTI_KBOARD int was_locked = single_kboard; #endif - int already_adjusted; + int already_adjusted = 0; current_kboard->Vprefix_arg = Qnil; current_kboard->Vlast_prefix_arg = Qnil; @@ -1435,17 +1442,7 @@ command_loop_1 () resize_echo_area_exactly (); if (!NILP (Vdeferred_action_list)) - call0 (Vdeferred_action_function); - - if (!NILP (Vpost_command_idle_hook) && !NILP (Vrun_hooks)) - { - if (NILP (Vunread_command_events) - && NILP (Vunread_input_method_events) - && NILP (Vunread_post_input_method_events) - && NILP (Vexecuting_macro) - && !NILP (sit_for (0, post_command_idle_delay, 0, 1, 1))) - safe_run_hooks (Qpost_command_idle_hook); - } + safe_run_hooks (Qdeferred_action_function); } Vmemory_full = Qnil; @@ -1513,7 +1510,7 @@ command_loop_1 () Is this a good idea? */ if (FRAMEP (internal_last_event_frame) && !EQ (internal_last_event_frame, selected_frame)) - Fselect_frame (internal_last_event_frame, Qnil); + Fselect_frame (internal_last_event_frame); #endif /* If it has changed current-menubar from previous value, really recompute the menubar from the value. */ @@ -1526,6 +1523,7 @@ command_loop_1 () Vthis_command = Qnil; real_this_command = Qnil; + Vthis_original_command = Qnil; /* Read next key sequence; i gets its length. */ i = read_key_sequence (keybuf, sizeof keybuf / sizeof keybuf[0], @@ -1571,11 +1569,11 @@ command_loop_1 () } cmd = read_key_sequence_cmd; - if (!NILP (Vexecuting_macro)) + if (!NILP (Vexecuting_kbd_macro)) { if (!NILP (Vquit_flag)) { - Vexecuting_macro = Qt; + Vexecuting_kbd_macro = Qt; QUIT; /* Make some noise. */ /* Will return since macro now empty. */ } @@ -1674,7 +1672,7 @@ command_loop_1 () && EQ (current_buffer->selective_display, Qnil) && !detect_input_pending () && NILP (XWINDOW (selected_window)->column_number_displayed) - && NILP (Vexecuting_macro)) + && NILP (Vexecuting_kbd_macro)) direct_output_forward_char (1); goto directly_done; } @@ -1709,7 +1707,7 @@ command_loop_1 () && EQ (current_buffer->selective_display, Qnil) && !detect_input_pending () && NILP (XWINDOW (selected_window)->column_number_displayed) - && NILP (Vexecuting_macro)) + && NILP (Vexecuting_kbd_macro)) direct_output_forward_char (-1); goto directly_done; } @@ -1722,7 +1720,7 @@ command_loop_1 () = translate_char (Vtranslation_table_for_input, XFASTINT (last_command_char), 0, 0, 0); int value; - if (NILP (Vexecuting_macro) + if (NILP (Vexecuting_kbd_macro) && !EQ (minibuf_window, selected_window)) { if (!nonundocount || nonundocount >= 20) @@ -1744,7 +1742,7 @@ command_loop_1 () || !EQ (current_buffer->selective_display, Qnil) || detect_input_pending () || !NILP (XWINDOW (selected_window)->column_number_displayed) - || !NILP (Vexecuting_macro)); + || !NILP (Vexecuting_kbd_macro)); value = internal_self_insert (c, 0); @@ -1772,7 +1770,7 @@ command_loop_1 () int scount = SPECPDL_INDEX (); if (display_hourglass_p - && NILP (Vexecuting_macro)) + && NILP (Vexecuting_kbd_macro)) { record_unwind_protect (cancel_hourglass_unwind, Qnil); start_hourglass (); @@ -1790,7 +1788,7 @@ command_loop_1 () hourglass cursor anyway. But don't cancel the hourglass within a macro just because a command in the macro finishes. */ - if (NILP (Vexecuting_macro)) + if (NILP (Vexecuting_kbd_macro)) unbind_to (scount, Qnil); #endif } @@ -1811,16 +1809,6 @@ command_loop_1 () 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 (Vunread_input_method_events) - && NILP (Vunread_post_input_method_events) - && NILP (Vexecuting_macro) - && !NILP (sit_for (0, post_command_idle_delay, 0, 1, 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, @@ -1936,10 +1924,13 @@ adjust_point_for_property (last_pt, modified) ? get_property_and_range (PT, Qdisplay, &val, &beg, &end, Qnil) : (beg = OVERLAY_POSITION (OVERLAY_START (overlay)), end = OVERLAY_POSITION (OVERLAY_END (overlay)))) - && beg < PT) /* && end > PT <- It's always the case. */ + && (beg < PT /* && end > PT <- It's always the case. */ + || (beg <= PT && STRINGP (val) && SCHARS (val) == 0))) { xassert (end > PT); - SET_PT (PT < last_pt ? beg : end); + SET_PT (PT < last_pt + ? (STRINGP (val) && SCHARS (val) == 0 ? beg - 1 : beg) + : end); check_composition = check_invisible = 1; } check_display = 0; @@ -2104,7 +2095,11 @@ poll_for_input (timer) struct atimer *timer; { if (poll_suppress_count == 0) +#ifdef SYNC_INPUT + interrupt_input_pending = 1; +#else poll_for_input_1 (); +#endif } #endif /* POLL_FOR_INPUT */ @@ -2116,7 +2111,10 @@ void start_polling () { #ifdef POLL_FOR_INPUT - if (read_socket_hook && !interrupt_input) + /* XXX This condition was (read_socket_hook && !interrupt_input), + but read_socket_hook is not global anymore. Let's pretend that + it's always set. */ + if (!interrupt_input) { /* Turn alarm handling on unconditionally. It might have been turned off in process.c. */ @@ -2150,7 +2148,10 @@ int input_polling_used () { #ifdef POLL_FOR_INPUT - return read_socket_hook && !interrupt_input; + /* XXX This condition was (read_socket_hook && !interrupt_input), + but read_socket_hook is not global anymore. Let's pretend that + it's always set. */ + return !interrupt_input; #else return 0; #endif @@ -2162,7 +2163,10 @@ void stop_polling () { #ifdef POLL_FOR_INPUT - if (read_socket_hook && !interrupt_input) + /* XXX This condition was (read_socket_hook && !interrupt_input), + but read_socket_hook is not global anymore. Let's pretend that + it's always set. */ + if (!interrupt_input) ++poll_suppress_count; #endif } @@ -2247,12 +2251,16 @@ make_ctrl_char (c) return c; } -/* Display help echo in the echo area. +/* Display the help-echo property of the character after the mouse pointer. + Either show it in the echo area, or call show-help-function to display + it by other means (maybe in a tooltip). + + If HELP is nil, that means clear the previous help echo. - HELP a string means display that string, HELP nil means clear the - help echo. If HELP is a function, call it with OBJECT and POS as - arguments; the function should return a help string or nil for - none. For all other types of HELP evaluate it to obtain a string. + If HELP is a string, display that string. If HELP is a function, + call it with OBJECT and POS as arguments; the function should + return a help string or nil for none. For all other types of HELP, + evaluate it to obtain a string. WINDOW is the window in which the help was generated, if any. It is nil if not in a window. @@ -2297,6 +2305,11 @@ show_help_echo (help, window, object, pos, ok_to_overwrite_keystroke_echo) return; } +#ifdef HAVE_MOUSE + if (!noninteractive && STRINGP (help)) + help = call1 (Qmouse_fixup_help_message, help); +#endif + if (STRINGP (help) || NILP (help)) { if (!NILP (Vshow_help_function)) @@ -2475,7 +2488,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu) this_command_key_count_reset = 0; - if (!NILP (Vexecuting_macro)) + if (!NILP (Vexecuting_kbd_macro)) { /* We set this to Qmacro; since that's not a frame, nobody will try to switch frames on us, and the selected window will @@ -2492,19 +2505,19 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu) /* Exit the macro if we are at the end. Also, some things replace the macro with t to force an early exit. */ - if (EQ (Vexecuting_macro, Qt) - || executing_macro_index >= XFASTINT (Flength (Vexecuting_macro))) + if (EQ (Vexecuting_kbd_macro, Qt) + || executing_kbd_macro_index >= XFASTINT (Flength (Vexecuting_kbd_macro))) { XSETINT (c, -1); goto exit; } - c = Faref (Vexecuting_macro, make_number (executing_macro_index)); - if (STRINGP (Vexecuting_macro) - && (XINT (c) & 0x80)) + c = Faref (Vexecuting_kbd_macro, make_number (executing_kbd_macro_index)); + if (STRINGP (Vexecuting_kbd_macro) + && (XINT (c) & 0x80) && (XUINT (c) <= 0xff)) XSETFASTINT (c, CHAR_META | (XINT (c) & ~0x80)); - executing_macro_index++; + executing_kbd_macro_index++; goto from_macro; } @@ -2613,6 +2626,9 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu) if (_setjmp (local_getcjmp)) { + /* We must have saved the outer value of getcjmp here, + so restore it now. */ + restore_getcjmp (save_jump); XSETINT (c, quit_char); internal_last_event_frame = selected_frame; Vlast_event_frame = internal_last_event_frame; @@ -3044,6 +3060,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu) /* Save the echo status. */ int saved_immediate_echo = current_kboard->immediate_echo; struct kboard *saved_ok_to_echo = ok_to_echo_at_next_pause; + Lisp_Object saved_echo_string = current_kboard->echo_string; int saved_echo_after_prompt = current_kboard->echo_after_prompt; #if 0 @@ -3098,6 +3115,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu) cancel_echoing (); ok_to_echo_at_next_pause = saved_ok_to_echo; + current_kboard->echo_string = saved_echo_string; current_kboard->echo_after_prompt = saved_echo_after_prompt; if (saved_immediate_echo) echo_now (); @@ -3439,10 +3457,11 @@ tracking_off (old_value) 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 (1)) + if (!readable_events (READABLE_EVENTS_DO_TIMERS_NOW)) { redisplay_preserve_echo_area (6); - get_input_pending (&input_pending, 1); + get_input_pending (&input_pending, + READABLE_EVENTS_DO_TIMERS_NOW); } } return Qnil; @@ -3494,20 +3513,21 @@ some_mouse_moved () /* 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_filtered_events (do_timers_now, filter_events) - int do_timers_now; - int filter_events; +readable_events (flags) + int flags; { - if (do_timers_now) - timer_check (do_timers_now); + if (flags & READABLE_EVENTS_DO_TIMERS_NOW) + timer_check (1); - /* If the buffer contains only FOCUS_IN_EVENT events, - and FILTER_EVENTS is nonzero, report it as empty. */ + /* If the buffer contains only FOCUS_IN_EVENT events, and + READABLE_EVENTS_FILTER_EVENTS is set, report it as empty. */ if (kbd_fetch_ptr != kbd_store_ptr) { - int have_live_event = 1; - - if (filter_events) + if (flags & (READABLE_EVENTS_FILTER_EVENTS +#ifdef USE_TOOLKIT_SCROLL_BARS + | READABLE_EVENTS_IGNORE_SQUEEZABLES +#endif + )) { struct input_event *event; @@ -3515,20 +3535,34 @@ readable_filtered_events (do_timers_now, filter_events) ? kbd_fetch_ptr : kbd_buffer); - while (have_live_event && event->kind == FOCUS_IN_EVENT) - { - event++; + do + { + if (!( +#ifdef USE_TOOLKIT_SCROLL_BARS + (flags & READABLE_EVENTS_FILTER_EVENTS) && +#endif + event->kind == FOCUS_IN_EVENT) +#ifdef USE_TOOLKIT_SCROLL_BARS + && !((flags & READABLE_EVENTS_IGNORE_SQUEEZABLES) + && event->kind == SCROLL_BAR_CLICK_EVENT + && event->part == scroll_bar_handle + && event->modifiers == 0) +#endif + ) + return 1; + event++; if (event == kbd_buffer + KBD_BUFFER_SIZE) event = kbd_buffer; - if (event == kbd_store_ptr) - have_live_event = 0; - } + } + while (event != kbd_store_ptr); } - if (have_live_event) return 1; + else + return 1; } #ifdef HAVE_MOUSE - if (!NILP (do_mouse_tracking) && some_mouse_moved ()) + if (!(flags & READABLE_EVENTS_IGNORE_SQUEEZABLES) + && !NILP (do_mouse_tracking) && some_mouse_moved ()) return 1; #endif if (single_kboard) @@ -3546,15 +3580,6 @@ readable_filtered_events (do_timers_now, filter_events) return 0; } -/* 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 (do_timers_now) - int do_timers_now; -{ - return readable_filtered_events (do_timers_now, 0); -} - /* Set this for debugging, to have a way to get out */ int stop_character; @@ -3677,7 +3702,7 @@ kbd_buffer_store_event_hold (event, hold_quit) } last_event_timestamp = event->timestamp; - interrupt_signal (0 /* dummy */); + handle_interrupt (); return; } @@ -3709,13 +3734,23 @@ kbd_buffer_store_event_hold (event, hold_quit) ++kbd_store_ptr; } - /* If we're in a section that requested to be interrupted as soon - as input comes, then set quit-flag to cause an interrupt. */ + /* If we're inside while-no-input, and this event qualifies + as input, set quit-flag to cause an interrupt. */ if (!NILP (Vthrow_on_input) && event->kind != FOCUS_IN_EVENT && event->kind != HELP_EVENT && event->kind != DEICONIFY_EVENT) - Vquit_flag = Vthrow_on_input; + { + Vquit_flag = Vthrow_on_input; + /* If we're inside a function that wants immediate quits, + do it now. */ + if (immediate_quit && NILP (Vinhibit_quit)) + { + immediate_quit = 0; + sigfree (); + QUIT; + } + } } @@ -3976,7 +4011,7 @@ kbd_buffer_get_event (kbp, used_mouse_menu) kbd_fetch_ptr = event + 1; } #endif -#if defined (HAVE_X11) || defined (HAVE_NTGUI) +#if defined (HAVE_X11) || defined (HAVE_NTGUI) || defined (MAC_OS) else if (event->kind == ICONIFY_EVENT) { /* Make an event (iconify-frame (FRAME)). */ @@ -4008,11 +4043,16 @@ kbd_buffer_get_event (kbp, used_mouse_menu) x_activate_menubar (XFRAME (event->frame_or_window)); } #endif -#ifdef WINDOWSNT +#if defined (WINDOWSNT) || defined (MAC_OS) else if (event->kind == LANGUAGE_CHANGE_EVENT) { +#ifdef MAC_OS + /* Make an event (language-change (KEY_SCRIPT)). */ + obj = Fcons (make_number (event->code), Qnil); +#else /* Make an event (language-change (FRAME CHARSET LCID)). */ obj = Fcons (event->frame_or_window, Qnil); +#endif obj = Fcons (Qlanguage_change, Fcons (obj, Qnil)); kbd_fetch_ptr = event + 1; } @@ -4131,7 +4171,11 @@ kbd_buffer_get_event (kbp, used_mouse_menu) If there is no valid info, it does not store anything so x remains nil. */ x = Qnil; - (*mouse_position_hook) (&f, 0, &bar_window, &part, &x, &y, &time); + + /* XXX Can f or mouse_position_hook be NULL here? */ + if (f && FRAME_DEVICE (f)->mouse_position_hook) + (*FRAME_DEVICE (f)->mouse_position_hook) (&f, 0, &bar_window, + &part, &x, &y, &time); obj = Qnil; @@ -4215,7 +4259,7 @@ swallow_events (do_display) } old_timers_run = timers_run; - get_input_pending (&input_pending, 1); + get_input_pending (&input_pending, READABLE_EVENTS_DO_TIMERS_NOW); if (timers_run != old_timers_run && do_display) redisplay_preserve_echo_area (7); @@ -6282,8 +6326,8 @@ modify_event_symbol (symbol_num, modifiers, symbol_kind, name_alist_or_stem, { int len = SBYTES (name_alist_or_stem); char *buf = (char *) alloca (len + 50); - sprintf (buf, "%s-%ld", SDATA (name_alist_or_stem), - (long) XINT (symbol_int) + 1); + sprintf (buf, "%s-%ld", SDATA (name_alist_or_stem), + (long) XINT (symbol_int) + 1); value = intern (buf); } else if (name_table != 0 && name_table[symbol_num]) @@ -6507,18 +6551,20 @@ lucid_event_type_list_p (object) but works even if FIONREAD does not exist. (In fact, this may actually read some input.) - If DO_TIMERS_NOW is nonzero, actually run timer events that are ripe. - If FILTER_EVENTS is nonzero, ignore internal events (FOCUS_IN_EVENT). */ + If READABLE_EVENTS_DO_TIMERS_NOW is set in FLAGS, actually run + timer events that are ripe. + If READABLE_EVENTS_FILTER_EVENTS is set in FLAGS, ignore internal + events (FOCUS_IN_EVENT). + If READABLE_EVENTS_IGNORE_SQUEEZABLES is set in FLAGS, ignore mouse + movements and toolkit scroll bar thumb drags. */ static void -get_filtered_input_pending (addr, do_timers_now, filter_events) +get_input_pending (addr, flags) int *addr; - int do_timers_now; - int filter_events; + int flags; { /* First of all, have we already counted some input? */ - *addr = (!NILP (Vquit_flag) - || readable_filtered_events (do_timers_now, filter_events)); + *addr = (!NILP (Vquit_flag) || readable_events (flags)); /* If input is being read as it arrives, and we have none, there is none. */ if (*addr > 0 || (interrupt_input && ! interrupts_deferred)) @@ -6526,23 +6572,7 @@ get_filtered_input_pending (addr, do_timers_now, filter_events) /* Try to read some input and see how much we get. */ gobble_input (0); - *addr = (!NILP (Vquit_flag) - || readable_filtered_events (do_timers_now, filter_events)); -} - -/* 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.) - - If DO_TIMERS_NOW is nonzero, actually run timer events that are ripe. */ - -static void -get_input_pending (addr, do_timers_now) - int *addr; - int do_timers_now; -{ - get_filtered_input_pending (addr, do_timers_now, 0); + *addr = (!NILP (Vquit_flag) || readable_events (flags)); } /* Interface to read_avail_input, blocking SIGIO or SIGALRM if necessary. */ @@ -6562,7 +6592,10 @@ gobble_input (expected) } else #ifdef POLL_FOR_INPUT - if (read_socket_hook && !interrupt_input && poll_suppress_count == 0) + /* XXX This condition was (read_socket_hook && !interrupt_input), + but read_socket_hook is not global anymore. Let's pretend that + it's always set. */ + if (!interrupt_input && poll_suppress_count == 0) { SIGMASKTYPE mask; mask = sigblock (sigmask (SIGALRM)); @@ -6639,146 +6672,214 @@ static int read_avail_input (expected) int expected; { - register int i; int nread = 0; + int err = 0; + struct device *d; - if (read_socket_hook) + /* Loop through the available devices, and call their input hooks. */ + d = device_list; + while (d) { - int nr; - struct input_event hold_quit; + struct device *next = d->next_device; - EVENT_INIT (hold_quit); - hold_quit.kind = NO_EVENT; + if (d->read_socket_hook) + { + int nr; + struct input_event hold_quit; - /* No need for FIONREAD or fcntl; just say don't wait. */ - while (nr = (*read_socket_hook) (input_fd, expected, &hold_quit), nr > 0) - { - nread += nr; - expected = 0; - } - if (hold_quit.kind != NO_EVENT) - kbd_buffer_store_event (&hold_quit); + EVENT_INIT (hold_quit); + hold_quit.kind = NO_EVENT; + + /* No need for FIONREAD or fcntl; just say don't wait. */ + while (nr = (*d->read_socket_hook) (d, expected, &hold_quit), nr > 0) + { + nread += nr; + expected = 0; + } + + if (nr == -1) /* Not OK to read input now. */ + { + err = 1; + } + else if (nr == -2) /* Non-transient error. */ + { + /* The display device terminated; it should be closed. */ + + /* Kill Emacs if this was our last display. */ + if (! device_list->next_device) + /* Formerly simply reported no input, but that + sometimes led to a failure of Emacs to terminate. + SIGHUP seems appropriate if we can't reach the + terminal. */ + /* ??? Is it really right to send the signal just to + this process rather than to the whole process + group? Perhaps on systems with FIONREAD Emacs is + alone in its group. */ + kill (getpid (), SIGHUP); + + /* XXX Is calling delete_device safe here? It calls Fdelete_frame. */ + if (d->delete_device_hook) + (*d->delete_device_hook) (d); + else + delete_device (d); + } + + if (hold_quit.kind != NO_EVENT) + kbd_buffer_store_event (&hold_quit); + } + + d = next; } - else - { - /* Using KBD_BUFFER_SIZE - 1 here avoids reading more than - the kbd_buffer can really hold. That may prevent loss - of characters on some systems when input is stuffed at us. */ - unsigned char cbuf[KBD_BUFFER_SIZE - 1]; - int n_to_read; - /* Determine how many characters we should *try* to read. */ + if (err && !nread) + nread = -1; + + return nread; +} + +/* This is the tty way of reading available input. + + Note that each terminal device has its own `struct device' object, + and so this function is called once for each individual termcap + display. The first parameter indicates which device to read from. */ + +int +tty_read_avail_input (struct device *device, + int expected, + struct input_event *hold_quit) +{ + /* Using KBD_BUFFER_SIZE - 1 here avoids reading more than + the kbd_buffer can really hold. That may prevent loss + of characters on some systems when input is stuffed at us. */ + unsigned char cbuf[KBD_BUFFER_SIZE - 1]; + int n_to_read, i; + struct tty_display_info *tty = device->display_info.tty; + int nread = 0; + + if (device->type != output_termcap) + abort (); + + /* XXX I think the following code should be moved to separate hook + functions in system-dependent files. */ #ifdef WINDOWSNT - return 0; + return 0; #else /* not WINDOWSNT */ #ifdef MSDOS - n_to_read = dos_keysns (); - if (n_to_read == 0) - return 0; + n_to_read = dos_keysns (); + if (n_to_read == 0) + return 0; + + cbuf[0] = dos_keyread (); + nread = 1; + #else /* not MSDOS */ + + if (! tty->term_initted) /* In case we get called during bootstrap. */ + return 0; + + if (! tty->input) + return 0; /* The terminal is suspended. */ + + /* Determine how many characters we should *try* to read. */ #ifdef FIONREAD - /* Find out how much input is available. */ - if (ioctl (input_fd, FIONREAD, &n_to_read) < 0) - /* Formerly simply reported no input, but that sometimes led to - a failure of Emacs to terminate. - SIGHUP seems appropriate if we can't reach the terminal. */ - /* ??? Is it really right to send the signal just to this process - rather than to the whole process group? - Perhaps on systems with FIONREAD Emacs is alone in its group. */ - { - if (! noninteractive) - kill (getpid (), SIGHUP); - else - n_to_read = 0; - } - if (n_to_read == 0) - return 0; - if (n_to_read > sizeof cbuf) - n_to_read = sizeof cbuf; + /* Find out how much input is available. */ + if (ioctl (fileno (tty->input), FIONREAD, &n_to_read) < 0) + { + if (! noninteractive) + return -2; /* Close this device. */ + else + n_to_read = 0; + } + if (n_to_read == 0) + return 0; + if (n_to_read > sizeof cbuf) + n_to_read = sizeof cbuf; #else /* no FIONREAD */ #if defined (USG) || defined (DGUX) || defined(CYGWIN) - /* Read some input if available, but don't wait. */ - n_to_read = sizeof cbuf; - fcntl (input_fd, F_SETFL, O_NDELAY); + /* Read some input if available, but don't wait. */ + n_to_read = sizeof cbuf; + fcntl (fileno (tty->input), F_SETFL, O_NDELAY); #else - you lose; + you lose; #endif #endif -#endif /* not MSDOS */ -#endif /* not WINDOWSNT */ - /* Now read; for one reason or another, this will not block. - NREAD is set to the number of chars read. */ - do - { -#ifdef MSDOS - cbuf[0] = dos_keyread (); - nread = 1; -#else - nread = emacs_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); + /* Now read; for one reason or another, this will not block. + NREAD is set to the number of chars read. */ + do + { + nread = emacs_read (fileno (tty->input), cbuf, n_to_read); + /* 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) + return -2; /* Close this device. */ #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 - O_NDELAY to be defined in fcntl.h as O_NONBLOCK, - and that causes a value other than 0 when there is no input. */ - if (nread == 0) - kill (0, SIGHUP); -#endif - } - while ( - /* We used to retry the read if it was interrupted. - But this does the wrong thing when O_NDELAY causes - an EAGAIN error. Does anybody know of a situation - where a retry is actually needed? */ + /* The kernel sometimes fails to deliver SIGHUP for ptys. + This looks incorrect, but it isn't, because _BSD causes + O_NDELAY to be defined in fcntl.h as O_NONBLOCK, + and that causes a value other than 0 when there is no input. */ + if (nread == 0) + return -2; /* Close this device. */ +#endif + } + while ( + /* We used to retry the read if it was interrupted. + But this does the wrong thing when O_NDELAY causes + an EAGAIN error. Does anybody know of a situation + where a retry is actually needed? */ #if 0 - nread < 0 && (errno == EAGAIN + nread < 0 && (errno == EAGAIN #ifdef EFAULT - || errno == EFAULT + || errno == EFAULT #endif #ifdef EBADSLT - || errno == EBADSLT + || errno == EBADSLT #endif - ) + ) #else - 0 + 0 #endif - ); + ); #ifndef FIONREAD #if defined (USG) || defined (DGUX) || defined (CYGWIN) - fcntl (input_fd, F_SETFL, 0); + fcntl (fileno (tty->input), F_SETFL, 0); #endif /* USG or DGUX or CYGWIN */ #endif /* no FIONREAD */ - for (i = 0; i < nread; i++) - { - struct input_event buf; - EVENT_INIT (buf); - buf.kind = ASCII_KEYSTROKE_EVENT; - buf.modifiers = 0; - if (meta_key == 1 && (cbuf[i] & 0x80)) - buf.modifiers = meta_modifier; - if (meta_key != 2) - cbuf[i] &= ~0x80; - - buf.code = cbuf[i]; - buf.frame_or_window = selected_frame; - buf.arg = Qnil; - - kbd_buffer_store_event (&buf); - /* Don't look at input that follows a C-g too closely. - This reduces lossage due to autorepeat on C-g. */ - if (buf.kind == ASCII_KEYSTROKE_EVENT - && buf.code == quit_char) - break; - } + + if (nread <= 0) + return nread; + +#endif /* not MSDOS */ +#endif /* not WINDOWSNT */ + + for (i = 0; i < nread; i++) + { + struct input_event buf; + EVENT_INIT (buf); + buf.kind = ASCII_KEYSTROKE_EVENT; + buf.modifiers = 0; + if (tty->meta_key == 1 && (cbuf[i] & 0x80)) + buf.modifiers = meta_modifier; + if (tty->meta_key != 2) + cbuf[i] &= ~0x80; + + buf.code = cbuf[i]; + /* Set the frame corresponding to the active tty. Note that the + value of selected_frame is not reliable here, redisplay tends + to temporarily change it. */ + buf.frame_or_window = tty->top_frame; + buf.arg = Qnil; + + kbd_buffer_store_event (&buf); + /* Don't look at input that follows a C-g too closely. + This reduces lossage due to autorepeat on C-g. */ + if (buf.kind == ASCII_KEYSTROKE_EVENT + && buf.code == quit_char) + break; } return nread; @@ -6829,30 +6930,16 @@ input_available_signal (signo) sigisheld (SIGIO); #endif - if (input_available_clear_time) - EMACS_SET_SECS_USECS (*input_available_clear_time, 0, 0); - #ifdef SYNC_INPUT interrupt_input_pending = 1; #else + SIGNAL_THREAD_CHECK (signo); +#endif -# if !defined (SYSTEM_MALLOC) && defined (HAVE_GTK_AND_PTHREAD) - extern pthread_t main_thread; - if (pthread_self () != main_thread) - { - /* POSIX says any thread can receive the signal. On GNU/Linux that is - not true, but for other systems (FreeBSD at least) it is. So direct - the signal to the correct thread and block it from this thread. */ - sigset_t new_mask; - - sigemptyset (&new_mask); - sigaddset (&new_mask, SIGIO); - pthread_sigmask (SIG_BLOCK, &new_mask, 0); - pthread_kill (main_thread, SIGIO); - return; - } -# endif /* HAVE_GTK_AND_PTHREAD */ + if (input_available_clear_time) + EMACS_SET_SECS_USECS (*input_available_clear_time, 0, 0); +#ifndef SYNC_INPUT handle_async_input (); #endif @@ -6915,8 +7002,6 @@ menu_bar_items (old) int i; - struct gcpro gcpro1; - /* In order to build the menus, we need to call the keymap accessors. They all call QUIT. But this function is called during redisplay, during which a quit is fatal. So inhibit @@ -6932,8 +7017,6 @@ menu_bar_items (old) menu_bar_items_vector = Fmake_vector (make_number (24), Qnil); menu_bar_items_index = 0; - GCPRO1 (menu_bar_items_vector); - /* Build our list of keymaps. If we recognize a function key and replace its escape sequence in keybuf with its symbol, or if the sequence starts with a mouse @@ -7037,7 +7120,6 @@ menu_bar_items (old) menu_bar_items_index = i; Vinhibit_quit = oquit; - UNGCPRO; return menu_bar_items_vector; } @@ -8583,8 +8665,8 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last, last_nonmenu_event = Qnil; delayed_switch_frame = Qnil; - fkey.map = fkey.parent = Vfunction_key_map; - keytran.map = keytran.parent = Vkey_translation_map; + fkey.map = fkey.parent = current_kboard->Vlocal_function_key_map; + keytran.map = keytran.parent = current_kboard->Vlocal_key_translation_map; /* If there is no translation-map, turn off scanning. */ fkey.start = fkey.end = KEYMAPP (fkey.map) ? 0 : bufsize + 1; keytran.start = keytran.end = KEYMAPP (keytran.map) ? 0 : bufsize + 1; @@ -9733,6 +9815,15 @@ DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_ Lisp_Object saved_keys, saved_last_point_position_buffer; Lisp_Object bindings, value; struct gcpro gcpro1, gcpro2, gcpro3; +#ifdef HAVE_X_WINDOWS + /* The call to Fcompleting_read wil start and cancel the hourglass, + but if the hourglass was already scheduled, this means that no + hourglass will be shown for the actual M-x command itself. + So we restart it if it is already scheduled. Note that checking + hourglass_shown_p is not enough, normally the hourglass is not shown, + just scheduled to be shown. */ + int hstarted = hourglass_started (); +#endif saved_keys = Fvector (this_command_key_count, XVECTOR (this_command_keys)->contents); @@ -9764,6 +9855,10 @@ DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_ Qt, Qnil, Qextended_command_history, Qnil, Qnil); +#ifdef HAVE_X_WINDOWS + if (hstarted) start_hourglass (); +#endif + if (STRINGP (function) && SCHARS (function) == 0) error ("No command name given"); @@ -9799,7 +9894,7 @@ DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_ /* If enabled, show which key runs this command. */ if (!NILP (Vsuggest_key_bindings) - && NILP (Vexecuting_macro) + && NILP (Vexecuting_kbd_macro) && SYMBOLP (function)) bindings = Fwhere_is_internal (function, Voverriding_local_map, Qt, Qnil, Qnil); @@ -9873,6 +9968,18 @@ detect_input_pending () return input_pending; } +/* Return nonzero if input events other than mouse movements are + pending. */ + +int +detect_input_pending_ignore_squeezables () +{ + if (!input_pending) + get_input_pending (&input_pending, READABLE_EVENTS_IGNORE_SQUEEZABLES); + + return input_pending; +} + /* Return nonzero if input events are pending, and run any pending timers. */ int @@ -9882,7 +9989,7 @@ detect_input_pending_run_timers (do_display) int old_timers_run = timers_run; if (!input_pending) - get_input_pending (&input_pending, 1); + get_input_pending (&input_pending, READABLE_EVENTS_DO_TIMERS_NOW); if (old_timers_run != timers_run && do_display) { @@ -9892,8 +9999,12 @@ detect_input_pending_run_timers (do_display) from an idle timer function. The symptom of the bug is that the cursor sometimes doesn't become visible until the next X event is processed. --gerd. */ - if (rif) - rif->flush_display (NULL); + { + Lisp_Object tail, frame; + FOR_EACH_FRAME (tail, frame) + if (FRAME_RIF (XFRAME (frame))) + FRAME_RIF (XFRAME (frame))->flush_display (XFRAME (frame)); + } } return input_pending; @@ -9931,7 +10042,9 @@ if there is a doubt, the value is t. */) if (!NILP (Vunread_command_events) || unread_command_char != -1) return (Qt); - get_filtered_input_pending (&input_pending, 1, 1); + get_input_pending (&input_pending, + READABLE_EVENTS_DO_TIMERS_NOW + | READABLE_EVENTS_FILTER_EVENTS); return input_pending > 0 ? Qt : Qnil; } @@ -10135,6 +10248,9 @@ On such systems, Emacs starts a subshell instead of suspending. */) int width, height; struct gcpro gcpro1; + if (tty_list && tty_list->next) + error ("There are other tty frames open; close them before suspending Emacs"); + if (!NILP (stuffstring)) CHECK_STRING (stuffstring); @@ -10143,11 +10259,11 @@ On such systems, Emacs starts a subshell instead of suspending. */) call1 (Vrun_hooks, intern ("suspend-hook")); GCPRO1 (stuffstring); - get_frame_size (&old_width, &old_height); - reset_sys_modes (); + get_tty_size (fileno (CURTTY ()->input), &old_width, &old_height); + reset_all_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 ((Lisp_Object (*) P_ ((Lisp_Object))) init_sys_modes, + record_unwind_protect ((Lisp_Object (*) P_ ((Lisp_Object))) init_all_sys_modes, Qnil); stuff_buffered_input (stuffstring); if (cannot_suspend) @@ -10159,7 +10275,7 @@ On such systems, Emacs starts a subshell instead of suspending. */) /* Check if terminal/window size has changed. Note that this is not useful when we are running directly with a window system; but suspend should be disabled in that case. */ - get_frame_size (&width, &height); + get_tty_size (fileno (CURTTY ()->input), &width, &height); if (width != old_width || height != old_height) change_frame_size (SELECTED_FRAME (), height, width, 0, 0, 0); @@ -10219,10 +10335,10 @@ set_waiting_for_input (time_to_clear) { input_available_clear_time = time_to_clear; - /* Tell interrupt_signal to throw back to read_char, */ + /* Tell handle_interrupt to throw back to read_char, */ waiting_for_input = 1; - /* If interrupt_signal was called before and buffered a C-g, + /* If handle_interrupt was called before and buffered a C-g, make it run again now, to avoid timing error. */ if (!NILP (Vquit_flag)) quit_throw_to_read_char (); @@ -10231,47 +10347,82 @@ set_waiting_for_input (time_to_clear) void clear_waiting_for_input () { - /* Tell interrupt_signal not to throw back to read_char, */ + /* Tell handle_interrupt not to throw back to read_char, */ waiting_for_input = 0; input_available_clear_time = 0; } -/* This routine is called at interrupt level in response to C-g. - - If interrupt_input, this is the handler for SIGINT. Otherwise, it - is called from kbd_buffer_store_event, in handling SIGIO or - SIGTINT. +/* The SIGINT handler. - If `waiting_for_input' is non zero, then unless `echoing' is - nonzero, immediately throw back to read_char. - - Otherwise it sets the Lisp variable quit-flag not-nil. This causes - eval to throw, when it gets a chance. If quit-flag is already - non-nil, it stops the job right away. */ + If we have a frame on the controlling tty, we assume that the + SIGINT was generated by C-g, so we call handle_interrupt. + Otherwise, the handler kills Emacs. */ static SIGTYPE interrupt_signal (signalnum) /* If we don't have an argument, */ int signalnum; /* some compilers complain in signal calls. */ { - char c; /* Must preserve main program's value of errno. */ int old_errno = errno; - struct frame *sf = SELECTED_FRAME (); + struct device *device; #if defined (USG) && !defined (POSIX_SIGNALS) - if (!read_socket_hook && NILP (Vwindow_system)) + /* USG systems forget handlers when they are used; + must reestablish each time */ + signal (SIGINT, interrupt_signal); + signal (SIGQUIT, interrupt_signal); +#endif /* USG */ + + SIGNAL_THREAD_CHECK (signalnum); + + /* See if we have an active display on our controlling terminal. */ + device = get_named_tty (NULL); + if (!device) { - /* USG systems forget handlers when they are used; - must reestablish each time */ - signal (SIGINT, interrupt_signal); - signal (SIGQUIT, interrupt_signal); + /* If there are no frames there, let's pretend that we are a + well-behaving UN*X program and quit. */ + fatal_error_signal (SIGTERM); } -#endif /* USG */ + else + { + /* Otherwise, the SIGINT was probably generated by C-g. */ + + /* Set internal_last_event_frame to the top frame of the + controlling tty, if we have a frame there. We disable the + interrupt key on secondary ttys, so the SIGINT must have come + from the controlling tty. */ + internal_last_event_frame = device->display_info.tty->top_frame; + + handle_interrupt (); + } + + errno = old_errno; +} + +/* This routine is called at interrupt level in response to C-g. + + It is called from the SIGINT handler or kbd_buffer_store_event. + + If `waiting_for_input' is non zero, then unless `echoing' is + nonzero, immediately throw back to read_char. + + Otherwise it sets the Lisp variable quit-flag not-nil. This causes + eval to throw, when it gets a chance. If quit-flag is already + non-nil, it stops the job right away. */ + +static void +handle_interrupt () +{ + char c; cancel_echoing (); + /* XXX This code needs to be revised for multi-tty support. */ if (!NILP (Vquit_flag) - && (FRAME_TERMCAP_P (sf) || FRAME_MSDOS_P (sf))) +#ifndef MSDOS + && get_named_tty (NULL) +#endif + ) { /* If SIGINT isn't blocked, don't let us be interrupted by another SIGINT, it might be harmful due to non-reentrancy @@ -10279,7 +10430,7 @@ interrupt_signal (signalnum) /* If we don't have an argument, */ sigblock (sigmask (SIGINT)); fflush (stdout); - reset_sys_modes (); + reset_all_sys_modes (); #ifdef SIGTSTP /* Support possible in later USG versions */ /* @@ -10358,7 +10509,7 @@ interrupt_signal (signalnum) /* If we don't have an argument, */ printf ("Continuing...\n"); #endif /* not MSDOS */ fflush (stdout); - init_sys_modes (); + init_all_sys_modes (); sigfree (); } else @@ -10386,9 +10537,7 @@ interrupt_signal (signalnum) /* If we don't have an argument, */ } if (waiting_for_input && !echoing) - quit_throw_to_read_char (); - - errno = old_errno; + quit_throw_to_read_char (); } /* Handle a C-g by making read_char return C-g. */ @@ -10435,6 +10584,11 @@ See also `current-input-mode'. */) (interrupt, flow, meta, quit) Lisp_Object interrupt, flow, meta, quit; { + /* XXX This function needs to be revised for multi-device support. + Currently it compiles fine, but its semantics are wrong. It sets + global parameters (e.g. interrupt_input) based on only the + current frame's device. */ + if (!NILP (quit) && (!INTEGERP (quit) || XINT (quit) < 0 || XINT (quit) > 0400)) error ("set-input-mode: QUIT must be an ASCII character"); @@ -10444,13 +10598,14 @@ See also `current-input-mode'. */) #endif #ifndef DOS_NT - /* this causes startup screen to be restored and messes with the mouse */ - reset_sys_modes (); + if (FRAME_TERMCAP_P (XFRAME (selected_frame))) + /* this causes startup screen to be restored and messes with the mouse */ + reset_sys_modes (CURTTY ()); #endif #ifdef SIGIO /* Note SIGIO has been undef'd if FIONREAD is missing. */ - if (read_socket_hook) + if (FRAME_DEVICE (SELECTED_FRAME ())->read_socket_hook) { /* When using X, don't give the user a real choice, because we haven't implemented the mechanisms to support it. */ @@ -10471,19 +10626,25 @@ See also `current-input-mode'. */) interrupt_input = 1; #endif - flow_control = !NILP (flow); - if (NILP (meta)) - meta_key = 0; - else if (EQ (meta, Qt)) - meta_key = 1; - else - meta_key = 2; + if (FRAME_TERMCAP_P (XFRAME (selected_frame))) + { + struct tty_display_info *tty = CURTTY (); + tty->flow_control = !NILP (flow); + if (NILP (meta)) + tty->meta_key = 0; + else if (EQ (meta, Qt)) + tty->meta_key = 1; + else + tty->meta_key = 2; + } + if (!NILP (quit)) /* Don't let this value be out of range. */ - quit_char = XINT (quit) & (meta_key ? 0377 : 0177); + quit_char = XINT (quit) & (NILP (meta) ? 0177 : 0377); #ifndef DOS_NT - init_sys_modes (); + if (FRAME_TERMCAP_P (XFRAME (selected_frame))) + init_sys_modes (CURTTY ()); #endif #ifdef POLL_FOR_INPUT @@ -10510,27 +10671,43 @@ The elements of this list correspond to the arguments of () { Lisp_Object val[4]; + struct frame *sf = XFRAME (selected_frame); val[0] = interrupt_input ? Qt : Qnil; - val[1] = flow_control ? Qt : Qnil; - val[2] = meta_key == 2 ? make_number (0) : meta_key == 1 ? Qt : Qnil; + if (FRAME_TERMCAP_P (sf)) + { + val[1] = FRAME_TTY (sf)->flow_control ? Qt : Qnil; + val[2] = (FRAME_TTY (sf)->meta_key == 2 + ? make_number (0) + : (CURTTY ()->meta_key == 1 ? Qt : Qnil)); + } + else + { + val[1] = Qnil; + val[2] = Qt; + } XSETFASTINT (val[3], quit_char); return Flist (sizeof (val) / sizeof (val[0]), val); } -DEFUN ("posn-at-x-y", Fposn_at_x_y, Sposn_at_x_y, 2, 3, 0, +DEFUN ("posn-at-x-y", Fposn_at_x_y, Sposn_at_x_y, 2, 4, 0, doc: /* Return position information for pixel coordinates X and Y. By default, X and Y are relative to text area of the selected window. -Optional third arg FRAME_OR_WINDOW non-nil specifies frame or window. +Optional third arg FRAME-OR-WINDOW non-nil specifies frame or window. +If optional fourth arg WHOLE is non-nil, X is relative to the left +edge of the window. The return value is similar to a mouse click position: (WINDOW AREA-OR-POS (X . Y) TIMESTAMP OBJECT POS (COL . ROW) IMAGE (DX . DY) (WIDTH . HEIGHT)) The `posn-' functions access elements of such lists. */) - (x, y, frame_or_window) - Lisp_Object x, y, frame_or_window; + (x, y, frame_or_window, whole) + Lisp_Object x, y, frame_or_window, whole; { + CHECK_NATNUM (x); + CHECK_NATNUM (y); + if (NILP (frame_or_window)) frame_or_window = selected_window; @@ -10542,7 +10719,10 @@ The `posn-' functions access elements of such lists. */) w = XWINDOW (frame_or_window); XSETINT (x, (WINDOW_TO_FRAME_PIXEL_X (w, XINT (x)) - + window_box_left_offset (w, TEXT_AREA))); + + (NILP (whole) + ? window_box_left_offset (w, TEXT_AREA) + : - (WINDOW_LEFT_SCROLL_BAR_COLS (w) + * WINDOW_FRAME_COLUMN_WIDTH (w))))); XSETINT (y, WINDOW_TO_FRAME_PIXEL_Y (w, XINT (y))); frame_or_window = w->frame; } @@ -10570,7 +10750,7 @@ The `posn-' functions access elements of such lists. */) tem = Fpos_visible_in_window_p (pos, window, Qt); if (!NILP (tem)) - tem = Fposn_at_x_y (XCAR (tem), XCAR (XCDR (tem)), window); + tem = Fposn_at_x_y (XCAR (tem), XCAR (XCDR (tem)), window, Qnil); return tem; } @@ -10599,6 +10779,10 @@ init_kboard (kb) kb->reference_count = 0; kb->Vsystem_key_alist = Qnil; kb->system_key_syms = Qnil; + kb->Vlocal_function_key_map = Fmake_sparse_keymap (Qnil); + Fset_keymap_parent (kb->Vlocal_function_key_map, Vfunction_key_map); + kb->Vlocal_key_translation_map = Fmake_sparse_keymap (Qnil); + Fset_keymap_parent (kb->Vlocal_key_translation_map, Vkey_translation_map); kb->Vdefault_minibuffer_frame = Qnil; } @@ -10635,7 +10819,7 @@ delete_kboard (kb) && FRAMEP (selected_frame) && FRAME_LIVE_P (XFRAME (selected_frame))) { - current_kboard = XFRAME (selected_frame)->kboard; + current_kboard = XFRAME (selected_frame)->device->kboard; if (current_kboard == kb) abort (); } @@ -10676,8 +10860,14 @@ init_keyboard () wipe_kboard (current_kboard); init_kboard (current_kboard); - if (!noninteractive && !read_socket_hook && NILP (Vwindow_system)) + if (!noninteractive) { + /* Before multi-tty support, these handlers used to be installed + only if the current session was a tty session. Now an Emacs + session may have multiple display types, so we always handle + SIGINT. There is special code in interrupt_signal to exit + Emacs on SIGINT when there are no termcap frames on the + controlling terminal. */ signal (SIGINT, interrupt_signal); #if defined (HAVE_TERMIO) || defined (HAVE_TERMIOS) /* For systems with SysV TERMIO, C-g is set up for both SIGINT and @@ -10796,9 +10986,6 @@ syms_of_keyboard () Qpost_command_hook = intern ("post-command-hook"); staticpro (&Qpost_command_hook); - Qpost_command_idle_hook = intern ("post-command-idle-hook"); - staticpro (&Qpost_command_idle_hook); - Qdeferred_action_function = intern ("deferred-action-function"); staticpro (&Qdeferred_action_function); @@ -10809,7 +10996,7 @@ syms_of_keyboard () staticpro (&Qfunction_key); Qmouse_click = intern ("mouse-click"); staticpro (&Qmouse_click); -#ifdef WINDOWSNT +#if defined (WINDOWSNT) || defined (MAC_OS) Qlanguage_change = intern ("language-change"); staticpro (&Qlanguage_change); #endif @@ -10817,7 +11004,7 @@ syms_of_keyboard () staticpro (&Qdrag_n_drop); Qsave_session = intern ("save-session"); - staticpro(&Qsave_session); + staticpro (&Qsave_session); Qusr1_signal = intern ("usr1-signal"); staticpro (&Qusr1_signal); @@ -10856,6 +11043,11 @@ syms_of_keyboard () Qmenu_bar = intern ("menu-bar"); staticpro (&Qmenu_bar); +#ifdef HAVE_MOUSE + Qmouse_fixup_help_message = intern ("mouse-fixup-help-message"); + staticpro (&Qmouse_fixup_help_message); +#endif + Qabove_handle = intern ("above-handle"); staticpro (&Qabove_handle); Qhandle = intern ("handle"); @@ -10971,6 +11163,9 @@ syms_of_keyboard () menu_bar_one_keymap_changed_items = Qnil; staticpro (&menu_bar_one_keymap_changed_items); + menu_bar_items_vector = Qnil; + staticpro (&menu_bar_items_vector); + defsubr (&Sevent_convert_list); defsubr (&Sread_key_sequence); defsubr (&Sread_key_sequence_vector); @@ -11055,7 +11250,10 @@ In other words, the present command is the event that made the previous command exit. The value `kill-region' is special; it means that the previous command -was a kill command. */); +was a kill command. + +`last-command' has a separate binding for each display device. +See Info node `(elisp)Multiple displays'. */); DEFVAR_KBOARD ("real-last-command", Vreal_last_command, doc: /* Same as `last-command', but never altered by Lisp code. */); @@ -11239,21 +11437,12 @@ the hook value is set to nil, since otherwise the error might happen repeatedly and make Emacs nonfunctional. */); Vpost_command_hook = Qnil; - DEFVAR_LISP ("post-command-idle-hook", &Vpost_command_idle_hook, - doc: /* Normal hook run after each command is executed, if idle. -Errors running the hook are caught and ignored. */); - Vpost_command_idle_hook = Qnil; - - DEFVAR_INT ("post-command-idle-delay", &post_command_idle_delay, - doc: /* Delay time before running `post-command-idle-hook'. -This is measured in microseconds. */); - post_command_idle_delay = 100000; - #if 0 DEFVAR_LISP ("echo-area-clear-hook", ..., doc: /* Normal hook run when clearing the echo area. */); #endif Qecho_area_clear_hook = intern ("echo-area-clear-hook"); + staticpro (&Qecho_area_clear_hook); SET_SYMBOL_VALUE (Qecho_area_clear_hook, Qnil); DEFVAR_LISP ("lucid-menu-bar-dirty-flag", &Vlucid_menu_bar_dirty_flag, @@ -11270,14 +11459,18 @@ The elements of the list are event types that may have menu bar bindings. */); doc: /* Per-terminal keymap that overrides all other local keymaps. If this variable is non-nil, it is used as a keymap instead of the buffer's local map, and the minor mode keymaps and text property keymaps. -It also overrides `overriding-local-map'. +It also replaces `overriding-local-map'. + This variable is intended to let commands such as `universal-argument' -set up a different keymap for reading the next command. */); +set up a different keymap for reading the next command. + +`overriding-terminal-local-map' has a separate binding for each display device. +See Info node `(elisp)Multiple displays'. */); DEFVAR_LISP ("overriding-local-map", &Voverriding_local_map, doc: /* Keymap that overrides all other local keymaps. -If this variable is non-nil, it is used as a keymap instead of the -buffer's local map, and the minor mode keymaps and text property keymaps. */); +If this variable is non-nil, it is used as a keymap--replacing the +buffer's local map, the minor mode keymaps, and char property keymaps. */); Voverriding_local_map = Qnil; DEFVAR_LISP ("overriding-local-map-menu-flag", &Voverriding_local_map_menu_flag, @@ -11297,7 +11490,70 @@ and the minor mode maps regardless of `overriding-local-map'. */); doc: /* Alist of system-specific X windows key symbols. Each element should have the form (N . SYMBOL) where N is the numeric keysym code (sans the \"system-specific\" bit 1<<28) -and SYMBOL is its name. */); +and SYMBOL is its name. + +`system-key-alist' has a separate binding for each display device. +See Info node `(elisp)Multiple displays'. + +Note that the currently selected frame has very little to do with +which binding of this variable is active at any given moment. If you +need set or get the binding on a specific display, use +`terminal-local-value' and `set-terminal-local-value'. */); + + DEFVAR_KBOARD ("local-function-key-map", Vlocal_function_key_map, + doc: /* Keymap mapping ASCII function key sequences onto their preferred forms. +This allows Emacs to recognize function keys sent from ASCII +terminals at any point in a key sequence. + +The `read-key-sequence' function replaces any subsequence bound by +`function-key-map' with its binding. More precisely, when the active +keymaps have no binding for the current key sequence but +`function-key-map' binds a suffix of the sequence to a vector or string, +`read-key-sequence' replaces the matching suffix with its binding, and +continues with the new sequence. + +The events that come from bindings in `function-key-map' are not +themselves looked up in `function-key-map'. + +For example, suppose `function-key-map' binds `ESC O P' to [f1]. +Typing `ESC O P' to `read-key-sequence' would return [f1]. Typing +`C-x ESC O P' would return [?\\C-x f1]. If [f1] were a prefix +key, typing `ESC O P x' would return [f1 x]. + +`function-key-map' has a separate binding for each display device. +See Info node `(elisp)Multiple displays'. If you need to define a +binding on all display devices, change `global-function-key-map' +instead. + +Note that the currently selected frame has very little to do with +which binding of this variable is active at any given moment. If you +need set or get the binding on a specific display, use +`terminal-local-value' and `set-terminal-local-value'. */); + + DEFVAR_LISP ("function-key-map", &Vfunction_key_map, + doc: /* The parent keymap of all `local-function-key-map' instances. +Function key definitions that apply to all display devices should go +here. */); + Vfunction_key_map = Fmake_sparse_keymap (Qnil); + + DEFVAR_KBOARD ("local-key-translation-map", Vlocal_key_translation_map, + doc: /* Keymap of key translations that can override keymaps. +This keymap works like `function-key-map', but comes after that, +and its non-prefix bindings override ordinary bindings. + +`key-translation-map' has a separate binding for each display device. +(See Info node `(elisp)Multiple displays'.) If you need to set a key +translation on all devices, change `global-key-translation-map' instead. + +Note that the currently selected frame has very little to do with +which binding of this variable is active at any given moment. If you +need set or get the binding on a specific display, use +`terminal-local-value' and `set-terminal-local-value'. */); + + DEFVAR_LISP ("key-translation-map", &Vkey_translation_map, + doc: /* The parent keymap of all `local-key-translation-map' instances. +Key translations that apply to all display devices should go here. */); + Vkey_translation_map = Fmake_sparse_keymap (Qnil); DEFVAR_LISP ("deferred-action-list", &Vdeferred_action_list, doc: /* List of deferred actions to be performed at a later time. @@ -11407,10 +11663,29 @@ keys_of_keyboard () initial_define_lispy_key (Vspecial_event_map, "delete-frame", "handle-delete-frame"); + /* Here we used to use `ignore-event' which would simple set prefix-arg to + current-prefix-arg, as is done in `handle-switch-frame'. + But `handle-switch-frame is not run from the special-map. + Commands from that map are run in a special way that automatically + preserves the prefix-arg. Restoring the prefix arg here is not just + redundant but harmful: + - C-u C-x v = + - current-prefix-arg is set to non-nil, prefix-arg is set to nil. + - after the first prompt, the exit-minibuffer-hook is run which may + iconify a frame and thus push a `iconify-frame' event. + - after running exit-minibuffer-hook, current-prefix-arg is + restored to the non-nil value it had before the prompt. + - we enter the second prompt. + current-prefix-arg is non-nil, prefix-arg is nil. + - before running the first real event, we run the special iconify-frame + event, but we pass the `special' arg to execute-command so + current-prefix-arg and prefix-arg are left untouched. + - here we foolishly copy the non-nil current-prefix-arg to prefix-arg. + - the next key event will have a spuriously non-nil current-prefix-arg. */ initial_define_lispy_key (Vspecial_event_map, "iconify-frame", - "ignore-event"); + "ignore"); initial_define_lispy_key (Vspecial_event_map, "make-frame-visible", - "ignore-event"); + "ignore"); /* Handling it at such a low-level causes read_key_sequence to get * confused because it doesn't realize that the current_buffer was * changed by read_char. @@ -11443,6 +11718,8 @@ mark_kboards () mark_object (kb->Vlast_kbd_macro); mark_object (kb->Vsystem_key_alist); mark_object (kb->system_key_syms); + mark_object (kb->Vlocal_function_key_map); + mark_object (kb->Vlocal_key_translation_map); mark_object (kb->Vdefault_minibuffer_frame); mark_object (kb->echo_string); }