Bugfix festival.
[bpt/emacs.git] / src / keyboard.c
index ad25732..217cc29 100644 (file)
@@ -22,9 +22,10 @@ Boston, MA 02111-1307, USA.  */
 #include <config.h>
 #include <signal.h>
 #include <stdio.h>
+#include "lisp.h"
+#include "systty.h" /* This must be included befor termchar.h. */
 #include "termchar.h"
 #include "termopts.h"
-#include "lisp.h"
 #include "termhooks.h"
 #include "macros.h"
 #include "keyboard.h"
@@ -55,7 +56,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 +89,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 +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;
-
 /* Non-zero means force key bindings update in parse_menu_item.  */
 
 int update_menu_bindings;
@@ -586,6 +578,8 @@ Lisp_Object Qvertical_line;
 Lisp_Object Qvertical_scroll_bar;
 Lisp_Object Qmenu_bar;
 extern Lisp_Object Qleft_margin, Qright_margin;
+extern Lisp_Object Qleft_fringe, Qright_fringe;
+extern Lisp_Object QCmap;
 
 Lisp_Object recursive_edit_unwind (), command_loop ();
 Lisp_Object Fthis_command_keys ();
@@ -4955,6 +4949,163 @@ EMACS_INT double_click_fuzz;
 
 int double_click_count;
 
