Rename `struct device' to `struct terminal'. Rename some terminal-related functions...
[bpt/emacs.git] / src / keyboard.c
index a04f0e6..8cfa4b3 100644 (file)
@@ -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
@@ -381,12 +377,15 @@ Lisp_Object real_this_command;
    command is stored in this-original-command.  It is nil otherwise.  */
 Lisp_Object Vthis_original_command;
 
-/* The value of point when the last command was executed.  */
+/* The value of point when the last command was started.  */
 int last_point_position;
 
 /* The buffer that was current when the last command was started.  */
 Lisp_Object last_point_position_buffer;
 
+/* The window that was selected when the last command was started.  */
+Lisp_Object last_point_position_window;
+
 /* The frame in which the last input event occurred, or Qmacro if the
    last event came from a macro.  We use this to determine when to
    generate switch-frame events.  This may be cleared by functions
@@ -419,16 +418,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 +441,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 +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;
-
 extern char *pending_malloc_warning;
 
 /* Circular buffer for pre-read keyboard input.  */
@@ -527,6 +517,9 @@ Lisp_Object Qlanguage_change;
 #endif
 Lisp_Object Qdrag_n_drop;
 Lisp_Object Qsave_session;
+#ifdef MAC_OS
+Lisp_Object Qmac_apple_event;
+#endif
 
 /* Lisp_Object Qmouse_movement; - also an event header */
 
@@ -600,9 +593,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 +671,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 +1034,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 +1111,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 +1122,81 @@ 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->terminal->kboard);
+}
+
+void
+pop_kboard ()
 {
 #ifdef MULTI_KBOARD
+  struct terminal *t;
   struct kboard_stack *p = kboard_stack;
-  current_kboard = p->kboard;
+  current_kboard = NULL;
+  for (t = terminal_list; t; t = t->next_terminal)
+    {
+      if (t->kboard == p->kboard)
+        {
+          current_kboard = p->kboard;
+          break;
+        }
+    }
+  if (current_kboard == NULL)
+    {
+      /* The terminal 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;
+}
 \f
 /* Handle errors that are not handled at inner levels
    by printing an error message and returning to the editor command loop.  */
@@ -1229,11 +1277,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 +1331,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 +1449,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;
@@ -1441,8 +1485,6 @@ command_loop_1 ()
        safe_run_hooks (Qdeferred_action_function);
     }
 
-  Vmemory_full = Qnil;
-
   /* Do this after running Vpost_command_hook, for consistency.  */
   current_kboard->Vlast_command = Vthis_command;
   current_kboard->Vreal_last_command = real_this_command;
@@ -1580,6 +1622,7 @@ command_loop_1 ()
       prev_buffer = current_buffer;
       prev_modiff = MODIFF;
       last_point_position = PT;
+      last_point_position_window = selected_window;
       XSETBUFFER (last_point_position_buffer, prev_buffer);
 
       /* By default, we adjust point to a boundary of a region that
@@ -2107,7 +2150,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 +2187,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 +2202,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
 }
@@ -2613,6 +2665,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
 
   if (_setjmp (local_getcjmp))
     {
+      /* Handle quits while reading the keyboard.  */
       /* We must have saved the outer value of getcjmp here,
         so restore it now.  */
       restore_getcjmp (save_jump);
@@ -2958,15 +3011,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;
@@ -3641,12 +3694,10 @@ kbd_buffer_store_event_hold (event, hold_quit)
       if (c == quit_char)
        {
 #ifdef MULTI_KBOARD
-         KBOARD *kb;
+         KBOARD *kb = FRAME_KBOARD (XFRAME (event->frame_or_window));
          struct input_event *sp;
 
-         if (single_kboard
-             && (kb = FRAME_KBOARD (XFRAME (event->frame_or_window)),
-                 kb != current_kboard))
+         if (single_kboard && kb != current_kboard)
            {
              kb->kbd_queue
                = Fcons (make_lispy_switch_frame (event->frame_or_window),
@@ -3689,7 +3740,7 @@ kbd_buffer_store_event_hold (event, hold_quit)
          }
 
          last_event_timestamp = event->timestamp;
-         interrupt_signal (0 /* dummy */);
+         handle_interrupt ();
          return;
        }
 
@@ -4154,11 +4205,15 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
       unsigned long time;
 
       *kbp = current_kboard;
-      /* Note that this uses F to determine which display to look at.
+      /* Note that this uses F to determine which terminal to look at.
         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_TERMINAL (f)->mouse_position_hook)
+        (*FRAME_TERMINAL (f)->mouse_position_hook) (&f, 0, &bar_window,
+                                                    &part, &x, &y, &time);
 
       obj = Qnil;
 
@@ -4455,10 +4510,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 +4528,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.  */
            }
@@ -5054,7 +5108,11 @@ make_lispy_position (f, x, y, time)
       XSETINT (*x, wx);
       XSETINT (*y, wy);
 
-      if (part == ON_MODE_LINE || part == ON_HEADER_LINE)
+      if (part == ON_TEXT)
+       {
+         wx += WINDOW_LEFT_MARGIN_WIDTH (w);
+       }
+      else if (part == ON_MODE_LINE || part == ON_HEADER_LINE)
        {
          /* Mode line or header line.  Look for a string under
             the mouse that may have a `local-map' property.  */
@@ -5090,20 +5148,37 @@ make_lispy_position (f, x, y, time)
                                         &object, &dx, &dy, &width, &height);
          if (STRINGP (string))
            string_info = Fcons (string, make_number (charpos));
+         if (part == ON_LEFT_MARGIN)
+           wx = 0;
+         else
+           wx = window_box_right_offset (w, TEXT_AREA) - 1;
+       }
+      else if (part == ON_LEFT_FRINGE)
+       {
+         posn = Qleft_fringe;
+         rx = 0;
+         dx = wx;
+         wx = (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
+               ? 0
+               : window_box_width (w, LEFT_MARGIN_AREA));
+         dx -= wx;
        }
