emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Emacs-diffs] trunk r114582: Support menus on text-mode terminals.


From: Eli Zaretskii
Subject: [Emacs-diffs] trunk r114582: Support menus on text-mode terminals.
Date: Tue, 08 Oct 2013 17:55:10 +0000
User-agent: Bazaar (2.6b2)

------------------------------------------------------------
revno: 114582 [merge]
revision-id: address@hidden
parent: address@hidden
parent: address@hidden
committer: Eli Zaretskii <address@hidden>
branch nick: trunk
timestamp: Tue 2013-10-08 20:49:20 +0300
message:
  Support menus on text-mode terminals.
  
   src/xterm.h (xw_popup_dialog): Add prototype.
   src/xmenu.c (Fx_popup_dialog): Function moved to menu.c.
   (xmenu_show): Block input here, instead in Fx_popup_menu.
   (xw_popup_dialog): New function, with X-specific bits of popup
   dialogs.
   src/xdisp.c (deep_copy_glyph_row, display_tty_menu_item): New
   functions.
   src/window.c (Fset_window_configuration): Use run-time tests of the
   frame type instead of compile-time conditionals, when menu-bar
   lines are considered.
   src/w32term.h (w32con_hide_cursor, w32con_show_cursor)
   (w32_popup_dialog): New prototypes.
   src/w32menu.c (Fx_popup_dialog): Function deleted.
   (w32_popup_dialog): New function, with w32 specific bits of popup
   dialogs.  Block input here.
   src/w32inevt.c (w32_console_read_socket): Minor change to add
   debugging TTY events.
   src/w32fns.c (show_hourglass): If returning early because the frame
   is not a GUI frame, unblock input.
   src/w32console.c (w32con_hide_cursor, w32con_show_cursor, cursorX)
   (cursorY): New functions.
   src/termhooks.h (cursorX, cursorY): Prototypes of functions on
   WINDOWSNT, macros that call curX and curY elsewhere.
   src/termchar.h (struct tty_display_info) <showing_menu>: New flag.
   src/term.c (tty_hide_cursor, tty_show_cursor) [WINDOWSNT]: Call w32
   specific function to hide and show cursor on a text-mode terminal.
   (tty_menu_struct, struct tty_menu_state): New structures.
   (tty_menu_create, tty_menu_make_room, tty_menu_search_pane)
   (tty_menu_calc_size, mouse_get_xy, tty_menu_display)
   (have_menus_p, tty_menu_add_pane, tty_menu_add_selection)
   (tty_menu_locate, save_and_enable_current_matrix)
   (restore_desired_matrix, screen_update, read_menu_input)
   (tty_menu_activate, tty_menu_destroy, tty_menu_help_callback)
   (tty_pop_down_menu, tty_menu_last_menubar_item)
   (tty_menu_new_item_coords, tty_menu_show): New functions.
   (syms_of_term): New DEFSYMs for tty-menu-* symbols.
   src/nsterm.h (ns_popup_dialog): Adjust prototype.
   src/nsmenu.m (ns_menu_show): Block and unblock input here, instead
   of in x-popup-menu.
   (ns_popup_dialog): Adapt order of arguments to the other
   *_menu_show implementations.
   (Fx_popup_dialog): Function deleted.
   src/msdos.c (x_set_menu_bar_lines): Delete unused function.
   src/menu.h (tty_menu_show, menu_item_width): provide prototypes.
   src/menu.c (have_boxes): New function.
   (single_keymap_panes): Use it instead of a compile-time
   conditional.
   (single_menu_item): Use run-time tests of the frame type instead
   of compile-time conditionals.
   (encode_menu_string): New function.
   (list_of_items, list_of_panes): Use it instead of ENCODE_STRING
   the macro, since different types of frame need different encoding
   of menu items.
   (digest_single_submenu): Use run-time tests of frame type instead
   of, or in addition to, compile-time conditionals.
   (menu_item_width, Fmenu_bar_menu_at_x_y): New functions.
   (Fx_popup_menu): Detect when the function is called from keyboard
   on a TTY.  Don't barf when invoked on a text-mode frame.  Check
   frame type at run time, instead of compile-time conditionals for
   invoking terminal-specific menu-show functions.  Call
   tty_menu_show on text-mode frames.
   (Fx_popup_dialog): Moved here from xmenu.c.  Test frame types at
   run time to determine which alternative to invoke; support dialogs
   on TTYs.
   src/keyboard.h <Qmouse_movement>: Declare.
   src/keyboard.c <Qmouse_movement>: Now extern.
   <Qecho_keystrokes>: New static variable.
   (read_key_sequence): Accept an additional argument, a flag to
   prevent redisplay during reading of the key sequence.  All callers
   changed.
   (read_menu_command): New function.
   (read_char): When COMMANDFLAG is -2, do not redisplay and do not
   autosave.
   (toolkit_menubar_in_use): New function.
   (make_lispy_event): Use it instead of a compile-time test.
   src/fns.c (Fyes_or_no_p) [HAVE_MENUS]: Don't condition on
   window-system being available.
   src/editfns.c (Fmessage_box) [HAVE_MENUS]: Don't condition the call
   to x-popup-dialog on the frame type, they all now support popup
   dialogs.
   src/dispnew.c (save_current_matrix): Save the margin areas.
   (restore_current_matrix): Restore margin areas.
   (update_frame_with_menu): New function.
   src/dispextern.h (display_tty_menu_item, update_frame_with_menu):
   Add prototypes.
   src/alloc.c (make_save_ptr): Now compiled unconditionally.
   
   lisp/tmm.el (tmm-menubar): Adapt doc string to TTY menus
   functionality.
   lisp/tooltip.el (tooltip-mode): Don't error out on TTYs.
   lisp/menu-bar.el (popup-menu, popup-menu-normalize-position): Moved
   here from mouse.el.
   (popup-menu): Support menu-bar navigation on TTYs using C-f/C-b
   and arrow keys.
   (tty-menu-navigation-map): New map for TTY menu navigation.
   lisp/loadup.el ("tooltip"): Load even if x-show-tip is not available.
   lisp/frame.el (display-mouse-p): Report text-mode mouse as available
   on w32.
   (display-popup-menus-p): Report availability if mouse is
   available; don't condition on window-system.
   lisp/faces.el (tty-menu-enabled-face, tty-menu-disabled-face)
   (tty-menu-selected-face): New faces.
  
   configure.ac (HAVE_MENUS): Define unconditionally.
  
   doc/emacs/screen.texi (Menu Bar): Adapt to TTY menus.
   doc/emacs/frames.texi (Frames): Mention menu support on text terminals.
   doc/emacs/files.texi (Visiting): Mention the "File" menu-bar menu.
   doc/emacs/display.texi (Standard Faces): Mention TTY faces for menus.
   
   doc/lispref/keymaps.texi (Defining Menus, Mouse Menus, Menu Bar): Modify
   wording to the effect that menus are supported on TTYs.
   doc/lisprefframes.texi (Pop-Up Menus, Dialog Boxes)
   (Display Feature Testing): Update for menu support on TTYs.
  
    etc/NEWS: Mention the new features.
modified:
  ChangeLog                      changelog-20091113204419-o5vbwnq5f7feedwu-1538
  configure.ac                   
configure.in-20091113204419-o5vbwnq5f7feedwu-783
  doc/emacs/ChangeLog            changelog-20091113204419-o5vbwnq5f7feedwu-6227
  doc/emacs/display.texi         
display.texi-20091113204419-o5vbwnq5f7feedwu-6243
  doc/emacs/files.texi           files.texi-20091113204419-o5vbwnq5f7feedwu-6249
  doc/emacs/frames.texi          
frames.texi-20091113204419-o5vbwnq5f7feedwu-6252
  doc/emacs/screen.texi          
screen.texi-20091113204419-o5vbwnq5f7feedwu-6275
  doc/lispref/ChangeLog          changelog-20091113204419-o5vbwnq5f7feedwu-6155
  doc/lispref/frames.texi        
frames.texi-20091113204419-o5vbwnq5f7feedwu-6180
  doc/lispref/keymaps.texi       
keymaps.texi-20091113204419-o5vbwnq5f7feedwu-6190
  etc/NEWS                       news-20100311060928-aoit31wvzf25yr1z-1
  lisp/ChangeLog                 changelog-20091113204419-o5vbwnq5f7feedwu-1432
  lisp/faces.el                  faces.el-20091113204419-o5vbwnq5f7feedwu-562
  lisp/frame.el                  frame.el-20091113204419-o5vbwnq5f7feedwu-275
  lisp/loadup.el                 loadup.el-20091113204419-o5vbwnq5f7feedwu-49
  lisp/menu-bar.el               menubar.el-20091113204419-o5vbwnq5f7feedwu-546
  lisp/mouse.el                  mouse.el-20091113204419-o5vbwnq5f7feedwu-123
  lisp/tmm.el                    tmm.el-20091113204419-o5vbwnq5f7feedwu-843
  lisp/tooltip.el                tooltip.el-20091113204419-o5vbwnq5f7feedwu-1322
  src/ChangeLog                  changelog-20091113204419-o5vbwnq5f7feedwu-1438
  src/alloc.c                    alloc.c-20091113204419-o5vbwnq5f7feedwu-252
  src/cm.h                       cm.h-20091113204419-o5vbwnq5f7feedwu-435
  src/dispextern.h               
dispextern.h-20091113204419-o5vbwnq5f7feedwu-218
  src/dispnew.c                  dispnew.c-20091113204419-o5vbwnq5f7feedwu-258
  src/editfns.c                  editfns.c-20091113204419-o5vbwnq5f7feedwu-255
  src/fns.c                      fns.c-20091113204419-o5vbwnq5f7feedwu-203
  src/frame.h                    frame.h-20091113204419-o5vbwnq5f7feedwu-229
  src/keyboard.c                 keyboard.c-20091113204419-o5vbwnq5f7feedwu-449
  src/keyboard.h                 keyboard.h-20091113204419-o5vbwnq5f7feedwu-450
  src/menu.c                     menu.c-20091113204419-o5vbwnq5f7feedwu-8676
  src/menu.h                     menu.h-20091113204419-o5vbwnq5f7feedwu-8702
  src/msdos.c                    msdos.c-20091113204419-o5vbwnq5f7feedwu-656
  src/nsmenu.m                   nsmenu.m-20091113204419-o5vbwnq5f7feedwu-8744
  src/nsterm.h                   nsterm.h-20091113204419-o5vbwnq5f7feedwu-8746
  src/term.c                     term.c-20091113204419-o5vbwnq5f7feedwu-220
  src/termchar.h                 termchar.h-20091113204419-o5vbwnq5f7feedwu-440
  src/termhooks.h                termhooks.h-20091113204419-o5vbwnq5f7feedwu-249
  src/w32console.c               
w32console.c-20091113204419-o5vbwnq5f7feedwu-812
  src/w32fns.c                   w32fns.c-20091113204419-o5vbwnq5f7feedwu-945
  src/w32inevt.c                 w32inevt.c-20091113204419-o5vbwnq5f7feedwu-813
  src/w32menu.c                  w32menu.c-20091113204419-o5vbwnq5f7feedwu-947
  src/w32term.h                  w32term.h-20091113204419-o5vbwnq5f7feedwu-954
  src/window.c                   window.c-20091113204419-o5vbwnq5f7feedwu-231
  src/xdisp.c                    xdisp.c-20091113204419-o5vbwnq5f7feedwu-240
  src/xmenu.c                    xmenu.c-20091113204419-o5vbwnq5f7feedwu-161
  src/xterm.h                    xterm.h-20091113204419-o5vbwnq5f7feedwu-228
=== modified file 'ChangeLog'
--- a/ChangeLog 2013-10-08 05:12:29 +0000
+++ b/ChangeLog 2013-10-08 17:49:20 +0000
@@ -1,3 +1,7 @@
+2013-10-08  Eli Zaretskii  <address@hidden>
+
+       * configure.ac (HAVE_MENUS): Define unconditionally.
+
 2013-10-07  Paul Eggert  <address@hidden>
 
        Improve support for popcount and counting trailing zeros (Bug#15550).

=== modified file 'configure.ac'
--- a/configure.ac      2013-09-25 03:44:34 +0000
+++ b/configure.ac      2013-09-26 07:37:16 +0000
@@ -1898,11 +1898,8 @@
    fi
 fi
 
-### If we're using X11, we should use the X menu package.
-HAVE_MENUS=no
-case ${HAVE_X11} in
-  yes ) HAVE_MENUS=yes ;;
-esac
+### We always support menus.
+HAVE_MENUS=yes
 
 # Does the opsystem file prohibit the use of the GNU malloc?
 # Assume not, until told otherwise.
@@ -3183,15 +3180,9 @@
     ## Extra CFLAGS applied to src/*.m files.
     GNU_OBJC_CFLAGS="$GNU_OBJC_CFLAGS -fgnu-runtime -Wno-import 
-fconstant-string-class=NSConstantString -DGNUSTEP_BASE_LIBRARY=1 
-DGNU_GUI_LIBRARY=1 -DGNU_RUNTIME=1 -DGSWARN -DGSDIAGNOSE"
   fi
-  # We also have mouse menus.
-  HAVE_MENUS=yes
   OTHER_FILES=ns-app
 fi
 
-if test "${HAVE_W32}" = "yes"; then
-  HAVE_MENUS=yes
-fi
-
 ### Use session management (-lSM -lICE) if available
 HAVE_X_SM=no
 LIBXSM=
@@ -4672,9 +4663,7 @@
 
 if test "${HAVE_MENUS}" = "yes" ; then
   AC_DEFINE(HAVE_MENUS, 1,
-           [Define to 1 if you have mouse menus.
-            (This is automatic if you use X, but the option to specify it 
remains.)
-            It is also defined with other window systems that support 
xmenu.c.])
+           [Define to 1 if you have mouse menus.  (This is supported in all 
configurations, but the option to specify it remains.)])
 fi
 
 if test "${GNU_MALLOC}" = "yes" ; then

=== modified file 'doc/emacs/ChangeLog'
--- a/doc/emacs/ChangeLog       2013-10-06 09:46:04 +0000
+++ b/doc/emacs/ChangeLog       2013-10-08 17:49:20 +0000
@@ -1,3 +1,14 @@
+2013-10-08  Eli Zaretskii  <address@hidden>
+
+       Support menus on text-mode terminals.
+       * screen.texi (Menu Bar): Adapt to TTY menus.
+
+       * frames.texi (Frames): Mention menu support on text terminals.
+
+       * files.texi (Visiting): Mention the "File" menu-bar menu.
+
+       * display.texi (Standard Faces): Mention TTY faces for menus.
+
 2013-10-06  Xue Fuqiao  <address@hidden>
 
        * cal-xtra.texi (Calendar Customizing, Diary Display): Remove @refill.

=== modified file 'doc/emacs/display.texi'
--- a/doc/emacs/display.texi    2013-07-26 06:56:35 +0000
+++ b/doc/emacs/display.texi    2013-10-02 17:27:52 +0000
@@ -710,6 +710,17 @@
 @cindex customization of @code{menu} face
 This face determines the colors and font of Emacs's menus.  @xref{Menu
 Bars}.
address@hidden tty-menu-enabled-face
address@hidden faces for text-mode menus
address@hidden TTY menu faces
+This face is used to display enabled menu items on text-mode
+terminals.
address@hidden tty-menu-disabled-face
+This face is used to display disabled menu items on text-mode
+terminals.
address@hidden tty-menu-selected-face
+This face is used to display on text-mode terminals the menu item that
+would be selected if you click a mouse or press @key{RET}.
 @end table
 
 @node Text Scale

=== modified file 'doc/emacs/files.texi'
--- a/doc/emacs/files.texi      2013-08-14 10:45:10 +0000
+++ b/doc/emacs/files.texi      2013-10-02 17:27:52 +0000
@@ -286,6 +286,10 @@
 moves or copies the file into the displayed directory.  For details,
 see @ref{Drag and Drop}, and @ref{Misc Dired Features}.
 
+  On text-mode terminals and on graphical displays when Emacs was
+built without a GUI toolkit, you can visit files via the menu-bar
+``File'' menu, which has a ``Visit New File'' item.
+
   Each time you visit a file, Emacs automatically scans its contents
 to detect what character encoding and end-of-line convention it uses,
 and converts these to Emacs's internal encoding and end-of-line

=== modified file 'doc/emacs/frames.texi'
--- a/doc/emacs/frames.texi     2013-01-01 09:11:05 +0000
+++ b/doc/emacs/frames.texi     2013-10-02 17:27:52 +0000
@@ -39,7 +39,7 @@
 @ifnottex
 @pxref{MS-DOS Mouse},
 @end ifnottex
-for doing so on MS-DOS).
+for doing so on MS-DOS).  Menus are supported on all text terminals.
 
 @menu
 * Mouse Commands::      Moving, cutting, and pasting, with the mouse.

