Merge from emacs-24; up to 2013-01-03T02:37:57Z!rgm@gnu.org
[bpt/emacs.git] / src / term.c
index 24add17..f86d71a 100644 (file)
@@ -51,6 +51,10 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 static int been_here = -1;
 #endif
 
 static int been_here = -1;
 #endif
 
+#ifdef USE_X_TOOLKIT
+#include "../lwlib/lwlib.h"
+#endif
+
 #include "cm.h"
 #ifdef HAVE_X_WINDOWS
 #include "xterm.h"
 #include "cm.h"
 #ifdef HAVE_X_WINDOWS
 #include "xterm.h"
@@ -216,6 +220,7 @@ tty_update_end (struct frame *f)
     tty_show_cursor (tty);
   tty_turn_off_insert (tty);
   tty_background_highlight (tty);
     tty_show_cursor (tty);
   tty_turn_off_insert (tty);
   tty_background_highlight (tty);
+  fflush (tty->output);
 }
 
 /* The implementation of set_terminal_window for termcap frames. */
 }
 
 /* The implementation of set_terminal_window for termcap frames. */
@@ -495,8 +500,12 @@ static ptrdiff_t encode_terminal_dst_size;
    Set CODING->produced to the byte-length of the resulting byte
    sequence, and return a pointer to that byte sequence.  */
 
    Set CODING->produced to the byte-length of the resulting byte
    sequence, and return a pointer to that byte sequence.  */
 
+#ifndef WINDOWSNT
+static
+#endif
 unsigned char *
 unsigned char *