-      else if (part == ON_LEFT_FRINGE || part == ON_RIGHT_FRINGE)
+      else if (part == ON_RIGHT_FRINGE)
        {
-         posn = (part == ON_LEFT_FRINGE) ? Qleft_fringe : Qright_fringe;
+         posn = Qright_fringe;
          rx = 0;
          dx = wx;
-         if (part == ON_RIGHT_FRINGE)
-           dx -= (window_box_width (w, LEFT_MARGIN_AREA)
-                  + window_box_width (w, TEXT_AREA)
-                  + (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
-                     ? window_box_width (w, RIGHT_MARGIN_AREA)
-                     : 0));
-         else if (!WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w))
-           dx -= window_box_width (w, LEFT_MARGIN_AREA);
+         wx = (window_box_width (w, LEFT_MARGIN_AREA)
+               + window_box_width (w, TEXT_AREA)
+               + (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
+                  ? window_box_width (w, RIGHT_MARGIN_AREA)
+                  : 0));
+         dx -= wx;
+       }
+      else
+       {
+         /* Note: We have no special posn for part == ON_SCROLL_BAR.  */
+         wx = max (WINDOW_LEFT_MARGIN_WIDTH (w), wx);
        }
 
       if (textpos < 0)
@@ -5112,7 +5187,6 @@ make_lispy_position (f, x, y, time)
          struct display_pos p;
          int dx2, dy2;
          int width2, height2;
-         wx = max (WINDOW_LEFT_MARGIN_WIDTH (w), wx);
          string2 = buffer_posn_from_coords (w, &wx, &wy, &p,
                                             &object2, &dx2, &dy2,
                                             &width2, &height2);