=== modified file 'doc/emacs/screen.texi'
--- a/doc/emacs/screen.texi     2013-01-01 09:11:05 +0000
+++ b/doc/emacs/screen.texi     2013-10-02 17:40:29 +0000
@@ -287,13 +287,12 @@
 
 @kindex M-`
 @kindex F10
address@hidden tmm-menubar
 @findex menu-bar-open
-  On a graphical display, you can use the mouse to choose a command
-from the menu bar.  An arrow on the right edge of a menu item means it
-leads to a subsidiary menu, or @dfn{submenu}.  A @samp{...} at the end
-of a menu item means that the command will prompt you for further
-input before it actually does anything.
+  On a display that support a mouse, you can use the mouse to choose a
+command from the menu bar.  An arrow on the right edge of a menu item
+means it leads to a subsidiary menu, or @dfn{submenu}.  A @samp{...}
+at the end of a menu item means that the command will prompt you for
+further input before it actually does anything.
 
   Some of the commands in the menu bar have ordinary key bindings as
 well; if so, a key binding is shown in parentheses after the item
@@ -305,14 +304,20 @@
 item by pressing @key{F10} (to run the command @code{menu-bar-open}).
 You can then navigate the menus with the arrow keys.  To activate a
 selected menu item, press @key{RET}; to cancel menu navigation, press
address@hidden
address@hidden or @kbd{ESC ESC ESC}.
 
-  On a text terminal, you can use the menu bar by typing @kbd{M-`} or
address@hidden (these run the command @code{tmm-menubar}).  This lets you
-select a menu item with the keyboard.  A provisional choice appears in
-the echo area.  You can use the up and down arrow keys to move through
-the menu to different items, and then you can type @key{RET} to select
-the item.  Each menu item is also designated by a letter or digit
-(usually the initial of some word in the item's name).  This letter or
-digit is separated from the item name by @samp{==>}.  You can type the
-item's letter or digit to select the item.
address@hidden tmm-menubar
address@hidden tty-menu-open-use-tmm
+  On a text terminal, you can optionally access the menu-bar menus in
+the echo area.  To this end, customize the variable
address@hidden to a address@hidden value.  Then typing
address@hidden will run the command @code{tmm-menubar} instead of dropping
+down the menu.  (You can also type @kbd{M-`}, which always invokes
address@hidden)  @code{tmm-menubar} lets you select a menu item
+with the keyboard.  A provisional choice appears in the echo area.
+You can use the up and down arrow keys to move through the menu to
+different items, and then you can type @key{RET} to select the item.
+Each menu item is also designated by a letter or digit (usually the
+initial of some word in the item's name).  This letter or digit is
+separated from the item name by @samp{==>}.  You can type the item's
+letter or digit to select the item.

=== modified file 'doc/lispref/ChangeLog'
--- a/doc/lispref/ChangeLog     2013-10-07 03:46:32 +0000
+++ b/doc/lispref/ChangeLog     2013-10-08 17:49:20 +0000
@@ -1,3 +1,12 @@
+2013-10-08  Eli Zaretskii  <address@hidden>
+
+       Support menus on text-mode terminals.
+       * keymaps.texi (Defining Menus, Mouse Menus, Menu Bar): Modify
+       wording to the effect that menus are supported on TTYs.
+
+       * frames.texi (Pop-Up Menus, Dialog Boxes)
+       (Display Feature Testing): Update for menu support on TTYs.
+
 2013-10-07  Stefan Monnier  <address@hidden>
 
        * tips.texi (Comment Tips): Discourage use of triple semi-colons for

=== modified file 'doc/lispref/frames.texi'
--- a/doc/lispref/frames.texi   2013-08-13 02:45:12 +0000
+++ b/doc/lispref/frames.texi   2013-10-03 19:10:34 +0000
@@ -1741,8 +1741,10 @@
 @node Pop-Up Menus
 @section Pop-Up Menus
 
-  When using a window system, a Lisp program can pop up a menu so that
-the user can choose an alternative with the mouse.
+  A Lisp program can pop up a menu so that the user can choose an
+alternative with the mouse.  On a text terminal, if the mouse is not
+available, the user can choose an alternative using the keyboard
+motion address@hidden, @kbd{C-p}, or up- and down-arrow keys.
 
 @defun x-popup-menu position menu
 This function displays a pop-up menu and returns an indication of
@@ -1763,20 +1765,22 @@
 may be a window or a frame.
 
 If @var{position} is @code{t}, it means to use the current mouse
-position.  If @var{position} is @code{nil}, it means to precompute the
-key binding equivalents for the keymaps specified in @var{menu},
-without actually displaying or popping up the menu.
+position (or the top-left corner of the frame if the mouse is not
+available on a text terminal).  If @var{position} is @code{nil}, it
+means to precompute the key binding equivalents for the keymaps
+specified in @var{menu}, without actually displaying or popping up the
+menu.
 
 The argument @var{menu} says what to display in the menu.  It can be a
 keymap or a list of keymaps (@pxref{Menu Keymaps}).  In this case, the
 return value is the list of events corresponding to the user's choice.
 This list has more than one element if the choice occurred in a
 submenu.  (Note that @code{x-popup-menu} does not actually execute the
-command bound to that sequence of events.)  On toolkits that support
-menu titles, the title is taken from the prompt string of @var{menu}
-if @var{menu} is a keymap, or from the prompt string of the first
-keymap in @var{menu} if it is a list of keymaps (@pxref{Defining
-Menus}).
+command bound to that sequence of events.)  On text terminals and
+toolkits that support menu titles, the title is taken from the prompt
+string of @var{menu} if @var{menu} is a keymap, or from the prompt
+string of the first keymap in @var{menu} if it is a list of keymaps
+(@pxref{Defining Menus}).
 
 Alternatively, @var{menu} can have the following form:
 
@@ -1800,7 +1804,7 @@
 
 If the user gets rid of the menu without making a valid choice, for
 instance by clicking the mouse away from a valid choice or by typing
-keyboard input, then this normally results in a quit and
address@hidden, then this normally results in a quit and
 @code{x-popup-menu} does not return.  But if @var{position} is a mouse
 button event (indicating that the user invoked the menu with the
 mouse) then no quit occurs and @code{x-popup-menu} returns @code{nil}.
@@ -1872,7 +1876,8 @@
 
 If @var{header} is address@hidden, the frame title for the box is
 @samp{Information}, otherwise it is @samp{Question}.  The former is used
-for @code{message-box} (@pxref{message-box}).
+for @code{message-box} (@pxref{message-box}).  (On text terminals, the
+box title is not displayed.)
 
 In some configurations, Emacs cannot display a real dialog box; so
 instead it displays the same items in a pop-up menu in the center of the
@@ -2284,9 +2289,9 @@
 
 @defun display-popup-menus-p &optional display
 This function returns @code{t} if popup menus are supported on
address@hidden, @code{nil} if not.  Support for popup menus requires that
-the mouse be available, since the user cannot choose menu items without
-a mouse.
address@hidden, @code{nil} if not.  Support for popup menus requires
+that the mouse be available, since the menu is popped up by clicking
+the mouse on some portion of the Emacs display.
 @end defun
 
 @defun display-graphic-p &optional display

=== modified file 'doc/lispref/keymaps.texi'
--- a/doc/lispref/keymaps.texi  2013-06-19 13:51:47 +0000
+++ b/doc/lispref/keymaps.texi  2013-10-03 19:10:34 +0000
@@ -2023,7 +2023,7 @@
 the menu's commands.  Emacs displays the overall prompt string as the
 menu title in some cases, depending on the toolkit (if any) used for
 displaying address@hidden is required for menus which do not use a
-toolkit, e.g., under MS-DOS.}  Keyboard menus also display the
+toolkit, e.g., on a text terminal.}  Keyboard menus also display the
 overall prompt string.
 
 The easiest way to construct a keymap with a prompt string is to
@@ -2371,16 +2371,17 @@
 items, the menu shows the contents of the nested keymap directly, not
 as a submenu.
 
-  However, if Emacs is compiled without X toolkit support, submenus
-are not supported.  Each nested keymap is shown as a menu item, but
-clicking on it does not automatically pop up the submenu.  If you wish
-to imitate the effect of submenus, you can do that by giving a nested
-keymap an item string which starts with @samp{@@}.  This causes Emacs
-to display the nested keymap using a separate @dfn{menu pane}; the
-rest of the item string after the @samp{@@} is the pane label.  If
-Emacs is compiled without X toolkit support, menu panes are not used;
-in that case, a @samp{@@} at the beginning of an item string is
-omitted when the menu label is displayed, and has no other effect.
+  However, if Emacs is compiled without X toolkit support, or on text
+terminals, submenus are not supported.  Each nested keymap is shown as
+a menu item, but clicking on it does not automatically pop up the
+submenu.  If you wish to imitate the effect of submenus, you can do
+that by giving a nested keymap an item string which starts with
address@hidden@@}.  This causes Emacs to display the nested keymap using a
+separate @dfn{menu pane}; the rest of the item string after the
address@hidden@@} is the pane label.  If Emacs is compiled without X toolkit
+support, or if a menu is displayed on a text terminal, menu panes are
+not used; in that case, a @samp{@@} at the beginning of an item string
+is omitted when the menu label is displayed, and has no other effect.
 
 @node Keyboard Menus
 @subsection Menus and the Keyboard
@@ -2485,10 +2486,10 @@
 @subsection The Menu Bar
 @cindex menu bar
 
-  On graphical displays, there is usually a @dfn{menu bar} at the top
-of each frame.  @xref{Menu Bars,,,emacs, The GNU Emacs Manual}.  Menu
-bar items are subcommands of the fake ``function key''
address@hidden, as defined in the active keymaps.
+  Emacs usually shows a @dfn{menu bar} at the top of each frame.
address@hidden Bars,,,emacs, The GNU Emacs Manual}.  Menu bar items are
+subcommands of the fake ``function key'' @code{menu-bar}, as defined
+in the active keymaps.
 
   To add an item to the menu bar, invent a fake ``function key'' of your
 own (let's call it @var{key}), and make a binding for the key sequence
@@ -2575,7 +2576,7 @@
 
   A @dfn{tool bar} is a row of clickable icons at the top of a frame,
 just below the menu bar.  @xref{Tool Bars,,,emacs, The GNU Emacs
-Manual}.
+Manual}.  Emacs normally shows a tool bar on graphical displays.
 
   On each frame, the frame parameter @code{tool-bar-lines} controls
 how many lines' worth of height to reserve for the tool bar.  A zero

=== modified file 'etc/NEWS'
--- a/etc/NEWS  2013-10-08 06:17:49 +0000
+++ b/etc/NEWS  2013-10-08 17:49:20 +0000
@@ -65,6 +65,22 @@
 
 * Changes in Emacs 24.4
 
++++
+** Emacs now supports menus on text-mode terminals.
+If the terminal supports a mouse, clicking on the menu bar, or on
+sensitive portions of the mode line or header line, will drop down the
+menu defined at that position.  Likewise, clicking C-mouse-2 or
+C-mouse-2 or C-mouse-3 on the text area will pop up the menus defined
+for those locations.
+
+If the text terminal does not support a mouse, you can activate the
+first menu-bar menu by typing F10, which invokes `menu-bar-open'.
+
+If you want the previous behavior, whereby F10 invoked `tmm-menubar',
+customize the option `tty-menu-open-use-tmm' to a non-nil value.
+(Typing M-` will always invoke `tmm-menubar', even if
+`tty-menu-open-use-tmm' is nil.)
+
 ** Key ? also describes prefix bindings like C-h.
 
 +++
@@ -653,6 +669,16 @@
 
 * Lisp Changes in Emacs 24.4
 
++++
+** Functions that pop up menus and dialogs now work on all terminal types,
+including TTYs.
+This includes `x-popup-menu', `x-popup-dialog', `message-box',
+`yes-or-no-p', etc.
+
+The function `display-popup-menus-p' will now return non-nil for a
+display or frame whenever a mouse is supported on that display or
+frame.
+
 ** New bool-vector set operation functions:
 *** `bool-vector-exclusive-or'
 *** `bool-vector-union'

=== modified file 'lisp/ChangeLog'
--- a/lisp/ChangeLog    2013-10-08 14:57:18 +0000
+++ b/lisp/ChangeLog    2013-10-08 17:49:20 +0000
@@ -1,3 +1,27 @@
+2013-10-08  Eli Zaretskii  <address@hidden>
+
+       Support menus on text-mode terminals.
+       * tmm.el (tmm-menubar): Adapt doc string to TTY menus
+       functionality.
+
+       * tooltip.el (tooltip-mode): Don't error out on TTYs.
+
+       * menu-bar.el (popup-menu, popup-menu-normalize-position): Moved
+       here from mouse.el.
+       (popup-menu): Support menu-bar navigation on TTYs using C-f/C-b
+       and arrow keys.
+       (tty-menu-navigation-map): New map for TTY menu navigation.
+
+       * loadup.el ("tooltip"): Load even if x-show-tip is not available.
+
+       * frame.el (display-mouse-p): Report text-mode mouse as available
+       on w32.
+       (display-popup-menus-p): Report availability if mouse is
+       available; don't condition on window-system.
+
+       * faces.el (tty-menu-enabled-face, tty-menu-disabled-face)
+       (tty-menu-selected-face): New faces.
+
 2013-10-08  Stefan Monnier  <address@hidden>
 
        * emacs-lisp/lisp-mode.el: Font-lock cl-lib constructs.

=== modified file 'lisp/faces.el'
--- a/lisp/faces.el     2013-09-28 10:01:50 +0000
+++ b/lisp/faces.el     2013-10-08 17:49:20 +0000
@@ -2142,7 +2142,6 @@
     (frame-set-background-mode frame t)
     (face-set-after-frame-default frame)))
 
-
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;; Standard faces.
@@ -2551,6 +2550,26 @@
   :version "24.1"
   :group 'basic-faces)
 
+;; Faces for TTY menus.
+(defface tty-menu-enabled-face
+  '((t
+     :foreground "yellow" :background "blue" :weight bold))
+  "Face for displaying enabled items in TTY menus."
+  :group 'basic-faces)
+
+(defface tty-menu-disabled-face
+  '((((class color) (min-colors 16))
+     :foreground "lightgray" :background "blue")
+    (t
+     :foreground "white" :background "blue"))
+  "Face for displaying disabled items in TTY menus."
+  :group 'basic-faces)
+
+(defface tty-menu-selected-face
+  '((t :background "red"))
+  "Face for displaying the currently selected item in TTY menus."
+  :group 'basic-faces)
+
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;; Manipulating font names.

=== modified file 'lisp/frame.el'
--- a/lisp/frame.el     2013-09-18 03:58:26 +0000
+++ b/lisp/frame.el     2013-10-02 18:44:40 +0000
@@ -1304,17 +1304,17 @@
               xterm-mouse-mode)
          ;; t-mouse is distributed with the GPM package.  It doesn't have
          ;; a toggle.
-         (featurep 't-mouse))))))
+         (featurep 't-mouse)
+         ;; No way to check whether a w32 console has a mouse, assume
+         ;; it always does.
+         (boundp 'w32-use-full-screen-buffer))))))
 
 (defun display-popup-menus-p (&optional display)
   "Return non-nil if popup menus are supported on DISPLAY.
 DISPLAY can be a display name, a frame, or nil (meaning the selected
 frame's display).
 Support for popup menus requires that the mouse be available."
-  (and
-   (let ((frame-type (framep-on-display display)))
-     (memq frame-type '(x w32 pc ns)))
-   (display-mouse-p display)))
+  (display-mouse-p display))
 
 (defun display-graphic-p (&optional display)
   "Return non-nil if DISPLAY is a graphic display.

=== modified file 'lisp/loadup.el'
--- a/lisp/loadup.el    2013-08-05 18:05:46 +0000
+++ b/lisp/loadup.el    2013-10-08 15:11:29 +0000
@@ -276,7 +276,7 @@
 
 (load "vc/vc-hooks")
 (load "vc/ediff-hook")
-(if (fboundp 'x-show-tip) (load "tooltip"))
+(if (not (eq system-type 'ms-dos)) (load "tooltip"))
 
 ;If you want additional libraries to be preloaded and their
 ;doc strings kept in the DOC file rather than in core,

=== modified file 'lisp/menu-bar.el'
--- a/lisp/menu-bar.el  2013-08-16 06:50:58 +0000
+++ b/lisp/menu-bar.el  2013-10-08 15:11:29 +0000
@@ -2182,13 +2182,211 @@
 (declare-function x-menu-bar-open "term/x-win" (&optional frame))
 (declare-function w32-menu-bar-open "term/w32-win" (&optional frame))
 
+(defun popup-menu (menu &optional position prefix from-menu-bar)
+  "Popup the given menu and call the selected option.
+MENU can be a keymap, an easymenu-style menu or a list of keymaps as for
+`x-popup-menu'.
+The menu is shown at the place where POSITION specifies. About
+the form of POSITION, see `popup-menu-normalize-position'.
+PREFIX is the prefix argument (if any) to pass to the command.
+FROM-MENU-BAR, if non-nil, means we are dropping one of menu-bar's menus."
+  (let* ((map (cond
+              ((keymapp menu) menu)
+              ((and (listp menu) (keymapp (car menu))) menu)
+              (t (let* ((map (easy-menu-create-menu (car menu) (cdr menu)))
+                        (filter (when (symbolp map)
+                                  (plist-get (get map 'menu-prop) :filter))))
+                   (if filter (funcall filter (symbol-function map)) map)))))
+        (frame (selected-frame))
+        event cmd)
+    (if from-menu-bar
+       (let* ((xy (posn-x-y position))
+              (menu-symbol (menu-bar-menu-at-x-y (car xy) (cdr xy))))
+         (setq position (list menu-symbol (list frame '(menu-bar)
+                                                xy 0))))
+      (setq position (popup-menu-normalize-position position)))
+    ;; The looping behavior was taken from lmenu's popup-menu-popup
+    (while (and map (setq event
+                         ;; map could be a prefix key, in which case
+                         ;; we need to get its function cell
+                         ;; definition.
+                         (x-popup-menu position (indirect-function map))))
+      ;; Strangely x-popup-menu returns a list.
+      ;; mouse-major-mode-menu was using a weird:
+      ;; (key-binding (apply 'vector (append '(menu-bar) menu-prefix events)))
+      (setq cmd
+           (cond
+            ((and from-menu-bar
+                  (consp event)
+                  (numberp (car event))
+                  (numberp (cdr event)))
+             (let ((x (car event))
+                   (y (cdr event))
+                   menu-symbol)
+               (setq menu-symbol (menu-bar-menu-at-x-y x y))
+               (setq position (list menu-symbol (list frame '(menu-bar)
+                                                event 0)))
+               (setq map
+                     (or
+                      (lookup-key global-map (vector 'menu-bar menu-symbol))
+                      (lookup-key (current-local-map) (vector 'menu-bar
+                                                              menu-symbol))))))
+            ((and (not (keymapp map)) (listp map))
+             ;; We were given a list of keymaps.  Search them all
+             ;; in sequence until a first binding is found.
+             (let ((mouse-click (apply 'vector event))
+                   binding)
+               (while (and map (null binding))
+                 (setq binding (lookup-key (car map) mouse-click))
+                 (if (numberp binding) ; `too long'
+                     (setq binding nil))
+                 (setq map (cdr map)))
+                 binding))
+            (t
+             ;; We were given a single keymap.
+             (lookup-key map (apply 'vector event)))))
+      ;; Clear out echoing, which perhaps shows a prefix arg.
+      (message "")
+      ;; Maybe try again but with the submap.
+      (setq map (if (keymapp cmd) cmd)))
+    ;; If the user did not cancel by refusing to select,
+    ;; and if the result is a command, run it.
+    (when (and (null map) (commandp cmd))
+      (setq prefix-arg prefix)
+      ;; `setup-specified-language-environment', for instance,
+      ;; expects this to be set from a menu keymap.
+      (setq last-command-event (car (last event)))
+      ;; mouse-major-mode-menu was using `command-execute' instead.
+      (call-interactively cmd))))
+
+(defun popup-menu-normalize-position (position)
+  "Convert the POSITION to the form which `popup-menu' expects internally.
+POSITION can an event, a posn- value, a value having
+form ((XOFFSET YOFFSET) WINDOW), or nil.
+If nil, the current mouse position is used."
+  (pcase position
+    ;; nil -> mouse cursor position
+    (`nil
+     (let ((mp (mouse-pixel-position)))
+       (list (list (cadr mp) (cddr mp)) (car mp))))
+    ;; Value returned from `event-end' or `posn-at-point'.
+    ((pred posnp)
+     (let ((xy (posn-x-y position)))
+       (list (list (car xy) (cdr xy))
+            (posn-window position))))
+    ;; Event.
+    ((pred eventp)
+     (popup-menu-normalize-position (event-end position)))
+    (t position)))
+
+(defvar tty-menu-navigation-map
+  (let ((map (make-sparse-keymap)))
+    ;; The next line is disabled because it breaks interpretation of
+    ;; escape sequences, produced by TTY arrow keys, as tty-menu-*
+    ;; commands.  Instead, we explicitly bind some keys to
+    ;; tty-menu-exit.
+    ;;(define-key map [t] 'tty-menu-exit)
+
+    ;; The tty-menu-* are just symbols interpreted by term.c, they are
+    ;; not real commands.
+    (substitute-key-definition 'keyboard-quit 'tty-menu-exit
+                              map (current-global-map))
+    (substitute-key-definition 'keyboard-escape-quit 'tty-menu-exit
+                              map (current-global-map))
+    ;; The bindings of menu-bar items are so that clicking on the menu
+    ;; bar when a menu is already shown pops down that menu.
+    ;; FIXME: we should iterate over all the visible menu-bar items,
+    ;; instead of naming them explicitly here.  Also, this doesn't
+    ;; include items added by current major mode.
+    (substitute-key-definition (lookup-key (current-global-map) [menu-bar 
file])
+                              'tty-menu-exit
+                              map (current-global-map))
+    (substitute-key-definition (lookup-key (current-global-map) [menu-bar 
edit])
+                              'tty-menu-exit
+                              map (current-global-map))
+    (substitute-key-definition (lookup-key (current-global-map) [menu-bar 
options])
+                              'tty-menu-exit
+                              map (current-global-map))
+    (substitute-key-definition (lookup-key (current-global-map) [menu-bar 
buffer])
+                              'tty-menu-exit
+                              map (current-global-map))
+    (substitute-key-definition (lookup-key (current-global-map) [menu-bar 
tools])
+                              'tty-menu-exit
+                              map (current-global-map))
+    (substitute-key-definition (lookup-key (current-global-map) [menu-bar 
help-menu])
+                              'tty-menu-exit
+                              map (current-global-map))
+    (substitute-key-definition 'forward-char 'tty-menu-next-menu
+                              map (current-global-map))
+    (substitute-key-definition 'backward-char 'tty-menu-prev-menu
+                              map (current-global-map))
+    ;; The following two will need to be revised if we ever support
+    ;; a right-to-left menu bar.
+    (substitute-key-definition 'right-char 'tty-menu-next-menu
+                              map (current-global-map))
+    (substitute-key-definition 'left-char 'tty-menu-prev-menu
+                              map (current-global-map))
+    (substitute-key-definition 'next-line 'tty-menu-next-item
+                              map (current-global-map))
+    (substitute-key-definition 'previous-line 'tty-menu-prev-item
+                              map (current-global-map))
+    (substitute-key-definition 'newline 'tty-menu-select
+                              map (current-global-map))
+    (substitute-key-definition 'newline-and-indent 'tty-menu-select
+                              map (current-global-map))
+    (define-key map [?\C-r] 'tty-menu-select)
+    (define-key map [?\C-j] 'tty-menu-select)
+    (define-key map [return] 'tty-menu-select)
+    (define-key map [linefeed] 'tty-menu-select)
+    (define-key map [down-mouse-1] 'tty-menu-select)
+    (define-key map [drag-mouse-1] 'tty-menu-select)
+    (define-key map [mode-line drag-mouse-1] 'tty-menu-select)
+    (define-key map [mode-line down-mouse-1] 'tty-menu-select)
+    (define-key map [header-line mouse-1] 'tty-menu-select)
+    (define-key map [header-line drag-mouse-1] 'tty-menu-select)
+    (define-key map [header-line down-mouse-1] 'tty-menu-select)
+    (define-key map [mode-line mouse-1] 'tty-menu-ignore)
+    (define-key map [mode-line mouse-2] 'tty-menu-ignore)
+    (define-key map [mode-line mouse-3] 'tty-menu-ignore)
+    (define-key map [mode-line C-mouse-1] 'tty-menu-ignore)
+    (define-key map [mode-line C-mouse-2] 'tty-menu-ignore)
+    (define-key map [mode-line C-mouse-3] 'tty-menu-ignore)
+    ;; The mouse events must be bound to tty-menu-ignore, otherwise
+    ;; the initial mouse click will select and immediately pop down
+    ;; the menu.
+    (define-key map [mouse-1] 'tty-menu-ignore)
+    (define-key map [C-mouse-1] 'tty-menu-ignore)
+    (define-key map [C-mouse-2] 'tty-menu-ignore)
+    (define-key map [C-mouse-3] 'tty-menu-ignore)
+    (define-key map [mouse-movement] 'tty-menu-mouse-movement)
+    map)
+  "Keymap used while processing TTY menus.")
+
+
+(defcustom tty-menu-open-use-tmm nil
+  "If non-nil, \\[menu-bar-open] on a TTY will invoke `tmm-menubar'.
+
+If nil, \\[menu-bar-open] will drop down the menu corresponding to the
+first (leftmost) menu-bar item; you can select other items by typing
+\\[forward-char], \\[backward-char], \\[right-char] and \\[left-char]."
+  :type '(choice (const :tag "F10 drops down TTY menus" nil)
+                (const :tag "F10 invokes tmm-menubar" t))
+  :group 'display
+  :version "24.4")
+
+(defvar tty-menu--initial-menu-x 1
+  "X coordinate of the first menu-bar menu dropped by F10.
+
+This is meant to be used only for debugging TTY menus.")
+
 (defun menu-bar-open (&optional frame)
   "Start key navigation of the menu bar in FRAME.
 
 This function decides which method to use to access the menu
 depending on FRAME's terminal device.  On X displays, it calls
-`x-menu-bar-open'; on Windows, `w32-menu-bar-open' otherwise it
-calls `tmm-menubar'.
+`x-menu-bar-open'; on Windows, `w32-menu-bar-open'; otherwise it
+calls either `popup-menu' or `tmm-menubar' depending on whether
+\`tty-menu-open-use-tmm' is nil or not.
 
 If FRAME is nil or not given, use the selected frame."
   (interactive)
@@ -2196,6 +2394,13 @@
     (cond
      ((eq type 'x) (x-menu-bar-open frame))
      ((eq type 'w32) (w32-menu-bar-open frame))
+     ((null tty-menu-open-use-tmm)
+      (let* ((x tty-menu--initial-menu-x)
+            (menu (menu-bar-menu-at-x-y x 0 frame)))
+       (popup-menu (or
+                    (lookup-key global-map (vector 'menu-bar menu))
+                    (lookup-key (current-local-map) (vector 'menu-bar menu)))
+                   (posn-at-x-y x 0 nil t) nil t)))
      (t (with-selected-frame (or frame (selected-frame))
           (tmm-menubar))))))
 

=== modified file 'lisp/mouse.el'
--- a/lisp/mouse.el     2013-09-18 04:21:29 +0000
+++ b/lisp/mouse.el     2013-09-26 07:37:16 +0000
@@ -144,79 +144,6 @@
 
 ;; Provide a mode-specific menu on a mouse button.
 
-(defun popup-menu (menu &optional position prefix)
-  "Popup the given menu and call the selected option.
-MENU can be a keymap, an easymenu-style menu or a list of keymaps as for
-`x-popup-menu'.
-The menu is shown at the place where POSITION specifies. About
-the form of POSITION, see `popup-menu-normalize-position'.
-PREFIX is the prefix argument (if any) to pass to the command."
-  (let* ((map (cond
-              ((keymapp menu) menu)
-              ((and (listp menu) (keymapp (car menu))) menu)
-              (t (let* ((map (easy-menu-create-menu (car menu) (cdr menu)))
-                        (filter (when (symbolp map)
-                                  (plist-get (get map 'menu-prop) :filter))))
-                   (if filter (funcall filter (symbol-function map)) map)))))
-        event cmd
-        (position (popup-menu-normalize-position position)))
-    ;; The looping behavior was taken from lmenu's popup-menu-popup
-    (while (and map (setq event
-                         ;; map could be a prefix key, in which case
-                         ;; we need to get its function cell
-                         ;; definition.
-                         (x-popup-menu position (indirect-function map))))
-      ;; Strangely x-popup-menu returns a list.
-      ;; mouse-major-mode-menu was using a weird:
-      ;; (key-binding (apply 'vector (append '(menu-bar) menu-prefix events)))
-      (setq cmd
-           (if (and (not (keymapp map)) (listp map))
-               ;; We were given a list of keymaps.  Search them all
-               ;; in sequence until a first binding is found.
-               (let ((mouse-click (apply 'vector event))
-                     binding)
-                 (while (and map (null binding))
-                   (setq binding (lookup-key (car map) mouse-click))
-                   (if (numberp binding)       ; `too long'
-                       (setq binding nil))
-                   (setq map (cdr map)))
-                 binding)
-             ;; We were given a single keymap.
-             (lookup-key map (apply 'vector event))))
-      ;; Clear out echoing, which perhaps shows a prefix arg.
-      (message "")
-      ;; Maybe try again but with the submap.
-      (setq map (if (keymapp cmd) cmd)))
-    ;; If the user did not cancel by refusing to select,
-    ;; and if the result is a command, run it.
-    (when (and (null map) (commandp cmd))
-      (setq prefix-arg prefix)
-      ;; `setup-specified-language-environment', for instance,
-      ;; expects this to be set from a menu keymap.
-      (setq last-command-event (car (last event)))
-      ;; mouse-major-mode-menu was using `command-execute' instead.
-      (call-interactively cmd))))
-
-(defun popup-menu-normalize-position (position)
-  "Convert the POSITION to the form which `popup-menu' expects internally.
-POSITION can an event, a posn- value, a value having
-form ((XOFFSET YOFFSET) WINDOW), or nil.
-If nil, the current mouse position is used."
-  (pcase position
-    ;; nil -> mouse cursor position
-    (`nil
-     (let ((mp (mouse-pixel-position)))
-       (list (list (cadr mp) (cddr mp)) (car mp))))
-    ;; Value returned from `event-end' or `posn-at-point'.
-    ((pred posnp)
-     (let ((xy (posn-x-y position)))
-       (list (list (car xy) (cdr xy))
-            (posn-window position))))
-    ;; Event.
-    ((pred eventp)
-     (popup-menu-normalize-position (event-end position)))
-    (t position)))
-
 (defun minor-mode-menu-from-indicator (indicator)
   "Show menu for minor mode specified by INDICATOR.
 Interactively, INDICATOR is read using completion.

=== modified file 'lisp/tmm.el'
--- a/lisp/tmm.el       2013-02-13 13:40:00 +0000
+++ b/lisp/tmm.el       2013-10-08 09:01:26 +0000
@@ -50,7 +50,11 @@
   "Text-mode emulation of looking and choosing from a menubar.
 See the documentation for `tmm-prompt'.
 X-POSITION, if non-nil, specifies a horizontal position within the menu bar;
-we make that menu bar item (the one at that position) the default choice."
+we make that menu bar item (the one at that position) the default choice.
+
+Note that \\[menu-bar-open] by default drops down TTY menus; if you want it
+to invoke `tmm-menubar' instead, customize the variable
+\`tty-menu-open-use-tmm' to a non-nil value."
   (interactive)
   (run-hooks 'menu-bar-update-hook)
   ;; Obey menu-bar-final-items; put those items last.

=== modified file 'lisp/tooltip.el'
--- a/lisp/tooltip.el   2013-05-24 06:50:22 +0000
+++ b/lisp/tooltip.el   2013-10-08 15:11:29 +0000
@@ -58,9 +58,7 @@
   :init-value t
   :initialize 'custom-initialize-delay
   :group 'tooltip
-  (unless (or (null tooltip-mode) (fboundp 'x-show-tip))
-    (error "Sorry, tooltips are not yet available on this system"))
-  (if tooltip-mode
+  (if (and tooltip-mode (fboundp 'x-show-tip))
       (progn
        (add-hook 'pre-command-hook 'tooltip-hide)
        (add-hook 'tooltip-functions 'tooltip-help-tips))

=== modified file 'src/ChangeLog'
--- a/src/ChangeLog     2013-10-08 14:56:15 +0000
+++ b/src/ChangeLog     2013-10-08 17:49:20 +0000
@@ -1,3 +1,116 @@
+2013-10-08  Eli Zaretskii  <address@hidden>
+
+       Support menus on text-mode terminals.
+       * xterm.h (xw_popup_dialog): Add prototype.
+
+       * xmenu.c (Fx_popup_dialog): Function moved to menu.c.
+       (xmenu_show): Block input here, instead in Fx_popup_menu.
+       (xw_popup_dialog): New function, with X-specific bits of popup
+       dialogs.
+
+       * xdisp.c (deep_copy_glyph_row, display_tty_menu_item): New
+       functions.
+
+       * window.c (Fset_window_configuration): Use run-time tests of the
+       frame type instead of compile-time conditionals, when menu-bar
+       lines are considered.
+
+       * w32term.h (w32con_hide_cursor, w32con_show_cursor)
+       (w32_popup_dialog): New prototypes.
+
+       * w32menu.c (Fx_popup_dialog): Function deleted.
+       (w32_popup_dialog): New function, with w32 specific bits of popup
+       dialogs.  Block input here.
+
+       * w32inevt.c (w32_console_read_socket): Minor change to add
+       debugging TTY events.
+
+       * w32fns.c (show_hourglass): If returning early because the frame
+       is not a GUI frame, unblock input.
+
+       * w32console.c (w32con_hide_cursor, w32con_show_cursor, cursorX)
+       (cursorY): New functions.
+
+       * termhooks.h (cursorX, cursorY): Prototypes of functions on
+       WINDOWSNT, macros that call curX and curY elsewhere.
+
+       * termchar.h (struct tty_display_info) <showing_menu>: New flag.
+
+       * term.c (tty_hide_cursor, tty_show_cursor) [WINDOWSNT]: Call w32
+       specific function to hide and show cursor on a text-mode terminal.
+       (tty_menu_struct, struct tty_menu_state): New structures.
+       (tty_menu_create, tty_menu_make_room, tty_menu_search_pane)
+       (tty_menu_calc_size, mouse_get_xy, tty_menu_display)
+       (have_menus_p, tty_menu_add_pane, tty_menu_add_selection)
+       (tty_menu_locate, save_and_enable_current_matrix)
+       (restore_desired_matrix, screen_update, read_menu_input)
+       (tty_menu_activate, tty_menu_destroy, tty_menu_help_callback)
+       (tty_pop_down_menu, tty_menu_last_menubar_item)
+       (tty_menu_new_item_coords, tty_menu_show): New functions.
+       (syms_of_term): New DEFSYMs for tty-menu-* symbols.
+
+       * nsterm.h (ns_popup_dialog): Adjust prototype.
+
+       * nsmenu.m (ns_menu_show): Block and unblock input here, instead
+       of in x-popup-menu.
+       (ns_popup_dialog): Adapt order of arguments to the other
+       *_menu_show implementations.
+       (Fx_popup_dialog): Function deleted.
+
+       * msdos.c (x_set_menu_bar_lines): Delete unused function.
+
+       * menu.h (tty_menu_show, menu_item_width): provide prototypes.
+
+       * menu.c (have_boxes): New function.
+       (single_keymap_panes): Use it instead of a compile-time
+       conditional.
+       (single_menu_item): Use run-time tests of the frame type instead
+       of compile-time conditionals.
+       (encode_menu_string): New function.
+       (list_of_items, list_of_panes): Use it instead of ENCODE_STRING
+       the macro, since different types of frame need different encoding
+       of menu items.
+       (digest_single_submenu): Use run-time tests of frame type instead
+       of, or in addition to, compile-time conditionals.
+       (menu_item_width, Fmenu_bar_menu_at_x_y): New functions.
+       (Fx_popup_menu): Detect when the function is called from keyboard
+       on a TTY.  Don't barf when invoked on a text-mode frame.  Check
+       frame type at run time, instead of compile-time conditionals for
+       invoking terminal-specific menu-show functions.  Call
+       tty_menu_show on text-mode frames.
+       (Fx_popup_dialog): Moved here from xmenu.c.  Test frame types at
+       run time to determine which alternative to invoke; support dialogs
+       on TTYs.
+
+       * keyboard.h <Qmouse_movement>: Declare.
+
+       * keyboard.c <Qmouse_movement>: Now extern.
+       <Qecho_keystrokes>: New static variable.
+       (read_key_sequence): Accept an additional argument, a flag to
+       prevent redisplay during reading of the key sequence.  All callers
+       changed.
+       (read_menu_command): New function.
+       (read_char): When COMMANDFLAG is -2, do not redisplay and do not
+       autosave.
+       (toolkit_menubar_in_use): New function.
+       (make_lispy_event): Use it instead of a compile-time test.
+
+       * fns.c (Fyes_or_no_p) [HAVE_MENUS]: Don't condition on
+       window-system being available.
+
+       * editfns.c (Fmessage_box) [HAVE_MENUS]: Don't condition the call
+       to x-popup-dialog on the frame type, they all now support popup
+       dialogs.
+
+       * dispnew.c (save_current_matrix): Save the margin areas.
+       (restore_current_matrix): Restore margin areas.
+       (update_frame_with_menu): New function.
+
+       * dispextern.h (display_tty_menu_item, update_frame_with_menu):
+       Add prototypes.
+
+       * alloc.c (make_save_ptr): Now compiled unconditionally.
+
 2013-10-08  Dmitry Antipov  <address@hidden>
 
        * dispnew.c (set_window_update_flags): Add buffer arg.  Adjust comment.

=== modified file 'src/alloc.c'
--- a/src/alloc.c       2013-10-08 04:25:33 +0000
+++ b/src/alloc.c       2013-10-08 17:49:20 +0000
@@ -3408,7 +3408,6 @@
   return val;
 }
 
-#if defined HAVE_NS || defined HAVE_NTGUI
 Lisp_Object
 make_save_ptr (void *a)
 {
@@ -3418,7 +3417,6 @@
   p->data[0].pointer = a;
   return val;
 }
-#endif
 
 Lisp_Object
 make_save_ptr_int (void *a, ptrdiff_t b)

=== modified file 'src/cm.h'
--- a/src/cm.h  2013-01-01 09:11:05 +0000
+++ b/src/cm.h  2013-09-05 11:00:55 +0000
@@ -139,7 +139,7 @@
 #define MultiDownCost(tty)     (tty)->Wcm->cc_multidown
 #define MultiLeftCost(tty)     (tty)->Wcm->cc_multileft
 #define MultiRightCost(tty)    (tty)->Wcm->cc_multiright
-#endif
+#endif /* NoCMShortHand */
 
 #define cmat(tty,row,col)      (curY(tty) = (row), curX(tty) = (col))
 #define cmplus(tty,n)                                              \

=== modified file 'src/dispextern.h'
--- a/src/dispextern.h  2013-10-08 14:56:15 +0000
+++ b/src/dispextern.h  2013-10-08 17:49:20 +0000
@@ -3256,6 +3256,7 @@
 extern int cursor_in_mouse_face_p (struct window *w);
 extern void tty_draw_row_with_mouse_face (struct window *, struct glyph_row *,
                                          int, int, enum draw_glyphs_face);
+extern void display_tty_menu_item (const char *, int, int, int, int, int);
 
 /* Flags passed to try_window.  */
 #define TRY_WINDOW_CHECK_MARGINS       (1 << 0)
@@ -3427,6 +3428,8 @@
 
 int popup_activated (void);
 
+/* Defined in dispnew.c */
+
 extern Lisp_Object buffer_posn_from_coords (struct window *,
                                             int *, int *,
                                             struct display_pos *,
@@ -3442,6 +3445,7 @@
                                          int *, int *, int *, int *);
 extern void redraw_frame (struct frame *);
 extern bool update_frame (struct frame *, bool, bool);
+extern void update_frame_with_menu (struct frame *);
 extern void bitch_at_user (void);
 extern void adjust_frame_glyphs (struct frame *);
 void free_glyphs (struct frame *);
@@ -3467,7 +3471,7 @@
 void init_display (void);
 void syms_of_display (void);
 extern Lisp_Object Qredisplay_dont_pause;
-void spec_glyph_lookup_face (struct window *, GLYPH *);
+extern void spec_glyph_lookup_face (struct window *, GLYPH *);
 
 /* Defined in terminal.c */
 

=== modified file 'src/dispnew.c'
--- a/src/dispnew.c     2013-10-08 14:56:15 +0000
+++ b/src/dispnew.c     2013-10-08 17:49:20 +0000
@@ -1844,9 +1844,28 @@
       struct glyph_row *from = f->current_matrix->rows + i;
       struct glyph_row *to = saved->rows + i;
       ptrdiff_t nbytes = from->used[TEXT_AREA] * sizeof (struct glyph);
+
       to->glyphs[TEXT_AREA] = xmalloc (nbytes);
       memcpy (to->glyphs[TEXT_AREA], from->glyphs[TEXT_AREA], nbytes);
       to->used[TEXT_AREA] = from->used[TEXT_AREA];
+      to->enabled_p = from->enabled_p;
+      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;
@@ -1866,9 +1885,30 @@
       struct glyph_row *from = saved->rows + i;
       struct glyph_row *to = f->current_matrix->rows + i;
       ptrdiff_t nbytes = from->used[TEXT_AREA] * sizeof (struct glyph);
+
       memcpy (to->glyphs[TEXT_AREA], from->glyphs[TEXT_AREA], nbytes);
       to->used[TEXT_AREA] = from->used[TEXT_AREA];
       xfree (from->glyphs[TEXT_AREA]);
+      nbytes = from->used[LEFT_MARGIN_AREA] * sizeof (struct glyph);
+      if (nbytes)
+       {
+         memcpy (to->glyphs[LEFT_MARGIN_AREA],
+                 from->glyphs[LEFT_MARGIN_AREA], nbytes);
+         to->used[LEFT_MARGIN_AREA] = from->used[LEFT_MARGIN_AREA];
+         xfree (from->glyphs[LEFT_MARGIN_AREA]);
+       }
+      else
+       to->used[LEFT_MARGIN_AREA] = 0;
+      nbytes = from->used[RIGHT_MARGIN_AREA] * sizeof (struct glyph);
+      if (nbytes)
+       {
+         memcpy (to->glyphs[RIGHT_MARGIN_AREA],
+                 from->glyphs[RIGHT_MARGIN_AREA], nbytes);
+         to->used[RIGHT_MARGIN_AREA] = from->used[RIGHT_MARGIN_AREA];
+         xfree (from->glyphs[RIGHT_MARGIN_AREA]);
+       }
+      else
+       to->used[RIGHT_MARGIN_AREA] = 0;
     }
 
   xfree (saved->rows);
@@ -3047,6 +3087,47 @@
   return paused_p;
 }
 
+/* Update a TTY frame F that has a menu dropped down over some of its
+   glyphs.  This is like the second part of update_frame, but it
+   doesn't call build_frame_matrix, because we already have the
+   desired matrix prepared, and don't want it to be overwritten by the
+   text of the normal display.  */
+void
+update_frame_with_menu (struct frame *f)
+{
+  struct window *root_window = XWINDOW (f->root_window);
+  bool paused_p;
+
+  eassert (FRAME_TERMCAP_P (f));
+
+  /* We are working on frame matrix basis.  Set the frame on whose
+     frame matrix we operate.  */
+  set_frame_matrix_frame (f);
+
+  /* Update the display  */
+  update_begin (f);
+  /* Force update_frame_1 not to stop due to pending input, and not
+     try scrolling.  */
+  paused_p = update_frame_1 (f, 1, 1);
+  update_end (f);
+
+  if (FRAME_TTY (f)->termscript)
+    fflush (FRAME_TTY (f)->termscript);
+  fflush (FRAME_TTY (f)->output);
+  /* Check window matrices for lost pointers.  */
+#if GLYPH_DEBUG
+#if 0
+      /* We cannot possibly survive the matrix pointers check, since
+        we have overwritten parts of the frame glyph matrix without
+        making any updates to the window matrices.  */
+  check_window_matrix_pointers (root_window);
+#endif
+  add_frame_display_history (f, paused_p);
+#endif
+
+  /* Reset flags indicating that a window should be updated.  */
+  set_window_update_flags (root_window, NULL, 0);
+}
 
 
 /************************************************************************

=== modified file 'src/editfns.c'
--- a/src/editfns.c     2013-10-05 15:06:17 +0000
+++ b/src/editfns.c     2013-10-08 17:49:20 +0000
@@ -3472,22 +3472,17 @@
     {
       Lisp_Object val = Fformat (nargs, args);
 #ifdef HAVE_MENUS
-      /* The MS-DOS frames support popup menus even though they are
-        not FRAME_WINDOW_P.  */
-      if (FRAME_WINDOW_P (XFRAME (selected_frame))
-         || FRAME_MSDOS_P (XFRAME (selected_frame)))
-      {
-       Lisp_Object pane, menu;
-       struct gcpro gcpro1;
-       pane = list1 (Fcons (build_string ("OK"), Qt));
-       GCPRO1 (pane);
-       menu = Fcons (val, pane);
-       Fx_popup_dialog (Qt, menu, Qt);
-       UNGCPRO;
-       return val;
-      }
-#endif /* HAVE_MENUS */
+      Lisp_Object pane, menu;
+      struct gcpro gcpro1;
+
+      pane = list1 (Fcons (build_string ("OK"), Qt));
+      GCPRO1 (pane);
+      menu = Fcons (val, pane);
+      Fx_popup_dialog (Qt, menu, Qt);
+      UNGCPRO;
+#else /* !HAVE_MENUS */
       message3 (val);
+#endif
       return val;
     }
 }

=== modified file 'src/fns.c'
--- a/src/fns.c 2013-09-24 06:43:20 +0000
+++ b/src/fns.c 2013-09-29 18:50:28 +0000
@@ -2434,8 +2434,8 @@
 The user must confirm the answer with RET, and can edit it until it
 has been confirmed.
 
-Under a windowing system a dialog box will be used if `last-nonmenu-event'
-is nil, and `use-dialog-box' is non-nil.  */)
+If dialog boxes are supported, a dialog box will be used
+if `last-nonmenu-event' is nil, and `use-dialog-box' is non-nil.  */)
   (Lisp_Object prompt)
 {
   register Lisp_Object ans;
@@ -2446,8 +2446,7 @@
 
 #ifdef HAVE_MENUS
   if ((NILP (last_nonmenu_event) || CONSP (last_nonmenu_event))
-      && use_dialog_box
-      && window_system_available (SELECTED_FRAME ()))
+      && use_dialog_box)
     {
       Lisp_Object pane, menu, obj;
       redisplay_preserve_echo_area (4);

=== modified file 'src/frame.h'
--- a/src/frame.h       2013-10-02 15:38:12 +0000
+++ b/src/frame.h       2013-10-08 17:49:20 +0000
@@ -1248,9 +1248,6 @@
                                   Lisp_Object oldval);
 extern void x_activate_menubar (struct frame *);
 extern void x_real_positions (struct frame *, int *, int *);
-extern void x_set_menu_bar_lines (struct frame *,
-                                  Lisp_Object,
-                                  Lisp_Object);
 extern void free_frame_menubar (struct frame *);
 extern void x_free_frame_resources (struct frame *);
 

=== modified file 'src/keyboard.c'
--- a/src/keyboard.c    2013-10-08 05:13:21 +0000
+++ b/src/keyboard.c    2013-10-08 17:49:20 +0000
@@ -289,7 +289,7 @@
    at inopportune times.  */
 
 /* Symbols to head events.  */
-static Lisp_Object Qmouse_movement;
+Lisp_Object Qmouse_movement;
 static Lisp_Object Qscroll_bar_movement;
 Lisp_Object Qswitch_frame;
 static Lisp_Object Qfocus_in, Qfocus_out;
@@ -354,6 +354,8 @@
 static Lisp_Object Qvertical_scroll_bar;
 Lisp_Object Qmenu_bar;
 
+static Lisp_Object Qecho_keystrokes;
+
 static void recursive_edit_unwind (Lisp_Object buffer);
 static Lisp_Object command_loop (void);
 static Lisp_Object Qcommand_execute;
@@ -1305,7 +1307,7 @@
    sans error-handling encapsulation.  */
 
 static int read_key_sequence (Lisp_Object *, int, Lisp_Object,
-                              bool, bool, bool);
+                              bool, bool, bool, bool);
 void safe_run_hooks (Lisp_Object);
 static void adjust_point_for_property (ptrdiff_t, bool);
 
@@ -1431,7 +1433,7 @@
 
       /* Read next key sequence; i gets its length.  */
       i = read_key_sequence (keybuf, sizeof keybuf / sizeof keybuf[0],
-                            Qnil, 0, 1, 1);
+                            Qnil, 0, 1, 1, 0);
 
       /* A filter may have run while we were reading the input.  */
       if (! FRAME_LIVE_P (XFRAME (selected_frame)))
@@ -1691,6 +1693,31 @@
     }
 }
 
+Lisp_Object
+read_menu_command (void)
+{
+  Lisp_Object cmd;
+  Lisp_Object keybuf[30];
+  ptrdiff_t count = SPECPDL_INDEX ();
+  int i;
+
+  /* We don't want to echo the keystrokes while navigating the
+     menus.  */
+  specbind (Qecho_keystrokes, make_number (0));
+
+  i = read_key_sequence (keybuf, sizeof keybuf / sizeof keybuf[0],
+                        Qnil, 0, 1, 1, 1);
+
+  unbind_to (count, Qnil);
+
+  if (! FRAME_LIVE_P (XFRAME (selected_frame)))
+    Fkill_emacs (Qnil);
+  if (i == 0 || i == -1)
+    return Qt;
+
+  return read_key_sequence_cmd;
+}
+
 /* Adjust point to a boundary of a region that has such a property
    that should be treated intangible.  For the moment, we check
    `composition', `display' and `invisible' properties.
@@ -2358,6 +2385,7 @@
 /* Read a character from the keyboard; call the redisplay if needed.  */
 /* commandflag 0 means do not autosave, but do redisplay.
    -1 means do not redisplay, but do autosave.
+   -2 means do neither.
    1 means do both.  */
 
 /* The arguments MAP is for menu prompting.  MAP is a keymap.
@@ -2722,7 +2750,7 @@
 
   /* Maybe auto save due to number of keystrokes.  */
 
-  if (commandflag != 0
+  if (commandflag != 0 && commandflag != -2
       && auto_save_interval > 0
       && num_nonmacro_input_events - last_auto_save > max (auto_save_interval, 
20)
       && !detect_input_pending_run_timers (0))
@@ -2774,7 +2802,7 @@
         9 at 200k, 11 at 300k, and 12 at 500k.  It is 15 at 1 meg.  */
 
       /* Auto save if enough time goes by without input.  */
-      if (commandflag != 0
+      if (commandflag != 0 && commandflag != -2
          && num_nonmacro_input_events > last_auto_save
          && INTEGERP (Vauto_save_timeout)
          && XINT (Vauto_save_timeout) > 0)
@@ -3870,7 +3898,22 @@
            }
        }
       else
-       wait_reading_process_output (0, 0, -1, 1, Qnil, NULL, 0);
+       {
+         bool do_display = true;
+
+         if (FRAME_TERMCAP_P (SELECTED_FRAME ()))
+           {
+             struct tty_display_info *tty = CURTTY ();
+
+             /* When this TTY is displaying a menu, we must prevent
+                any redisplay, because we modify the frame's glyph
+                matrix behind the back of the display engine.  */
+             if (tty->showing_menu)
+               do_display = false;
+           }
+
+         wait_reading_process_output (0, 0, -1, do_display, Qnil, NULL, 0);
+       }
 
       if (!interrupt_input && kbd_fetch_ptr == kbd_store_ptr)
        gobble_input ();
@@ -5363,6 +5406,20 @@
                                     extra_info))));
 }
 
+/* Return non-zero if F is a GUI frame that uses some toolkit-managed
+   menu bar.  This really means that Emacs draws and manages the menu
+   bar as part of its normal display, and therefore can compute its
+   geometry.  */
+static bool
+toolkit_menubar_in_use (struct frame *f)
+{
+#if defined (USE_X_TOOLKIT) || defined (USE_GTK) || defined (HAVE_NS) || 
defined (HAVE_NTGUI)
+  return !(!FRAME_WINDOW_P (f));
+#else
+  return false;
+#endif
+}
+
 /* 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.
@@ -5514,64 +5571,64 @@
        if (event->kind == MOUSE_CLICK_EVENT)
          {
            struct frame *f = XFRAME (event->frame_or_window);
-#if ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK) && ! defined (HAVE_NS)
            int row, column;
-#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) && ! defined (HAVE_NS)
            /* 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);
-
-           /* In the non-toolkit version, clicks on the menu bar
-              are ordinary button events in the event buffer.
-              Distinguish them, and invoke the menu.
-
-              (In the toolkit version, the toolkit handles the menu bar
-              and Emacs doesn't know about it until after the user
-              makes a selection.)  */
-           if (row >= 0 && row < FRAME_MENU_BAR_LINES (f)
-               && (event->modifiers & down_modifier))
+           if (!toolkit_menubar_in_use (f))
              {
-               Lisp_Object items, item;
-
-               /* Find the menu bar item under `column'.  */
-               item = Qnil;
-               items = FRAME_MENU_BAR_ITEMS (f);
-               for (i = 0; i < ASIZE (items); i += 4)
+               pixel_to_glyph_coords (f, XINT (event->x), XINT (event->y),
+                                      &column, &row, NULL, 1);
+
+               /* In the non-toolkit version, clicks on the menu bar
+                  are ordinary button events in the event buffer.
+                  Distinguish them, and invoke the menu.
+
+                  (In the toolkit version, the toolkit handles the
+                  menu bar and Emacs doesn't know about it until
+                  after the user makes a selection.)  */
+               if (row >= 0 && row < FRAME_MENU_BAR_LINES (f)
+                 && (event->modifiers & down_modifier))
                  {
-                   Lisp_Object pos, string;
-                   string = AREF (items, i + 1);
-                   pos = AREF (items, i + 3);
-                   if (NILP (string))
-                     break;
-                   if (column >= XINT (pos)
-                       && column < XINT (pos) + SCHARS (string))
+                   Lisp_Object items, item;
+
+                   /* Find the menu bar item under `column'.  */
+                   item = Qnil;
+                   items = FRAME_MENU_BAR_ITEMS (f);
+                   for (i = 0; i < ASIZE (items); i += 4)
                      {
-                       item = AREF (items, i);
-                       break;
+                       Lisp_Object pos, string;
+                       string = AREF (items, i + 1);
+                       pos = AREF (items, i + 3);
+                       if (NILP (string))
+                         break;
+                       if (column >= XINT (pos)
+                           && column < XINT (pos) + SCHARS (string))
+                         {
+                           item = AREF (items, i);
+                           break;
+                         }
                      }
+
+                   /* ELisp manual 2.4b says (x y) are window
+                      relative but code says they are
+                      frame-relative.  */
+                   position = list4 (event->frame_or_window,
+                                     Qmenu_bar,
+                                     Fcons (event->x, event->y),
+                                     make_number (event->timestamp));
+
+                   return list2 (item, position);
                  }
-
-               /* ELisp manual 2.4b says (x y) are window relative but
-                  code says they are frame-relative.  */
-               position = list4 (event->frame_or_window,
-                                 Qmenu_bar,
-                                 Fcons (event->x, event->y),
-                                 make_number (event->timestamp));
-
-               return list2 (item, position);
              }
-#endif /* not USE_X_TOOLKIT && not USE_GTK && not HAVE_NS */
 
            position = make_lispy_position (f, event->x, event->y,
                                            event->timestamp);
@@ -8792,6 +8849,9 @@
 
    Echo starting immediately unless `prompt' is 0.
 
+   If PREVENT_REDISPLAY is non-zero, avoid redisplay by calling
+   read_char with a suitable COMMANDFLAG argument.
+
    Where a key sequence ends depends on the currently active keymaps.
    These include any minor mode keymaps active in the current buffer,
    the current buffer's local map, and the global map.
@@ -8824,7 +8884,7 @@
 static int
 read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
                   bool dont_downcase_last, bool can_return_switch_frame,
-                  bool fix_current_buffer)
+                  bool fix_current_buffer, bool prevent_redisplay)
 {
   ptrdiff_t count = SPECPDL_INDEX ();
 
@@ -8905,8 +8965,8 @@
     {
       if (!NILP (prompt))
        {
-         /* Install the string STR as the beginning of the string of
-            echoing, so that it serves as a prompt for the next
+         /* Install the string PROMPT as the beginning of the string
+            of echoing, so that it serves as a prompt for the next
             character.  */
          kset_echo_string (current_kboard, prompt);
          current_kboard->echo_after_prompt = SCHARS (prompt);
@@ -9061,7 +9121,9 @@
          {
            KBOARD *interrupted_kboard = current_kboard;
            struct frame *interrupted_frame = SELECTED_FRAME ();
-           key = read_char (NILP (prompt),
+           /* Calling read_char with COMMANDFLAG = -2 avoids
+              redisplay in read_char and its subroutines.  */
+           key = read_char (prevent_redisplay ? -2 : NILP (prompt),
                             current_binding, last_nonmenu_event,
                              &used_mouse_menu, NULL);
            if ((INTEGERP (key) && XINT (key) == -2) /* wrong_kboard_jmpbuf */
@@ -9757,7 +9819,7 @@
 
   i = read_key_sequence (keybuf, (sizeof keybuf / sizeof (keybuf[0])),
                         prompt, ! NILP (dont_downcase_last),
-                        ! NILP (can_return_switch_frame), 0);
+                        ! NILP (can_return_switch_frame), 0, 0);
 
 #if 0  /* The following is fine for code reading a key sequence and
          then proceeding with a lengthy computation, but it's not good
@@ -11003,6 +11065,8 @@
 
   DEFSYM (Qhelp_form_show, "help-form-show");
 
+  DEFSYM (Qecho_keystrokes, "echo-keystrokes");
+
   Fset (Qinput_method_exit_on_first_char, Qnil);
   Fset (Qinput_method_use_echo_area, Qnil);
 

=== modified file 'src/keyboard.h'
--- a/src/keyboard.h    2013-09-20 15:34:36 +0000
+++ b/src/keyboard.h    2013-09-26 07:37:16 +0000
@@ -450,7 +450,7 @@
 extern Lisp_Object Qevent_kind;
 
 /* The values of Qevent_kind properties.  */
-extern Lisp_Object Qmouse_click;
+extern Lisp_Object Qmouse_click, Qmouse_movement;
 
 extern Lisp_Object Qhelp_echo;
 

=== modified file 'src/menu.c'
--- a/src/menu.c        2013-09-13 15:03:51 +0000
+++ b/src/menu.c        2013-10-08 14:28:37 +0000
@@ -30,6 +30,7 @@
 #include "termhooks.h"
 #include "blockinput.h"
 #include "dispextern.h"
+#include "buffer.h"
 
 #ifdef USE_X_TOOLKIT
 #include "../lwlib/lwlib.h"
@@ -50,10 +51,16 @@
 
 #include "menu.h"
 
-/* Define HAVE_BOXES if menus can handle radio and toggle buttons.  */
+/* Return non-zero if menus can handle radio and toggle buttons.  */
+static bool
+have_boxes (void)
+{
 #if defined (USE_X_TOOLKIT) || defined (USE_GTK) || defined (HAVE_NTGUI)
-#define HAVE_BOXES 1
+  if (FRAME_WINDOW_P (XFRAME (Vmenu_updating_frame)))
+    return 1;
 #endif
+  return 0;
+}
 
 Lisp_Object menu_items;
 
@@ -283,13 +290,14 @@
 
   push_menu_pane (pane_name, prefix);
 
-#ifndef HAVE_BOXES
-  /* Remember index for first item in this pane so we can go back and
-     add a prefix when (if) we see the first button.  After that, notbuttons
-     is set to 0, to mark that we have seen a button and all non button
-     items need a prefix.  */
-  skp.notbuttons = menu_items_used;
-#endif
+  if (!have_boxes ())
+    {
+      /* Remember index for first item in this pane so we can go back
+        and add a prefix when (if) we see the first button.  After
+        that, notbuttons is set to 0, to mark that we have seen a
+        button and all non button items need a prefix.  */
+      skp.notbuttons = menu_items_used;
+    }
 
   GCPRO1 (skp.pending_maps);
   map_keymap_canonical (keymap, single_menu_item, Qnil, &skp);
@@ -345,77 +353,72 @@
       return;
     }
 
-#if defined (HAVE_X_WINDOWS) || defined (MSDOS)
-#ifndef HAVE_BOXES
   /* Simulate radio buttons and toggle boxes by putting a prefix in
      front of them.  */
-  {
-    Lisp_Object prefix = Qnil;
-    Lisp_Object type = AREF (item_properties, ITEM_PROPERTY_TYPE);
-    if (!NILP (type))
-      {
-       Lisp_Object selected
-         = AREF (item_properties, ITEM_PROPERTY_SELECTED);
-
-       if (skp->notbuttons)
-         /* The first button. Line up previous items in this menu.  */
-         {
-           int idx = skp->notbuttons; /* Index for first item this menu.  */
-           int submenu = 0;
-           Lisp_Object tem;
-           while (idx < menu_items_used)
-             {
-               tem
-                 = AREF (menu_items, idx + MENU_ITEMS_ITEM_NAME);
-               if (NILP (tem))
-                 {
-                   idx++;
-                   submenu++;          /* Skip sub menu.  */
-                 }
-               else if (EQ (tem, Qlambda))
-                 {
-                   idx++;
-                   submenu--;          /* End sub menu.  */
-                 }
-               else if (EQ (tem, Qt))
-                 idx += 3;             /* Skip new pane marker. */
-               else if (EQ (tem, Qquote))
-                 idx++;                /* Skip a left, right divider. */
-               else
-                 {
-                   if (!submenu && SREF (tem, 0) != '\0'
-                       && SREF (tem, 0) != '-')
-                     ASET (menu_items, idx + MENU_ITEMS_ITEM_NAME,
-                           concat2 (build_string ("    "), tem));
-                   idx += MENU_ITEMS_ITEM_LENGTH;
-                 }
-             }
-           skp->notbuttons = 0;
-         }
-
-       /* Calculate prefix, if any, for this item.  */
-       if (EQ (type, QCtoggle))
-         prefix = build_string (NILP (selected) ? "[ ] " : "[X] ");
-       else if (EQ (type, QCradio))
-         prefix = build_string (NILP (selected) ? "( ) " : "(*) ");
-      }
-    /* Not a button. If we have earlier buttons, then we need a prefix.  */
-    else if (!skp->notbuttons && SREF (item_string, 0) != '\0'
-            && SREF (item_string, 0) != '-')
-      prefix = build_string ("    ");
-
-    if (!NILP (prefix))
-      item_string = concat2 (prefix, item_string);
+  if (!have_boxes ())
+    {
+      Lisp_Object prefix = Qnil;
+      Lisp_Object type = AREF (item_properties, ITEM_PROPERTY_TYPE);
+      if (!NILP (type))
+       {
+         Lisp_Object selected
+           = AREF (item_properties, ITEM_PROPERTY_SELECTED);
+
+         if (skp->notbuttons)
+           /* The first button. Line up previous items in this menu.  */
+           {
+             int idx = skp->notbuttons; /* Index for first item this menu.  */
+             int submenu = 0;
+             Lisp_Object tem;
+             while (idx < menu_items_used)
+               {
+                 tem
+                   = AREF (menu_items, idx + MENU_ITEMS_ITEM_NAME);
+                 if (NILP (tem))
+                   {
+                     idx++;
+                     submenu++;                /* Skip sub menu.  */
+                   }
+                 else if (EQ (tem, Qlambda))
+                   {
+                     idx++;
+                     submenu--;                /* End sub menu.  */
+                   }
+                 else if (EQ (tem, Qt))
+                   idx += 3;           /* Skip new pane marker. */
+                 else if (EQ (tem, Qquote))
+                   idx++;              /* Skip a left, right divider. */
+                 else
+                   {
+                     if (!submenu && SREF (tem, 0) != '\0'
+                         && SREF (tem, 0) != '-')
+                       ASET (menu_items, idx + MENU_ITEMS_ITEM_NAME,
+                             concat2 (build_string ("    "), tem));
+                     idx += MENU_ITEMS_ITEM_LENGTH;
+                   }
+               }
+             skp->notbuttons = 0;
+           }
+
+         /* Calculate prefix, if any, for this item.  */
+         if (EQ (type, QCtoggle))
+           prefix = build_string (NILP (selected) ? "[ ] " : "[X] ");
+         else if (EQ (type, QCradio))
+           prefix = build_string (NILP (selected) ? "( ) " : "(*) ");
+       }
+      /* Not a button. If we have earlier buttons, then we need a prefix.  */
+      else if (!skp->notbuttons && SREF (item_string, 0) != '\0'
+              && SREF (item_string, 0) != '-')
+       prefix = build_string ("    ");
+
+      if (!NILP (prefix))
+       item_string = concat2 (prefix, item_string);
   }
-#endif /* not HAVE_BOXES */
 
-#if ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK)
-  if (!NILP (map))
+  if (FRAME_TERMCAP_P (XFRAME (Vmenu_updating_frame))
+      && !NILP (map))
     /* Indicate visually that this is a submenu.  */
     item_string = concat2 (item_string, build_string (" >"));
-#endif
-
-#endif /* HAVE_X_WINDOWS || MSDOS */
 
   push_menu_item (item_string, enabled, key,
                  AREF (item_properties, ITEM_PROPERTY_DEF),
@@ -426,7 +429,8 @@
 
 #if defined (USE_X_TOOLKIT) || defined (USE_GTK) || defined (HAVE_NS) || 
defined (HAVE_NTGUI)
   /* Display a submenu using the toolkit.  */
-  if (! (NILP (map) || NILP (enabled)))
+  if (FRAME_WINDOW_P (XFRAME (Vmenu_updating_frame))
+      && ! (NILP (map) || NILP (enabled)))
     {
       push_submenu_start ();
       single_keymap_panes (map, Qnil, key, skp->maxdepth - 1);
@@ -455,6 +459,16 @@
   finish_menu_items ();
 }
 
+/* Encode a menu string as appropriate for menu-updating-frame's type.  */
+static Lisp_Object
+encode_menu_string (Lisp_Object str)
+{
+  /* TTY menu strings are encoded by write_glyphs, when they are
+     delivered to the glass, so no need to encode them here.  */
+  if (FRAME_TERMCAP_P (XFRAME (Vmenu_updating_frame)))
+    return str;
+  return ENCODE_MENU_STRING (str);
+}
 
 /* Push the items in a single pane defined by the alist PANE.  */
 static void
@@ -466,13 +480,13 @@
     {
       item = XCAR (tail);
       if (STRINGP (item))
-       push_menu_item (ENCODE_MENU_STRING (item), Qnil, Qnil, Qt,
+       push_menu_item (encode_menu_string (item), Qnil, Qnil, Qt,
                        Qnil, Qnil, Qnil, Qnil);
       else if (CONSP (item))
        {
          item1 = XCAR (item);
          CHECK_STRING (item1);
-         push_menu_item (ENCODE_MENU_STRING (item1), Qt, XCDR (item),
+         push_menu_item (encode_menu_string (item1), Qt, XCDR (item),
                          Qt, Qnil, Qnil, Qnil, Qnil);
        }
       else
@@ -497,7 +511,7 @@
       elt = XCAR (tail);
       pane_name = Fcar (elt);
       CHECK_STRING (pane_name);
-      push_menu_pane (ENCODE_MENU_STRING (pane_name), Qnil);
+      push_menu_pane (encode_menu_string (pane_name), Qnil);
       pane_data = Fcdr (elt);
       CHECK_CONS (pane_data);
       list_of_items (pane_data);
@@ -614,6 +628,7 @@
   int submenu_depth = 0;
   widget_value **submenu_stack;
   bool panes_seen = 0;
+  struct frame *f = XFRAME (Vmenu_updating_frame);
 
   submenu_stack = alloca (menu_items_used * sizeof *submenu_stack);
   wv = xmalloc_widget_value ();
@@ -663,30 +678,35 @@
 
          pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
 
+         /* TTY menus display menu items via tty_write_glyphs, which
+            will encode the strings as appropriate.  */
+         if (!FRAME_TERMCAP_P (f))
+           {
 #ifdef HAVE_NTGUI
-         if (STRINGP (pane_name))
-           {
-             if (unicode_append_menu)
-               /* Encode as UTF-8 for now.  */
-               pane_name = ENCODE_UTF_8 (pane_name);
-             else if (STRING_MULTIBYTE (pane_name))
-               pane_name = ENCODE_SYSTEM (pane_name);
+             if (STRINGP (pane_name))
+               {
+                 if (unicode_append_menu)
+                   /* Encode as UTF-8 for now.  */
+                   pane_name = ENCODE_UTF_8 (pane_name);
+                 else if (STRING_MULTIBYTE (pane_name))
+                   pane_name = ENCODE_SYSTEM (pane_name);
 
-             ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name);
-           }
+                 ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name);
+               }
 #elif defined (USE_LUCID) && defined (HAVE_XFT)
-         if (STRINGP (pane_name))
-            {
-              pane_name = ENCODE_UTF_8 (pane_name);
-             ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name);
-            }
+             if (STRINGP (pane_name))
+               {
+                 pane_name = ENCODE_UTF_8 (pane_name);
+                 ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name);
+               }
 #elif !defined (HAVE_MULTILINGUAL_MENU)
-         if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
-           {
-             pane_name = ENCODE_MENU_STRING (pane_name);
-             ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name);
+             if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
+               {
+                 pane_name = ENCODE_MENU_STRING (pane_name);
+                 ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name);
+               }
+#endif
            }
-#endif
 
          pane_string = (NILP (pane_name)
                         ? "" : SSDATA (pane_name));
@@ -737,47 +757,52 @@
          selected = AREF (menu_items, i + MENU_ITEMS_ITEM_SELECTED);
          help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
 
+         /* TTY menu items and their descriptions will be encoded by
+            tty_write_glyphs.  */
+         if (!FRAME_TERMCAP_P (f))
+           {
 #ifdef HAVE_NTGUI
-         if (STRINGP (item_name))
-           {
-             if (unicode_append_menu)
-               item_name = ENCODE_UTF_8 (item_name);
-             else if (STRING_MULTIBYTE (item_name))
-               item_name = ENCODE_SYSTEM (item_name);
-
-             ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name);
-           }
-
-         if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
-           {
-             descrip = ENCODE_SYSTEM (descrip);
-             ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip);
-           }
+             if (STRINGP (item_name))
+               {
+                 if (unicode_append_menu)
+                   item_name = ENCODE_UTF_8 (item_name);
+                 else if (STRING_MULTIBYTE (item_name))
+                   item_name = ENCODE_SYSTEM (item_name);
+
+                 ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name);
+               }
+
+             if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
+               {
+                 descrip = ENCODE_SYSTEM (descrip);
+                 ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip);
+               }
 #elif USE_LUCID
-         if (STRINGP (item_name))
-           {
-              item_name = ENCODE_UTF_8 (item_name);
-             ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name);
-           }
+             if (STRINGP (item_name))
+               {
+                 item_name = ENCODE_UTF_8 (item_name);
+                 ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name);
+               }
 
-         if (STRINGP (descrip))
-           {
-             descrip = ENCODE_UTF_8 (descrip);
-             ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip);
-           }
+             if (STRINGP (descrip))
+               {
+                 descrip = ENCODE_UTF_8 (descrip);
+                 ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip);
+               }
 #elif !defined (HAVE_MULTILINGUAL_MENU)
-          if (STRING_MULTIBYTE (item_name))
-           {
-             item_name = ENCODE_MENU_STRING (item_name);
-             ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name);
-           }
+             if (STRING_MULTIBYTE (item_name))
+               {
+                 item_name = ENCODE_MENU_STRING (item_name);
+                 ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name);
+               }
 
-          if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
-           {
-             descrip = ENCODE_MENU_STRING (descrip);
-             ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip);
-           }
+             if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
+               {
+                 descrip = ENCODE_MENU_STRING (descrip);
+                 ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip);
+               }
 #endif
+           }
 
          wv = xmalloc_widget_value ();
          if (prev_wv)
@@ -1011,6 +1036,85 @@
 }
 #endif  /* HAVE_NS */
 
+int
+menu_item_width (const char *str)
+{
+  int len;
+  const char *p;
+
+  for (len = 0, p = str; *p; )
+    {
+      int ch_len;
+      int ch = STRING_CHAR_AND_LENGTH (p, ch_len);
+
+      len += CHAR_WIDTH (ch);
+      p += ch_len;
+    }
+  return len;
+}
+
+DEFUN ("menu-bar-menu-at-x-y", Fmenu_bar_menu_at_x_y, Smenu_bar_menu_at_x_y,
+       2, 3, 0,
+       doc: /* Return the menu-bar menu on FRAME at pixel coordinates X, Y.
+X and Y are frame-relative pixel coordinates, assumed to define
+a location within the menu bar.
+If FRAME is nil or omitted, it defaults to the selected frame.
+
+Value is the symbol of the menu at X/Y, or nil if the specified
+coordinates are not within the FRAME's menu bar.  The symbol can
+be used to look up the menu like this:
+
+     (lookup-key MAP [menu-bar SYMBOL])
+
+where MAP is either the current global map or the current local map,
+since menu-bar items come from both.
+
+This function can return non-nil only on a text-terminal frame
+or on an X frame that doesn't use any GUI toolkit.  Otherwise,
+Emacs does not manage the menu bar and cannot convert coordinates
+into menu items.  */)
+  (Lisp_Object x, Lisp_Object y, Lisp_Object frame)
+{
+  int row, col;
+  struct frame *f = decode_any_frame (frame);
+
+  if (!FRAME_LIVE_P (f))
+    return Qnil;
+
+  pixel_to_glyph_coords (f, XINT (x), XINT (y), &col, &row, NULL, 1);
+  if (0 <= row && row < FRAME_MENU_BAR_LINES (f))
+    {
+      Lisp_Object items, item;
+      int i;
+
+      /* Find the menu bar item under `col'.  */
+      item = Qnil;
+      items = FRAME_MENU_BAR_ITEMS (f);
+      /* This loop assumes a single menu-bar line, and will fail to
+        find an item if it is not in the first line.  Note that
+        make_lispy_event in keyboard.c makes the same assumption.  */
+      for (i = 0; i < ASIZE (items); i += 4)
+       {
+         Lisp_Object pos, str;
+
+         str = AREF (items, i + 1);
+         pos = AREF (items, i + 3);
+         if (NILP (str))
+           return item;
+         if (XINT (pos) <= col
+             /* We use <= so the blank between 2 items on a TTY is
+                considered part of the previous item.  */
+             && col <= XINT (pos) + menu_item_width (SSDATA (str)))
+           {
+             item = AREF (items, i);
+             return item;
+           }
+       }
+    }
+  return Qnil;
+}
+
+
 DEFUN ("x-popup-menu", Fx_popup_menu, Sx_popup_menu, 2, 2, 0,
        doc: /* Pop up a deck-of-cards menu and return user's selection.
 POSITION is a position specification.  This is either a mouse button event
@@ -1056,7 +1160,7 @@
 no quit occurs and `x-popup-menu' returns nil.  */)
   (Lisp_Object position, Lisp_Object menu)
 {
-  Lisp_Object keymap, tem;
+  Lisp_Object keymap, tem, tem2;
   int xpos = 0, ypos = 0;
   Lisp_Object title;
   const char *error_name = NULL;
@@ -1065,6 +1169,7 @@
   Lisp_Object x, y, window;
   bool keymaps = 0;
   bool for_click = 0;
+  bool kbd_menu_navigation = 0;
   ptrdiff_t specpdl_count = SPECPDL_INDEX ();
   struct gcpro gcpro1;
 
@@ -1077,8 +1182,6 @@
   {
     bool get_current_pos_p = 0;
 
-    check_window_system (SELECTED_FRAME ());
-
     /* Decode the first argument: find the window and the coordinates.  */
     if (EQ (position, Qt)
        || (CONSP (position) && (EQ (XCAR (position), Qmenu_bar)
@@ -1100,6 +1203,22 @@
            for_click = 1;
            tem = Fcar (Fcdr (position));  /* EVENT_START (position) */
            window = Fcar (tem);             /* POSN_WINDOW (tem) */
+           tem2 = Fcar (Fcdr (tem));        /* POSN_POSN (tem) */
+           /* The kbd_menu_navigation flag is set when the menu was
+              invoked by F10, which probably means they have no
+              mouse.  In that case, we let them switch between
+              top-level menu-bar menus by using C-f/C-b and
+              horizontal arrow keys, since they cannot click the
+              mouse to open a different submenu.  This flag is only
+              supported by tty_menu_show.  We set it when POSITION
+              and last_nonmenu_event are different, which means we
+              constructed POSITION by hand (in popup-menu, see
+              menu-bar.el) to look like a mouse click on the menu bar
+              event.  */
+           if (!EQ (POSN_POSN (last_nonmenu_event),
+                    POSN_POSN (position))
+               && CONSP (tem2) && EQ (Fcar (tem2), Qmenu_bar))
+             kbd_menu_navigation = 1;
            tem = Fcar (Fcdr (Fcdr (tem))); /* POSN_WINDOW_POSN (tem) */
            x = Fcar (tem);
            y = Fcdr (tem);
@@ -1194,11 +1313,6 @@
     xpos += XINT (x);
     ypos += XINT (y);
 
-    /* FIXME: Find a more general check!  */
-    if (!(FRAME_X_P (f) || FRAME_MSDOS_P (f)
-         || FRAME_W32_P (f) || FRAME_NS_P (f)))
-      error ("Can not put GUI menu on this terminal");
-
     XSETFRAME (Vmenu_updating_frame, f);
   }
 #endif /* HAVE_MENUS */
@@ -1287,7 +1401,8 @@
 #ifdef HAVE_MENUS
 #ifdef HAVE_WINDOW_SYSTEM
   /* Hide a previous tip, if any.  */
-  Fx_hide_tip ();
+  if (!FRAME_TERMCAP_P (f))
+    Fx_hide_tip ();
 #endif
 
 #ifdef HAVE_NTGUI     /* FIXME: Is it really w32-specific?  --Stef  */
@@ -1296,7 +1411,7 @@
      can occur if you press ESC or click outside a menu without selecting
      a menu item.
   */
-  if (current_popup_menu)
+  if (current_popup_menu && FRAME_W32_P (f))
     {
       discard_menu_items ();
       FRAME_DISPLAY_INFO (f)->grabbed = 0;
@@ -1310,26 +1425,34 @@
 #endif
 
   /* Display them in a menu.  */
-  block_input ();
 
   /* FIXME: Use a terminal hook!  */
 #if defined HAVE_NTGUI
-  selection = w32_menu_show (f, xpos, ypos, for_click,
-                            keymaps, title, &error_name);
-#elif defined HAVE_NS
-  selection = ns_menu_show (f, xpos, ypos, for_click,
-                           keymaps, title, &error_name);
-#else /* MSDOS and X11 */
+  if (FRAME_W32_P (f))
+    selection = w32_menu_show (f, xpos, ypos, for_click,
+                              keymaps, title, &error_name);
+  else
+#endif
+#if defined HAVE_NS
+  if (FRAME_NS_P (f))
+    selection = ns_menu_show (f, xpos, ypos, for_click,
+                             keymaps, title, &error_name);
+  else
+#endif
+#if (defined (HAVE_X_WINDOWS) || defined (MSDOS))
   /* Assume last_event_timestamp is the timestamp of the button event.
      Is this assumption ever violated?  We can't use the timestamp
      stored within POSITION because there the top bits from the actual
      timestamp may be truncated away (Bug#4930).  */
-  selection = xmenu_show (f, xpos, ypos, for_click,
-                         keymaps, title, &error_name,
-                         last_event_timestamp);
+  if (FRAME_X_P (f) || FRAME_MSDOS_P (f))
+    selection = xmenu_show (f, xpos, ypos, for_click,
+                           keymaps, title, &error_name,
+                           last_event_timestamp);
+  else
 #endif
-
-  unblock_input ();
+  if (FRAME_TERMCAP_P (f))
+    selection = tty_menu_show (f, xpos, ypos, for_click, keymaps, title,
+                              kbd_menu_navigation, &error_name);
 
 #ifdef HAVE_NS
   unbind_to (specpdl_count, Qnil);
@@ -1338,7 +1461,8 @@
 #endif
 
 #ifdef HAVE_NTGUI     /* FIXME: Is it really w32-specific?  --Stef  */
-  FRAME_DISPLAY_INFO (f)->grabbed = 0;
+  if (FRAME_W32_P (f))
+    FRAME_DISPLAY_INFO (f)->grabbed = 0;
 #endif
 
 #endif /* HAVE_MENUS */
@@ -1349,6 +1473,145 @@
   return selection;
 }
 
+#ifdef HAVE_MENUS
+
+DEFUN ("x-popup-dialog", Fx_popup_dialog, Sx_popup_dialog, 2, 3, 0,
+       doc: /* Pop up a dialog box and return user's selection.
+POSITION specifies which frame to use.
+This is normally a mouse button event or a window or frame.
+If POSITION is t, it means to use the frame the mouse is on.
+The dialog box appears in the middle of the specified frame.
+
+CONTENTS specifies the alternatives to display in the dialog box.
+It is a list of the form (DIALOG ITEM1 ITEM2...).
+Each ITEM is a cons cell (STRING . VALUE).
+The return value is VALUE from the chosen item.
+
+An ITEM may also be just a string--that makes a nonselectable item.
+An ITEM may also be nil--that means to put all preceding items
+on the left of the dialog box and all following items on the right.
+\(By default, approximately half appear on each side.)
+
+If HEADER is non-nil, the frame title for the box is "Information",
+otherwise it is "Question".
+
+If the user gets rid of the dialog box without making a valid choice,
+for instance using the window manager, then this produces a quit and
+`x-popup-dialog' does not return.  */)
+  (Lisp_Object position, Lisp_Object contents, Lisp_Object header)
+{
+  struct frame *f = NULL;
+  Lisp_Object window;
+
+  /* Decode the first argument: find the window or frame to use.  */
+  if (EQ (position, Qt)
+      || (CONSP (position) && (EQ (XCAR (position), Qmenu_bar)
+                              || EQ (XCAR (position), Qtool_bar))))
+    {
+#if 0 /* Using the frame the mouse is on may not be right.  */
+      /* Use the mouse's current position.  */
+      struct frame *new_f = SELECTED_FRAME ();
+      Lisp_Object bar_window;
+      enum scroll_bar_part part;
+      Time time;
+      Lisp_Object x, y;
+
+      (*mouse_position_hook) (&new_f, 1, &bar_window, &part, &x, &y, &time);
+
+      if (new_f != 0)
+       XSETFRAME (window, new_f);
+      else
+       window = selected_window;
+#endif
+      window = selected_window;
+    }
+  else if (CONSP (position))
+    {
+      Lisp_Object tem = XCAR (position);
+      if (CONSP (tem))
+       window = Fcar (XCDR (position));
+      else
+       {
+         tem = Fcar (XCDR (position));  /* EVENT_START (position) */
+         window = Fcar (tem);       /* POSN_WINDOW (tem) */
+       }
+    }
+  else if (WINDOWP (position) || FRAMEP (position))
+    window = position;
+  else
+    window = Qnil;
+
+  /* Decode where to put the menu.  */
+
+  if (FRAMEP (window))
+    f = XFRAME (window);
+  else if (WINDOWP (window))
+    {
+      CHECK_LIVE_WINDOW (window);
+      f = XFRAME (WINDOW_FRAME (XWINDOW (window)));
+    }
+  else
+    /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
+       but I don't want to make one now.  */
+    CHECK_WINDOW (window);
+
+  /* Force a redisplay before showing the dialog.  If a frame is created
+     just before showing the dialog, its contents may not have been fully
+     drawn, as this depends on timing of events from the X server.  Redisplay
+     is not done when a dialog is shown.  If redisplay could be done in the
+     X event loop (i.e. the X event loop does not run in a signal handler)
+     this would not be needed.
+
+     Do this before creating the widget value that points to Lisp
+     string contents, because Fredisplay may GC and relocate them.  */
+  Fredisplay (Qt);
+#if defined (USE_X_TOOLKIT) || defined (USE_GTK)
+  if (FRAME_WINDOW_P (f))
+    return xw_popup_dialog (f, header, contents);
+  else
+#endif
+#if defined (HAVE_NTGUI) && defined (HAVE_DIALOGS)
+  if (FRAME_W32_P (f))
+    return w32_popup_dialog (f, header, contents);
+  else
+#endif
+#ifdef HAVE_NS
+  if (FRAME_NS_P (f))
+    return ns_popup_dialog (position, header, contents);
+  else
+#endif
+  /* Display a menu with these alternatives
+     in the middle of frame F.  */
+  {
+    Lisp_Object x, y, frame, newpos, prompt;
+    int x_coord, y_coord;
+
+    prompt = Fcar (contents);
+    if (FRAME_WINDOW_P (f))
+      {
+       x_coord = FRAME_PIXEL_WIDTH (f);
+       y_coord = FRAME_PIXEL_HEIGHT (f);
+      }
+    else
+      {
+       x_coord = FRAME_COLS (f);
+       /* Center the title at frame middle.  (TTY menus have their
+          upper-left corner at the given position.)  */
+       if (STRINGP (prompt))
+         x_coord -= SCHARS (prompt);
+       y_coord = FRAME_LINES (f);
+      }
+    XSETFRAME (frame, f);
+    XSETINT (x, x_coord / 2);
+    XSETINT (y, y_coord / 2);
+    newpos = list2 (list2 (x, y), frame);
+
+    return Fx_popup_menu (newpos, list2 (prompt, contents));
+  }
+}
+
+#endif /* HAVE_MENUS */
+
 void
 syms_of_menu (void)
 {
@@ -1357,4 +1620,9 @@
   menu_items_inuse = Qnil;
 
   defsubr (&Sx_popup_menu);
+
+#ifdef HAVE_MENUS
+  defsubr (&Sx_popup_dialog);
+#endif
+  defsubr (&Smenu_bar_menu_at_x_y);
 }

=== modified file 'src/menu.h'
--- a/src/menu.h        2013-08-03 03:29:03 +0000
+++ b/src/menu.h        2013-10-08 14:28:37 +0000
@@ -51,4 +51,7 @@
                                 Lisp_Object, const char **);
 extern Lisp_Object xmenu_show (struct frame *, int, int, bool, bool,
                               Lisp_Object, const char **, Time);
+extern Lisp_Object tty_menu_show (struct frame *, int, int, int, int,
+                                 Lisp_Object, int, const char **);
+extern int menu_item_width (const char *);
 #endif /* MENU_H */

=== modified file 'src/msdos.c'
--- a/src/msdos.c       2013-09-24 06:43:20 +0000
+++ b/src/msdos.c       2013-09-26 07:37:16 +0000
@@ -1379,13 +1379,6 @@
   emacs_abort ();
 }
 
-/* set-window-configuration on window.c needs this.  */
-void
-x_set_menu_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval)
-{
-  set_menu_bar_lines (f, value, oldval);
-}
-
 /* This was copied from xfaces.c  */
 
 extern Lisp_Object Qbackground_color;

=== modified file 'src/nsmenu.m'
--- a/src/nsmenu.m      2013-09-22 14:26:10 +0000
+++ b/src/nsmenu.m      2013-09-29 18:38:56 +0000
@@ -833,6 +833,8 @@
   ptrdiff_t specpdl_count = SPECPDL_INDEX ();
   widget_value *wv, *first_wv = 0;
 
+  block_input ();
+
   p.x = x; p.y = y;
 
   /* now parse stage 2 as in ns_update_menubar */
@@ -1035,6 +1037,7 @@
   popup_activated_flag = 0;
   [[FRAME_NS_VIEW (SELECTED_FRAME ()) window] makeKeyWindow];
 
+  unblock_input ();
   return tem;
 }
 
@@ -1449,7 +1452,7 @@
 
 
 Lisp_Object
-ns_popup_dialog (Lisp_Object position, Lisp_Object contents, Lisp_Object 
header)
+ns_popup_dialog (Lisp_Object position, Lisp_Object header, Lisp_Object 
contents)
 {
   id dialog;
   Lisp_Object window, tem, title;
@@ -1916,34 +1919,6 @@
 }
 
 
-DEFUN ("x-popup-dialog", Fx_popup_dialog, Sx_popup_dialog, 2, 3, 0,
-       doc: /* Pop up a dialog box and return user's selection.
-POSITION specifies which frame to use.
-This is normally a mouse button event or a window or frame.
-If POSITION is t, it means to use the frame the mouse is on.
-The dialog box appears in the middle of the specified frame.
-
-CONTENTS specifies the alternatives to display in the dialog box.
-It is a list of the form (DIALOG ITEM1 ITEM2...).
-Each ITEM is a cons cell (STRING . VALUE).
-The return value is VALUE from the chosen item.
-
-An ITEM may also be just a string--that makes a nonselectable item.
-An ITEM may also be nil--that means to put all preceding items
-on the left of the dialog box and all following items on the right.
-\(By default, approximately half appear on each side.)
-
-If HEADER is non-nil, the frame title for the box is "Information",
-otherwise it is "Question".
-
-If the user gets rid of the dialog box without making a valid choice,
-for instance using the window manager, then this produces a quit and
-`x-popup-dialog' does not return.  */)
-     (Lisp_Object position, Lisp_Object contents, Lisp_Object header)
-{
-  return ns_popup_dialog (position, contents, header);
-}
-
 DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p, 
Smenu_or_popup_active_p, 0, 0, 0,
        doc: /* Return t if a menu or popup dialog is active.  */)
      (void)
@@ -1965,7 +1940,6 @@
      update menus there.  */
   trackingMenu = 1;
 #endif
-  defsubr (&Sx_popup_dialog);
   defsubr (&Sns_reset_menu);
   defsubr (&Smenu_or_popup_active_p);
 

=== modified file 'src/nsterm.h'
--- a/src/nsterm.h      2013-09-28 10:01:50 +0000
+++ b/src/nsterm.h      2013-10-08 17:49:20 +0000
@@ -850,8 +850,8 @@
 extern Lisp_Object find_and_return_menu_selection (struct frame *f,
                                                    bool keymaps,
                                                    void *client_data);
-extern Lisp_Object ns_popup_dialog (Lisp_Object position, Lisp_Object contents,
-                                    Lisp_Object header);
+extern Lisp_Object ns_popup_dialog (Lisp_Object position, Lisp_Object header,
+                                    Lisp_Object contents);
 
 #define NSAPP_DATA2_RUNASSCRIPT 10
 extern void ns_run_ascript (void);

=== modified file 'src/term.c'
--- a/src/term.c        2013-09-11 08:24:05 +0000
+++ b/src/term.c        2013-10-08 17:49:20 +0000
@@ -56,6 +56,8 @@
 #include "xterm.h"
 #endif
 
+#include "menu.h"
+
 /* The name of the default console device.  */
 #ifdef WINDOWSNT
 #define DEV_TTY  "CONOUT$"
@@ -302,7 +304,11 @@
   if (tty->cursor_hidden == 0)
     {
       tty->cursor_hidden = 1;
+#ifdef WINDOWSNT
+      w32con_hide_cursor ();
+#else
       OUTPUT_IF (tty, tty->TS_cursor_invisible);
+#endif
     }
 }
 
@@ -315,9 +321,13 @@
   if (tty->cursor_hidden)
     {
       tty->cursor_hidden = 0;
+#ifdef WINDOWSNT
+      w32con_show_cursor ();
+#else
       OUTPUT_IF (tty, tty->TS_cursor_normal);
       if (visible_cursor)
         OUTPUT_IF (tty, tty->TS_cursor_visible);
+#endif
     }
 }
 
@@ -2755,6 +2765,1107 @@
 #endif /* HAVE_GPM */
 
 
+/***********************************************************************
+                              Menus
+ ***********************************************************************/
+
+#if defined (HAVE_MENUS) && !defined (MSDOS)
+
+/* TTY menu implementation and main ideas are borrowed from msdos.c.
+
+   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
+   contents when the menu selection changes or when the final
+   selection is made and the menu should be popped down.
+
+   The idea of this implementation was suggested by Gerd Moellmann.  */
+
+#define TTYM_FAILURE -1
+#define TTYM_SUCCESS 1
+#define TTYM_NO_SELECT 2
+#define TTYM_IA_SELECT 3
+#define TTYM_NEXT 4
+#define TTYM_PREV 5
+
+/* These hold text of the current and the previous menu help messages.  */
+static const char *menu_help_message, *prev_menu_help_message;
+/* Pane number and item number of the menu item which generated the
+   last menu help message.  */
+static int menu_help_paneno, menu_help_itemno;
+
+static Lisp_Object Qtty_menu_navigation_map, Qtty_menu_exit;
+static Lisp_Object Qtty_menu_prev_item, Qtty_menu_next_item;
+static Lisp_Object Qtty_menu_next_menu, Qtty_menu_prev_menu;
+static Lisp_Object Qtty_menu_select, Qtty_menu_ignore;
+static Lisp_Object Qtty_menu_mouse_movement;
+
+typedef struct tty_menu_struct
+{
+  int count;
+  char **text;
+  struct tty_menu_struct **submenu;
+  int *panenumber; /* Also used as enabled flag.  */
+  int allocated;
+  int panecount;
+  int width;
+  const char **help_text;
+} tty_menu;
+
+/* Create a brand new menu structure.  */
+
+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;
+}
+
+/* Allocate some (more) memory for MENU ensuring that there is room for one
+   for item.  */
+
+static void
+tty_menu_make_room (tty_menu *menu)
+{
+  if (menu->allocated == 0)
+    {
+      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 *));
+    }
+}
+
+/* Search the given menu structure for a given pane number.  */
+
+static tty_menu *
+tty_menu_search_pane (tty_menu *menu, int pane)
+{
+  int i;
+  tty_menu *try;
+
+  for (i = 0; i < menu->count; i++)
+    if (menu->submenu[i])
+      {
+       if (pane == menu->panenumber[i])
+         return menu->submenu[i];
+       if ((try = tty_menu_search_pane (menu->submenu[i], pane)))
+         return try;
+      }
+  return (tty_menu *) 0;
+}
+
+/* Determine how much screen space a given menu needs.  */
+
+static void
+tty_menu_calc_size (tty_menu *menu, int *width, int *height)
+{
+  int i, h2, w2, maxsubwidth, maxheight;
+
+  maxsubwidth = menu->width;
+  maxheight = menu->count;
+  for (i = 0; i < menu->count; i++)
+    {
+      if (menu->submenu[i])
+       {
+         tty_menu_calc_size (menu->submenu[i], &w2, &h2);
+         if (w2 > maxsubwidth) maxsubwidth = w2;
+         if (i + h2 > maxheight) maxheight = i + h2;
+       }
+    }
+  *width = maxsubwidth;
+  *height = maxheight;
+}
+
+static void
+mouse_get_xy (int *x, int *y)
+{
+  struct frame *sf = SELECTED_FRAME ();
+  Lisp_Object lmx = Qnil, lmy = Qnil, lisp_dummy;
+  enum scroll_bar_part part_dummy;
+  Time time_dummy;
+
+  if (FRAME_TERMINAL (sf)->mouse_position_hook)
+    (*FRAME_TERMINAL (sf)->mouse_position_hook) (&sf, -1,
+                                                 &lisp_dummy, &part_dummy,
+                                                &lmx, &lmy,
+                                                &time_dummy);
+  if (!NILP (lmx))
+    {
+      *x = XINT (lmx);
+      *y = XINT (lmy);
+    }
+}
+
+/* Display MENU at (X,Y) using 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 i, face, width, enabled, mousehere, row, col;
+  struct frame *sf = SELECTED_FRAME ();
+  struct tty_display_info *tty = FRAME_TTY (sf);
+
+  menu_help_message = NULL;
+
+  width = menu->width;
+  col = cursorX (tty);
+  row = cursorY (tty);
+  for (i = 0; i < menu->count; i++)
+    {
+      int max_width = width + 2; /* +2 for padding blanks on each side */
+
+      cursor_to (sf, y + i, x);
+      if (menu->submenu[i])
+       max_width += 2; /* for displaying " >" after the item */
+      enabled
+       = (!menu->submenu[i] && menu->panenumber[i]) || (menu->submenu[i]);
+      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
+        the menu item is currently disabled.  That's what the GUI
+        code does.  */
+      if (disp_help && enabled + mousehere * 2 >= 2)
+       {
+         menu_help_message = menu->help_text[i];
+         menu_help_paneno = pn - 1;
+         menu_help_itemno = i;
+       }
+      display_tty_menu_item (menu->text[i], max_width, face, x, y + i,
+                            menu->submenu[i] != NULL);
+    }
+  update_frame_with_menu (sf);
+  cursor_to (sf, row, col);
+}
+
+/* --------------------------- 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;
+  const char *p;
+
+  tty_menu_make_room (menu);
+  menu->submenu[menu->count] = tty_menu_create ();
+  menu->text[menu->count] = (char *)txt;
+  menu->panenumber[menu->count] = ++menu->panecount;
+  menu->help_text[menu->count] = NULL;
+  menu->count++;
+
+  /* Update the menu width, if necessary.  */
+  for (len = 0, p = txt; *p; )
+    {
+      int ch_len;
+      int ch = STRING_CHAR_AND_LENGTH (p, ch_len);
+
+      len += CHAR_WIDTH (ch);
+      p += ch_len;
+    }
+
+  if (len > menu->width)
+    menu->width = len;
+
+  return menu->panecount;
+}
+
+/* Create a new item in a menu pane.  */
+
+int
+tty_menu_add_selection (tty_menu *menu, int pane,
+                       char *txt, int enable, char const *help_text)
+{
+  int len;
+  char *p;
+
+  if (pane)
+    if (!(menu = tty_menu_search_pane (menu, pane)))
+      return TTYM_FAILURE;
+  tty_menu_make_room (menu);
+  menu->submenu[menu->count] = (tty_menu *) 0;
+  menu->text[menu->count] = txt;
+  menu->panenumber[menu->count] = enable;
+  menu->help_text[menu->count] = help_text;
+  menu->count++;
+
+  /* Update the menu width, if necessary.  */
+  for (len = 0, p = txt; *p; )
+    {
+      int ch_len;
+      int ch = STRING_CHAR_AND_LENGTH (p, ch_len);
+
+      len += CHAR_WIDTH (ch);
+      p += ch_len;
+    }
+
+  if (len > menu->width)
+    menu->width = len;
+
+  return TTYM_SUCCESS;
+}
+
+/* Decide where the menu would be placed if requested at (X,Y).  */
+
+void
+tty_menu_locate (tty_menu *menu, int x, int y,
+                int *ulx, int *uly, int *width, int *height)
+{
+  tty_menu_calc_size (menu, width, height);
+  *ulx = x + 1;
+  *uly = y;
+  *width += 2;
+}
+
+struct tty_menu_state
+{
+  struct glyph_matrix *screen_behind;
+  tty_menu *menu;
+  int pane;
+  int x, y;
+};
+
+/* Save away the contents of frame F's current frame matrix, and
+   enable all its rows.  Value is a glyph matrix holding the contents
+   of F's current frame matrix with all its glyph rows enabled.  */
+
+static struct glyph_matrix *
+save_and_enable_current_matrix (struct frame *f)
+{
+  int i;
+  struct glyph_matrix *saved = xzalloc (sizeof *saved);
+  saved->nrows = f->current_matrix->nrows;
+  saved->rows = xzalloc (saved->nrows * sizeof *saved->rows);
+
+  for (i = 0; i < saved->nrows; ++i)
+    {
+      struct glyph_row *from = f->current_matrix->rows + i;
+      struct glyph_row *to = saved->rows + i;
+      ptrdiff_t nbytes = from->used[TEXT_AREA] * sizeof (struct glyph);
+
+      to->glyphs[TEXT_AREA] = xmalloc (nbytes);
+      memcpy (to->glyphs[TEXT_AREA], from->glyphs[TEXT_AREA], nbytes);
+      to->used[TEXT_AREA] = from->used[TEXT_AREA];
+      /* Make sure every row is enabled, or else update_frame will not
+        redraw them.  (Rows that are identical to what is already on
+        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;
+}
+
+/* Restore the contents of frame F's desired frame matrix from SAVED,
+   and free memory associated with SAVED.  */
+
+static void
+restore_desired_matrix (struct frame *f, struct glyph_matrix *saved)
+{
+  int i;
+
+  for (i = 0; i < saved->nrows; ++i)
+    {
+      struct glyph_row *from = saved->rows + i;
+      struct glyph_row *to = f->desired_matrix->rows + i;
+      ptrdiff_t nbytes = from->used[TEXT_AREA] * sizeof (struct glyph);
+
+      eassert (to->glyphs[TEXT_AREA] != from->glyphs[TEXT_AREA]);
+      memcpy (to->glyphs[TEXT_AREA], from->glyphs[TEXT_AREA], nbytes);
+      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;
+    }
+}
+
+static void
+free_saved_screen (struct glyph_matrix *saved)
+{
+  int i;
+
+  if (!saved)
+    return;    /* already freed */
+
+  for (i = 0; i < saved->nrows; ++i)
+    {
+      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);
+}
+
+/* Update the display of frame F from its saved contents.  */
+static void
+screen_update (struct frame *f, struct glyph_matrix *mtx)
+{
+  restore_desired_matrix (f, mtx);
+  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.
+
+   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_menu_input (struct frame *sf, int *x, int *y, int min_y, int max_y,
+                bool *first_time)
+{
+  if (*first_time)
+    {
+      *first_time = false;
+      sf->mouse_moved = 1;
+    }
+  else
+    {
+      extern Lisp_Object read_menu_command (void);
+      Lisp_Object cmd;
+      int usable_input = 1;
+      int st = 0;
+      struct tty_display_info *tty = FRAME_TTY (sf);
+      Lisp_Object saved_mouse_tracking = do_mouse_tracking;
+
+      /* Signal the keyboard reading routines we are displaying a menu
+        on this terminal.  */
+      tty->showing_menu = 1;
+      /* We want mouse movements be reported by read_menu_command.  */
+      do_mouse_tracking = Qt;
+      do {
+       cmd = read_menu_command ();
+      } while (NILP (cmd));
+      tty->showing_menu = 0;
+      do_mouse_tracking = saved_mouse_tracking;
+
+      if (EQ (cmd, Qt) || EQ (cmd, Qtty_menu_exit))
+       return -1;
+      if (EQ (cmd, Qtty_menu_mouse_movement))
+       {
+         int mx, my;
+
+         mouse_get_xy (&mx, &my);
+         *x = mx;
+         *y = my;
+       }
+      else if (EQ (cmd, Qtty_menu_next_menu))
+       {
+         usable_input = 0;
+         st = 2;
+       }
+      else if (EQ (cmd, Qtty_menu_prev_menu))
+       {
+         usable_input = 0;
+         st = 3;
+       }
+      else if (EQ (cmd, Qtty_menu_next_item))
+       {
+         if (*y < max_y)
+           *y += 1;
+       }
+      else if (EQ (cmd, Qtty_menu_prev_item))
+       {
+         if (*y > min_y)
+           *y -= 1;
+       }
+      else if (EQ (cmd, Qtty_menu_select))
+       st = 1;
+      else if (!EQ (cmd, Qtty_menu_ignore))
+       usable_input = 0;
+      if (usable_input)
+       sf->mouse_moved = 1;
+      return st;
+    }
+  return 0;
+}
+
+/* Display menu, wait for user's response, and return that response.  */
+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),
+                  int kbd_navigation)
+{
+  struct tty_menu_state *state;
+  int statecount, x, y, i, b, leave, result, onepane;
+  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;
+
+  /* Don't allow non-positive x0 and y0, lest the menu will wrap
+     around the display.  */
+  if (x0 <= 0)
+    x0 = 1;
+  if (y0 <= 0)
+    y0 = 1;
+
+  state = alloca (menu->panecount * sizeof (struct tty_menu_state));
+  memset (state, 0, sizeof (*state));
+  faces[0]
+    = lookup_derived_face (sf, intern ("tty-menu-disabled-face"),
+                          DEFAULT_FACE_ID, 1);
+  faces[1]
+    = lookup_derived_face (sf, intern ("tty-menu-enabled-face"),
+                          DEFAULT_FACE_ID, 1);
+  selectface = intern ("tty-menu-selected-face");
+  faces[2] = lookup_derived_face (sf, selectface,
+                                 faces[0], 1);
+  faces[3] = lookup_derived_face (sf, selectface,
+                                 faces[1], 1);
+
+  /* Make sure the menu title is always displayed with
+     `tty-menu-selected-face', no matter where the mouse pointer is.  */
+  for (i = 0; i < 4; i++)
+    title_faces[i] = faces[3];
+
+  statecount = 1;
+
+  /* Don't let the title for the "Buffers" popup menu include a
+     digit (which is ugly).
+
+     This is a terrible kludge, but I think the "Buffers" case is
+     the only one where the title includes a number, so it doesn't
+     seem to be necessary to make this more general.  */
+  if (strncmp (menu->text[0], "Buffers 1", 9) == 0)
+    {
+      menu->text[0][7] = '\0';
+      buffers_num_deleted = 1;
+    }
+
+  /* Force update of the current frame, so that the desired and the
+     current matrices are identical.  */
+  update_frame_with_menu (sf);
+  state[0].menu = menu;
+  state[0].screen_behind = save_and_enable_current_matrix (sf);
+
+  /* Display the menu title.  We subtract 1 from x0 and y0 because we
+     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);
+
+  /* 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]))
+    {
+      menu->width = menu->submenu[0]->width;
+      state[0].menu = menu->submenu[0];
+    }
+  else
+    {
+      state[0].menu = menu;
+    }
+  state[0].x = x0 - 1;
+  state[0].y = y0;
+  state[0].pane = onepane;
+
+  x = state[0].x;
+  y = state[0].y;
+  first_time = true;
+
+  leave = 0;
+  while (!leave)
+    {
+      int input_status;
+      int min_y = state[0].y, max_y = min_y + state[0].menu->count - 1;
+
+      input_status = read_menu_input (sf, &x, &y, min_y, max_y, &first_time);
+      if (input_status)
+       {
+         leave = 1;
+         if (input_status == -1)
+           {
+             /* 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)
+           {
+             if (kbd_navigation)
+               result = TTYM_NEXT;
+             else
+               leave = 0;
+           }
+         else if (input_status == 3)
+           {
+             if (kbd_navigation)
+               result = TTYM_PREV;
+             else
+               leave = 0;
+           }
+       }
+      if (sf->mouse_moved && input_status != -1)
+       {
+         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;
+               if (0 <= dy && dy < state[i].menu->count)
+                 {
+                   if (!state[i].menu->submenu[dy])
+                     {
+                       if (state[i].menu->panenumber[dy])
+                         result = TTYM_SUCCESS;
+                       else
+                         result = TTYM_IA_SELECT;
+                     }
+                   *pane = state[i].pane - 1;
+                   *selidx = dy;
+                   /* We hit some part of a menu, so drop extra menus that
+                      have been opened.  That does not include an open and
+                      active submenu.  */
+                   if (i != statecount - 2
+                       || state[i].menu->submenu[dy] != state[i+1].menu)
+                     while (i != statecount - 1)
+                       {
+                         statecount--;
+                         screen_update (sf, state[statecount].screen_behind);
+                         state[statecount].screen_behind = NULL;
+                       }
+                   if (i == statecount - 1 && state[i].menu->submenu[dy])
+                     {
+                       tty_menu_display (state[i].menu,
+                                         state[i].x,
+                                         state[i].y,
+                                         state[i].pane,
+                                         faces, x, y, 1);
+                       state[statecount].menu = state[i].menu->submenu[dy];
+                       state[statecount].pane = state[i].menu->panenumber[dy];
+                       state[statecount].screen_behind
+                         = save_and_enable_current_matrix (sf);
+                       state[statecount].x
+                         = state[i].x + state[i].menu->width + 2;
+                       state[statecount].y = y;
+                       statecount++;
+                     }
+                 }
+             }
+         tty_menu_display (state[statecount - 1].menu,
+                           state[statecount - 1].x,
+                           state[statecount - 1].y,
+                           state[statecount - 1].pane,
+                           faces, x, y, 1);
+         tty_hide_cursor (tty);
+         fflush (tty->output);
+       }
+
+      /* Display the help-echo message for the currently-selected menu
+        item.  */
+      if ((menu_help_message || prev_menu_help_message)
+         && menu_help_message != prev_menu_help_message)
+       {
+         help_callback (menu_help_message,
+                        menu_help_paneno, menu_help_itemno);
+         tty_hide_cursor (tty);
+         fflush (tty->output);
+         prev_menu_help_message = menu_help_message;
+       }
+    }
+
+  sf->mouse_moved = 0;
+  screen_update (sf, state[0].screen_behind);
+  while (statecount--)
+    free_saved_screen (state[statecount].screen_behind);
+  tty_show_cursor (tty);       /* turn cursor back on */
+
+/* Clean up any mouse events that are waiting inside Emacs event queue.
+     These events are likely to be generated before the menu was even
+     displayed, probably because the user pressed and released the button
+     (which invoked the menu) too quickly.  If we don't remove these events,
+     Emacs will process them after we return and surprise the user.  */
+  discard_mouse_events ();
+  if (!kbd_buffer_events_waiting ())
+    clear_input_pending ();
+  SET_FRAME_GARBAGED (sf);
+  return result;
+}
+
+/* Dispose of a menu.  */
+
+void
+tty_menu_destroy (tty_menu *menu)
+{
+  int i;
+  if (menu->allocated)
+    {
+      for (i = 0; i < menu->count; i++)
+       if (menu->submenu[i])
+         tty_menu_destroy (menu->submenu[i]);
+      xfree (menu->text);
+      xfree (menu->submenu);
+      xfree (menu->panenumber);
+      xfree (menu->help_text);
+    }
+  xfree (menu);
+  menu_help_message = prev_menu_help_message = NULL;
+}
+
+/* Show help HELP_STRING, or clear help if HELP_STRING is null.
+
+   PANE is the pane number, and ITEM is the menu item number in
+   the menu (currently not used).  */
+
+static void
+tty_menu_help_callback (char const *help_string, int pane, int item)
+{
+  Lisp_Object *first_item;
+  Lisp_Object pane_name;
+  Lisp_Object menu_object;
+
+  first_item = XVECTOR (menu_items)->u.contents;
+  if (EQ (first_item[0], Qt))
+    pane_name = first_item[MENU_ITEMS_PANE_NAME];
+  else if (EQ (first_item[0], Qquote))
+    /* This shouldn't happen, see xmenu_show.  */
+    pane_name = empty_unibyte_string;
+  else
+    pane_name = first_item[MENU_ITEMS_ITEM_NAME];
+
+  /* (menu-item MENU-NAME PANE-NUMBER)  */
+  menu_object = list3 (Qmenu_item, pane_name, make_number (pane));
+  show_help_echo (help_string ? build_string (help_string) : Qnil,
+                 Qnil, menu_object, make_number (item));
+}
+
+static void
+tty_pop_down_menu (Lisp_Object arg)
+{
+  tty_menu *menu = XSAVE_POINTER (arg, 0);
+
+  block_input ();
+  tty_menu_destroy (menu);
+  unblock_input ();
+}
+
+/* Return the zero-based index of the last menu-bar item on frame F.  */
+static int
+tty_menu_last_menubar_item (struct frame *f)
+{
+  int i = 0;
+
+  eassert (FRAME_TERMCAP_P (f) && FRAME_LIVE_P (f));
+  if (FRAME_TERMCAP_P (f) && FRAME_LIVE_P (f))
+    {
+      Lisp_Object items = FRAME_MENU_BAR_ITEMS (f);
+
+      while (i < ASIZE (items))
+       {
+         Lisp_Object str;
+
+         str = AREF (items, i + 1);
+         if (NILP (str))
+           break;
+         i += 4;
+       }
+      i -= 4;  /* went one too far */
+    }
+  return i;
+}
+
+/* Find in frame F's menu bar the menu item that is next or previous
+   to the item at X/Y, and return that item's position in X/Y.  WHICH
+   says which one--next or previous--item to look for.  X and Y are
+   measured in character cells.  This should only be called on TTY
+   frames.  */
+static void
+tty_menu_new_item_coords (struct frame *f, int which, int *x, int *y)
+{
+  eassert (FRAME_TERMCAP_P (f) && FRAME_LIVE_P (f));
+  if (FRAME_TERMCAP_P (f) && FRAME_LIVE_P (f))
+    {
+      Lisp_Object items = FRAME_MENU_BAR_ITEMS (f);
+      int last_i = tty_menu_last_menubar_item (f);
+      int i, prev_x;
+
+      /* This loop assumes a single menu-bar line, and will fail to
+        find an item if it is not in the first line.  Note that
+        make_lispy_event in keyboard.c makes the same assumption.  */
+      for (i = 0, prev_x = -1; i < ASIZE (items); i += 4)
+       {
+         Lisp_Object pos, str;
+         int ix;
+
+         str = AREF (items, i + 1);
+         pos = AREF (items, i + 3);
+         if (NILP (str))
+           return;
+         ix = XINT (pos);
+         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)))
+           {
+             /* Found current item.  Now compute the X coordinate of
+                the previous or next item.  */
+             if (which == TTYM_NEXT)
+               {
+                 if (i < last_i)
+                   *x = XINT (AREF (items, i + 4 + 3));
+                 else
+                   *x = 0;     /* wrap around to the first item */
+               }
+             else if (prev_x < 0)
+               {
+                 /* Wrap around to the last item.  */
+                 *x = XINT (AREF (items, last_i + 3));
+               }
+             else
+               *x = prev_x;
+             return;
+           }
+         prev_x = ix;
+       }
+    }
+}
+
+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 *menu;
+  int pane, selidx, lpane, status;
+  Lisp_Object entry, pane_prefix;
+  char *datap;
+  int ulx, uly, width, height;
+  int item_x, item_y;
+  int dispwidth, dispheight;
+  int i, j, lines, maxlines;
+  int maxwidth;
+  int dummy_int;
+  unsigned int dummy_uint;
+  ptrdiff_t specpdl_count = SPECPDL_INDEX ();
+
+  if (! FRAME_TERMCAP_P (f))
+    emacs_abort ();
+
+  *error_name = 0;
+  if (menu_items_n_panes == 0)
+    return Qnil;
+
+  if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
+    {
+      *error_name = "Empty menu";
+      return Qnil;
+    }
+
+  /* Make the menu on that window.  */
+  menu = tty_menu_create ();
+  if (menu == NULL)
+    {
+      *error_name = "Can't create menu";
+      return Qnil;
+    }
+
+  /* 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 ();
+
+  /* Adjust coordinates to be root-window-relative.  */
+  item_x = x += f->left_pos;
+  item_y = y += f->top_pos;
+
+  /* Create all the necessary panes and their items.  */
+  maxwidth = maxlines = lines = i = 0;
+  lpane = TTYM_FAILURE;
+  while (i < menu_items_used)
+    {
+      if (EQ (AREF (menu_items, i), Qt))
+       {
+         /* Create a new pane.  */
+         Lisp_Object pane_name, prefix;
+         const char *pane_string;
+
+          maxlines = max (maxlines, lines);
+          lines = 0;
+         pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
+         prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
+         pane_string = (NILP (pane_name)
+                        ? "" : SSDATA (pane_name));
+         if (keymaps && !NILP (prefix))
+           pane_string++;
+
+         lpane = tty_menu_add_pane (menu, pane_string);
+         if (lpane == TTYM_FAILURE)
+           {
+             tty_menu_destroy (menu);
+             *error_name = "Can't create pane";
+             return Qnil;
+           }
+         i += MENU_ITEMS_PANE_LENGTH;
+
+         /* Find the width of the widest item in this pane.  */
+         j = i;
+         while (j < menu_items_used)
+           {
+             Lisp_Object item;
+             item = AREF (menu_items, j);
+             if (EQ (item, Qt))
+               break;
+             if (NILP (item))
+               {
+                 j++;
+                 continue;
+               }
+             width = SBYTES (item);
+             if (width > maxwidth)
+               maxwidth = width;
+
+             j += MENU_ITEMS_ITEM_LENGTH;
+           }
+       }
+      /* Ignore a nil in the item list.
+        It's meaningful only for dialog boxes.  */
+      else if (EQ (AREF (menu_items, i), Qquote))
+       i += 1;
+      else
+       {
+         /* Create a new item within current pane.  */
+         Lisp_Object item_name, enable, descrip, help;
+         char *item_data;
+         char const *help_string;
+
+         item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
+         enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
+         descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
+         help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
+         help_string = STRINGP (help) ? SSDATA (help) : NULL;
+
+         if (!NILP (descrip))
+           {
+             /* if alloca is fast, use that to make the space,
+                to reduce gc needs.  */
+             item_data = (char *) alloca (maxwidth + SBYTES (descrip) + 1);
+             memcpy (item_data, SSDATA (item_name), SBYTES (item_name));
+             for (j = SCHARS (item_name); j < maxwidth; j++)
+               item_data[j] = ' ';
+             memcpy (item_data + j, SSDATA (descrip), SBYTES (descrip));
+             item_data[j + SBYTES (descrip)] = 0;
+           }
+         else
+           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_destroy (menu);
+             *error_name = "Can't add selection to menu";
+             return Qnil;
+           }
+         i += MENU_ITEMS_ITEM_LENGTH;
+          lines++;
+       }
+    }
+
+  maxlines = max (maxlines, lines);
+
+  /* All set and ready to fly.  */
+  dispwidth = f->text_cols;
+  dispheight = f->text_lines;
+  x = min (x, dispwidth);
+  y = min (y, dispheight);
+  x = max (x, 1);
+  y = max (y, 1);
+  tty_menu_locate (menu, x, y, &ulx, &uly, &width, &height);
+  if (ulx+width > dispwidth)
+    {
+      x -= (ulx + width) - dispwidth;
+      ulx = dispwidth - width;
+    }
+  if (uly+height > dispheight)
+    {
+      y -= (uly + height) - dispheight;
+      uly = dispheight - height;
+    }
+
+  if (FRAME_HAS_MINIBUF_P (f) && uly+height > dispheight - 2)
+    {
+      /* Move the menu away of the echo area, to avoid overwriting the
+        menu with help echo messages or vice versa.  */
+      if (BUFFERP (echo_area_buffer[0]) && WINDOWP (echo_area_window))
+       {
+         y -= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window)) + 1;
+         uly -= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window)) + 1;
+       }
+      else
+       {
+         y -= 2;
+         uly -= 2;
+       }
+    }
+
+  if (ulx < 0) x -= ulx;
+  if (uly < 0) y -= uly;
+
+#if 0
+  /* This code doesn't make sense on a TTY, since it can easily annul
+     the adjustments above that carefully avoid truncation of the menu
+     items.  I think it was written to fix some problem that only
+     happens on X11.  */
+  if (! for_click)
+    {
+      /* If position was not given by a mouse click, adjust so upper left
+         corner of the menu as a whole ends up at given coordinates.  This
+         is what x-popup-menu says in its documentation.  */
+      x += width/2;
+      y += 1.5*height/(maxlines+2);
+    }
+#endif
+
+  pane = selidx = 0;
+
+  record_unwind_protect (tty_pop_down_menu, make_save_ptr (menu));
+
+  specbind (Qoverriding_terminal_local_map,
+           Fsymbol_value (Qtty_menu_navigation_map));
+  status = tty_menu_activate (menu, &pane, &selidx, x, y, &datap,
+                             tty_menu_help_callback, kbd_navigation);
+  entry = pane_prefix = Qnil;
+
+  switch (status)
+    {
+    case TTYM_SUCCESS:
+      /* Find the item number SELIDX in pane number PANE.  */
+      i = 0;
+      while (i < menu_items_used)
+       {
+         if (EQ (AREF (menu_items, i), Qt))
+           {
+             if (pane == 0)
+               pane_prefix
+                 = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
+             pane--;
+             i += MENU_ITEMS_PANE_LENGTH;
+           }
+         else
+           {
+             if (pane == -1)
+               {
+                 if (selidx == 0)
+                   {
+                     entry
+                       = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
+                     if (keymaps != 0)
+                       {
+                         entry = Fcons (entry, Qnil);
+                         if (!NILP (pane_prefix))
+                           entry = Fcons (pane_prefix, entry);
+                       }
+                     break;
+                   }
+                 selidx--;
+               }
+             i += MENU_ITEMS_ITEM_LENGTH;
+           }
+       }
+      break;
+
+    case TTYM_NEXT:
+    case TTYM_PREV:
+      tty_menu_new_item_coords (f, status, &item_x, &item_y);
+      entry = Fcons (make_number (item_x), make_number (item_y));
+      break;
+
+    case TTYM_FAILURE:
+      *error_name = "Can't activate menu";
+    case TTYM_IA_SELECT:
+      break;
+    case TTYM_NO_SELECT:
+      /* Make "Cancel" equivalent to C-g unless FOR_CLICK (which means
+        the menu was invoked with a mouse event as POSITION).  */
+      if (! for_click)
+        Fsignal (Qquit, Qnil);
+      break;
+    }
+
+  unbind_to (specpdl_count, Qnil);
+
+  return entry;
+}
+
+#endif /* HAVE_MENUS && !MSDOS */
+
+
 #ifndef MSDOS
 /***********************************************************************
                            Initialization
@@ -3514,4 +4625,14 @@
 
   encode_terminal_src = NULL;
   encode_terminal_dst = NULL;
+
+  DEFSYM (Qtty_menu_next_item, "tty-menu-next-item");
+  DEFSYM (Qtty_menu_prev_item, "tty-menu-prev-item");
+  DEFSYM (Qtty_menu_next_menu, "tty-menu-next-menu");
+  DEFSYM (Qtty_menu_prev_menu, "tty-menu-prev-menu");
+  DEFSYM (Qtty_menu_select, "tty-menu-select");
+  DEFSYM (Qtty_menu_ignore, "tty-menu-ignore");
+  DEFSYM (Qtty_menu_exit, "tty-menu-exit");
+  DEFSYM (Qtty_menu_mouse_movement, "tty-menu-mouse-movement");
+  DEFSYM (Qtty_menu_navigation_map, "tty-menu-navigation-map");
 }

=== modified file 'src/termchar.h'
--- a/src/termchar.h    2013-09-11 08:24:05 +0000
+++ b/src/termchar.h    2013-09-26 07:37:16 +0000
@@ -194,6 +194,9 @@
   /* Nonzero means use ^S/^Q for flow control.  */
 
   unsigned flow_control : 1;