+/* Return position of a mouse click or wheel event */
+
+static Lisp_Object
+make_lispy_position (f, x, y, time)
+     struct frame *f;
+     Lisp_Object *x, *y;
+     unsigned long time;
+{
+  Lisp_Object window;
+  enum window_part part;
+  Lisp_Object posn = Qnil;
+  Lisp_Object extra_info = Qnil;
+  int wx, wy;
+
+  /* Set `window' to the window under frame pixel coordinates (x,y)  */
+  if (f)
+    window = window_from_coordinates (f, XINT (*x), XINT (*y),
+                                     &part, &wx, &wy, 0);
+  else
+    window = Qnil;
+
+  if (WINDOWP (window))
+    {
+      /* It's a click in window window at frame coordinates (x,y)  */
+      struct window *w = XWINDOW (window);
+      Lisp_Object object = Qnil;
+      int textpos = -1, rx = -1, ry = -1;
+      int dx = -1, dy = -1;
+
+      /* Set event coordinates to window-relative coordinates
+        for constructing the Lisp event below.  */
+      XSETINT (*x, wx);
+      XSETINT (*y, wy);
+
+      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.  */
+         Lisp_Object string;
+         int charpos;
+
+         posn = part == ON_MODE_LINE ? Qmode_line : Qheader_line;
+         rx = wx, ry = wy;
+         string = mode_line_string (w, &rx, &ry, &dx, &dy, part, &charpos);
+         if (STRINGP (string))
+           object = Fcons (string, make_number (charpos));
+         if (w == XWINDOW (selected_window))
+           textpos = PT;
+         else
+           textpos = XMARKER (w->pointm)->charpos;
+       }
+      else if (part == ON_VERTICAL_BORDER)
+       {
+         posn = Qvertical_line;
+         wx = -1;
+         dx = 0;
+       }
+      else if (part == ON_LEFT_MARGIN || part == ON_RIGHT_MARGIN)
+       {
+         Lisp_Object string;
+         int charpos;
+         
+         posn = (part == ON_LEFT_MARGIN) ? Qleft_margin : Qright_margin;
+         rx = wx, ry = wy;
+         string = marginal_area_string (w, &rx, &ry, &dx, &dy, part, &charpos);
+         if (STRINGP (string))
+           object = Fcons (string, make_number (charpos));
+#ifdef HAVE_WINDOW_SYSTEM
+         else if (IMAGEP (string))
+           {
+             Lisp_Object image_map, hotspot;
+             object = string;
+             if ((image_map = Fplist_get (XCDR (object), QCmap),
+                  !NILP (image_map))
+                 && (hotspot = find_hot_spot (image_map, dx, dy),
+                     CONSP (hotspot))
+                 && (hotspot = XCDR (hotspot), CONSP (hotspot)))
+               posn = XCAR (hotspot);
+           }
+#endif
+       }
+      else if (part == ON_LEFT_FRINGE || part == ON_RIGHT_FRINGE)
+       {
+         posn = (part == ON_LEFT_FRINGE) ? Qleft_fringe : 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);
+       }
+
+      if (textpos < 0)
+       {
+         Lisp_Object string;
+         struct display_pos p;
+         int dx2, dy2;
+         wx = max (WINDOW_LEFT_MARGIN_WIDTH (w), wx);
+         buffer_posn_from_coords (w, &wx, &wy, &dx2, &dy2, &string, &p);
+         textpos = CHARPOS (p.pos);
+         if (rx < 0) rx = wx;
+         if (ry < 0) ry = wy;
+         if (dx < 0) dx = dx2;
+         if (dy < 0) dy = dy2;
+
+         if (NILP (posn))
+           {
+             posn = make_number (textpos);
+             if (STRINGP (string))
+               object = Fcons (string,
+                               make_number (CHARPOS (p.string_pos)));
+#ifdef HAVE_WINDOW_SYSTEM
+             else if (IMAGEP (string))
+               {
+                 Lisp_Object image_map, hotspot;
+                 object = string;
+                 if ((image_map = Fplist_get (XCDR (object), QCmap),
+                      !NILP (image_map))
+                     && (hotspot = find_hot_spot (image_map, dx, dy),
+                         CONSP (hotspot))
+                     && (hotspot = XCDR (hotspot), CONSP (hotspot)))
+                   posn = XCAR (hotspot);
+               }
+#endif
+           }
+       }
+
+      extra_info = Fcons (object,
+                         Fcons (make_number (textpos),
+                                Fcons (Fcons (make_number (rx),
+                                              make_number (ry)),
+                                       Fcons (Fcons (make_number (dx),
+                                                     make_number (dy)),
+                                              Qnil))));
+    }
+  else if (f != 0)
+    {
+      XSETFRAME (window, f);
+    }
+  else
+    {
+      window = Qnil;
+      XSETFASTINT (*x, 0);
+      XSETFASTINT (*y, 0);
+    }
+
+  return Fcons (window,
+               Fcons (posn,
+                      Fcons (Fcons (*x, *y),
+                             Fcons (make_number (time),
+                                    extra_info))));
+}
+
 /* Given a struct input_event, build the lisp event which represents
    it.  If EVENT is 0, build a mouse movement event from the mouse
    movement buffer, which should have a movement event in it.
@@ -5089,25 +5240,23 @@ make_lispy_event (event)
        Lisp_Object position;
        Lisp_Object *start_pos_ptr;
        Lisp_Object start_pos;
-       Lisp_Object window;
 
        position = Qnil;
 
        /* Build the position as appropriate for this mouse click.  */
        if (event->kind == MOUSE_CLICK_EVENT)
          {
-           enum window_part part;
            struct frame *f = XFRAME (event->frame_or_window);
-           Lisp_Object posn;
-           Lisp_Object string_info = Qnil;
+#if ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK)
            int row, column;
-           int wx, wy;
+#endif
 
            /* Ignore mouse events that were made on frame that
               have been deleted.  */
            if (! FRAME_LIVE_P (f))
              return Qnil;
 
+#if ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK)
            /* EVENT->x and EVENT->y are frame-relative pixel
               coordinates at this place.  Under old redisplay, COLUMN
               and ROW are set to frame relative glyph coordinates
@@ -5116,7 +5265,6 @@ make_lispy_event (event)
            pixel_to_glyph_coords (f, XINT (event->x), XINT (event->y),
                                   &column, &row, NULL, 1);
 
-#if ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK)
            /* In the non-toolkit version, clicks on the menu bar
               are ordinary button events in the event buffer.
               Distinguish them, and invoke the menu.
@@ -5170,77 +5318,14 @@ make_lispy_event (event)
              }
 #endif /* not USE_X_TOOLKIT && not USE_GTK */
 
-           /* Set `window' to the window under frame pixel coordinates
-              event->x/event->y.  */
-           window = window_from_coordinates (f, XINT (event->x),
-                                             XINT (event->y),
-                                             &part, &wx, &wy, 0);
-
-           if (!WINDOWP (window))
-             {
-               window = event->frame_or_window;
-               posn = Qnil;
-             }
-           else
-             {
-               /* It's a click in window window at frame coordinates
-                  event->x/ event->y.  */
-               struct window *w = XWINDOW (window);
-
-               /* Set event coordinates to window-relative coordinates
-                  for constructing the Lisp event below.  */
-               XSETINT (event->x, wx);
-               XSETINT (event->y, wy);
-
-               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.  */
-                   Lisp_Object string;
-                   int charpos;
-
-                   posn = part == ON_MODE_LINE ? Qmode_line : Qheader_line;
-                   string = mode_line_string (w, wx, wy, part, &charpos);
-                   if (STRINGP (string))
-                     string_info = Fcons (string, make_number (charpos));
-                 }
-               else if (part == ON_VERTICAL_BORDER)
-                 posn = Qvertical_line;
-               else if (part == ON_LEFT_MARGIN || part == ON_RIGHT_MARGIN)
-                 {
-                   int charpos;
-                   Lisp_Object object = marginal_area_string (w, wx, wy, part,
-                                                              &charpos);
-                   posn = (part == ON_LEFT_MARGIN) ? Qleft_margin : Qright_margin;
-                   if (STRINGP (object))
-                     string_info = Fcons (object, make_number (charpos));
-                 }
-               else
-                 {
-                   Lisp_Object object;
-                   struct display_pos p;
-                   buffer_posn_from_coords (w, &wx, &wy, &object, &p);
-                   posn = make_number (CHARPOS (p.pos));
-                   if (STRINGP (object))
-                     string_info
-                       = Fcons (object,
-                                make_number (CHARPOS (p.string_pos)));
-                 }
-             }
-
-           position
-             = Fcons (window,
-                      Fcons (posn,
-                             Fcons (Fcons (event->x, event->y),
-                                    Fcons (make_number (event->timestamp),
-                                           (NILP (string_info)
-                                            ? Qnil
-                                            : Fcons (string_info, Qnil))))));
+           position = make_lispy_position (f, &event->x, &event->y,
+                                           event->timestamp);
          }
 #ifndef USE_TOOLKIT_SCROLL_BARS
        else
          {
            /* It's a scrollbar click.  */
+           Lisp_Object window;
            Lisp_Object portion_whole;
            Lisp_Object part;
 
@@ -5405,97 +5490,18 @@ make_lispy_event (event)
     case WHEEL_EVENT:
       {
        Lisp_Object position;
-       Lisp_Object window;
        Lisp_Object head;
        
        /* Build the position as appropriate for this mouse click.  */
-       enum window_part part;
        struct frame *f = XFRAME (event->frame_or_window);
-       Lisp_Object posn;
-       Lisp_Object string_info = Qnil;
-       int row, column;
-       int wx, wy;
-       position = Qnil;
 
        /* Ignore wheel events that were made on frame that have been
           deleted.  */
        if (! FRAME_LIVE_P (f))
          return Qnil;
 
-       /* EVENT->x and EVENT->y are frame-relative pixel
-          coordinates at this place.  Under old redisplay, COLUMN
-          and ROW are set to frame relative glyph coordinates
-          which are then used to determine whether this click is
-          in a menu (non-toolkit version).  */
-       pixel_to_glyph_coords (f, XINT (event->x), XINT (event->y),
-                              &column, &row, NULL, 1);
-
-       /* Set `window' to the window under frame pixel coordinates
-          event->x/event->y.  */
-       window = window_from_coordinates (f, XINT (event->x),
-                                         XINT (event->y),
-                                         &part, &wx, &wy, 0);
-
-       if (!WINDOWP (window))
-         {
-           window = event->frame_or_window;
-           posn = Qnil;
-         }
-       else
-         {
-           /* It's a click in window window at frame coordinates
-              event->x/ event->y.  */
-           struct window *w = XWINDOW (window);
-       
-           /* Set event coordinates to window-relative coordinates
-              for constructing the Lisp event below.  */
-           XSETINT (event->x, wx);
-           XSETINT (event->y, wy);
-       
-           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.  */
-               Lisp_Object string;
-               int charpos;
-
-               posn = part == ON_MODE_LINE ? Qmode_line : Qheader_line;
-               string = mode_line_string (w, wx, wy, part, &charpos);
-               if (STRINGP (string))
-                 string_info = Fcons (string, make_number (charpos));
-             }
-           else if (part == ON_VERTICAL_BORDER)
-             posn = Qvertical_line;
-           else if (part == ON_LEFT_MARGIN || part == ON_RIGHT_MARGIN)
-             {
-               int charpos;
-               Lisp_Object object = marginal_area_string (w, wx, wy, part,
-                                                          &charpos);
-               posn = (part == ON_LEFT_MARGIN) ? Qleft_margin : Qright_margin;
-               if (STRINGP (object))
-                 string_info = Fcons (object, make_number (charpos));
-             }
-           else
-             {
-               Lisp_Object object;
-               struct display_pos p;
-               buffer_posn_from_coords (w, &wx, &wy, &object, &p);
-               posn = make_number (CHARPOS (p.pos));
-               if (STRINGP (object))
-                 string_info
-                   = Fcons (object,
-                            make_number (CHARPOS (p.string_pos)));
-             }
-         }
-       
-       position
-         = Fcons (window,
-                  Fcons (posn,
-                         Fcons (Fcons (event->x, event->y),
-                                Fcons (make_number (event->timestamp),
-                                       (NILP (string_info)
-                                        ? Qnil
-                                        : Fcons (string_info, Qnil))))));
+       position = make_lispy_position (f, &event->x, &event->y,
+                                       event->timestamp);
 
        /* Set double or triple modifiers to indicate the wheel speed.  */
        {
@@ -5689,12 +5695,9 @@ make_lispy_event (event)
 
     case DRAG_N_DROP_EVENT:
       {
-       enum window_part part;
        FRAME_PTR f;
-       Lisp_Object window;
-       Lisp_Object posn;
+       Lisp_Object head, position;
        Lisp_Object files;
-       int wx, wy;
 
        /* The frame_or_window field should be a cons of the frame in
           which the event occurred and a list of the filenames
@@ -5710,60 +5713,17 @@ make_lispy_event (event)
        if (! FRAME_LIVE_P (f))
          return Qnil;
 
-       window = window_from_coordinates (f, XINT (event->x),
-                                          XINT (event->y),
-                                         &part, &wx, &wy, 0);
-
-       if (!WINDOWP (window))
-         {
-           window = XCAR (event->frame_or_window);
-           posn = Qnil;
-         }
-       else
-         {
-           /* It's an event in window `window' at frame coordinates
-              event->x/ event->y.  */
-           struct window *w = XWINDOW (window);
-
-           /* Set event coordinates to window-relative coordinates
-              for constructing the Lisp event below.  */
-           XSETINT (event->x, wx);
-           XSETINT (event->y, wy);
-
-           if (part == ON_MODE_LINE)
-             posn = Qmode_line;
-           else if (part == ON_VERTICAL_BORDER)
-             posn = Qvertical_line;
-           else if (part == ON_HEADER_LINE)
-             posn = Qheader_line;
-           else
-             {
-               Lisp_Object object;
-               struct display_pos p;
-               buffer_posn_from_coords (w, &wx, &wy, &object, &p);
-               posn = make_number (CHARPOS (p.pos));
-             }
-         }
-
-       {
-         Lisp_Object head, position;
-
-         position
-           = Fcons (window,
-                    Fcons (posn,
-                           Fcons (Fcons (event->x, event->y),
-                                  Fcons (make_number (event->timestamp),
-                                         Qnil))));
-
-         head = modify_event_symbol (0, event->modifiers,
-                                     Qdrag_n_drop, Qnil,
-                                     lispy_drag_n_drop_names,
-                                     &drag_n_drop_syms, 1);
-         return Fcons (head,
-                       Fcons (position,
-                              Fcons (files,
-                                     Qnil)));
-       }
+       position = make_lispy_position (f, &event->x, &event->y,
+                                       event->timestamp);
+
+       head = modify_event_symbol (0, event->modifiers,
+                                   Qdrag_n_drop, Qnil,
+                                   lispy_drag_n_drop_names,
+                                   &drag_n_drop_syms, 1);
+       return Fcons (head,
+                     Fcons (position,
+                            Fcons (files,
+                                   Qnil)));
       }
 #endif /* HAVE_MOUSE */
 
@@ -5836,59 +5796,12 @@ make_lispy_movement (frame, bar_window, part, x, y, time)
   /* Or is it an ordinary mouse movement?  */
   else
     {
-      enum window_part area;
-      Lisp_Object window;
-      Lisp_Object posn;
-      int wx, wy;
-
-      if (frame)
-       /* It's in a frame; which window on that frame?  */
-       window = window_from_coordinates (frame, XINT (x), XINT (y),
-                                         &area, &wx, &wy, 0);
-      else
-       window = Qnil;
+      Lisp_Object position;
 
-      if (WINDOWP (window))
-       {
-         struct window *w = XWINDOW (window);
-
-         /* Set window relative coordinates.  */
-         XSETINT (x, wx);
-         XSETINT (y, wy);
-
-         if (area == ON_MODE_LINE)
-           posn = Qmode_line;
-         else if (area == ON_VERTICAL_BORDER)
-           posn = Qvertical_line;
-         else if (area == ON_HEADER_LINE)
-           posn = Qheader_line;
-         else
-           {
-             Lisp_Object object;
-             struct display_pos p;
-             buffer_posn_from_coords (w, &wx, &wy, &object, &p);
-             posn = make_number (CHARPOS (p.pos));
-           }
-       }
-      else if (frame != 0)
-       {
-         XSETFRAME (window, frame);
-         posn = Qnil;
-       }
-      else
-       {
-         window = Qnil;
-         posn = Qnil;
-         XSETFASTINT (x, 0);
-         XSETFASTINT (y, 0);
-       }
+      position = make_lispy_position (frame, &x, &y, time);
 
       return Fcons (Qmouse_movement,
-                   Fcons (Fcons (window,
-                                 Fcons (posn,
-                                        Fcons (Fcons (x, y),
-                                               Fcons (make_number (time),
-                                                      Qnil)))),
+                   Fcons (position,
                           Qnil));
     }
 }
@@ -6126,7 +6039,7 @@ parse_modifiers (symbol)
                                         SBYTES (SYMBOL_NAME (symbol)) - end),
                            Qnil);
 