@@ -5507,13 +5581,23 @@ make_lispy_event (event)
                if (CONSP (down)
                    && INTEGERP (XCAR (down)) && INTEGERP (XCDR (down)))
                  {
-                   xdiff = XFASTINT (event->x) - XFASTINT (XCAR (down));
-                   ydiff = XFASTINT (event->y) - XFASTINT (XCDR (down));
+                   xdiff = XINT (event->x) - XINT (XCAR (down));
+                   ydiff = XINT (event->y) - XINT (XCDR (down));
                  }
 
                if (xdiff < double_click_fuzz && xdiff > - double_click_fuzz
-                   && ydiff < double_click_fuzz
-                   && ydiff > - double_click_fuzz)
+                   && ydiff < double_click_fuzz && ydiff > - double_click_fuzz
+                 /* Maybe the mouse has moved a lot, caused scrolling, and
+                    eventually ended up at the same screen position (but
+                    not buffer position) in which case it is a drag, not
+                    a click.  */
+                   /* FIXME: OTOH if the buffer position has changed
+                      because of a timer or process filter rather than
+                      because of mouse movement, it should be considered as
+                      a click.  But mouse-drag-region completely ignores
+                      this case and it hasn't caused any real problem, so
+                      it's probably OK to ignore it as well.  */
+                   && EQ (Fcar (Fcdr (start_pos)), Fcar (Fcdr (position))))
                  /* Mouse hasn't moved (much).  */
                  event->modifiers |= click_modifier;
                else
@@ -5774,14 +5858,8 @@ make_lispy_event (event)
        Lisp_Object head, position;
        Lisp_Object files;
 
-       /* The frame_or_window field should be a cons of the frame in
-          which the event occurred and a list of the filenames
-          dropped.  */
-       if (! CONSP (event->frame_or_window))
-         abort ();
-
-       f = XFRAME (XCAR (event->frame_or_window));
-       files = XCDR (event->frame_or_window);
+       f = XFRAME (event->frame_or_window);
+       files = event->arg;
 
        /* Ignore mouse events that were made on frames that
           have been deleted.  */
@@ -5836,6 +5914,20 @@ make_lispy_event (event)
     case SAVE_SESSION_EVENT:
       return Qsave_session;
 
+#ifdef MAC_OS
+    case MAC_APPLE_EVENT:
+      {
+       Lisp_Object spec[2];
+
+       spec[0] = event->x;
+       spec[1] = event->y;
+       return Fcons (Qmac_apple_event,
+                     Fcons (Fvector (2, spec),
+                            Fcons (mac_make_lispy_event_code (event->code),
+                                   Qnil)));
+      }
+#endif
+
       /* The 'kind' field of the event is something we don't recognize.  */
     default:
       abort ();
