From: Eli Zaretskii Date: Tue, 8 Oct 2013 17:49:20 +0000 (+0300) Subject: Support menus on text-mode terminals. X-Git-Tag: emacs-24.3.90~173^2^2~42^2~45^2~387^2~1328 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=4ed774157d1687cc5236ecaf088dc48442e92431;p=emacs.git 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) : 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 : Declare. src/keyboard.c : Now extern. : 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. --- 4ed774157d1687cc5236ecaf088dc48442e92431 diff --cc ChangeLog index ae182046d9b,f8a219d6a15..b7f8c1e8ec0 --- a/ChangeLog +++ b/ChangeLog @@@ -1,28 -1,3 +1,32 @@@ ++2013-10-08 Eli Zaretskii ++ ++ * configure.ac (HAVE_MENUS): Define unconditionally. ++ +2013-10-07 Paul Eggert + + Improve support for popcount and counting trailing zeros (Bug#15550). + Do this by using the Gnulib modules for this. + This should generate faster code on non-GCC, non-MSC platforms, + and make the code a bit more portable, at least in theory. + * lib/count-one-bits.c, lib/count-one-bits.h: + * lib/count-trailing-zeros.c, lib/count-trailing-zeros.h: + * m4/count-one-bits.m4, m4/count-trailing-zeros.m4: + New files, copied from gnulib. + * lib/gnulib.mk, m4/gnulib-comp.m4: Regenerate. + +2013-10-04 Paul Eggert + + Use hardware support for byteswapping on glibc x86 etc. + * lib/byteswap.in.h, m4/byteswap.m4: New files, copied from Gnulib. + * lib/gnulib.mk, m4/gnulib-comp.m4: Regenerate. + +2013-10-03 Paul Eggert + + Merge from gnulib, incorporating: + 2013-10-02 verify: new macro 'assume' + 2013-09-26 dup2, dup3: work around another cygwin crasher + 2013-09-26 getdtablesize: work around cygwin issue + 2013-09-25 Paul Eggert Merge from gnulib, incorporating: diff --cc doc/emacs/ChangeLog index 368d106fc48,abe173d31cc..66665d6ddf9 --- a/doc/emacs/ChangeLog +++ b/doc/emacs/ChangeLog @@@ -1,11 -1,13 +1,22 @@@ -2013-10-02 Eli Zaretskii ++2013-10-08 Eli Zaretskii + ++ 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 + + * cal-xtra.texi (Calendar Customizing, Diary Display): Remove @refill. + +2013-09-29 Xue Fuqiao + + * fortran-xtra.texi (Fortran Abbrev): Remove @refill. + 2013-09-26 Xue Fuqiao * dired.texi (Flagging Many Files): Use @emph instead of @strong. diff --cc doc/lispref/ChangeLog index 0a89dbea3d9,c93f1b7c659..4f6a92ef5f3 --- a/doc/lispref/ChangeLog +++ b/doc/lispref/ChangeLog @@@ -1,25 -1,11 +1,34 @@@ -2013-10-03 Eli Zaretskii ++2013-10-08 Eli Zaretskii + ++ 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 + + * tips.texi (Comment Tips): Discourage use of triple semi-colons for + non-headings. + +2013-10-05 Xue Fuqiao + + * syntax.texi (Categories): Add an index for category sets. + +2013-10-03 Xue Fuqiao + + * syntax.texi (Syntax Flags): + (Syntax Table Functions): Add indexes. + +2013-10-02 Xue Fuqiao + + * syntax.texi (Syntax Class Table): Add an index for syntax class table. + +2013-09-29 Xue Fuqiao + + * searching.texi (Regexp Search): Refine. + 2013-09-22 Xue Fuqiao * nonascii.texi (Default Coding Systems): Typo fix. diff --cc lisp/ChangeLog index 74ca0a23c97,971cc182448..e24ffa5893f --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@@ -1,375 -1,3 +1,399 @@@ ++2013-10-08 Eli Zaretskii ++ ++ 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 + + * emacs-lisp/lisp-mode.el: Font-lock cl-lib constructs. + (lisp-el-font-lock-keywords, lisp-el-font-lock-keywords-1) + (lisp-el-font-lock-keywords-2, lisp-cl-font-lock-keywords) + (lisp-cl-font-lock-keywords-1, lisp-cl-font-lock-keywords-2): + New constants. + (lisp-mode-variables): New `elisp' argument. + (emacs-lisp-mode): Use it. + * font-lock.el (lisp-font-lock-keywords, lisp-font-lock-keywords-1) + (lisp-font-lock-keywords-2): Move to lisp-mode.el. + + * indent.el: Use lexical-binding. + (indent-region): Add progress reporter. + (tab-stop-list): Make it implicitly extend to infinity by repeating the + last step. + (indent--next-tab-stop): New function to implement this behavior. + (tab-to-tab-stop, move-to-tab-stop): Use it. + +2013-10-08 Teemu Likonen + + * indent.el (indent-rigidly--current-indentation): New function. + (indent-rigidly-map): New var. + (indent-rigidly): Use it to provide interactive mode (bug#8196). + +2013-10-08 Bastien Guerry + + * register.el (insert-register): Fix 2013-10-07T01:28:34Z!sdl.web@gmail.com. + +2013-10-08 Stefan Monnier + + * progmodes/perl-mode.el: Use lexical-binding. + Remove redundant :group args. + (perl-nochange): Change default to be closer to other major modes's + standard behavior. + (perl-indent-line): Don't consider text on current line as a + valid beginning of function from which to indent. + + * emacs-lisp/backquote.el (backquote-process): Catch uses of , and ,@ + with more than one argument (bug#15538). + + * mpc.el (mpc-songs-jump-to): Adjust to different playlist format. + + * vc/pcvs.el: Use lexical-binding. + (cvs-temp-buffer, cvs-make-cvs-buffer): Pass some vars in the lexical + environment of `eval'. + (cvs-mode-run, cvs-mode-do): Change `postproc' to be a function rather + than a list of expressions. Adjust callers. + * vc/pcvs-defs.el (cvs-postprocess): Remove, unused. + +2013-10-07 Dmitry Gutov + + * progmodes/ruby-mode.el (ruby-smie--implicit-semi-p): Handle the + case of the dot in a chained method call being on the following line. + +2013-10-07 Stefan Monnier + + * electric.el (electric-indent-inhibit): New var. + (electric-indent-post-self-insert-function): Use it. + * progmodes/python.el (python-mode): Set it. + + * progmodes/ruby-mode.el (ruby-smie-rules): Tweak handling of + open braces. + + * emacs-lisp/smie.el (smie-next-sexp): Refine last fix. + + * textmodes/css-mode.el (css-smie-rules): Fix indentation (bug#15467). + (css-mode): Use electric-indent-chars. + + * nxml/nxml-mode.el: Use lexical-binding and syntax-propertize. + (font-lock-beg, font-lock-end): Move before first use. + (nxml-mode): Use syntax-propertize-function. + (nxml-after-change, nxml-after-change1): Adjust accordingly. + (nxml-extend-after-change-region): Remove. + * nxml/xmltok.el: Use lexical-binding. + (xmltok-save): Use `declare'. + (xmltok-unclosed-reparse-p, xmltok-semi-closed-reparse-p): Remove. + * nxml/nxml-util.el: Use lexical-binding. + (nxml-with-degradation-on-error, nxml-with-invisible-motion): + Use `declare'. + * nxml/nxml-ns.el: Use lexical-binding. + (nxml-ns-save): Use `declare'. + (nxml-ns-prefixes-for): Avoid add-to-list. + * nxml/rng-match.el: Use lexical-binding. + (rng--ipattern): Use cl-defstruct. + (rng-compute-start-tag-open-deriv, rng-compute-start-attribute-deriv) + (rng-cons-group-after, rng-subst-group-after) + (rng-subst-interleave-after, rng-apply-after, rng-compute-data-deriv): + Use closures instead of `(lambda...). + +2013-10-07 Michael Albinus + + * net/tramp.el (tramp-handle-insert-file-contents): Improve handling + of BEG and END. + + * net/tramp-gvfs.el (tramp-gvfs-file-name-handler-alist): + Use `tramp-handle-insert-file-contents'. + (tramp-gvfs-handle-insert-file-contents): Remove function. + + * net/tramp-sh.el (tramp-sh-handle-insert-directory): + Use `save-restriction' in order to keep markers. + + * net/trampver.el: Update release number. + +2013-10-07 Stefan Monnier + + * progmodes/compile.el (compilation-parse-errors): + Use compilation--put-prop. + (compilation--ensure-parse): Check compilation-multiline. + + * emacs-lisp/easymenu.el (easy-menu-create-menu): Use closures. + + * emacs-lisp/lisp-mode.el (eval-defun-2): Simplify, using + lexical-binding. + + * emacs-lisp/tq.el (tq-create): Use a closure instead of `(lambda...). + + * progmodes/ruby-mode.el: Fix recently added tests. + (ruby-smie-grammar): Add - and +. + (ruby-smie--redundant-do-p, ruby-smie--forward-id) + (ruby-smie--backward-id): New functions. + (ruby-smie--forward-token, ruby-smie--backward-token): Use them. + (ruby-smie-rules): Handle hanging do. Get rid of hack, not needed + any more. + +2013-10-07 Leo Liu + + * register.el (register-preview-delay) + (register-preview-functions): New variables. + (register-read-with-preview, register-preview) + (register-describe-oneline): New functions. + (point-to-register, window-configuration-to-register) + (frame-configuration-to-register, jump-to-register) + (number-to-register, view-register, insert-register) + (copy-to-register, append-to-register, prepend-to-register) + (copy-rectangle-to-register): Use register-read-with-preview to + read register. (Bug#15525) + +2013-10-06 Dato Simó (tiny change) + + * net/network-stream.el (network-stream-open-starttls): Don't add + --insecure if it's already present, because that gnutls-cli + rejects getting that parameter twice. + +2013-10-06 Dmitry Gutov + + * progmodes/ruby-mode.el (ruby-smie-rules): Dedent `ensure' + keyword, too. + +2013-10-05 Dmitry Gutov + + * newcomment.el (comment-use-global-state): Change default value + to t, mark obsolete (Bug#15251). + (comment-beginning): In addition to `comment-to-syntax', check the + value of `comment-use-global-state'. + +2013-10-05 Stefan Monnier + + * progmodes/ruby-mode.el (ruby-use-smie): Change default. + (ruby-comment-column): Follow the global default, by default. + (ruby-smie-grammar): Add assignment syntax. + (ruby-smie--implicit-semi-p): No implicit semi-colon after an + open-paren, a comma, or a \. + (ruby-smie--forward-token, ruby-smie--backward-token): Handle heredocs, + and line continuations. + (ruby-smie-rules): Adjust handling of open-paren, now that it's never + followed by implicit semi-colons. Add rule for string concatenation + and for indentation at BOB. + (ruby-forward-sexp, ruby-backward-sexp): Adjust for when smie is in use. + + * emacs-lisp/smie.el (smie-next-sexp): Don't go back to pos before + calling next-sexp, since next-token may have skipped chars which + next-sexp doesn't know should be skipped! + +2013-10-05 Leo Liu + + * progmodes/octave.el (octave-send-region): + Call compilation-forget-errors. + +2013-10-04 Xue Fuqiao + + * vc/vc-svn.el (vc-svn-find-admin-dir): + * vc/vc-rcs.el (vc-rcs-find-admin-dir): + * vc/vc-mtn.el (vc-mtn-find-admin-dir): + * vc/vc-cvs.el (vc-cvs-find-admin-dir): + * vc/vc-arch.el (vc-arch-find-admin-dir): New functions. + +2013-10-04 Stefan Monnier + + * textmodes/css-mode.el (css-smie-rules): Toplevel's a list (bug#15467). + +2013-10-04 Stefan Monnier + + * subr.el (read-passwd): Hide chars even when called within a context + where after-change-functions is disabled (bug#15501). + (set-temporary-overlay-map): Don't remove oneself from pre-command-hook + until we removed ourself from overriding-terminal-local-map. + +2013-10-04 Leo Liu + + * progmodes/octave.el (inferior-octave-mode): + Call compilation-forget-errors. + +2013-10-04 Xue Fuqiao + + * emacs-lisp/syntax.el (syntax-ppss): Doc fix. + +2013-10-04 Michael Albinus + + * net/secrets.el (secrets-create-collection): Add optional + argument ALIAS. Use proper Label keyword. Append ALIAS as + dbus-call-method argument. (Bug#15516) + +2013-10-04 Leo Liu + + * progmodes/octave.el (inferior-octave-error-regexp-alist) + (inferior-octave-compilation-font-lock-keywords): New variables. + (compilation-error-regexp-alist) + (compilation-mode-font-lock-keywords): Defvar to pacify compiler. + (inferior-octave-mode): Use compilation-shell-minor-mode. + +2013-10-04 Jorgen Schaefer + + * minibuffer.el (completion--replace): Be careful that `end' might be + a marker. + +2013-10-03 Daiki Ueno + + Add support for package signature checking. + * emacs-lisp/package.el (url-http-file-exists-p) + (epg-make-context, epg-context-set-home-directory) + (epg-verify-string, epg-context-result-for) + (epg-signature-status, epg-signature-to-string) + (epg-check-configuration, epg-configuration) + (epg-import-keys-from-file): Declare. + (package-check-signature): New user option. + (package-unsigned-archives): New user option. + (package-desc): Add `signed' field. + (package-load-descriptor): Set `signed' field if .signed file exists. + (package--archive-file-exists-p): New function. + (package--check-signature): New function. + (package-install-from-archive): Check package signature. + (package--download-one-archive): Check archive signature. + (package-delete): Remove .signed file. + (package-import-keyring): New command. + (package-refresh-contents): Import default keyring. + (package-desc-status): Add "unsigned" status. + (describe-package-1, package-menu--print-info) + (package-menu-mark-delete, package-menu--find-upgrades) + (package-menu--status-predicate): Support "unsigned" status. + +2013-10-03 Stefan Monnier + + * emacs-lisp/cconv.el (cconv-convert, cconv-analyse-form): Adjust for + the new compilation scheme using the new byte-codes. + + * emacs-lisp/bytecomp.el (byte-pushcatch, byte-pushconditioncase) + (byte-pophandler): New byte codes. + (byte-goto-ops): Adjust accordingly. + (byte-compile--use-old-handlers): New var. + (byte-compile-catch): Use new byte codes depending on + byte-compile--use-old-handlers. + (byte-compile-condition-case--old): Rename from + byte-compile-condition-case. + (byte-compile-condition-case--new): New function. + (byte-compile-condition-case): New function that dispatches depending + on byte-compile--use-old-handlers. + (byte-compile-unwind-protect): Pass a function to byte-unwind-protect + when we can. + + * emacs-lisp/byte-opt.el (byte-optimize-form-code-walker): + Optimize under `condition-case' and `catch' if + byte-compile--use-old-handlers is nil. + (disassemble-offset): Handle new bytecodes. + +2013-10-03 Stefan Monnier + + * subr.el (error): Use `declare'. + (decode-char, encode-char): Use advertised-calling-convention instead + of the docstring to discourage use of the `restriction' arg. + +2013-10-03 Daiki Ueno + + * epg.el (epg-verify-file): Add a comment saying that it does not + notify verification error as a return value nor a signal. + (epg-verify-string): Ditto. + +2013-10-02 Kevin Rodgers + + * progmodes/compile.el (compilation-start): Try globbing the arg to + `cd' (bug#15417). + +2013-10-02 Michael Albinus + + Sync with Tramp 2.2.8. + + * net/tramp-cmds.el (tramp-bug, tramp-append-tramp-buffers): + * net/tramp-cache.el (tramp-cache-print): Use `tramp-compat-funcall'. + * net/trampver.el: Update release number. + +2013-10-01 Jan Djärv + + * term/ns-win.el (ns-initialize-window-system): Set locale-coding-system + and default-process-coding-system for darwin only. + +2013-10-01 Stefan Monnier + + * emacs-lisp/package.el (package-desc): Simplify (bug#15495). + +2013-10-01 Mitchel Humpherys (tiny change) + + * vc/vc-git.el (vc-git-grep): Disable pager. + +2013-10-01 Dmitry Gutov + + * emacs-lisp/package.el (package-buffer-info, describe-package-1): + Use :url instead of :homepage, as per + http://lists.gnu.org/archive/html/emacs-devel/2013-09/msg00622.html + + * newcomment.el (comment-beginning): When `comment-use-syntax' is + non-nil, use `syntax-ppss' (Bug#15251). + +2013-09-30 Rüdiger Sonderfeld + + * progmodes/octave.el (inferior-octave-startup-file): + Prefer ~/.emacs.d/init_octave.m. + +2013-09-29 Dmitry Gutov + + * emacs-lisp/package.el (package-desc-from-define): + Accept additional arguments as plist, convert them to an alist and store + them in the `extras' slot. + (package-generate-description-file): Convert extras alist back to + plist and append to the `define-package' form arguments. + (package--alist-to-plist): New function. + (package--ac-desc): Add `extras' slot. + (package--add-to-archive-contents): Check if the archive-contents + vector is long enough, and if it is, pass its `extras' slot value + to `package-desc-create'. + (package-buffer-info): Call `lm-homepage', pass the returned value + to `package-desc-from-define'. + (describe-package-1): Render the homepage button (Bug#13291). + + * emacs-lisp/package-x.el (package-upload-buffer-internal): + Pass `extras' slot from `package-desc' to `package-make-ac-desc'. + +2013-09-29 Jan Djärv + + * term/ns-win.el (ns-initialize-window-system): Set locale-coding-system + and default-process-coding-system to utf-8-unix (Bug#15402). + +2013-09-29 Xue Fuqiao + + * subr.el (looking-back): Do not recommend using looking-back. + +2013-09-28 Alan Mackenzie + + Fix indentation/fontification of Java enum with "implements". + + * progmodes/cc-langs.el (c-postfix-decl-spec-key): New variable, a + regexp which matches "implements", etc., in Java. + * progmodes/cc-engine.el (c-inside-bracelist-p): Check for extra + specifier clauses coming after "enum". + * progmodes/cc-fonts.el (c-font-lock-declarations) + (c-font-lock-enum-tail): Check for extra specifier clauses coming + after "enum". + +2013-09-28 Jan Djärv + + * faces.el (region): Change ns_selection_color to + ns_selection_fg_color, add ns_selection_bg_color. + 2013-09-28 Leo Liu * progmodes/octave.el (inferior-octave-completion-table) diff --cc src/ChangeLog index fc2f7a9d57c,a6774e30b0c..e30194d1dfb --- a/src/ChangeLog +++ b/src/ChangeLog @@@ -1,246 -1,3 +1,359 @@@ ++2013-10-08 Eli Zaretskii ++ ++ 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) : 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 : Declare. ++ ++ * keyboard.c : Now extern. ++ : 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 + + * dispnew.c (set_window_update_flags): Add buffer arg. Adjust comment. + (redraw_frame, update_frame): Adjust users. + * dispextern.h (set_window_update_flags): Adjust prototype. + * xdisp.c (redisplay_internal): When updating all frames with zero + windows_or_buffers_changed, assume that only the windows that shows + current buffer should be really updated. + +2013-10-08 Dmitry Antipov + + Do not allocate huge temporary memory areas and objects while encoding + for file I/O, thus reducing an enormous memory usage for large buffers. + See http://lists.gnu.org/archive/html/emacs-devel/2013-10/msg00180.html. + * coding.h (struct coding_system): New member raw_destination. + * coding.c (setup_coding_system): Initialize it to zero. + (encode_coding_object): If raw_destination is set, do not create + dst_object. Add comment. + * fileio.c (toplevel): New constant E_WRITE_MAX. + (e_write): Do not encode more than E_WRITE_MAX characters per one loop + iteration. Use raw_destination if E_WRITE_MAX characters is encoded. + +2013-10-08 Jan Djärv + + * nsterm.m (windowDidExitFullScreen:): + (toggleFullScreen:): Change NS_IMPL_COCOA to HAVE_NATIVE_FS. + +2013-10-08 Paul Eggert + + Fix race where emacs aborts when sent SIGTERM (Bug#15534). + * keyboard.c (unblock_input_to): Don't process pending signals + if a fatal error is in progress. + + * lisp.h (bits_word, BITS_WORD_MAX): New type and macro. + All uses of 'size_t' and 'SIZE_MAX' changed to use them, when + they're talking about words in Lisp bool vectors. + (BITS_PER_BITS_WORD): Rename from BITS_PER_SIZE_T. All uses changed. + * data.c (popcount_bits_word): Rename from popcount_size_t. + (bits_word_to_host_endian): Rename from size_t_to_host_endian. + All uses changed. + +2013-10-07 Paul Eggert + + Improve support for popcount and counting trailing zeros (Bug#15550). + * data.c: Include , . + (USE_MSC_POPCOUNT, POPCOUNT_STATIC_INLINE) + (NEED_GENERIC_POPCOUNT, popcount_size_t_generic) + (popcount_size_t_msc, popcount_size_t_gcc): + Remove; now done by Gnulib. + (popcount_size_t): Now a macro that defers to Gnulib. + (count_trailing_zero_bits): Return int, for consistency with + Gnulib and because Emacs prefers signed to unsigned int. + Don't assume that size_t is either unsigned int or unsigned long + or unsigned long long. + (size_t_to_host_endian): Do not assume that size_t is either + exactly 32 or exactly 64 bits wide. + * lisp.h (BITS_PER_SIZE_T): Define consistently with BITS_PER_LONG + etc., so that it's now an enum constant, not a macro. + No need to assume that it's either 32 or 64. + +2013-10-07 Jan Djärv + + * nsterm.m (windowDidEnterFullScreen:): setPresentationOptions only + on >= 10.7. + +2013-10-07 Dmitry Antipov + + * insdel.c (insert_from_gap): Prefer ptrdiff_t to int where needed. + * xdisp.c (handle_fontified_prop): Likewise. Use bool for boolean. + +2013-10-07 Paul Eggert + + emacs_read and emacs_write now use void *, not char *. + * alloc.c (valid_pointer_p) [!WINDOWSNT]: Remove now-unnecessary cast. + * sysdep.c (emacs_read, emacs_write, emacs_write_sig): + Buffer arg is now void *, not char *. This matches plain + 'read' and 'write' better, and avoids a constraint violation + on Solaris 9 with Oracle Studio. + +2013-10-07 Dmitry Antipov + + * alloc.c (Fmake_string): For ASCII char initializer, prefer + memset to explicit loop. Otherwise copy largest possible chunk + from initialized to uninitialized part, thus allowing the longer + memcpy runs and reducing the number of loop iterations. + +2013-10-06 Jan Djärv + + * nsterm.m (ns_update_begin): If native fullscreen and no toolbar, + hide toolbar (Bug#15388). + (windowDidEnterFullScreen:): If presentation options are zero, + set them here (Bug#15388). + (ns_update_auto_hide_menu_bar): Remove runtime check. + Don't auto hide dock unless menubar is also auto hidden. + +2013-10-05 Xue Fuqiao + + * editfns.c (message): Mention batch mode in doc string. + +2013-10-05 Jan Djärv + + * nsterm.m (check_native_fs): Remove erroneous comment. + +2013-10-04 Dmitry Antipov + + * xdisp.c (redisplay_internal): Simplify because scan_for_column now + uses find_newline instead of scan_newline and so doesn't move point. + +2013-10-04 Paul Eggert + + Use hardware support for byteswapping on glibc x86 etc. + On Fedora 19 x86-64, the new bswap_64 needs 1 instruction, + whereas the old swap64 needed 30. + * fringe.c (init_fringe_bitmap) [WORDS_BIGENDIAN]: + * sound.c (le2hl, le2hs, be2hl) [!WINDOWSNT]: + Use byteswap.h's macros to swap bytes. + * lisp.h (swap16, swap32, swap64): Remove. + All uses replaced by bswap_16, bswap_32, bswap_64. + + * bytecode.c (exec_byte_code): Use some more volatile variables + to work around local variables getting clobbered by longjmp. + Port to pre-C99, which doesn't allow decls after stmts. + +2013-10-03 Paul Eggert + + * lisp.h (eassert): Assume that COND is true when optimizing. + In other words, take on the behavior of eassert_and_assume. + This makes Emacs 0.2% smaller on my platform (Fedora 19, x86-64). + (eassert_and_assume): Remove. All uses replaced by eassert. + + * xdisp.c (Qglyphless_char): Now static. + + Adjust to merge from gnulib. + * conf_post.h (__has_builtin, assume): Remove; gnulib now does these. + * lisp.h: Include , for 'assume'. + + * eval.c (clobbered_eassert): New macro. + (internal_catch, internal_condition_case) + (internal_condition_case_1, internal_condition_case_2) + (internal_condition_case_n): Use it instead of eassert + when the argument contains locals clobbered by longjmp. + Don't use clobbered locals outside of clobbered_eassert. + (internal_lisp_condition_case): Use a volatile variable + to work around a local variable's getting clobbered. + +2013-10-03 Stefan Monnier + + * lisp.h (struct handler): Merge struct handler and struct catchtag. + (PUSH_HANDLER): New macro. + (catchlist): Remove. + (handlerlist): Always declare. + + * eval.c (catchlist): Remove (merge with handlerlist). + (handlerlist, lisp_eval_depth): Not static any more. + (internal_catch, internal_condition_case, internal_condition_case_1) + (internal_condition_case_2, internal_condition_case_n): + Use PUSH_HANDLER. + (unwind_to_catch, Fthrow, Fsignal): Adjust to merged + handlerlist/catchlist. + (internal_lisp_condition_case): Use PUSH_HANDLER. Adjust to new + handlerlist which can only handle a single condition-case handler at + a time. + (find_handler_clause): Simplify since we only a single branch here + any more. + + * bytecode.c (BYTE_CODES): Add Bpushcatch, Bpushconditioncase + and Bpophandler. + (bcall0): New function. + (exec_byte_code): Add corresponding cases. Improve error message when + encountering an invalid byte-code. Let Bunwind_protect accept + a function (rather than a list of expressions) as argument. + + * alloc.c (Fgarbage_collect): Merge scans of handlerlist and catchlist, + and make them unconditional now that they're heap-allocated. + +2013-10-03 Stefan Monnier + + * charset.c (Fdecode_char, Fencode_char): Remove description of + `restriction' arg. now that it's hidden by advertised-calling-convention. + +2013-10-02 Jan Djärv + + * macfont.m (mac_ctfont_create_preferred_family_for_attributes): + Remove unused variable (from mac-port). + (macfont_draw): Use s->ybase for correct y position. + +2013-10-02 Dmitry Antipov + + * frame.h (struct frame): Drop has_minibuffer member because... + (FRAME_HAS_MINIBUF_P): ...this macro can be implemented without it. + * frame.c (make_frame, make_minibuffer_frame): Adjust users. + +2013-10-02 Dmitry Antipov + + * window.h (struct window): Prefer enum text_cursor_kinds to int + for phys_cursor_type member. Move the latter, phys_cursor_width, + phys_cursor_ascent and phys_cursor_height under HAVE_WINDOW_SYSTEM. + * window.c (replace_window, make_window): Adjust users. + +2013-10-02 Dmitry Antipov + + * fringe.c (toplevel): Do not use HAVE_WINDOW_SYSTEM because + this module is never compiled otherwise. + +2013-10-01 Alp Aker + + * macfont.m (macfont_draw): Use CGRectMake rather than NSMakeRect + (Bug#15500). + +2013-09-29 Eli Zaretskii + + * xdisp.c (get_next_display_element): Don't call face_for_font in + a build configured --without-x. (Bug#15484) + +2013-09-29 Jan Djärv + + * window.c (calc_absolute_offset): #elif should be #elif defined. + + * frame.c (delete_frame): Block/unblock input to overcome race + condition (Bug#15475). + +2013-09-29 Andreas Politz (tiny change) + + * frame.c (delete_frame): Record selected frame only after + calling Qdelete_frame_functions (Bug#15477). + +2013-09-28 Jan Djärv + + * nsterm.m (ns_selection_color): Remove. + (ns_get_color): Check for ns_selection_(fg|bg)_color using + NSColor selectedText(Background)Color. Only for COCOA. + (ns_term_init): Remove assignment of ns_selection_color, logic + moved to ns_get_color. + + * nsterm.h (NS_SELECTION_BG_COLOR_DEFAULT): Rename from + NS_SELECTION_COLOR_DEFAULT. + (NS_SELECTION_FG_COLOR_DEFAULT): New. + +2013-09-28 Eli Zaretskii + + * xdisp.c (Fdump_tool_bar_row): Ifdef away the body if 'struct + frame' does not have the tool_bar_window member. + 2013-09-26 Barry O'Reilly Signal error when reading an empty byte-code object (Bug#15405) diff --cc src/dispnew.c index 8507a330a92,b1384a6feb3..f5d213e03f4 --- a/src/dispnew.c +++ b/src/dispnew.c @@@ -3047,6 -3087,47 +3087,47 @@@ update_frame (struct frame *f, bool for 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, 0); ++ set_window_update_flags (root_window, NULL, 0); + } /************************************************************************ diff --cc src/term.c index fd5ea5a1b8d,24add173245..44a83b6a4c8 --- a/src/term.c +++ b/src/term.c @@@ -2754,6 -2764,1107 +2764,1107 @@@ DEFUN ("gpm-mouse-stop", Fgpm_mouse_sto } #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. */ + -struct glyph_matrix * ++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 /***********************************************************************