-      if (modifiers & ~VALMASK)
+      if (modifiers & ~INTMASK)
        abort ();
       XSETFASTINT (mask, modifiers);
       elements = Fcons (unmodified, Fcons (mask, Qnil));
@@ -6163,7 +6076,7 @@ apply_modifiers (modifiers, base)
   Lisp_Object cache, index, entry, new_symbol;
 
   /* Mask out upper bits.  We don't know where this value's been.  */
-  modifiers &= VALMASK;
+  modifiers &= INTMASK;
 
   /* The click modifier never figures into cache indices.  */
   cache = Fget (base, Qmodifier_cache);
@@ -6566,7 +6479,7 @@ get_filtered_input_pending (addr, do_timers_now, filter_events)
   /* If input is being read as it arrives, and we have none, there is none.  */
   if (*addr > 0 || (interrupt_input && ! interrupts_deferred))
     return;
-
+  
   /* Try to read some input and see how much we get.  */
   gobble_input (0);
   *addr = (!NILP (Vquit_flag)
@@ -6685,13 +6598,13 @@ read_avail_input (expected)
   struct input_event buf[KBD_BUFFER_SIZE];
   register int i;
   int nread;
-
+  
   for (i = 0; i < KBD_BUFFER_SIZE; i++)
     EVENT_INIT (buf[i]);
 
   if (read_socket_hook)
     /* No need for FIONREAD or fcntl; just say don't wait.  */
-    nread = (*read_socket_hook) (input_fd, buf, KBD_BUFFER_SIZE, expected);
+    nread = (*read_socket_hook) (buf, KBD_BUFFER_SIZE, expected);
   else
     {
       /* Using KBD_BUFFER_SIZE - 1 here avoids reading more than
@@ -6699,8 +6612,9 @@ read_avail_input (expected)
         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.  */
+      struct tty_output *tty;
+      Lisp_Object frame;
+      
 #ifdef WINDOWSNT
       return 0;
 #else /* not WINDOWSNT */
@@ -6708,94 +6622,140 @@ read_avail_input (expected)
       n_to_read = dos_keysns ();
       if (n_to_read == 0)
        return 0;
+
+      cbuf[0] = dos_keyread ();
+      nread = 1;
+
 #else /* not MSDOS */
+
+      nread = 0;
+
+      /* Try to read from each available tty, until one succeeds. */
+      for (tty = tty_list; tty; tty = tty->next) {
+
+        if (! tty->term_initted)
+          continue;
+        
+        /* 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.  */
-       kill (getpid (), SIGHUP);
-      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 (tty)), 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.  */
+            /* It appears to be the case, see narrow_foreground_group. */
+            if (! noninteractive)
+              {
+                if (! tty_list->next)
+                  kill (getpid (), SIGHUP); /* This was the last terminal. */
+                else
+                  n_to_read = 0; /* XXX tty should be closed here. */
+              }
+            else
+              {
+                n_to_read = 0;
+              }
+          }
+        if (n_to_read == 0)
+          continue;
+        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 (tty)), 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 (tty)), 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)
+              {
+                if (! tty_list->next)
+                  kill (0, SIGHUP); /* This was the last terminal. */
+                else
+                  ;             /* XXX tty should be closed here. */
+              }
 #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);