+
+  /* Non-zero means we are displaying a TTY menu on this tty.  */
+  unsigned showing_menu : 1;
 };
 
 /* A chain of structures for all tty devices currently in use. */

=== modified file 'src/termhooks.h'
--- a/src/termhooks.h   2013-09-20 15:34:36 +0000
+++ b/src/termhooks.h   2013-09-26 07:37:16 +0000
@@ -656,6 +656,14 @@
 extern void close_gpm (int gpm_fd);
 #endif
 
+#ifdef WINDOWSNT
+extern int cursorX (struct tty_display_info *);
+extern int cursorY (struct tty_display_info *);
+#else
+#define cursorX(t)  curX(t)
+#define cursorY(t)  curY(t)
+#endif
+
 INLINE_HEADER_END
 
 #endif /* EMACS_TERMHOOKS_H */

=== modified file 'src/w32console.c'
--- a/src/w32console.c  2013-09-23 03:30:55 +0000
+++ b/src/w32console.c  2013-09-26 07:37:16 +0000
@@ -62,6 +62,7 @@
 static WORD    char_attr_normal;
 static DWORD   prev_console_mode;
 
+static CONSOLE_CURSOR_INFO console_cursor_info;
 #ifndef USE_SEPARATE_SCREEN
 static CONSOLE_CURSOR_INFO prev_console_cursor;
 #endif
