diff options
Diffstat (limited to 'src/keyboard.c')
-rw-r--r-- | src/keyboard.c | 495 |
1 files changed, 316 insertions, 179 deletions
diff --git a/src/keyboard.c b/src/keyboard.c index 3e58a2a75a8..5e8397e7458 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -22,13 +22,13 @@ Boston, MA 02111-1307, 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" @@ -55,7 +55,6 @@ Boston, MA 02111-1307, USA. */ #endif /* not MSDOS */ #include "syssignal.h" -#include "systty.h" #include <sys/types.h> #ifdef HAVE_UNISTD_H @@ -89,9 +88,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 @@ -464,11 +460,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; @@ -595,9 +586,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 @@ -674,6 +662,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)); /* Nonzero means don't try to suspend even if the operating system seems to support it. */ @@ -1184,9 +1173,7 @@ cmd_error_internal (data, context) 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; @@ -1335,6 +1322,7 @@ cancel_hourglass_unwind (arg) Lisp_Object arg; { cancel_hourglass (); + return Qnil; } #endif @@ -2050,7 +2038,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. */ @@ -2084,7 +2075,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 @@ -2096,7 +2090,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 } @@ -3612,7 +3609,7 @@ kbd_buffer_store_event_hold (event, hold_quit) } last_event_timestamp = event->timestamp; - interrupt_signal (0 /* dummy */); + handle_interrupt (); return; } @@ -4088,7 +4085,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_DISPLAY (f)->mouse_position_hook) + (*FRAME_DISPLAY (f)->mouse_position_hook) (&f, 0, &bar_window, + &part, &x, &y, &time); obj = Qnil; @@ -6529,7 +6530,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)); @@ -6608,145 +6612,215 @@ read_avail_input (expected) { register int i; int nread = 0; + int err; + struct display *d; - if (read_socket_hook) + /* Loop through the available displays, and call their input hooks. */ + d = display_list; + while (d) { - int discard = 0; - int nr; - struct input_event hold_quit; + struct display *next = d->next_display; - EVENT_INIT (hold_quit); - hold_quit.kind = NO_EVENT; + if (d->read_socket_hook) + { + int discard = 0; + int nr; - /* 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); + 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 (! display_list->next_display) + /* 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_display safe here? It calls Fdelete_frame. */ + if (d->delete_display_hook) + (*d->delete_display_hook) (d); + else + delete_display (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 display' 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 display *display, + 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 = display->display_info.tty; + int nread = 0; + + if (display->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 display. */ + 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 display. */ #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 display. */ +#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; @@ -9862,8 +9936,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; @@ -10105,6 +10183,9 @@ On such systems, Emacs starts a subshell instead of suspending. */) int width, height; struct gcpro gcpro1; + if (tty_list && tty_list->next) + error ("Suspend is not supported with multiple ttys"); + if (!NILP (stuffstring)) CHECK_STRING (stuffstring); @@ -10113,11 +10194,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) @@ -10129,7 +10210,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); @@ -10189,10 +10270,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 (); @@ -10201,45 +10282,76 @@ 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, 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 display *display; #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 */ + + /* See if we have a display on our controlling terminal. */ + display = get_named_tty_display (NULL); + if (!display) { - /* 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. */ + Fkill_emacs (Qnil); + } + 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 = display->display_info.tty->top_frame; + + handle_interrupt (); } -#endif /* USG */ + + 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; + struct frame *sf = SELECTED_FRAME (); 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))) { @@ -10249,7 +10361,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 */ /* @@ -10328,7 +10440,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 @@ -10356,9 +10468,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. */ @@ -10405,6 +10515,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"); @@ -10415,12 +10530,12 @@ See also `current-input-mode'. */) #ifndef DOS_NT /* this causes startup screen to be restored and messes with the mouse */ - reset_sys_modes (); + reset_all_sys_modes (); #endif #ifdef SIGIO /* Note SIGIO has been undef'd if FIONREAD is missing. */ - if (read_socket_hook) + if (FRAME_DISPLAY (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. */ @@ -10441,19 +10556,24 @@ 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 (); + init_all_sys_modes (); #endif #ifdef POLL_FOR_INPUT @@ -10480,10 +10600,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); @@ -10591,8 +10722,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 |