diff options
Diffstat (limited to 'src/keyboard.c')
-rw-r--r-- | src/keyboard.c | 750 |
1 files changed, 511 insertions, 239 deletions
diff --git a/src/keyboard.c b/src/keyboard.c index 96bc115412e..f6a65560268 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -23,13 +23,13 @@ Boston, MA 02110-1301, USA. */ #include <config.h> #include <signal.h> #include <stdio.h> +#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" @@ -59,7 +59,6 @@ Boston, MA 02110-1301, USA. */ #endif /* not MSDOS */ #include "syssignal.h" -#include "systty.h" #include <sys/types.h> #ifdef HAVE_UNISTD_H @@ -97,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 @@ -419,16 +415,6 @@ Lisp_Object Vecho_keystrokes; /* Form to evaluate (if non-nil) when Emacs is started. */ 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; @@ -452,6 +438,12 @@ Lisp_Object Qpre_command_hook, Vpre_command_hook; Lisp_Object Qpost_command_hook, Vpost_command_hook; Lisp_Object Qcommand_hook_internal, Vcommand_hook_internal; +/* 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. */ Lisp_Object Vdeferred_action_list; @@ -469,11 +461,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; - extern char *pending_malloc_warning; /* Circular buffer for pre-read keyboard input. */ @@ -600,9 +587,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 @@ -681,7 +665,9 @@ static void restore_getcjmp P_ ((jmp_buf)); 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 Lisp_Object restore_kboard_configuration P_ ((Lisp_Object)); 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)); @@ -1042,24 +1028,19 @@ This function is called by the editor initialization to begin editing. */) like it is done in the splash screen display, we have to make sure that we restore single_kboard as command_loop_1 would have done if it were left normally. */ - record_unwind_protect (recursive_edit_unwind, - Fcons (buffer, single_kboard ? Qt : Qnil)); + temporarily_switch_to_single_kboard (FRAME_KBOARD (SELECTED_FRAME ())); + record_unwind_protect (recursive_edit_unwind, buffer); recursive_edit_1 (); return unbind_to (count, Qnil); } Lisp_Object -recursive_edit_unwind (info) - Lisp_Object info; +recursive_edit_unwind (buffer) + Lisp_Object buffer; { - if (BUFFERP (XCAR (info))) - Fset_buffer (XCAR (info)); - - if (NILP (XCDR (info))) - any_kboard_state (); - else - single_kboard_state (); + if (BUFFERP (buffer)) + Fset_buffer (buffer); command_loop_level--; update_mode_lines = 1; @@ -1124,8 +1105,8 @@ struct kboard_stack static struct kboard_stack *kboard_stack; void -push_frame_kboard (f) - FRAME_PTR f; +push_kboard (k) + struct kboard *k; { #ifdef MULTI_KBOARD struct kboard_stack *p @@ -1135,20 +1116,82 @@ push_frame_kboard (f) p->kboard = current_kboard; kboard_stack = p; - current_kboard = FRAME_KBOARD (f); + current_kboard = k; #endif } void -pop_frame_kboard () +push_frame_kboard (f) + FRAME_PTR f; +{ + push_kboard (f->device->kboard); +} + +void +pop_kboard () { #ifdef MULTI_KBOARD + struct device *d; struct kboard_stack *p = kboard_stack; - current_kboard = p->kboard; + int ok = 0; + current_kboard = NULL; + for (d = device_list; d; d = d->next_device) + { + if (d->kboard == p->kboard) + { + current_kboard = p->kboard; + break; + } + } + if (current_kboard == NULL) + { + /* The display we remembered has been deleted. */ + current_kboard = FRAME_KBOARD (SELECTED_FRAME ()); + } kboard_stack = p->next; xfree (p); #endif } + +/* Switch to single_kboard mode. If K is non-nil, set it as the + current keyboard. Use record_unwind_protect to return to the + previous state later. */ + +void +temporarily_switch_to_single_kboard (k) + struct kboard *k; +{ +#ifdef MULTI_KBOARD + int was_locked = single_kboard; + if (k != NULL) + push_kboard (k); + else + push_kboard (current_kboard); + single_kboard_state (); + record_unwind_protect (restore_kboard_configuration, + (was_locked ? Qt : Qnil)); +#endif +} + +void +record_single_kboard_state () +{ + push_kboard (current_kboard); + record_unwind_protect (restore_kboard_configuration, + (single_kboard ? Qt : Qnil)); +} + +static Lisp_Object +restore_kboard_configuration (was_locked) + Lisp_Object was_locked; +{ + if (NILP (was_locked)) + any_kboard_state (); + else + single_kboard_state (); + pop_kboard (); + return Qnil; +} /* Handle errors that are not handled at inner levels by printing an error message and returning to the editor command loop. */ @@ -1229,11 +1272,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; @@ -1287,10 +1326,10 @@ command_loop () 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_kbd_macro = Qnil; @@ -1405,12 +1444,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; @@ -2107,7 +2146,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. */ @@ -2141,7 +2183,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 @@ -2153,7 +2198,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 } @@ -2958,15 +3006,15 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu) if (XINT (c) == -1) goto exit; - if ((STRINGP (Vkeyboard_translate_table) - && SCHARS (Vkeyboard_translate_table) > (unsigned) XFASTINT (c)) - || (VECTORP (Vkeyboard_translate_table) - && XVECTOR (Vkeyboard_translate_table)->size > (unsigned) XFASTINT (c)) - || (CHAR_TABLE_P (Vkeyboard_translate_table) + if ((STRINGP (current_kboard->Vkeyboard_translate_table) + && SCHARS (current_kboard->Vkeyboard_translate_table) > (unsigned) XFASTINT (c)) + || (VECTORP (current_kboard->Vkeyboard_translate_table) + && XVECTOR (current_kboard->Vkeyboard_translate_table)->size > (unsigned) XFASTINT (c)) + || (CHAR_TABLE_P (current_kboard->Vkeyboard_translate_table) && CHAR_VALID_P (XINT (c), 0))) { Lisp_Object d; - d = Faref (Vkeyboard_translate_table, c); + d = Faref (current_kboard->Vkeyboard_translate_table, c); /* nil in keyboard-translate-table means no translation. */ if (!NILP (d)) c = d; @@ -3689,7 +3737,7 @@ kbd_buffer_store_event_hold (event, hold_quit) } last_event_timestamp = event->timestamp; - interrupt_signal (0 /* dummy */); + handle_interrupt (); return; } @@ -4158,7 +4206,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; @@ -4455,10 +4507,13 @@ timer_check (do_it_now) { if (NILP (vector[0])) { - int was_locked = single_kboard; int count = SPECPDL_INDEX (); Lisp_Object old_deactivate_mark = Vdeactivate_mark; + /* On unbind_to, resume allowing input from any kboard, if that + was true before. */ + record_single_kboard_state (); + /* Mark the timer as triggered to prevent problems if the lisp code fails to reschedule it right. */ vector[0] = Qt; @@ -4470,10 +4525,6 @@ timer_check (do_it_now) timers_run++; unbind_to (count, Qnil); - /* Resume allowing input from any kboard, if that was true before. */ - if (!was_locked) - any_kboard_state (); - /* Since we have handled the event, we don't need to tell the caller to wake up and do it. */ } @@ -6339,8 +6390,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]) @@ -6605,7 +6656,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)); @@ -6682,146 +6736,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; + + 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); + } - /* 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); + 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 <jch@bsdi.com> 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 <jch@bsdi.com> 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; @@ -8605,8 +8727,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; @@ -9939,8 +10061,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; @@ -10184,6 +10310,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); @@ -10192,11 +10321,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) @@ -10208,7 +10337,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); @@ -10268,10 +10397,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 (); @@ -10280,48 +10409,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); - } + /* 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) + { + /* If there are no frames there, let's pretend that we are a + well-behaving UN*X program and quit. */ + fatal_error_signal (SIGTERM); + } + 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 @@ -10329,7 +10492,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 */ /* @@ -10408,7 +10571,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 @@ -10436,9 +10599,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. */ @@ -10485,6 +10646,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"); @@ -10494,13 +10660,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. */ @@ -10521,19 +10688,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 @@ -10560,10 +10733,21 @@ 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); @@ -10655,6 +10839,7 @@ init_kboard (kb) kb->Voverriding_terminal_local_map = Qnil; kb->Vlast_command = Qnil; kb->Vreal_last_command = Qnil; + kb->Vkeyboard_translate_table = Qnil; kb->Vprefix_arg = Qnil; kb->Vlast_prefix_arg = Qnil; kb->kbd_queue = Qnil; @@ -10669,6 +10854,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; } @@ -10705,7 +10894,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 (); } @@ -10746,8 +10935,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 @@ -11125,7 +11320,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. */); @@ -11237,8 +11435,8 @@ for that character after that prefix key. */); Useful to set before you dump a modified Emacs. */); Vtop_level = Qnil; - DEFVAR_LISP ("keyboard-translate-table", &Vkeyboard_translate_table, - doc: /* Translate table for keyboard input, or nil. + DEFVAR_KBOARD ("keyboard-translate-table", Vkeyboard_translate_table, + doc: /* Translate table for local keyboard input, or nil. If non-nil, the value should be a char-table. Each character read from the keyboard is looked up in this char-table. If the value found there is non-nil, then it is used instead of the actual input character. @@ -11248,8 +11446,10 @@ If it is a string or vector of length N, character codes N and up are left untranslated. In a vector, an element which is nil means "no translation". This is applied to the characters supplied to input methods, not their -output. See also `translation-table-for-input'. */); - Vkeyboard_translate_table = Qnil; +output. See also `translation-table-for-input'. + +`local-keyboard-translate-table' has a separate binding for each +terminal. See Info node `(elisp)Multiple displays'. */); DEFVAR_BOOL ("cannot-suspend", &cannot_suspend, doc: /* Non-nil means to always spawn a subshell instead of suspending. @@ -11334,7 +11534,10 @@ buffer's local map, and the minor mode keymaps and text property keymaps. 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. @@ -11359,7 +11562,73 @@ 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 +`local-function-key-map' with its binding. More precisely, when the +active keymaps have no binding for the current key sequence but +`local-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 `local-function-key-map' are not +themselves looked up in `local-function-key-map'. + +For example, suppose `local-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]. + +`local-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 `function-key-map' +instead. Initially, `local-function-key-map' is an empty keymap that +has `function-key-map' as its parent on all display devices. + +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. If a mapping is defined in both the current +`local-function-key-map' binding and this variable, then the local +definition will take precendence. */); + 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. @@ -11511,6 +11780,7 @@ mark_kboards () mark_object (kb->Voverriding_terminal_local_map); mark_object (kb->Vlast_command); mark_object (kb->Vreal_last_command); + mark_object (kb->Vkeyboard_translate_table); mark_object (kb->Vprefix_arg); mark_object (kb->Vlast_prefix_arg); mark_object (kb->kbd_queue); @@ -11518,6 +11788,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); } |