@@ -95,6 +96,22 @@
   SetConsoleCursorPosition (cur_screen, cursor_coords);
 }
 
+void
+w32con_hide_cursor (void)
+{
+  GetConsoleCursorInfo (cur_screen, &console_cursor_info);
+  console_cursor_info.bVisible = FALSE;
+  SetConsoleCursorInfo (cur_screen, &console_cursor_info);
+}
+
+void
+w32con_show_cursor (void)
+{
+  GetConsoleCursorInfo (cur_screen, &console_cursor_info);
+  console_cursor_info.bVisible = TRUE;
+  SetConsoleCursorInfo (cur_screen, &console_cursor_info);
+}
+
 /* Clear from cursor to end of screen.  */
 static void
 w32con_clear_to_end (struct frame *f)
@@ -552,6 +569,21 @@
 }
 
 
+/* Report the current cursor position.  The following two functions
+   are used in term.c's tty menu code, so they are not really
+   "stubs".  */
+int
+cursorX (struct tty_display_info *tty)
+{
+  return cursor_coords.X;
+}
+
+int
+cursorY (struct tty_display_info *tty)
+{
+  return cursor_coords.Y;
+}
+
 /***********************************************************************
                                Faces
  ***********************************************************************/

=== modified file 'src/w32fns.c'
--- a/src/w32fns.c      2013-09-15 08:28:30 +0000
+++ b/src/w32fns.c      2013-09-26 07:37:16 +0000
@@ -5467,7 +5467,10 @@
     f = SELECTED_FRAME ();
 
   if (!FRAME_W32_P (f))