-encode_terminal_code (struct glyph *src, int src_len, struct coding_system *coding)
+encode_terminal_code (struct glyph *src, int src_len,
+                     struct coding_system *coding)
 {
   struct glyph *src_end = src + src_len;
   unsigned char *buf;
 {
   struct glyph *src_end = src + src_len;
   unsigned char *buf;
@@ -1883,55 +1892,18 @@ static void
 turn_on_face (struct frame *f, int face_id)
 {
   struct face *face = FACE_FROM_ID (f, face_id);
 turn_on_face (struct frame *f, int face_id)
 {
   struct face *face = FACE_FROM_ID (f, face_id);
-  long fg = face->foreground;
-  long bg = face->background;
+  unsigned long fg = face->foreground;
+  unsigned long bg = face->background;
   struct tty_display_info *tty = FRAME_TTY (f);
 
   struct tty_display_info *tty = FRAME_TTY (f);
 
-  /* Do this first because TS_end_standout_mode may be the same
+  /* Use reverse video if the face specifies that.
+     Do this first because TS_end_standout_mode may be the same
      as TS_exit_attribute_mode, which turns all appearances off. */
      as TS_exit_attribute_mode, which turns all appearances off. */
-  if (MAY_USE_WITH_COLORS_P (tty, NC_REVERSE))
-    {
-      if (tty->TN_max_colors > 0)
-       {
-         if (fg >= 0 && bg >= 0)
-           {
-             /* If the terminal supports colors, we can set them
-                below without using reverse video.  The face's fg
-                and bg colors are set as they should appear on
-                the screen, i.e. they take the inverse-video'ness
-                of the face already into account.  */
-           }
-         else if (inverse_video)
-           {
-             if (fg == FACE_TTY_DEFAULT_FG_COLOR
-                 || bg == FACE_TTY_DEFAULT_BG_COLOR)
-               tty_toggle_highlight (tty);
-           }
-         else
-           {
-             if (fg == FACE_TTY_DEFAULT_BG_COLOR
-                 || bg == FACE_TTY_DEFAULT_FG_COLOR)
-               tty_toggle_highlight (tty);
-           }
-       }
-      else
-       {
-         /* If we can't display colors, use reverse video
-            if the face specifies that.  */
-         if (inverse_video)
-           {
-             if (fg == FACE_TTY_DEFAULT_FG_COLOR
-                 || bg == FACE_TTY_DEFAULT_BG_COLOR)
-               tty_toggle_highlight (tty);
-           }
-         else
-           {
-             if (fg == FACE_TTY_DEFAULT_BG_COLOR
-                 || bg == FACE_TTY_DEFAULT_FG_COLOR)
-               tty_toggle_highlight (tty);
-           }
-       }
-    }
+  if (MAY_USE_WITH_COLORS_P (tty, NC_REVERSE)
+      && (inverse_video
+         ? fg == FACE_TTY_DEFAULT_FG_COLOR || bg == FACE_TTY_DEFAULT_BG_COLOR
+         : fg == FACE_TTY_DEFAULT_BG_COLOR || bg == FACE_TTY_DEFAULT_FG_COLOR))
+    tty_toggle_highlight (tty);
 
   if (face->tty_bold_p && MAY_USE_WITH_COLORS_P (tty, NC_BOLD))
     OUTPUT1_IF (tty, tty->TS_enter_bold_mode);
 
   if (face->tty_bold_p && MAY_USE_WITH_COLORS_P (tty, NC_BOLD))
     OUTPUT1_IF (tty, tty->TS_enter_bold_mode);
@@ -1956,7 +1928,7 @@ turn_on_face (struct frame *f, int face_id)
       char *p;
 
       ts = tty->standout_mode ? tty->TS_set_background : tty->TS_set_foreground;
       char *p;
 
       ts = tty->standout_mode ? tty->TS_set_background : tty->TS_set_foreground;
-      if (fg >= 0 && ts)
+      if (face_tty_specified_color (fg) && ts)
        {
           p = tparam (ts, NULL, 0, fg, 0, 0, 0);
          OUTPUT (tty, p);
        {
           p = tparam (ts, NULL, 0, fg, 0, 0, 0);
          OUTPUT (tty, p);
@@ -1964,7 +1936,7 @@ turn_on_face (struct frame *f, int face_id)
        }
 
       ts = tty->standout_mode ? tty->TS_set_foreground : tty->TS_set_background;
        }
 
       ts = tty->standout_mode ? tty->TS_set_foreground : tty->TS_set_background;
-      if (bg >= 0 && ts)
+      if (face_tty_specified_color (bg) && ts)
        {
           p = tparam (ts, NULL, 0, bg, 0, 0, 0);
          OUTPUT (tty, p);
        {
           p = tparam (ts, NULL, 0, bg, 0, 0, 0);
          OUTPUT (tty, p);
@@ -2018,12 +1990,10 @@ turn_off_face (struct frame *f, int face_id)
 
 
 /* Return true if the terminal on frame F supports all of the
 
 
 /* Return true if the terminal on frame F supports all of the
-   capabilities in CAPS simultaneously, with foreground and background
-   colors FG and BG.  */
+   capabilities in CAPS simultaneously.  */
 
 bool
 
 bool
-tty_capable_p (struct tty_display_info *tty, unsigned int caps,
-              unsigned long fg, unsigned long bg)
+tty_capable_p (struct tty_display_info *tty, unsigned int caps)
 {
 #define TTY_CAPABLE_P_TRY(tty, cap, TS, NC_bit)                                \
   if ((caps & (cap)) && (!(TS) || !MAY_USE_WITH_COLORS_P(tty, NC_bit)))        \
 {
 #define TTY_CAPABLE_P_TRY(tty, cap, TS, NC_bit)                                \
   if ((caps & (cap)) && (!(TS) || !MAY_USE_WITH_COLORS_P(tty, NC_bit)))        \
@@ -2776,10 +2746,10 @@ DEFUN ("gpm-mouse-stop", Fgpm_mouse_stop, Sgpm_mouse_stop,
    However, unlike on MSDOS, where the menu text is drawn directly to
    the display video memory, on a TTY we use display_string (see
    display_tty_menu_item in xdisp.c) to put the glyphs produced from
    However, unlike on MSDOS, where the menu text is drawn directly to
    the display video memory, on a TTY we use display_string (see
    display_tty_menu_item in xdisp.c) to put the glyphs produced from
-   the menu items directly into the frame's 'desired_matrix' glyph
-   matrix, and then call update_frame_with_menu to deliver the results
-   to the glass.  The previous contents of the screen, in the form of
-   the current_matrix, is stashed away, and used to restore screen
+   the menu items into the frame's 'desired_matrix' glyph matrix, and
+   then call update_frame_with_menu to deliver the results to the
+   glass.  The previous contents of the screen, in the form of the
+   current_matrix, is stashed away, and used to restore screen
    contents when the menu selection changes or when the final
    selection is made and the menu should be popped down.
 
    contents when the menu selection changes or when the final
    selection is made and the menu should be popped down.
 
@@ -2810,7 +2780,7 @@ typedef struct tty_menu_struct
   char **text;
   struct tty_menu_struct **submenu;
   int *panenumber; /* Also used as enabled flag.  */
   char **text;
   struct tty_menu_struct **submenu;
   int *panenumber; /* Also used as enabled flag.  */
-  int allocated;
+  ptrdiff_t allocated;
   int panecount;
   int width;
   const char **help_text;
   int panecount;
   int width;
   const char **help_text;
@@ -2821,38 +2791,27 @@ typedef struct tty_menu_struct
 static tty_menu *
 tty_menu_create (void)
 {
 static tty_menu *
 tty_menu_create (void)
 {
-  tty_menu *menu;
-
-  menu = (tty_menu *) xmalloc (sizeof (tty_menu));
-  menu->allocated = menu->count = menu->panecount = menu->width = 0;
-  return menu;
+  return xzalloc (sizeof *tty_menu_create ());
 }
 
 /* Allocate some (more) memory for MENU ensuring that there is room for one
 }
 
 /* Allocate some (more) memory for MENU ensuring that there is room for one
-   for item.  */
+   more item.  */
 
 static void
 tty_menu_make_room (tty_menu *menu)
 {
 
 static void
 tty_menu_make_room (tty_menu *menu)
 {
-  if (menu->allocated == 0)
+  if (menu->allocated == menu->count)
     {
     {
-      int count = menu->allocated = 10;
-      menu->text = (char **) xmalloc (count * sizeof (char *));
-      menu->submenu = (tty_menu **) xmalloc (count * sizeof (tty_menu *));
-      menu->panenumber = (int *) xmalloc (count * sizeof (int));
-      menu->help_text = (const char **) xmalloc (count * sizeof (char *));
-    }
-  else if (menu->allocated == menu->count)
-    {
-      int count = menu->allocated = menu->allocated + 10;
-      menu->text
-       = (char **) xrealloc (menu->text, count * sizeof (char *));
-      menu->submenu
-       = (tty_menu **) xrealloc (menu->submenu, count * sizeof (tty_menu *));
-      menu->panenumber
-       = (int *) xrealloc (menu->panenumber, count * sizeof (int));
-      menu->help_text
-       = (const char **) xrealloc (menu->help_text, count * sizeof (char *));
+      ptrdiff_t allocated = menu->allocated;
+      menu->text = xpalloc (menu->text, &allocated, 1, -1, sizeof *menu->text);
+      menu->text = xrealloc (menu->text, allocated * sizeof *menu->text);
+      menu->submenu = xrealloc (menu->submenu,
+                               allocated * sizeof *menu->submenu);
+      menu->panenumber = xrealloc (menu->panenumber,
+                                  allocated * sizeof *menu->panenumber);
+      menu->help_text = xrealloc (menu->help_text,
+                                 allocated * sizeof *menu->help_text);
+      menu->allocated = allocated;
     }
 }
 
     }
 }
 
@@ -2869,7 +2828,8 @@ tty_menu_search_pane (tty_menu *menu, int pane)
       {
        if (pane == menu->panenumber[i])
          return menu->submenu[i];
       {
        if (pane == menu->panenumber[i])
          return menu->submenu[i];
-       if ((try = tty_menu_search_pane (menu->submenu[i], pane)))
+       try = tty_menu_search_pane (menu->submenu[i], pane);
+       if (try)
          return try;
       }
   return (tty_menu *) 0;
          return try;
       }
   return (tty_menu *) 0;
@@ -2917,30 +2877,35 @@ mouse_get_xy (int *x, int *y)
     }
 }
 
     }
 }
 
-/* Display MENU at (X,Y) using FACES.  */
+/* Display MENU at (X,Y) using FACES, starting with FIRST_ITEM
+   (zero-based).  */
 
 static void
 tty_menu_display (tty_menu *menu, int x, int y, int pn, int *faces,
 
 static void
 tty_menu_display (tty_menu *menu, int x, int y, int pn, int *faces,
-                 int mx, int my, int disp_help)
+                 int mx, int my, int first_item, bool disp_help)
 {
   int i, face, width, enabled, mousehere, row, col;
   struct frame *sf = SELECTED_FRAME ();
   struct tty_display_info *tty = FRAME_TTY (sf);
 {
   int i, face, width, enabled, mousehere, row, col;
   struct frame *sf = SELECTED_FRAME ();
   struct tty_display_info *tty = FRAME_TTY (sf);
+  /* Don't try to display more menu items than the console can display
+     using the available screen lines.  Exclude the echo area line, as
+     it will be overwritten by the help-echo anyway.  */
+  int max_items = min (menu->count - first_item, FRAME_LINES (sf) - 1 - y);
 
   menu_help_message = NULL;
 
   width = menu->width;
   col = cursorX (tty);
   row = cursorY (tty);
 
   menu_help_message = NULL;
 
   width = menu->width;
   col = cursorX (tty);
   row = cursorY (tty);
-  for (i = 0; i < menu->count; i++)
+  for (i = 0; i < max_items; i++)
     {
       int max_width = width + 2; /* +2 for padding blanks on each side */
     {
       int max_width = width + 2; /* +2 for padding blanks on each side */
+      int j = i + first_item;
 
 
-      cursor_to (sf, y + i, x);
-      if (menu->submenu[i])
+      if (menu->submenu[j])
        max_width += 2; /* for displaying " >" after the item */
       enabled
        max_width += 2; /* for displaying " >" after the item */
       enabled
-       = (!menu->submenu[i] && menu->panenumber[i]) || (menu->submenu[i]);
+       = (!menu->submenu[j] && menu->panenumber[j]) || (menu->submenu[j]);
       mousehere = (y + i == my && x <= mx && mx < x + max_width);
       face = faces[enabled + mousehere * 2];
       /* Display the menu help string for the i-th menu item even if
       mousehere = (y + i == my && x <= mx && mx < x + max_width);
       face = faces[enabled + mousehere * 2];
       /* Display the menu help string for the i-th menu item even if
@@ -2948,12 +2913,12 @@ tty_menu_display (tty_menu *menu, int x, int y, int pn, int *faces,
         code does.  */
       if (disp_help && enabled + mousehere * 2 >= 2)
        {
         code does.  */
       if (disp_help && enabled + mousehere * 2 >= 2)
        {
-         menu_help_message = menu->help_text[i];
+         menu_help_message = menu->help_text[j];
          menu_help_paneno = pn - 1;
          menu_help_paneno = pn - 1;
-         menu_help_itemno = i;
+         menu_help_itemno = j;
        }
        }
-      display_tty_menu_item (menu->text[i], max_width, face, x, y + i,
-                            menu->submenu[i] != NULL);
+      display_tty_menu_item (menu->text[j], max_width, face, x, y + i,
+                            menu->submenu[j] != NULL);
     }
   update_frame_with_menu (sf);
   cursor_to (sf, row, col);
     }
   update_frame_with_menu (sf);
   cursor_to (sf, row, col);
@@ -2961,18 +2926,13 @@ tty_menu_display (tty_menu *menu, int x, int y, int pn, int *faces,
 
 /* --------------------------- X Menu emulation ---------------------- */
 
 
 /* --------------------------- X Menu emulation ---------------------- */
 
-/* Report availability of menus.  */
-
-int
-have_menus_p (void) {  return 1; }
-
 /* Create a new pane and place it on the outer-most level.  */
 
 static int
 tty_menu_add_pane (tty_menu *menu, const char *txt)
 {
   int len;
 /* Create a new pane and place it on the outer-most level.  */
 
 static int
 tty_menu_add_pane (tty_menu *menu, const char *txt)
 {
   int len;
-  const char *p;
+  const unsigned char *p;
 
   tty_menu_make_room (menu);
   menu->submenu[menu->count] = tty_menu_create ();
 
   tty_menu_make_room (menu);
   menu->submenu[menu->count] = tty_menu_create ();
@@ -2982,7 +2942,7 @@ tty_menu_add_pane (tty_menu *menu, const char *txt)
   menu->count++;
 
   /* Update the menu width, if necessary.  */
   menu->count++;
 
   /* Update the menu width, if necessary.  */
-  for (len = 0, p = txt; *p; )
+  for (len = 0, p = (unsigned char *) txt; *p; )
     {
       int ch_len;
       int ch = STRING_CHAR_AND_LENGTH (p, ch_len);
     {
       int ch_len;
       int ch = STRING_CHAR_AND_LENGTH (p, ch_len);
@@ -2999,16 +2959,19 @@ tty_menu_add_pane (tty_menu *menu, const char *txt)
 
 /* Create a new item in a menu pane.  */
 
 
 /* Create a new item in a menu pane.  */
 
-int
+static bool
 tty_menu_add_selection (tty_menu *menu, int pane,
 tty_menu_add_selection (tty_menu *menu, int pane,
-                       char *txt, int enable, char const *help_text)
+                       char *txt, bool enable, char const *help_text)
 {
   int len;
 {
   int len;
-  char *p;
+  unsigned char *p;
 
   if (pane)
 
   if (pane)
-    if (!(menu = tty_menu_search_pane (menu, pane)))
-      return TTYM_FAILURE;
+    {
+      menu = tty_menu_search_pane (menu, pane);
+      if (! menu)
+       return 0;
+    }
   tty_menu_make_room (menu);
   menu->submenu[menu->count] = (tty_menu *) 0;
   menu->text[menu->count] = txt;
   tty_menu_make_room (menu);
   menu->submenu[menu->count] = (tty_menu *) 0;
   menu->text[menu->count] = txt;
@@ -3017,7 +2980,7 @@ tty_menu_add_selection (tty_menu *menu, int pane,
   menu->count++;
 
   /* Update the menu width, if necessary.  */
   menu->count++;
 
   /* Update the menu width, if necessary.  */
-  for (len = 0, p = txt; *p; )
+  for (len = 0, p = (unsigned char *) txt; *p; )
     {
       int ch_len;
       int ch = STRING_CHAR_AND_LENGTH (p, ch_len);
     {
       int ch_len;
       int ch = STRING_CHAR_AND_LENGTH (p, ch_len);
@@ -3029,12 +2992,12 @@ tty_menu_add_selection (tty_menu *menu, int pane,
   if (len > menu->width)
     menu->width = len;
 
   if (len > menu->width)
     menu->width = len;
 
-  return TTYM_SUCCESS;
+  return 1;
 }
 
 /* Decide where the menu would be placed if requested at (X,Y).  */
 
 }
 
 /* Decide where the menu would be placed if requested at (X,Y).  */
 
-void
+static void
 tty_menu_locate (tty_menu *menu, int x, int y,
                 int *ulx, int *uly, int *width, int *height)
 {
 tty_menu_locate (tty_menu *menu, int x, int y,
                 int *ulx, int *uly, int *width, int *height)
 {
@@ -3056,7 +3019,7 @@ struct tty_menu_state
    enable all its rows.  Value is a glyph matrix holding the contents
    of F's current frame matrix with all its glyph rows enabled.  */
 
    enable all its rows.  Value is a glyph matrix holding the contents
    of F's current frame matrix with all its glyph rows enabled.  */
 
-struct glyph_matrix *
+static struct glyph_matrix *
 save_and_enable_current_matrix (struct frame *f)
 {
   int i;
 save_and_enable_current_matrix (struct frame *f)
 {
   int i;
@@ -3078,22 +3041,6 @@ save_and_enable_current_matrix (struct frame *f)
         screen will not be redrawn anyway.)  */
       to->enabled_p = 1;
       to->hash = from->hash;
         screen will not be redrawn anyway.)  */
       to->enabled_p = 1;
       to->hash = from->hash;
-      if (from->used[LEFT_MARGIN_AREA])
-       {
-         nbytes = from->used[LEFT_MARGIN_AREA] * sizeof (struct glyph);
-         to->glyphs[LEFT_MARGIN_AREA] = (struct glyph *) xmalloc (nbytes);
-         memcpy (to->glyphs[LEFT_MARGIN_AREA],
-                 from->glyphs[LEFT_MARGIN_AREA], nbytes);
-         to->used[LEFT_MARGIN_AREA] = from->used[LEFT_MARGIN_AREA];
-       }
-      if (from->used[RIGHT_MARGIN_AREA])
-       {
-         nbytes = from->used[RIGHT_MARGIN_AREA] * sizeof (struct glyph);
-         to->glyphs[RIGHT_MARGIN_AREA] = (struct glyph *) xmalloc (nbytes);
-         memcpy (to->glyphs[RIGHT_MARGIN_AREA],
-                 from->glyphs[RIGHT_MARGIN_AREA], nbytes);
-         to->used[RIGHT_MARGIN_AREA] = from->used[RIGHT_MARGIN_AREA];
-       }
     }
 
   return saved;
     }
 
   return saved;
@@ -3118,26 +3065,6 @@ restore_desired_matrix (struct frame *f, struct glyph_matrix *saved)
       to->used[TEXT_AREA] = from->used[TEXT_AREA];
       to->enabled_p = from->enabled_p;
       to->hash = from->hash;
       to->used[TEXT_AREA] = from->used[TEXT_AREA];
       to->enabled_p = from->enabled_p;
       to->hash = from->hash;
-      nbytes = from->used[LEFT_MARGIN_AREA] * sizeof (struct glyph);
-      if (nbytes)
-       {
-         eassert (to->glyphs[LEFT_MARGIN_AREA] != from->glyphs[LEFT_MARGIN_AREA]);
-         memcpy (to->glyphs[LEFT_MARGIN_AREA],
-                 from->glyphs[LEFT_MARGIN_AREA], nbytes);
-         to->used[LEFT_MARGIN_AREA] = from->used[LEFT_MARGIN_AREA];
-       }
-      else
-       to->used[LEFT_MARGIN_AREA] = 0;
-      nbytes = from->used[RIGHT_MARGIN_AREA] * sizeof (struct glyph);
-      if (nbytes)
-       {
-         eassert (to->glyphs[RIGHT_MARGIN_AREA] != from->glyphs[RIGHT_MARGIN_AREA]);
-         memcpy (to->glyphs[RIGHT_MARGIN_AREA],
-                 from->glyphs[RIGHT_MARGIN_AREA], nbytes);
-         to->used[RIGHT_MARGIN_AREA] = from->used[RIGHT_MARGIN_AREA];
-       }
-      else
-       to->used[RIGHT_MARGIN_AREA] = 0;
     }
 }
 
     }
 }
 
@@ -3154,10 +3081,6 @@ free_saved_screen (struct glyph_matrix *saved)
       struct glyph_row *from = saved->rows + i;
 
       xfree (from->glyphs[TEXT_AREA]);
       struct glyph_row *from = saved->rows + i;
 
       xfree (from->glyphs[TEXT_AREA]);
-      if (from->used[LEFT_MARGIN_AREA])
-       xfree (from->glyphs[LEFT_MARGIN_AREA]);
-      if (from->used[RIGHT_MARGIN_AREA])
-       xfree (from->glyphs[RIGHT_MARGIN_AREA]);
     }
 
   xfree (saved->rows);
     }
 
   xfree (saved->rows);
@@ -3172,14 +3095,20 @@ screen_update (struct frame *f, struct glyph_matrix *mtx)
   update_frame_with_menu (f);
 }
 
   update_frame_with_menu (f);
 }
 
-/* Read user input and return X and Y coordinates where that input
-   puts us.  We only consider mouse movement and click events and
-   keyboard movement commands; the rest are ignored.
+typedef enum {
+  MI_QUIT_MENU      = -1,
+  MI_CONTINUE       = 0,
+  MI_ITEM_SELECTED  = 1,
+  MI_NEXT_ITEM      = 2,
+  MI_PREV_ITEM      = 3,
+  MI_SCROLL_FORWARD = 4,
+  MI_SCROLL_BACK    = 5
+} mi_result;
 
 
-   Value is -1 if C-g was pressed, 1 if an item was selected, 2 or 3
-   if we need to move to the next or previous menu-bar menu, zero
-   otherwise.  */
-static int
+/* Read user input and return X and Y coordinates where that input
+   puts us.  We only consider mouse movement and click events, and
+   keyboard movement commands; the rest are ignored.  */
+static mi_result
 read_menu_input (struct frame *sf, int *x, int *y, int min_y, int max_y,
                 bool *first_time)
 {
 read_menu_input (struct frame *sf, int *x, int *y, int min_y, int max_y,
                 bool *first_time)
 {
@@ -3190,10 +3119,9 @@ read_menu_input (struct frame *sf, int *x, int *y, int min_y, int max_y,
     }
   else
     {
     }
   else
     {
-      extern Lisp_Object read_menu_command (void);
       Lisp_Object cmd;
       Lisp_Object cmd;
-      int usable_input = 1;
-      int st = 0;
+      bool usable_input = 1;
+      mi_result st = MI_CONTINUE;
       struct tty_display_info *tty = FRAME_TTY (sf);
       Lisp_Object saved_mouse_tracking = do_mouse_tracking;
 
       struct tty_display_info *tty = FRAME_TTY (sf);
       Lisp_Object saved_mouse_tracking = do_mouse_tracking;
 
@@ -3209,44 +3137,42 @@ read_menu_input (struct frame *sf, int *x, int *y, int min_y, int max_y,
       do_mouse_tracking = saved_mouse_tracking;
 
       if (EQ (cmd, Qt) || EQ (cmd, Qtty_menu_exit))
       do_mouse_tracking = saved_mouse_tracking;
 
       if (EQ (cmd, Qt) || EQ (cmd, Qtty_menu_exit))
-       return -1;
+       return MI_QUIT_MENU;
       if (EQ (cmd, Qtty_menu_mouse_movement))
       if (EQ (cmd, Qtty_menu_mouse_movement))
-       {
-         int mx, my;
-
-         mouse_get_xy (&mx, &my);
-         *x = mx;
-         *y = my;
-       }
+       mouse_get_xy (x, y);
       else if (EQ (cmd, Qtty_menu_next_menu))
        {
          usable_input = 0;
       else if (EQ (cmd, Qtty_menu_next_menu))
        {
          usable_input = 0;
-         st = 2;
+         st = MI_NEXT_ITEM;
        }
       else if (EQ (cmd, Qtty_menu_prev_menu))
        {
          usable_input = 0;
        }
       else if (EQ (cmd, Qtty_menu_prev_menu))
        {
          usable_input = 0;
-         st = 3;
+         st = MI_PREV_ITEM;
        }
       else if (EQ (cmd, Qtty_menu_next_item))
        {
          if (*y < max_y)
            *y += 1;
        }
       else if (EQ (cmd, Qtty_menu_next_item))
        {
          if (*y < max_y)
            *y += 1;
+         else
+           st = MI_SCROLL_FORWARD;
        }
       else if (EQ (cmd, Qtty_menu_prev_item))
        {
          if (*y > min_y)
            *y -= 1;
        }
       else if (EQ (cmd, Qtty_menu_prev_item))
        {
          if (*y > min_y)
            *y -= 1;
+         else
+           st = MI_SCROLL_BACK;
        }
       else if (EQ (cmd, Qtty_menu_select))
        }
       else if (EQ (cmd, Qtty_menu_select))
-       st = 1;
+       st = MI_ITEM_SELECTED;
       else if (!EQ (cmd, Qtty_menu_ignore))
        usable_input = 0;
       if (usable_input)
        sf->mouse_moved = 1;
       return st;
     }
       else if (!EQ (cmd, Qtty_menu_ignore))
        usable_input = 0;
       if (usable_input)
        sf->mouse_moved = 1;
       return st;
     }
-  return 0;
+  return MI_CONTINUE;
 }
 
 /* Display menu, wait for user's response, and return that response.  */
 }
 
 /* Display menu, wait for user's response, and return that response.  */
@@ -3254,16 +3180,19 @@ static int
 tty_menu_activate (tty_menu *menu, int *pane, int *selidx,
                   int x0, int y0, char **txt,
                   void (*help_callback)(char const *, int, int),
 tty_menu_activate (tty_menu *menu, int *pane, int *selidx,
                   int x0, int y0, char **txt,
                   void (*help_callback)(char const *, int, int),
-                  int kbd_navigation)
+                  bool kbd_navigation)
 {
   struct tty_menu_state *state;
 {
   struct tty_menu_state *state;
-  int statecount, x, y, i, b, leave, result, onepane;
+  int statecount, x, y, i;
+  bool leave, onepane;
+  int result IF_LINT (= 0);
   int title_faces[4];          /* face to display the menu title */
   int faces[4], buffers_num_deleted = 0;
   struct frame *sf = SELECTED_FRAME ();
   struct tty_display_info *tty = FRAME_TTY (sf);
   bool first_time;
   int title_faces[4];          /* face to display the menu title */
   int faces[4], buffers_num_deleted = 0;
   struct frame *sf = SELECTED_FRAME ();
   struct tty_display_info *tty = FRAME_TTY (sf);
   bool first_time;
-  Lisp_Object saved_echo_area_message, selectface;
+  Lisp_Object selectface;
+  int first_item = 0;
 
   /* Don't allow non-positive x0 and y0, lest the menu will wrap
      around the display.  */
 
   /* Don't allow non-positive x0 and y0, lest the menu will wrap
      around the display.  */
@@ -3315,14 +3244,15 @@ tty_menu_activate (tty_menu *menu, int *pane, int *selidx,
      want to interpret them as zero-based column and row coordinates,
      and also because we want the first item of the menu, not its
      title, to appear at x0,y0.  */
      want to interpret them as zero-based column and row coordinates,
      and also because we want the first item of the menu, not its
      title, to appear at x0,y0.  */
-  tty_menu_display (menu, x0 - 1, y0 - 1, 1, title_faces, x0 - 1, y0 - 1, 0);
+  tty_menu_display (menu, x0 - 1, y0 - 1, 1, title_faces, x0 - 1, y0 - 1, 0, 0);
 
   /* Turn off the cursor.  Otherwise it shows through the menu
      panes, which is ugly.  */
   tty_hide_cursor (tty);
   if (buffers_num_deleted)
     menu->text[0][7] = ' ';
 
   /* Turn off the cursor.  Otherwise it shows through the menu
      panes, which is ugly.  */
   tty_hide_cursor (tty);
   if (buffers_num_deleted)
     menu->text[0][7] = ' ';
-  if ((onepane = menu->count == 1 && menu->submenu[0]))
+  onepane = menu->count == 1 && menu->submenu[0];
+  if (onepane)
     {
       menu->width = menu->submenu[0]->width;
       state[0].menu = menu->submenu[0];
     {
       menu->width = menu->submenu[0]->width;
       state[0].menu = menu->submenu[0];
@@ -3342,43 +3272,67 @@ tty_menu_activate (tty_menu *menu, int *pane, int *selidx,
   leave = 0;
   while (!leave)
     {
   leave = 0;
   while (!leave)
     {
-      int input_status;
-      int min_y = state[0].y, max_y = min_y + state[0].menu->count - 1;
+      mi_result input_status;
+      int min_y = state[0].y;
+      int max_y = min (min_y + state[0].menu->count, FRAME_LINES (sf) - 1) - 1;
 
       input_status = read_menu_input (sf, &x, &y, min_y, max_y, &first_time);
       if (input_status)
        {
          leave = 1;
 
       input_status = read_menu_input (sf, &x, &y, min_y, max_y, &first_time);
       if (input_status)
        {
          leave = 1;
-         if (input_status == -1)
+         switch (input_status)
            {
            {
+           case MI_QUIT_MENU:
              /* Remove the last help-echo, so that it doesn't
                 re-appear after "Quit".  */
              show_help_echo (Qnil, Qnil, Qnil, Qnil);
              result = TTYM_NO_SELECT;
              /* Remove the last help-echo, so that it doesn't
                 re-appear after "Quit".  */
              show_help_echo (Qnil, Qnil, Qnil, Qnil);
              result = TTYM_NO_SELECT;
-           }
-         else if (input_status == 2)
-           {
+             break;
+           case MI_NEXT_ITEM:
              if (kbd_navigation)
                result = TTYM_NEXT;
              else
                leave = 0;
              if (kbd_navigation)
                result = TTYM_NEXT;
              else
                leave = 0;
-           }
-         else if (input_status == 3)
-           {
+             break;
+           case MI_PREV_ITEM:
              if (kbd_navigation)
                result = TTYM_PREV;
              else
                leave = 0;
              if (kbd_navigation)
                result = TTYM_PREV;
              else
                leave = 0;
+             break;
+           case MI_SCROLL_FORWARD:
+             if (y - min_y == state[0].menu->count - 1 - first_item)
+               {
+                 y = min_y;
+                 first_item = 0;
+               }
+             else
+               first_item++;
+             leave = 0;
+             break;
+           case MI_SCROLL_BACK:
+             if (first_item == 0)
+               {
+                 y = max_y;
+                 first_item = state[0].menu->count - 1 - (y - min_y);
+               }
+             else
+               first_item--;
+             leave = 0;
+             break;
+           default:
+             /* MI_ITEM_SELECTED is handled below, so nothing to do.  */
+             break;
            }
        }
            }
        }
-      if (sf->mouse_moved && input_status != -1)
+      if (sf->mouse_moved && input_status != MI_QUIT_MENU)
        {
          sf->mouse_moved = 0;
          result = TTYM_IA_SELECT;
          for (i = 0; i < statecount; i++)
            if (state[i].x <= x && x < state[i].x + state[i].menu->width + 2)
              {
        {
          sf->mouse_moved = 0;
          result = TTYM_IA_SELECT;
          for (i = 0; i < statecount; i++)
            if (state[i].x <= x && x < state[i].x + state[i].menu->width + 2)
              {
-               int dy = y - state[i].y;
+               int dy = y - state[i].y + first_item;
                if (0 <= dy && dy < state[i].menu->count)
                  {
                    if (!state[i].menu->submenu[dy])
                if (0 <= dy && dy < state[i].menu->count)
                  {
                    if (!state[i].menu->submenu[dy])
@@ -3407,7 +3361,7 @@ tty_menu_activate (tty_menu *menu, int *pane, int *selidx,
                                          state[i].x,
                                          state[i].y,
                                          state[i].pane,
                                          state[i].x,
                                          state[i].y,
                                          state[i].pane,
-                                         faces, x, y, 1);
+                                         faces, x, y, first_item, 1);
                        state[statecount].menu = state[i].menu->submenu[dy];
                        state[statecount].pane = state[i].menu->panenumber[dy];
                        state[statecount].screen_behind
                        state[statecount].menu = state[i].menu->submenu[dy];
                        state[statecount].pane = state[i].menu->panenumber[dy];
                        state[statecount].screen_behind
@@ -3423,7 +3377,7 @@ tty_menu_activate (tty_menu *menu, int *pane, int *selidx,
                            state[statecount - 1].x,
                            state[statecount - 1].y,
                            state[statecount - 1].pane,
                            state[statecount - 1].x,
                            state[statecount - 1].y,
                            state[statecount - 1].pane,
-                           faces, x, y, 1);
+                           faces, x, y, first_item, 1);
          tty_hide_cursor (tty);
          fflush (tty->output);
        }
          tty_hide_cursor (tty);
          fflush (tty->output);
        }
@@ -3446,6 +3400,7 @@ tty_menu_activate (tty_menu *menu, int *pane, int *selidx,
   while (statecount--)
     free_saved_screen (state[statecount].screen_behind);
   tty_show_cursor (tty);       /* turn cursor back on */
   while (statecount--)
     free_saved_screen (state[statecount].screen_behind);
   tty_show_cursor (tty);       /* turn cursor back on */
+  fflush (tty->output);
 
 /* Clean up any mouse events that are waiting inside Emacs event queue.
      These events are likely to be generated before the menu was even
 
 /* Clean up any mouse events that are waiting inside Emacs event queue.
      These events are likely to be generated before the menu was even
@@ -3455,13 +3410,12 @@ tty_menu_activate (tty_menu *menu, int *pane, int *selidx,
   discard_mouse_events ();
   if (!kbd_buffer_events_waiting ())
     clear_input_pending ();
   discard_mouse_events ();
   if (!kbd_buffer_events_waiting ())
     clear_input_pending ();
-  SET_FRAME_GARBAGED (sf);
   return result;
 }
 
 /* Dispose of a menu.  */
 
   return result;
 }
 
 /* Dispose of a menu.  */
 
-void
+static void
 tty_menu_destroy (tty_menu *menu)
 {
   int i;
 tty_menu_destroy (tty_menu *menu)
 {
   int i;
@@ -3491,7 +3445,7 @@ tty_menu_help_callback (char const *help_string, int pane, int item)
   Lisp_Object pane_name;
   Lisp_Object menu_object;
 
   Lisp_Object pane_name;
   Lisp_Object menu_object;
 
-  first_item = XVECTOR (menu_items)->u.contents;
+  first_item = XVECTOR (menu_items)->contents;
   if (EQ (first_item[0], Qt))
     pane_name = first_item[MENU_ITEMS_PANE_NAME];
   else if (EQ (first_item[0], Qquote))
   if (EQ (first_item[0], Qt))
     pane_name = first_item[MENU_ITEMS_PANE_NAME];
   else if (EQ (first_item[0], Qquote))
@@ -3572,7 +3526,7 @@ tty_menu_new_item_coords (struct frame *f, int which, int *x, int *y)
          if (ix <= *x
              /* We use <= so the blank between 2 items on a TTY is
                 considered part of the previous item.  */
          if (ix <= *x
              /* We use <= so the blank between 2 items on a TTY is
                 considered part of the previous item.  */
-             && *x <= ix + menu_item_width (SSDATA (str)))
+             && *x <= ix + menu_item_width (SDATA (str)))
            {
              /* Found current item.  Now compute the X coordinate of
                 the previous or next item.  */
            {
              /* Found current item.  Now compute the X coordinate of
                 the previous or next item.  */
@@ -3598,8 +3552,8 @@ tty_menu_new_item_coords (struct frame *f, int which, int *x, int *y)
 }
 
 Lisp_Object
 }
 
 Lisp_Object
-tty_menu_show (struct frame *f, int x, int y, int for_click, int keymaps,
-              Lisp_Object title, int kbd_navigation, const char **error_name)
+tty_menu_show (struct frame *f, int x, int y, bool for_click, bool keymaps,
+              Lisp_Object title, bool kbd_navigation, const char **error_name)
 {
   tty_menu *menu;
   int pane, selidx, lpane, status;
 {
   tty_menu *menu;
   int pane, selidx, lpane, status;
@@ -3610,12 +3564,9 @@ tty_menu_show (struct frame *f, int x, int y, int for_click, int keymaps,
   int dispwidth, dispheight;
   int i, j, lines, maxlines;
   int maxwidth;
   int dispwidth, dispheight;
   int i, j, lines, maxlines;
   int maxwidth;
-  int dummy_int;
-  unsigned int dummy_uint;
-  ptrdiff_t specpdl_count = SPECPDL_INDEX ();
+  ptrdiff_t specpdl_count;
 
 
-  if (! FRAME_TERMCAP_P (f))
-    emacs_abort ();
+  eassert (FRAME_TERMCAP_P (f));
 
   *error_name = 0;
   if (menu_items_n_panes == 0)
 
   *error_name = 0;
   if (menu_items_n_panes == 0)
@@ -3637,7 +3588,7 @@ tty_menu_show (struct frame *f, int x, int y, int for_click, int keymaps,
 
   /* Don't GC while we prepare and show the menu, because we give the
      menu functions pointers to the contents of strings.  */
 
   /* Don't GC while we prepare and show the menu, because we give the
      menu functions pointers to the contents of strings.  */
-  inhibit_garbage_collection ();
+  specpdl_count = inhibit_garbage_collection ();
 
   /* Adjust coordinates to be root-window-relative.  */
   item_x = x += f->left_pos;
 
   /* Adjust coordinates to be root-window-relative.  */
   item_x = x += f->left_pos;
@@ -3668,7 +3619,8 @@ tty_menu_show (struct frame *f, int x, int y, int for_click, int keymaps,
            {
              tty_menu_destroy (menu);
              *error_name = "Can't create pane";
            {
              tty_menu_destroy (menu);
              *error_name = "Can't create pane";
-             return Qnil;
+             entry = Qnil;
+             goto tty_menu_end;
            }
          i += MENU_ITEMS_PANE_LENGTH;
 
            }
          i += MENU_ITEMS_PANE_LENGTH;
 
@@ -3724,13 +3676,13 @@ tty_menu_show (struct frame *f, int x, int y, int for_click, int keymaps,
            item_data = SSDATA (item_name);
 
          if (lpane == TTYM_FAILURE
            item_data = SSDATA (item_name);
 
          if (lpane == TTYM_FAILURE
-             || (tty_menu_add_selection (menu, lpane, item_data,
-                                         !NILP (enable), help_string)
-                 == TTYM_FAILURE))
+             || (! tty_menu_add_selection (menu, lpane, item_data,
+                                           !NILP (enable), help_string)))
            {
              tty_menu_destroy (menu);
              *error_name = "Can't add selection to menu";
            {
              tty_menu_destroy (menu);
              *error_name = "Can't add selection to menu";
-             return Qnil;
+             entry = Qnil;
+             goto tty_menu_end;
            }
          i += MENU_ITEMS_ITEM_LENGTH;
           lines++;
            }
          i += MENU_ITEMS_ITEM_LENGTH;
           lines++;
@@ -3747,12 +3699,12 @@ tty_menu_show (struct frame *f, int x, int y, int for_click, int keymaps,
   x = max (x, 1);
   y = max (y, 1);
   tty_menu_locate (menu, x, y, &ulx, &uly, &width, &height);
   x = max (x, 1);
   y = max (y, 1);
   tty_menu_locate (menu, x, y, &ulx, &uly, &width, &height);
-  if (ulx+width > dispwidth)
+  if (ulx + width > dispwidth)
     {
       x -= (ulx + width) - dispwidth;
       ulx = dispwidth - width;
     }
     {
       x -= (ulx + width) - dispwidth;
       ulx = dispwidth - width;
     }
-  if (uly+height > dispheight)
+  if (uly + height > dispheight)
     {
       y -= (uly + height) - dispheight;
       uly = dispheight - height;
     {
       y -= (uly + height) - dispheight;
       uly = dispheight - height;
@@ -3858,8 +3810,9 @@ tty_menu_show (struct frame *f, int x, int y, int for_click, int keymaps,
       break;
     }
 
       break;
     }
 
-  unbind_to (specpdl_count, Qnil);
+ tty_menu_end:
 
 
+  unbind_to (specpdl_count, Qnil);
   return entry;
 }
 
   return entry;
 }
 
@@ -4252,9 +4205,9 @@ use the Bourne shell command `TERM=... export TERM' (C-shell:\n\
   /* Since we make MagicWrap terminals look like AutoWrap, we need to have
      the former flag imply the latter.  */
   AutoWrap (tty) = MagicWrap (tty) || tgetflag ("am");
   /* Since we make MagicWrap terminals look like AutoWrap, we need to have
      the former flag imply the latter.  */
   AutoWrap (tty) = MagicWrap (tty) || tgetflag ("am");
-  terminal->memory_below_frame = tgetflag ("db");
+  tty->memory_below_frame = tgetflag ("db");
   tty->TF_hazeltine = tgetflag ("hz");
   tty->TF_hazeltine = tgetflag ("hz");
-  terminal->must_write_spaces = tgetflag ("in");
+  tty->must_write_spaces = tgetflag ("in");
   tty->meta_key = tgetflag ("km") || tgetflag ("MT");
   tty->TF_insmode_motion = tgetflag ("mi");
   tty->TF_standout_motion = tgetflag ("ms");
   tty->meta_key = tgetflag ("km") || tgetflag ("MT");
   tty->TF_insmode_motion = tgetflag ("mi");
   tty->TF_standout_motion = tgetflag ("ms");
@@ -4274,7 +4227,7 @@ use the Bourne shell command `TERM=... export TERM' (C-shell:\n\
     tty->specified_window = height;
 
     FRAME_VERTICAL_SCROLL_BAR_TYPE (f) = vertical_scroll_bar_none;
     tty->specified_window = height;
 
     FRAME_VERTICAL_SCROLL_BAR_TYPE (f) = vertical_scroll_bar_none;
-    terminal->char_ins_del_ok = 1;
+    tty->char_ins_del_ok = 1;
     baud_rate = 19200;
   }
 #else  /* MSDOS */
     baud_rate = 19200;
   }
 #else  /* MSDOS */
@@ -4287,7 +4240,7 @@ use the Bourne shell command `TERM=... export TERM' (C-shell:\n\
     get_tty_size (fileno (tty->input), &width, &height);
     FrameCols (tty) = width;
     FrameRows (tty) = height;
     get_tty_size (fileno (tty->input), &width, &height);
     FrameCols (tty) = width;
     FrameRows (tty) = height;
-    terminal->char_ins_del_ok = 0;
+    tty->char_ins_del_ok = 0;
     init_baud_rate (fileno (tty->input));
   }
 #endif /* MSDOS */
     init_baud_rate (fileno (tty->input));
   }
 #endif /* MSDOS */
@@ -4306,12 +4259,12 @@ use the Bourne shell command `TERM=... export TERM' (C-shell:\n\
   tty->delete_in_insert_mode = 1;
 
   UseTabs (tty) = 0;
   tty->delete_in_insert_mode = 1;
 
   UseTabs (tty) = 0;
-  terminal->scroll_region_ok = 0;
+  tty->scroll_region_ok = 0;
 
   /* Seems to insert lines when it's not supposed to, messing up the
      display.  In doing a trace, it didn't seem to be called much, so I
      don't think we're losing anything by turning it off.  */
 
   /* Seems to insert lines when it's not supposed to, messing up the
      display.  In doing a trace, it didn't seem to be called much, so I
      don't think we're losing anything by turning it off.  */
-  terminal->line_ins_del_ok = 0;
+  tty->line_ins_del_ok = 0;
 
   tty->TN_max_colors = 16;  /* Must be non-zero for tty-display-color-p.  */
 #endif /* DOS_NT */
 
   tty->TN_max_colors = 16;  /* Must be non-zero for tty-display-color-p.  */
 #endif /* DOS_NT */
@@ -4321,11 +4274,7 @@ use the Bourne shell command `TERM=... export TERM' (C-shell:\n\
   tty->mouse_highlight.mouse_face_window = Qnil;
 #endif
 
   tty->mouse_highlight.mouse_face_window = Qnil;
 #endif
 
-  terminal->kboard = xmalloc (sizeof *terminal->kboard);
-  init_kboard (terminal->kboard);
-  kset_window_system (terminal->kboard, Qnil);
-  terminal->kboard->next_kboard = all_kboards;
-  all_kboards = terminal->kboard;
+  terminal->kboard = allocate_kboard (Qnil);
   terminal->kboard->reference_count++;
   /* Don't let the initial kboard remain current longer than necessary.
      That would cause problems if a file loaded on startup tries to
   terminal->kboard->reference_count++;
   /* Don't let the initial kboard remain current longer than necessary.
      That would cause problems if a file loaded on startup tries to
@@ -4446,23 +4395,21 @@ use the Bourne shell command `TERM=... export TERM' (C-shell:\n\
 
   UseTabs (tty) = tabs_safe_p (fileno (tty->input)) && TabWidth (tty) == 8;
 
 
   UseTabs (tty) = tabs_safe_p (fileno (tty->input)) && TabWidth (tty) == 8;
 
-  terminal->scroll_region_ok
+  tty->scroll_region_ok
     = (tty->Wcm->cm_abs
        && (tty->TS_set_window || tty->TS_set_scroll_region || tty->TS_set_scroll_region_1));
 
     = (tty->Wcm->cm_abs
        && (tty->TS_set_window || tty->TS_set_scroll_region || tty->TS_set_scroll_region_1));
 
-  terminal->line_ins_del_ok
+  tty->line_ins_del_ok
     = (((tty->TS_ins_line || tty->TS_ins_multi_lines)
         && (tty->TS_del_line || tty->TS_del_multi_lines))
     = (((tty->TS_ins_line || tty->TS_ins_multi_lines)
         && (tty->TS_del_line || tty->TS_del_multi_lines))
-       || (terminal->scroll_region_ok
+       || (tty->scroll_region_ok
            && tty->TS_fwd_scroll && tty->TS_rev_scroll));
 
            && tty->TS_fwd_scroll && tty->TS_rev_scroll));
 
-  terminal->char_ins_del_ok
+  tty->char_ins_del_ok
     = ((tty->TS_ins_char || tty->TS_insert_mode
         || tty->TS_pad_inserted_char || tty->TS_ins_multi_chars)
        && (tty->TS_del_char || tty->TS_del_multi_chars));
 
     = ((tty->TS_ins_char || tty->TS_insert_mode
         || tty->TS_pad_inserted_char || tty->TS_ins_multi_chars)
        && (tty->TS_del_char || tty->TS_del_multi_chars));
 
-  terminal->fast_clear_end_of_line = tty->TS_clr_line != 0;
-
   init_baud_rate (fileno (tty->input));
 
 #endif /* not DOS_NT */
   init_baud_rate (fileno (tty->input));
 
 #endif /* not DOS_NT */