+            /* 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)
+              {
+                if (! tty_list->next)
+                  kill (0, SIGHUP); /* This was the last terminal. */
+                else
+                  ;             /* XXX tty should be closed here. */
+              }
 #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?  */
+          }
+        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 (tty)), F_SETFL, 0);
 #endif /* USG or DGUX or CYGWIN */
 #endif /* no FIONREAD */
+
+        if (nread > 0)
+          break;
+      } /* for each tty */
+      
+      if (nread <= 0)
+        return 0;
+      
+#endif /* not MSDOS */
+#endif /* not WINDOWSNT */
+
+      /* Select frame corresponding to the active tty.  Note that the
+         value of selected_frame is not reliable here, redisplay tends
+         to temporarily change it.  But tty should always be non-NULL. */
+      frame = (tty ? tty->top_frame : selected_frame);
+
       for (i = 0; i < nread; i++)
        {
          buf[i].kind = ASCII_KEYSTROKE_EVENT;
          buf[i].modifiers = 0;
-         if (meta_key == 1 && (cbuf[i] & 0x80))
+         if (tty->meta_key == 1 && (cbuf[i] & 0x80))
            buf[i].modifiers = meta_modifier;
-         if (meta_key != 2)
+         if (tty->meta_key != 2)
            cbuf[i] &= ~0x80;
 
-         buf[i].code = cbuf[i];
-         buf[i].frame_or_window = selected_frame;
+          buf[i].code = cbuf[i];
+         buf[i].frame_or_window = frame;
          buf[i].arg = Qnil;
        }
     }