-    return;
+    {
+      unblock_input ();
+      return;
+    }
 
   w32_show_hourglass (f);
   unblock_input ();

=== modified file 'src/w32inevt.c'
--- a/src/w32inevt.c    2013-08-03 03:29:03 +0000
+++ b/src/w32inevt.c    2013-09-21 14:53:04 +0000
@@ -712,12 +712,17 @@
       while (nev > 0)
         {
          struct input_event inev;
+         /* Having a separate variable with this value makes
+            debugging easier, as otherwise the compiler might
+            rearrange the switch below in a way that makes it hard to
+            track the event type.  */
+         unsigned evtype = queue_ptr->EventType;
 
          EVENT_INIT (inev);
          inev.kind = NO_EVENT;
          inev.arg = Qnil;
 
-         switch (queue_ptr->EventType)
+         switch (evtype)
             {
             case KEY_EVENT:
              add = key_event (&queue_ptr->Event.KeyEvent, &inev, &isdead);

=== modified file 'src/w32menu.c'
--- a/src/w32menu.c     2013-09-24 06:43:20 +0000
+++ b/src/w32menu.c     2013-09-29 18:38:56 +0000
@@ -115,129 +115,34 @@
 void w32_free_menu_strings (HWND);
 
 #ifdef HAVE_MENUS
-
-DEFUN ("x-popup-dialog", Fx_popup_dialog, Sx_popup_dialog, 2, 3, 0,
-       doc: /* Pop up a dialog box and return user's selection.
-POSITION specifies which frame to use.
-This is normally a mouse button event or a window or frame.
-If POSITION is t, it means to use the frame the mouse is on.
-The dialog box appears in the middle of the specified frame.
-
-CONTENTS specifies the alternatives to display in the dialog box.
-It is a list of the form (TITLE ITEM1 ITEM2...).
-Each ITEM is a cons cell (STRING . VALUE).
-The return value is VALUE from the chosen item.
-
-An ITEM may also be just a string--that makes a nonselectable item.
-An ITEM may also be nil--that means to put all preceding items
-on the left of the dialog box and all following items on the right.
-\(By default, approximately half appear on each side.)
-
-If HEADER is non-nil, the frame title for the box is "Information",
-otherwise it is "Question". */)
-  (Lisp_Object position, Lisp_Object contents, Lisp_Object header)
+#ifdef HAVE_DIALOGS
+Lisp_Object
+w32_popup_dialog (struct frame *f, Lisp_Object header, Lisp_Object contents)
 {
-  struct frame *f = NULL;
-  Lisp_Object window;
-
-  /* Decode the first argument: find the window or frame to use.  */
-  if (EQ (position, Qt)
-      || (CONSP (position) && (EQ (XCAR (position), Qmenu_bar)
-                               || EQ (XCAR (position), Qtool_bar))))
-    {
-#if 0 /* Using the frame the mouse is on may not be right.  */
-      /* Use the mouse's current position.  */
-      struct frame *new_f = SELECTED_FRAME ();
-      Lisp_Object bar_window;
-      enum scroll_bar_part part;
-      Time time;
-      Lisp_Object x, y;
-
-      (*mouse_position_hook) (&new_f, 1, &bar_window, &part, &x, &y, &time);
-
-      if (new_f != 0)
-       XSETFRAME (window, new_f);
-      else
-       window = selected_window;
-#endif
-      window = selected_window;
-    }
-  else if (CONSP (position))
-    {
-      Lisp_Object tem = XCAR (position);
-      if (CONSP (tem))
-       window = Fcar (XCDR (position));
-      else
-       {
-         tem = Fcar (XCDR (position));  /* EVENT_START (position) */
-         window = Fcar (tem);       /* POSN_WINDOW (tem) */
-       }
-    }
-  else if (WINDOWP (position) || FRAMEP (position))
-    window = position;
-  else
-    window = Qnil;
-
-  /* Decode where to put the menu.  */
-
-  if (FRAMEP (window))
-    f = XFRAME (window);
-  else if (WINDOWP (window))
-    {
-      CHECK_LIVE_WINDOW (window);
-      f = XFRAME (WINDOW_FRAME (XWINDOW (window)));
-    }
-  else
-    /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
-       but I don't want to make one now.  */
-    CHECK_WINDOW (window);
+  Lisp_Object title;
+  char *error_name;
+  Lisp_Object selection;
 
   check_window_system (f);
 
-#ifndef HAVE_DIALOGS
-
-  {
-    /* Handle simple Yes/No choices as MessageBox popups.  */
-    if (is_simple_dialog (contents))
-      return simple_dialog_show (f, contents, header);
-    else
-      {
-       /* Display a menu with these alternatives
-          in the middle of frame F.  */
-       Lisp_Object x, y, frame, newpos;
-       XSETFRAME (frame, f);
-       XSETINT (x, FRAME_PIXEL_WIDTH (f) / 2);
-       XSETINT (y, FRAME_PIXEL_HEIGHT (f) / 2);
-       newpos = Fcons (Fcons (x, Fcons (y, Qnil)), Fcons (frame, Qnil));
-       return Fx_popup_menu (newpos,
-                             Fcons (Fcar (contents), Fcons (contents, Qnil)));
-      }
-  }
-#else /* HAVE_DIALOGS */
-  {
-    Lisp_Object title;
-    char *error_name;
-    Lisp_Object selection;
-
-    /* Decode the dialog items from what was specified.  */
-    title = Fcar (contents);
-    CHECK_STRING (title);
-
-    list_of_panes (Fcons (contents, Qnil));
-
-    /* Display them in a dialog box.  */
-    block_input ();
-    selection = w32_dialog_show (f, 0, title, header, &error_name);
-    unblock_input ();
-
-    discard_menu_items ();
-    FRAME_DISPLAY_INFO (f)->grabbed = 0;
-
-    if (error_name) error (error_name);
-    return selection;
-  }
+  /* Decode the dialog items from what was specified.  */
+  title = Fcar (contents);
+  CHECK_STRING (title);
+
+  list_of_panes (Fcons (contents, Qnil));
+
+  /* Display them in a dialog box.  */
+  block_input ();
+  selection = w32_dialog_show (f, 0, title, header, &error_name);
+  unblock_input ();
+
+  discard_menu_items ();
+  FRAME_DISPLAY_INFO (f)->grabbed = 0;
+
+  if (error_name) error (error_name);
+  return selection;
+}
 #endif /* HAVE_DIALOGS */
-}
 
 /* Activate the menu bar of frame F.
    This is called from keyboard.c when it gets the
@@ -682,6 +587,8 @@
       return Qnil;
     }
 
+  block_input ();
+
   /* Create a tree of widget_value objects
      representing the panes and their items.  */
   wv = xmalloc_widget_value ();
@@ -940,6 +847,7 @@
                        if (!NILP (subprefix_stack[j]))
                          entry = Fcons (subprefix_stack[j], entry);
                    }