@@ -6309,8 +6401,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])
@@ -6575,7 +6667,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));
@@ -6652,146 +6747,214 @@ static int
 read_avail_input (expected)
      int expected;
 {
-  register int i;
   int nread = 0;
+  int err = 0;
+  struct terminal *t;
 
-  if (read_socket_hook)
+  /* Loop through the available terminals, and call their input hooks. */
+  t = terminal_list;
+  while (t)
     {
-      int nr;
-      struct input_event hold_quit;
+      struct terminal *next = t->next_terminal;
 
-      EVENT_INIT (hold_quit);
-      hold_quit.kind = NO_EVENT;
+      if (t->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 = (*t->read_socket_hook) (t, 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 terminal device terminated; it should be closed. */
+              
+              /* Kill Emacs if this was our last terminal. */
+              if (!terminal_list->next_terminal)
+                /* 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_terminal safe here?  It calls Fdelete_frame. */
+              if (t->delete_terminal_hook)
+                (*t->delete_terminal_hook) (t);
+              else
+                delete_terminal (t);
+            }
+
+          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);
+      t = 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 terminal' object,
+   and so this function is called once for each individual termcap
+   terminal.  The first parameter indicates which terminal to read from.  */
+
+int
+tty_read_avail_input (struct terminal *terminal,
+                      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 = terminal->display_info.tty;
+  int nread = 0;
+
+  if (terminal->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 terminal. */
+      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 terminal. */
 #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 terminal. */
+#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;
@@ -8575,12 +8738,7 @@ 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;
-  /* 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;
-
+  
   if (INTERACTIVE)
     {
       if (!NILP (prompt))
@@ -8620,6 +8778,14 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
      keybuf[0..mock_input] holds the sequence we should reread.  */
  replay_sequence:
 
+  /* We may switch keyboards between rescans, so we need to
+     reinitialize fkey and keytran before each replay.  */
+  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;
+
   starting_buffer = current_buffer;
   first_unbound = bufsize + 1;
 
@@ -9909,8 +10075,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;
@@ -10154,6 +10324,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);
 
@@ -10162,11 +10335,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)
@@ -10178,7 +10351,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);
 
@@ -10238,10 +10411,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 ();
@@ -10250,48 +10423,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.
+/* The SIGINT handler.
 
-   If interrupt_input, this is the handler for SIGINT.  Otherwise, it
-   is called from kbd_buffer_store_event, in handling SIGIO or
-   SIGTINT.
-
-   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 terminal *terminal;
 
 #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 terminal on our controlling tty. */
+  terminal = get_named_tty (NULL);
+  if (!terminal)
+    {
+      /* 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 = terminal->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
@@ -10299,7 +10506,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 */
 /*
@@ -10378,7 +10585,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
@@ -10406,9 +10613,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.  */
@@ -10441,75 +10646,204 @@ quit_throw_to_read_char ()
   _longjmp (getcjmp, 1);
 }
 \f
-DEFUN ("set-input-mode", Fset_input_mode, Sset_input_mode, 3, 4, 0,
-       doc: /* Set mode of reading keyboard input.
-First arg INTERRUPT non-nil means use input interrupts;
- nil means use CBREAK mode.
-Second arg FLOW non-nil means use ^S/^Q flow control for output to terminal
- (no effect except in CBREAK mode).
-Third arg META t means accept 8-bit input (for a Meta key).
- META nil means ignore the top bit, on the assumption it is parity.
- Otherwise, accept 8-bit input and don't use the top bit for Meta.
-Optional fourth arg QUIT if non-nil specifies character to use for quitting.
+DEFUN ("set-input-interrupt-mode", Fset_input_interrupt_mode, Sset_input_interrupt_mode, 1, 1, 0,
+       doc: /* Set interrupt mode of reading keyboard input.
+If INTERRUPT is non-nil, Emacs will use input interrupts;
+otherwise Emacs uses CBREAK mode.
+
 See also `current-input-mode'.  */)
-     (interrupt, flow, meta, quit)
-     Lisp_Object interrupt, flow, meta, quit;
+     (interrupt)
+     Lisp_Object interrupt;
 {
-  if (!NILP (quit)
-      && (!INTEGERP (quit) || XINT (quit) < 0 || XINT (quit) > 0400))
-    error ("set-input-mode: QUIT must be an ASCII character");
-
-#ifdef POLL_FOR_INPUT
-  stop_polling ();
-#endif
-
-#ifndef DOS_NT
-  /* this causes startup screen to be restored and messes with the mouse */
-  reset_sys_modes ();
-#endif
-
+  int new_interrupt_input;
 #ifdef SIGIO
 /* Note SIGIO has been undef'd if FIONREAD is missing.  */
-  if (read_socket_hook)
+  if (0
+#ifdef HAVE_X_WINDOWS
+      || x_display_list != NULL
+#endif
+      )
     {
       /* When using X, don't give the user a real choice,
         because we haven't implemented the mechanisms to support it.  */
 #ifdef NO_SOCK_SIGIO
-      interrupt_input = 0;
+      new_interrupt_input = 0;
 #else /* not NO_SOCK_SIGIO */
-      interrupt_input = 1;
+      new_interrupt_input = 1;
 #endif /* NO_SOCK_SIGIO */
     }
   else
-    interrupt_input = !NILP (interrupt);
+    new_interrupt_input = !NILP (interrupt);
 #else /* not SIGIO */
-  interrupt_input = 0;
+  new_interrupt_input = 0;
 #endif /* not SIGIO */
 
 /* Our VMS input only works by interrupts, as of now.  */
 #ifdef VMS
-  interrupt_input = 1;
+  new_interrupt_input = 1;
 #endif
 
-  flow_control = !NILP (flow);
+  if (new_interrupt_input != interrupt_input) 
+    {
+#ifdef POLL_FOR_INPUT
+      stop_polling ();
+#endif
+#ifndef DOS_NT
+      /* this causes startup screen to be restored and messes with the mouse */
+      reset_all_sys_modes ();
+#endif
+      interrupt_input = new_interrupt_input;
+#ifndef DOS_NT
+      init_all_sys_modes ();
+#endif
+
+#ifdef POLL_FOR_INPUT
+      poll_suppress_count = 1;
+      start_polling ();
+#endif
+    }
+  return Qnil;
+}
+  
+DEFUN ("set-output-flow-control", Fset_output_flow_control, Sset_output_flow_control, 1, 2, 0,
+       doc: /* Enable or disable ^S/^Q flow control for output to TERMINAL.
+If FLOW is non-nil, flow control is enabled and you cannot use C-s or
+C-q in key sequences.
+
+This setting only has an effect on tty terminals and only when
+Emacs reads input in CBREAK mode; see `set-input-interrupt-mode'.
+
+See also `current-input-mode'.  */)
+       (flow, terminal)
+       Lisp_Object flow, terminal;
+{
+  struct terminal *t = get_terminal (terminal, 1);
+  struct tty_display_info *tty;
+  if (t == NULL || t->type != output_termcap)
+    return Qnil;
+  tty = t->display_info.tty;
+
+  if (tty->flow_control != !NILP (flow))
+    {
+#ifndef DOS_NT
+      /* this causes startup screen to be restored and messes with the mouse */
+      reset_sys_modes (tty);
+#endif
+
+      tty->flow_control = !NILP (flow);
+
+#ifndef DOS_NT
+      init_sys_modes (tty);
+#endif
+    }
+  return Qnil;
+}
+
+DEFUN ("set-input-meta-mode", Fset_input_meta_mode, Sset_input_meta_mode, 1, 2, 0,
+       doc: /* Enable or disable 8-bit input on TERMINAL.
+If META is t, Emacs will accept 8-bit input, and interpret the 8th
+bit as the Meta modifier.
+
+If META is nil, Emacs will ignore the top bit, on the assumption it is
+parity.
+
+Otherwise, Emacs will accept and pass through 8-bit input without
+specially interpreting the top bit.
+
+This setting only has an effect on tty terminal devices.
+
+Optional parameter TERMINAL specifies the tty terminal device to use.
+It may be a terminal id, a frame, or nil for the terminal used by the
+currently selected frame.
+
+See also `current-input-mode'.  */)
+       (meta, terminal)
+       Lisp_Object meta, terminal;
+{
+  struct terminal *t = get_terminal (terminal, 1);
+  struct tty_display_info *tty;
+  int new_meta;
+  
+  if (t == NULL || t->type != output_termcap)
+    return Qnil;
+  tty = t->display_info.tty;
+
   if (NILP (meta))
-    meta_key = 0;
+    new_meta = 0;
   else if (EQ (meta, Qt))
-    meta_key = 1;
+    new_meta = 1;
   else
-    meta_key = 2;
-  if (!NILP (quit))
-    /* Don't let this value be out of range.  */
-    quit_char = XINT (quit) & (meta_key ? 0377 : 0177);
+    new_meta = 2;
 
+  if (tty->meta_key != new_meta) 
+    {
 #ifndef DOS_NT
-  init_sys_modes ();
+      /* this causes startup screen to be restored and messes with the mouse */
+      reset_sys_modes (tty);
 #endif
 
-#ifdef POLL_FOR_INPUT
-  poll_suppress_count = 1;
-  start_polling ();
+      tty->meta_key = new_meta;
+  
+#ifndef DOS_NT
+      init_sys_modes (tty);
+#endif
+    }
+  return Qnil;
+}
+
+DEFUN ("set-quit-char", Fset_quit_char, Sset_quit_char, 1, 1, 0,
+       doc: /* Specify character used for quitting.
+QUIT must be an ASCII character.
+
+This function only has an effect on the terminal on the controlling
+tty of the Emacs process.
+
+See also `current-input-mode'.  */)
+       (quit)
+       Lisp_Object quit;
+{
+  struct terminal *t = get_named_tty (NULL);
+  struct tty_display_info *tty;
+  if (t == NULL || t->type != output_termcap)
+    return Qnil;
+  tty = t->display_info.tty;
+
+#ifndef DOS_NT
+  /* this causes startup screen to be restored and messes with the mouse */
+  reset_sys_modes (tty);
+#endif
+  
+  if (NILP (quit) || !INTEGERP (quit) || XINT (quit) < 0 || XINT (quit) > 0400)
+    error ("QUIT must be an ASCII character");
+
+  /* Don't let this value be out of range.  */
+  quit_char = XINT (quit) & (tty->meta_key == 0 ? 0177 : 0377);
+
+#ifndef DOS_NT
+  init_sys_modes (tty);
 #endif
+
+  return Qnil;
+}
+       
+DEFUN ("set-input-mode", Fset_input_mode, Sset_input_mode, 3, 4, 0,
+       doc: /* Set mode of reading keyboard input.
+First arg INTERRUPT non-nil means use input interrupts;
+ nil means use CBREAK mode.
+Second arg FLOW non-nil means use ^S/^Q flow control for output to terminal
+ (no effect except in CBREAK mode).
+Third arg META t means accept 8-bit input (for a Meta key).
+ META nil means ignore the top bit, on the assumption it is parity.
+ Otherwise, accept 8-bit input and don't use the top bit for Meta.
+Optional fourth arg QUIT if non-nil specifies character to use for quitting.
+See also `current-input-mode'.  */)
+     (interrupt, flow, meta, quit)
+     Lisp_Object interrupt, flow, meta, quit;
+{
+  Fset_input_interrupt_mode (interrupt);
+  Fset_output_flow_control (flow, Qnil);
+  Fset_input_meta_mode (meta, Qnil);
+  Fset_quit_char (quit);
   return Qnil;
 }
 
@@ -10530,10 +10864,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);
@@ -10566,11 +10911,11 @@ The `posn-' functions access elements of such lists.  */)
       CHECK_LIVE_WINDOW (frame_or_window);
 
       w = XWINDOW (frame_or_window);
-      XSETINT (x, (WINDOW_TO_FRAME_PIXEL_X (w, XINT (x))
+      XSETINT (x, (XINT (x)
+                  + WINDOW_LEFT_EDGE_X (w)
                   + (NILP (whole)
                      ? window_box_left_offset (w, TEXT_AREA)
-                     : - (WINDOW_LEFT_SCROLL_BAR_COLS (w)
-                          * WINDOW_FRAME_COLUMN_WIDTH (w)))));
+                     : 0)));
       XSETINT (y, WINDOW_TO_FRAME_PIXEL_Y (w, XINT (y)));
       frame_or_window = w->frame;
     }
@@ -10596,9 +10941,21 @@ The `posn-' functions access elements of such lists.  */)
 {
   Lisp_Object tem;
 
+  if (NILP (window))
+    window = selected_window;
+
   tem = Fpos_visible_in_window_p (pos, window, Qt);
   if (!NILP (tem))
-    tem = Fposn_at_x_y (XCAR (tem), XCAR (XCDR (tem)), window, Qnil);
+    {
+      Lisp_Object x = XCAR (tem);
+      Lisp_Object y = XCAR (XCDR (tem));
+
+      /* Point invisible due to hscrolling?  */
+      if (XINT (x) < 0)
+       return Qnil;
+      tem = Fposn_at_x_y (x, y, window, Qnil);
+    }
+
   return tem;
 }
 