@@ -8928,6 +8888,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
       if (EVENT_HAS_PARAMETERS (key))
        {
          Lisp_Object kind;
+         Lisp_Object string;
 
          kind = EVENT_HEAD_KIND (EVENT_HEAD (key));
          if (EQ (kind, Qmouse_click))
@@ -9044,11 +9005,11 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
 
                  /* If on a mode line string with a local keymap,
                     reconsider the key sequence with that keymap.  */
-                 if (CONSP (POSN_STRING (EVENT_START (key))))
+                 if (string = POSN_STRING (EVENT_START (key)),
+                     (CONSP (string) && STRINGP (XCAR (string))))
                    {
-                     Lisp_Object string, pos, map, map2;
+                     Lisp_Object pos, map, map2;
 
-                     string = POSN_STRING (EVENT_START (key));
                      pos = XCDR (string);
                      string = XCAR (string);
                       if (XINT (pos) >= 0
@@ -9067,16 +9028,16 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
 
                  goto replay_key;
                }
-             else if (CONSP (POSN_STRING (EVENT_START (key)))
-                      && NILP (from_string))
+             else if (NILP (from_string)
+                      && (string = POSN_STRING (EVENT_START (key)),
+                          (CONSP (string) && STRINGP (XCAR (string)))))
                {
                  /* For a click on a string, i.e. overlay string or a
                     string displayed via the `display' property,
                     consider `local-map' and `keymap' properties of
                     that string.  */
-                 Lisp_Object string, pos, map, map2;
+                 Lisp_Object pos, map, map2;
 
-                 string = POSN_STRING (EVENT_START (key));
                  pos = XCDR (string);
                  string = XCAR (string);
                  if (XINT (pos) >= 0
@@ -9421,6 +9382,8 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
 
              keybuf[t - 1] = new_key;
              mock_input = max (t, mock_input);
+             fkey.start = fkey.end = KEYMAPP (fkey.map) ? 0 : bufsize + 1;
+             keytran.start = keytran.end = KEYMAPP (keytran.map) ? 0 : bufsize + 1;
 
              goto replay_sequence;
            }
@@ -10153,6 +10116,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);
 
@@ -10161,12 +10127,12 @@ 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 (CURTTY (), &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,
-                        Qnil);
+                        (Lisp_Object)CURTTY()); /* XXX */
   stuff_buffered_input (stuffstring);
   if (cannot_suspend)
     sys_subshell ();
@@ -10177,7 +10143,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 (CURTTY (), &width, &height);
   if (width != old_width || height != old_height)
     change_frame_size (SELECTED_FRAME (), height, width, 0, 0, 0);
 
@@ -10301,7 +10267,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 */
 /*
@@ -10380,7 +10346,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
@@ -10467,7 +10433,7 @@ See also `current-input-mode'.  */)
 
 #ifndef DOS_NT
   /* this causes startup screen to be restored and messes with the mouse */