+                 unblock_input ();
                  return entry;
                }
              i += MENU_ITEMS_ITEM_LENGTH;
@@ -947,9 +855,13 @@
        }
     }
   else if (!for_click)
-    /* Make "Cancel" equivalent to C-g.  */
-    Fsignal (Qquit, Qnil);
+    {
+      unblock_input ();
+      /* Make "Cancel" equivalent to C-g.  */
+      Fsignal (Qquit, Qnil);
+    }
 
+  unblock_input ();
   return Qnil;
 }
 
@@ -1717,9 +1629,6 @@
   DEFSYM (Qdebug_on_next_call, "debug-on-next-call");
 
   defsubr (&Smenu_or_popup_active_p);
-#ifdef HAVE_MENUS
-  defsubr (&Sx_popup_dialog);
-#endif
 }
 
 /*

=== modified file 'src/w32term.h'
--- a/src/w32term.h     2013-09-19 07:48:53 +0000
+++ b/src/w32term.h     2013-09-29 18:38:56 +0000
@@ -264,6 +264,10 @@
 
 extern Lisp_Object x_get_focus_frame (struct frame *);
 
+/* w32console.c */
+extern void w32con_hide_cursor (void);
+extern void w32con_show_cursor (void);
+
 
 #define PIX_TYPE COLORREF
 