@@ -10613,6 +10970,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;
@@ -10627,6 +10985,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;
 }
 
@@ -10663,7 +11025,7 @@ delete_kboard (kb)
       && FRAMEP (selected_frame)
       && FRAME_LIVE_P (XFRAME (selected_frame)))
     {
-      current_kboard = XFRAME (selected_frame)->kboard;
+      current_kboard = XFRAME (selected_frame)->terminal->kboard;
       if (current_kboard == kb)
        abort ();
     }
@@ -10704,8 +11066,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
@@ -10743,11 +11111,6 @@ init_keyboard ()
   poll_suppress_count = 1;
   start_polling ();
 #endif
-
-#ifdef MAC_OSX
-  /* At least provide an escape route since C-g doesn't work.  */
-  signal (SIGINT, interrupt_signal);
-#endif
 }
 
 /* This type's only use is in syms_of_keyboard, to initialize the
@@ -10844,6 +11207,11 @@ syms_of_keyboard ()
   Qsave_session = intern ("save-session");
   staticpro (&Qsave_session);
 
+#ifdef MAC_OS
+  Qmac_apple_event = intern ("mac-apple-event");
+  staticpro (&Qmac_apple_event);
+#endif
+
   Qusr1_signal = intern ("usr1-signal");
   staticpro (&Qusr1_signal);
   Qusr2_signal = intern ("usr2-signal");
@@ -10934,6 +11302,7 @@ syms_of_keyboard ()
   Fset (Qinput_method_use_echo_area, Qnil);
 
   last_point_position_buffer = Qnil;
+  last_point_position_window = Qnil;
 
   {
     struct event_head *p;
@@ -11027,6 +11396,10 @@ syms_of_keyboard ()
   defsubr (&Stop_level);
   defsubr (&Sdiscard_input);
   defsubr (&Sopen_dribble_file);
+  defsubr (&Sset_input_interrupt_mode);
+  defsubr (&Sset_output_flow_control);
+  defsubr (&Sset_input_meta_mode);
+  defsubr (&Sset_quit_char);
   defsubr (&Sset_input_mode);
   defsubr (&Scurrent_input_mode);
   defsubr (&Sexecute_extended_command);
@@ -11088,7 +11461,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 terminal 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.  */);
@@ -11200,8 +11576,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.
@@ -11211,8 +11587,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'.
+
+This variable 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.
@@ -11297,7 +11675,11 @@ 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
+terminal device.
+See Info node `(elisp)Multiple displays'.  */);
 
   DEFVAR_LISP ("overriding-local-map", &Voverriding_local_map,
               doc: /* Keymap that overrides all other local keymaps.
@@ -11322,7 +11704,61 @@ 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 terminal device.
+See Info node `(elisp)Multiple displays'.  */);
+
+  DEFVAR_KBOARD ("local-function-key-map", Vlocal_function_key_map,
+                 doc: /* Keymap that translates key sequences to key sequences during input.
+This is used mainly for mapping ASCII function key sequences into
+real Emacs function key events (symbols).
+
+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.
+
+If the binding is a function, it is called with one argument (the prompt)
+and its return value (a key sequence) is used.
+
+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 terminal
+device.  See Info node `(elisp)Multiple displays'.  If you need to
+define a binding on all terminals, change `function-key-map'
+instead.  Initially, `local-function-key-map' is an empty keymap that
+has `function-key-map' as its parent on all terminal devices.  */);
+
+  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 terminal 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 terminal device.
+(See Info node `(elisp)Multiple displays'.)  If you need to set a key
+translation on all terminals, change `global-key-translation-map' instead.  */);
+
+  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 terminal 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.
@@ -11474,6 +11910,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);
@@ -11481,6 +11918,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);
     }