-  reset_sys_modes ();
+  reset_sys_modes (CURTTY ());
 #endif
 
 #ifdef SIGIO
@@ -10495,17 +10461,17 @@ See also `current-input-mode'.  */)
 
   flow_control = !NILP (flow);
   if (NILP (meta))
-    meta_key = 0;
+    CURTTY ()->meta_key = 0;
   else if (EQ (meta, Qt))
-    meta_key = 1;
+    CURTTY ()->meta_key = 1;
   else
-    meta_key = 2;
+    CURTTY ()->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) & (CURTTY ()->meta_key ? 0377 : 0177);
 
 #ifndef DOS_NT
-  init_sys_modes ();
+  init_sys_modes (CURTTY ());
 #endif
 
 #ifdef POLL_FOR_INPUT
@@ -10535,7 +10501,9 @@ The elements of this list correspond to the arguments of
 
   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;
+  val[2] = FRAME_TTY (SELECTED_FRAME ())->meta_key == 2
+    ? make_number (0)
+    : FRAME_TTY (SELECTED_FRAME ())->meta_key == 1 ? Qt : Qnil;
   XSETFASTINT (val[3], quit_char);
 
   return Flist (sizeof (val) / sizeof (val[0]), val);
@@ -11392,19 +11360,19 @@ mark_kboards ()
     {
       if (kb->kbd_macro_buffer)
        for (p = kb->kbd_macro_buffer; p < kb->kbd_macro_ptr; p++)
-         mark_object (p);
-      mark_object (&kb->Voverriding_terminal_local_map);
-      mark_object (&kb->Vlast_command);
-      mark_object (&kb->Vreal_last_command);
-      mark_object (&kb->Vprefix_arg);
-      mark_object (&kb->Vlast_prefix_arg);
-      mark_object (&kb->kbd_queue);
-      mark_object (&kb->defining_kbd_macro);
-      mark_object (&kb->Vlast_kbd_macro);
-      mark_object (&kb->Vsystem_key_alist);
-      mark_object (&kb->system_key_syms);
-      mark_object (&kb->Vdefault_minibuffer_frame);
-      mark_object (&kb->echo_string);
+         mark_object (*p);
+      mark_object (kb->Voverriding_terminal_local_map);
+      mark_object (kb->Vlast_command);
+      mark_object (kb->Vreal_last_command);
+      mark_object (kb->Vprefix_arg);
+      mark_object (kb->Vlast_prefix_arg);
+      mark_object (kb->kbd_queue);
+      mark_object (kb->defining_kbd_macro);
+      mark_object (kb->Vlast_kbd_macro);
+      mark_object (kb->Vsystem_key_alist);
+      mark_object (kb->system_key_syms);
+      mark_object (kb->Vdefault_minibuffer_frame);
+      mark_object (kb->echo_string);
     }
   {
     struct input_event *event;
@@ -11412,10 +11380,13 @@ mark_kboards ()
       {
        if (event == kbd_buffer + KBD_BUFFER_SIZE)
          event = kbd_buffer;
-       mark_object (&event->x);
-       mark_object (&event->y);
-       mark_object (&event->frame_or_window);
-       mark_object (&event->arg);
+       mark_object (event->x);
+       mark_object (event->y);
+       mark_object (event->frame_or_window);
+       mark_object (event->arg);
       }
   }
 }
+
+/* arch-tag: 774e34d7-6d31-42f3-8397-e079a4e4c9ca
+   (do not change this comment) */