@@ -794,6 +798,10 @@
 
 #define GUI_SDATA(x) ((guichar_t*) SDATA (x))
 
+#if defined HAVE_DIALOGS
+extern Lisp_Object w32_popup_dialog (struct frame *, Lisp_Object, Lisp_Object);
+#endif
+
 extern void syms_of_w32term (void);
 extern void syms_of_w32menu (void);
 extern void syms_of_w32fns (void);

=== modified file 'src/window.c'
--- a/src/window.c      2013-10-02 12:08:27 +0000
+++ b/src/window.c      2013-10-08 17:49:20 +0000
@@ -5540,18 +5540,26 @@
          || data->frame_cols != previous_frame_cols)
        change_frame_size (f, data->frame_lines,
                           data->frame_cols, 0, 0, 0);
-#if defined (HAVE_WINDOW_SYSTEM) || defined (MSDOS)
+#ifdef HAVE_MENUS
       if (data->frame_menu_bar_lines
          != previous_frame_menu_bar_lines)
-       x_set_menu_bar_lines (f, make_number (data->frame_menu_bar_lines),
-                             make_number (0));
+       {
+#ifdef HAVE_WINDOW_SYSTEM
+         if (FRAME_WINDOW_P (f))
+           x_set_menu_bar_lines (f, make_number (data->frame_menu_bar_lines),
+                                 make_number (0));
+         else  /* TTY or MSDOS */
+#endif
+           set_menu_bar_lines (f, make_number (data->frame_menu_bar_lines),
+                               make_number (0));
+       }
+#endif
 #ifdef HAVE_WINDOW_SYSTEM
       if (data->frame_tool_bar_lines
          != previous_frame_tool_bar_lines)
        x_set_tool_bar_lines (f, make_number (data->frame_tool_bar_lines),
                              make_number (0));
 #endif
-#endif
 
       /* "Swap out" point from the selected window's buffer
         into the window itself.  (Normally the pointm of the selected
@@ -5738,16 +5746,25 @@
          || previous_frame_cols != FRAME_COLS (f))
        change_frame_size (f, previous_frame_lines, previous_frame_cols,
                           0, 0, 0);
-#if defined (HAVE_WINDOW_SYSTEM) || defined (MSDOS)
+#ifdef HAVE_MENUS
       if (previous_frame_menu_bar_lines != FRAME_MENU_BAR_LINES (f))
-       x_set_menu_bar_lines (f, make_number (previous_frame_menu_bar_lines),
-                             make_number (0));
+       {
+#ifdef HAVE_WINDOW_SYSTEM
+         if (FRAME_WINDOW_P (f))
+           x_set_menu_bar_lines (f,
+                                 make_number (previous_frame_menu_bar_lines),
+                                 make_number (0));
+         else  /* TTY or MSDOS */
+#endif
+           set_menu_bar_lines (f, make_number (previous_frame_menu_bar_lines),
+                               make_number (0));
+       }
+#endif
 #ifdef HAVE_WINDOW_SYSTEM
       if (previous_frame_tool_bar_lines != FRAME_TOOL_BAR_LINES (f))
        x_set_tool_bar_lines (f, make_number (previous_frame_tool_bar_lines),
                              make_number (0));
 #endif
-#endif
 
       /* Now, free glyph matrices in windows that were not reused.  */
       for (i = n = 0; i < n_leaf_windows; ++i)

=== modified file 'src/xdisp.c'
--- a/src/xdisp.c       2013-10-08 14:56:15 +0000
+++ b/src/xdisp.c       2013-10-08 17:49:20 +0000
@@ -20584,7 +20584,128 @@
   compute_line_metrics (&it);
 }
 
-
+#ifdef HAVE_MENUS
+/* Deep copy of a glyph row, including the glyphs.  */
+static void
+deep_copy_glyph_row (struct glyph_row *to, struct glyph_row *from)
+{
+  int area, i, sum_used = 0;
+  struct glyph *pointers[1 + LAST_AREA];
+
+  /* Save glyph pointers of TO.  */
+  memcpy (pointers, to->glyphs, sizeof to->glyphs);
+
+  /* Do a structure assignment.  */
+  *to = *from;
+
+  /* Restore original pointers of TO.  */
+  memcpy (to->glyphs, pointers, sizeof to->glyphs);
+
+  /* Count how many glyphs to copy and update glyph pointers.  */
+  for (area = LEFT_MARGIN_AREA; area < LAST_AREA; ++area)
+    {
+      if (area > LEFT_MARGIN_AREA)
+       {
+         eassert (from->glyphs[area] - from->glyphs[area - 1]
+                  == from->used[area - 1]);
+         to->glyphs[area] = to->glyphs[area - 1] + to->used[area - 1];
+       }
+      sum_used += from->used[area];
+    }
+
+  /* Copy the glyphs.  */
+  eassert (sum_used <= to->glyphs[LAST_AREA] - to->glyphs[LEFT_MARGIN_AREA]);
+  for (i = 0; i < sum_used; i++)
+    to->glyphs[LEFT_MARGIN_AREA][i] = from->glyphs[LEFT_MARGIN_AREA][i];
+}
+
+/* Display one menu item on a TTY, by overwriting the glyphs in the
+   frame F's desired glyph matrix with glyphs produced from the menu
+   item text.  Called from term.c to display TTY drop-down menus one
+   item at a time.
+
+   ITEM_TEXT is the menu item text as a C string.
+
+   FACE_ID is the face ID to be used for this menu item.  FACE_ID
+   could specify one of 3 faces: a face for an enabled item, a face
+   for a disabled item, or a face for a selected item.
+
+   X and Y are coordinates of the first glyph in the frame's desired
+   matrix to be overwritten by the menu item.  Since this is a TTY, Y
+   is the zero-based number of the glyph row and X is the zero-based
+   glyph number in the row, starting from left, where to start
+   displaying the item.
+
+   SUBMENU non-zero means this menu item drops down a submenu, which
+   should be indicated by displaying a proper visual cue after the
+   item text.  */
+
+void
+display_tty_menu_item (const char *item_text, int width, int face_id,
+                      int x, int y, int submenu)
+{
+  struct it it;
+  struct frame *f = SELECTED_FRAME ();
+  struct window *w = XWINDOW (f->selected_window);
+  int saved_used, saved_truncated, saved_width, saved_reversed;
+  struct glyph_row *row;
+  size_t item_len = strlen (item_text);
+
+  eassert (FRAME_TERMCAP_P (f));
+
+  init_iterator (&it, w, -1, -1, f->desired_matrix->rows + y, MENU_FACE_ID);
+  it.first_visible_x = 0;
+  it.last_visible_x = FRAME_COLS (f) - 1;
+  row = it.glyph_row;
+  /* Start with the row contents from the current matrix.  */
+  deep_copy_glyph_row (row, f->current_matrix->rows + y);
+  saved_width = row->full_width_p;
+  row->full_width_p = 1;
+  saved_reversed = row->reversed_p;
+  row->reversed_p = 0;
+  row->enabled_p = 1;
+
+  /* Arrange for the menu item glyphs to start at (X,Y) and have the
+     desired face.  */
+  it.current_x = it.hpos = x;
+  it.current_y = it.vpos = y;
+  saved_used = row->used[TEXT_AREA];
+  saved_truncated = row->truncated_on_right_p;
+  row->used[TEXT_AREA] = x;
+  it.face_id = face_id;
+  it.line_wrap = TRUNCATE;
+
+  /* FIXME: This should be controlled by a user option.  See the
+     comments in redisplay_tool_bar and display_mode_line about this.
+     Also, if paragraph_embedding could ever be R2L, changes will be
+     needed to avoid shifting to the right the row characters in
+     term.c:append_glyph.  */
+  it.paragraph_embedding = L2R;
+
+  /* Pad with a space on the left.  */
+  display_string (" ", Qnil, Qnil, 0, 0, &it, 1, 0, FRAME_COLS (f) - 1, -1);
+  width--;
+  /* Display the menu item, pad with spaces to WIDTH.  */
+  if (submenu)
+    {
+      display_string (item_text, Qnil, Qnil, 0, 0, &it,
+                     item_len, 0, FRAME_COLS (f) - 1, -1);
+      width -= item_len;
+      /* Indicate with " >" that there's a submenu.  */
+      display_string (" >", Qnil, Qnil, 0, 0, &it, width, 0,
+                     FRAME_COLS (f) - 1, -1);
+    }
+  else
+    display_string (item_text, Qnil, Qnil, 0, 0, &it,
+                   width, 0, FRAME_COLS (f) - 1, -1);
+
+  row->used[TEXT_AREA] = max (saved_used, row->used[TEXT_AREA]);
+  row->truncated_on_right_p = saved_truncated;
+  row->hash = row_hash (row);
+  row->full_width_p = saved_width;
+  row->reversed_p = saved_reversed;
+}
+#endif /* HAVE_MENUS */
 
 /***********************************************************************
                              Mode Line

=== modified file 'src/xmenu.c'
--- a/src/xmenu.c       2013-09-24 06:43:20 +0000
+++ b/src/xmenu.c       2013-09-29 18:38:56 +0000
@@ -192,149 +192,6 @@
 
 #endif /* HAVE_X_WINDOWS */
 
-#ifdef HAVE_MENUS
-
-DEFUN ("x-popup-dialog", Fx_popup_dialog, Sx_popup_dialog, 2, 3, 0,
-       doc: /* Pop up a dialog box and return user's selection.
-POSITION specifies which frame to use.
-This is normally a mouse button event or a window or frame.
-If POSITION is t, it means to use the frame the mouse is on.
-The dialog box appears in the middle of the specified frame.
-
-CONTENTS specifies the alternatives to display in the dialog box.
-It is a list of the form (DIALOG ITEM1 ITEM2...).
-Each ITEM is a cons cell (STRING . VALUE).
-The return value is VALUE from the chosen item.
-
-An ITEM may also be just a string--that makes a nonselectable item.
-An ITEM may also be nil--that means to put all preceding items
-on the left of the dialog box and all following items on the right.
-\(By default, approximately half appear on each side.)
-
-If HEADER is non-nil, the frame title for the box is "Information",
-otherwise it is "Question".
-
-If the user gets rid of the dialog box without making a valid choice,
-for instance using the window manager, then this produces a quit and
-`x-popup-dialog' does not return.  */)
-  (Lisp_Object position, Lisp_Object contents, Lisp_Object header)
-{
-  struct frame *f = NULL;
-  Lisp_Object window;
-
-  /* Decode the first argument: find the window or frame to use.  */
-  if (EQ (position, Qt)
-      || (CONSP (position) && (EQ (XCAR (position), Qmenu_bar)
-                              || EQ (XCAR (position), Qtool_bar))))
-    {
-#if 0 /* Using the frame the mouse is on may not be right.  */
-      /* Use the mouse's current position.  */
-      struct frame *new_f = SELECTED_FRAME ();
-      Lisp_Object bar_window;
-      enum scroll_bar_part part;
-      Time time;
-      Lisp_Object x, y;
-
-      (*mouse_position_hook) (&new_f, 1, &bar_window, &part, &x, &y, &time);
-
-      if (new_f != 0)
-       XSETFRAME (window, new_f);
-      else
-       window = selected_window;
-#endif
-      window = selected_window;
-    }
-  else if (CONSP (position))
-    {
-      Lisp_Object tem = XCAR (position);
-      if (CONSP (tem))
-       window = Fcar (XCDR (position));
-      else
-       {
-         tem = Fcar (XCDR (position));  /* EVENT_START (position) */
-         window = Fcar (tem);       /* POSN_WINDOW (tem) */
-       }
-    }
-  else if (WINDOWP (position) || FRAMEP (position))
-    window = position;
-  else
-    window = Qnil;
-
-  /* Decode where to put the menu.  */
-
-  if (FRAMEP (window))
-    f = XFRAME (window);
-  else if (WINDOWP (window))
-    {
-      CHECK_LIVE_WINDOW (window);
-      f = XFRAME (WINDOW_FRAME (XWINDOW (window)));
-    }
-  else
-    /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
-       but I don't want to make one now.  */
-    CHECK_WINDOW (window);
-
-  check_window_system (f);
-
-  /* Force a redisplay before showing the dialog.  If a frame is created
-     just before showing the dialog, its contents may not have been fully
-     drawn, as this depends on timing of events from the X server.  Redisplay
-     is not done when a dialog is shown.  If redisplay could be done in the
-     X event loop (i.e. the X event loop does not run in a signal handler)
-     this would not be needed.
-
-     Do this before creating the widget value that points to Lisp
-     string contents, because Fredisplay may GC and relocate them.  */
-  Fredisplay (Qt);
-
-#if ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK)
-  /* Display a menu with these alternatives
-     in the middle of frame F.  */
-  {
-    Lisp_Object x, y, frame, newpos;
-    XSETFRAME (frame, f);
-    XSETINT (x, FRAME_PIXEL_WIDTH (f) / 2);
-    XSETINT (y, FRAME_PIXEL_HEIGHT (f) / 2);
-    newpos = list2 (list2 (x, y), frame);
-
-    return Fx_popup_menu (newpos,
-                         list2 (Fcar (contents), contents));
-  }
-#else
-  {
-    Lisp_Object title;
-    const char *error_name;
-    Lisp_Object selection;
-    ptrdiff_t specpdl_count = SPECPDL_INDEX ();
-
-    /* Decode the dialog items from what was specified.  */
-    title = Fcar (contents);
-    CHECK_STRING (title);
-    record_unwind_protect_void (unuse_menu_items);
-
-    if (NILP (Fcar (Fcdr (contents))))
-      /* No buttons specified, add an "Ok" button so users can pop down
-         the dialog.  Also, the lesstif/motif version crashes if there are
-         no buttons.  */
-      contents = list2 (title, Fcons (build_string ("Ok"), Qt));
-
-    list_of_panes (list1 (contents));
-
-    /* Display them in a dialog box.  */
-    block_input ();
-    selection = xdialog_show (f, 0, title, header, &error_name);
-    unblock_input ();
-
-    unbind_to (specpdl_count, Qnil);
-    discard_menu_items ();
-
-    if (error_name) error ("%s", error_name);
-    return selection;
-  }
-#endif
-}
-
-
 #ifndef MSDOS
 
 #if defined USE_GTK || defined USE_MOTIF
@@ -1618,6 +1475,8 @@
       return Qnil;
     }
 
+  block_input ();
+
   /* Create a tree of widget_value objects
      representing the panes and their items.  */
   wv = xmalloc_widget_value ();
@@ -1857,6 +1716,7 @@
                        if (!NILP (subprefix_stack[j]))
                          entry = Fcons (subprefix_stack[j], entry);
                    }
+                 unblock_input ();
                  return entry;
                }
              i += MENU_ITEMS_ITEM_LENGTH;
@@ -1864,9 +1724,13 @@
        }
     }
   else if (!for_click)
-    /* Make "Cancel" equivalent to C-g.  */
-    Fsignal (Qquit, Qnil);
+    {
+      unblock_input ();
+      /* Make "Cancel" equivalent to C-g.  */
+      Fsignal (Qquit, Qnil);
+    }
 
+  unblock_input ();
   return Qnil;
 }
 
@@ -2163,6 +2027,41 @@
   return Qnil;
 }
 
+Lisp_Object
+xw_popup_dialog (struct frame *f, Lisp_Object header, Lisp_Object contents)
+{
+  Lisp_Object title;
+  const char *error_name;
+  Lisp_Object selection;
+  ptrdiff_t specpdl_count = SPECPDL_INDEX ();
+
+  check_window_system (f);
+
+  /* Decode the dialog items from what was specified.  */
+  title = Fcar (contents);
+  CHECK_STRING (title);
+  record_unwind_protect_void (unuse_menu_items);
+
+  if (NILP (Fcar (Fcdr (contents))))
+    /* No buttons specified, add an "Ok" button so users can pop down
+       the dialog.  Also, the lesstif/motif version crashes if there are
+       no buttons.  */
+    contents = list2 (title, Fcons (build_string ("Ok"), Qt));
+
+  list_of_panes (list1 (contents));
+
+  /* Display them in a dialog box.  */
+  block_input ();
+  selection = xdialog_show (f, 0, title, header, &error_name);
+  unblock_input ();
+
+  unbind_to (specpdl_count, Qnil);
+  discard_menu_items ();
+
+  if (error_name) error ("%s", error_name);
+  return selection;
+}
+
 #else /* not USE_X_TOOLKIT && not USE_GTK */
 
 /* The frame of the last activated non-toolkit menu bar.
@@ -2261,6 +2160,8 @@
       return Qnil;
     }
 
+  block_input ();
+
   /* Figure out which root window F is on.  */
   XGetGeometry (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &root,
                &dummy_int, &dummy_int, &dummy_uint, &dummy_uint,
@@ -2271,6 +2172,7 @@
   if (menu == NULL)
     {
       *error_name = "Can't create menu";
+      unblock_input ();
       return Qnil;
     }
 
@@ -2314,6 +2216,7 @@
            {
              XMenuDestroy (FRAME_X_DISPLAY (f), menu);
              *error_name = "Can't create pane";
+             unblock_input ();
              return Qnil;
            }
          i += MENU_ITEMS_PANE_LENGTH;
@@ -2378,6 +2281,7 @@
            {
              XMenuDestroy (FRAME_X_DISPLAY (f), menu);
              *error_name = "Can't add selection to menu";
+             unblock_input ();
              return Qnil;
            }
          i += MENU_ITEMS_ITEM_LENGTH;
@@ -2504,10 +2408,14 @@
       /* Make "Cancel" equivalent to C-g unless FOR_CLICK (which means
         the menu was invoked with a mouse event as POSITION).  */
       if (! for_click)
-        Fsignal (Qquit, Qnil);
+       {
+         unblock_input ();
+         Fsignal (Qquit, Qnil);
+       }
       break;
     }
 
+  unblock_input ();
   unbind_to (specpdl_count, Qnil);
 
   return entry;
@@ -2515,8 +2423,6 @@
 
 #endif /* not USE_X_TOOLKIT */
 
-#endif /* HAVE_MENUS */
-
 #ifndef MSDOS
 /* Detect if a dialog or menu has been posted.  MSDOS has its own
    implementation on msdos.c.  */
@@ -2558,8 +2464,4 @@
   Ffset (intern_c_string ("accelerate-menu"),
         intern_c_string (Sx_menu_bar_open_internal.symbol_name));
 #endif
-
-#ifdef HAVE_MENUS
-  defsubr (&Sx_popup_dialog);
-#endif
 }

=== modified file 'src/xterm.h'
--- a/src/xterm.h       2013-09-19 07:48:53 +0000
+++ b/src/xterm.h       2013-09-29 18:38:56 +0000
@@ -1035,6 +1035,10 @@
 
 /* Defined in xmenu.c */
 
+#if defined USE_X_TOOLKIT || defined USE_GTK
+extern Lisp_Object xw_popup_dialog (struct frame *, Lisp_Object, Lisp_Object);
+#endif
+
 #if defined USE_GTK || defined USE_MOTIF
 extern void x_menu_set_in_use (int);
 #endif


reply via email to

[Prev in Thread] Current Thread [Next in Thread]