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.
This commit is contained in:
Eli Zaretskii 2013-10-08 20:49:20 +03:00
commit 4ed774157d
46 changed files with 2559 additions and 695 deletions

View file

@ -1,3 +1,7 @@
2013-10-08 Eli Zaretskii <eliz@gnu.org>
* configure.ac (HAVE_MENUS): Define unconditionally.
2013-10-07 Paul Eggert <eggert@cs.ucla.edu>
Improve support for popcount and counting trailing zeros (Bug#15550).

View file

@ -1898,11 +1898,8 @@ to configure.])
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 @@ if test "${HAVE_NS}" = "yes"; then
## 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 @@ AC_SUBST(OLDXMENU_DEPS)
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

View file

@ -1,3 +1,14 @@
2013-10-08 Eli Zaretskii <eliz@gnu.org>
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 <xfq.free@gmail.com>
* cal-xtra.texi (Calendar Customizing, Diary Display): Remove @refill.

View file

@ -710,6 +710,17 @@ This face determines the color of tool bar icons. @xref{Tool Bars}.
@cindex customization of @code{menu} face
This face determines the colors and font of Emacs's menus. @xref{Menu
Bars}.
@item tty-menu-enabled-face
@cindex faces for text-mode menus
@cindex TTY menu faces
This face is used to display enabled menu items on text-mode
terminals.
@item tty-menu-disabled-face
This face is used to display disabled menu items on text-mode
terminals.
@item 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

View file

@ -286,6 +286,10 @@ exception, dropping a file into a window displaying a Dired buffer
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

View file

@ -39,7 +39,7 @@ doing so on GNU and Unix systems; and
@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.

View file

@ -287,13 +287,12 @@ here, as you can more easily see them yourself.
@kindex M-`
@kindex F10
@findex 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 @@ the usual way (@pxref{Key Help}).
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
@key{ESC}.
@kbd{C-g} or @kbd{ESC ESC ESC}.
On a text terminal, you can use the menu bar by typing @kbd{M-`} or
@key{F10} (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.
@findex tmm-menubar
@vindex 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
@code{tty-menu-open-use-tmm} to a non-@code{nil} value. Then typing
@key{F10} will run the command @code{tmm-menubar} instead of dropping
down the menu. (You can also type @kbd{M-`}, which always invokes
@code{tmm-menubar}.) @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.

View file

@ -1,3 +1,12 @@
2013-10-08 Eli Zaretskii <eliz@gnu.org>
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 <monnier@iro.umontreal.ca>
* tips.texi (Comment Tips): Discourage use of triple semi-colons for

View file

@ -1741,8 +1741,10 @@ allows to know if the pointer has been hidden.
@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 keys---@kbd{C-n}, @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 @@ pixels, counting from the top left corner of @var{window}. @var{window}
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 @@ cell; this makes a non-selectable menu item.
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
@kbd{C-g}, 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 @@ window don't matter; only the frame matters.
If @var{header} is non-@code{nil}, 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 @@ obtain information about displays.
@defun display-popup-menus-p &optional display
This function returns @code{t} if popup menus are supported on
@var{display}, @code{nil} if not. Support for popup menus requires that
the mouse be available, since the user cannot choose menu items without
a mouse.
@var{display}, @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

View file

@ -2023,7 +2023,7 @@ which is a string that appears as an element of the keymap.
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 menus.@footnote{It 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 @@ if the menu keymap contains a single nested keymap and no other menu
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
@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, 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 @@ can do it this way:
@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''
@code{menu-bar}, as defined in the active keymaps.
Emacs usually shows 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'' @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 @@ in Documentation}.
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

View file

@ -65,6 +65,22 @@ To use the old backend by default, do on the command line:
* 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 @@ for something (not just adding elements to it), it ought not to affect you.
* 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'

View file

@ -1,3 +1,27 @@
2013-10-08 Eli Zaretskii <eliz@gnu.org>
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 <monnier@iro.umontreal.ca>
* emacs-lisp/lisp-mode.el: Font-lock cl-lib constructs.

View file

@ -2142,7 +2142,6 @@ terminal type to a different value."
(frame-set-background-mode frame t)
(face-set-after-frame-default frame)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Standard faces.
@ -2551,6 +2550,26 @@ It is used for characters of no fonts too."
: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.

View file

@ -1304,17 +1304,17 @@ frame's display)."
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.

View file

@ -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,

View file

@ -2182,13 +2182,211 @@ See `menu-bar-mode' for more information."
(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 @@ If FRAME is nil or not given, use the selected frame."
(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))))))

View file

@ -144,79 +144,6 @@ Expects to be bound to `down-mouse-1' in `key-translation-map'."
;; 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.

View file

@ -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.

View file

@ -58,9 +58,7 @@ echo area, instead of making a pop-up window."
: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))

View file

@ -1,3 +1,116 @@
2013-10-08 Eli Zaretskii <eliz@gnu.org>
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 <dmantipov@yandex.ru>
* dispnew.c (set_window_update_flags): Add buffer arg. Adjust comment.

View file

@ -3408,7 +3408,6 @@ make_save_obj_obj_obj_obj (Lisp_Object a, Lisp_Object b, Lisp_Object c,
return val;
}
#if defined HAVE_NS || defined HAVE_NTGUI
Lisp_Object
make_save_ptr (void *a)
{
@ -3418,7 +3417,6 @@ make_save_ptr (void *a)
p->data[0].pointer = a;
return val;
}
#endif
Lisp_Object
make_save_ptr_int (void *a, ptrdiff_t b)

View file

@ -139,7 +139,7 @@ struct cm
#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) \

View file

@ -3256,6 +3256,7 @@ extern int clear_mouse_face (Mouse_HLInfo *);
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 @@ extern void hide_hourglass (void);
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 @@ extern Lisp_Object marginal_area_string (struct window *, enum window_part,
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 change_frame_size (struct frame *, int, int, bool, bool, bool);
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 */

View file

@ -1844,9 +1844,28 @@ save_current_matrix (struct frame *f)
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 @@ restore_current_matrix (struct frame *f, struct glyph_matrix *saved)
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 @@ update_frame (struct frame *f, bool force_p, bool inhibit_hairy_id_p)
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);
}
/************************************************************************

View file

@ -3472,22 +3472,17 @@ usage: (message-box FORMAT-STRING &rest ARGS) */)
{
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;
}
}

View file

@ -2434,8 +2434,8 @@ a space; `yes-or-no-p' adds \"(yes or no) \" to it.
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 @@ is nil, and `use-dialog-box' is non-nil. */)
#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);

View file

@ -1248,9 +1248,6 @@ extern void x_set_tool_bar_lines (struct frame *f,
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 *);

View file

@ -289,7 +289,7 @@ static struct input_event * volatile kbd_store_ptr;
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 @@ Lisp_Object Qvertical_line;
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 @@ some_mouse_moved (void)
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 @@ command_loop_1 (void)
/* 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 @@ command_loop_1 (void)
}
}
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_decoded_event_from_main_queue (struct timespec *end_time,
/* 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 @@ read_char (int commandflag, Lisp_Object map,
/* 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 @@ read_char (int commandflag, Lisp_Object map,
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 @@ kbd_buffer_get_event (KBOARD **kbp,
}
}
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 @@ make_lispy_position (struct frame *f, Lisp_Object x, Lisp_Object y,
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 @@ make_lispy_event (struct input_event *event)
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;
pixel_to_glyph_coords (f, XINT (event->x), XINT (event->y),
&column, &row, NULL, 1);
/* Find the menu bar item under `column'. */
item = Qnil;
items = FRAME_MENU_BAR_ITEMS (f);
for (i = 0; i < ASIZE (items); i += 4)
/* 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 @@ test_undefined (Lisp_Object binding)
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 @@ test_undefined (Lisp_Object binding)
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 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
{
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 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
{
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 @@ read_key_sequence_vs (Lisp_Object prompt, Lisp_Object continue_echo,
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 @@ syms_of_keyboard (void)
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);

View file

@ -450,7 +450,7 @@ extern Lisp_Object Qswitch_frame;
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;

View file

@ -30,6 +30,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
#include "termhooks.h"
#include "blockinput.h"
#include "dispextern.h"
#include "buffer.h"
#ifdef USE_X_TOOLKIT
#include "../lwlib/lwlib.h"
@ -50,10 +51,16 @@ extern HMENU current_popup_menu;
#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 @@ single_keymap_panes (Lisp_Object keymap, Lisp_Object pane_name,
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 @@ single_menu_item (Lisp_Object key, Lisp_Object item, Lisp_Object dummy, void *sk
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 (!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;
}
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 (" ");
/* 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 (!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 @@ single_menu_item (Lisp_Object key, Lisp_Object item, Lisp_Object dummy, void *sk
#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 @@ keymap_panes (Lisp_Object *keymaps, ptrdiff_t nmaps)
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 @@ list_of_items (Lisp_Object pane)
{
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 @@ list_of_panes (Lisp_Object menu)
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 @@ digest_single_submenu (int start, int end, bool top_level_items)
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 @@ digest_single_submenu (int start, int end, bool top_level_items)
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
}
pane_string = (NILP (pane_name)
? "" : SSDATA (pane_name));
@ -737,47 +757,52 @@ digest_single_submenu (int start, int end, bool top_level_items)
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);
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);
}
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 (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 @@ find_and_return_menu_selection (struct frame *f, bool keymaps, void *client_data
}
#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 @@ event (indicating that the user invoked the menu with the mouse) then
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 @@ no quit occurs and `x-popup-menu' returns nil. */)
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 @@ no quit occurs and `x-popup-menu' returns nil. */)
{
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 @@ no quit occurs and `x-popup-menu' returns nil. */)
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 @@ no quit occurs and `x-popup-menu' returns nil. */)
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 @@ no quit occurs and `x-popup-menu' returns nil. */)
#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 @@ no quit occurs and `x-popup-menu' returns nil. */)
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 @@ no quit occurs and `x-popup-menu' returns nil. */)
#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 @@ no quit occurs and `x-popup-menu' returns nil. */)
#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 @@ no quit occurs and `x-popup-menu' returns nil. */)
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 @@ syms_of_menu (void)
menu_items_inuse = Qnil;
defsubr (&Sx_popup_menu);
#ifdef HAVE_MENUS
defsubr (&Sx_popup_dialog);
#endif
defsubr (&Smenu_bar_menu_at_x_y);
}

View file

@ -51,4 +51,7 @@ extern Lisp_Object ns_menu_show (struct frame *, int, int, bool, bool,
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 */

View file

@ -1379,13 +1379,6 @@ IT_delete_glyphs (struct frame *f, int n)
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;

View file

@ -833,6 +833,8 @@ - (Lisp_Object)runMenuAt: (NSPoint)p forFrame: (struct frame *)f
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 @@ - (Lisp_Object)runMenuAt: (NSPoint)p forFrame: (struct frame *)f
popup_activated_flag = 0;
[[FRAME_NS_VIEW (SELECTED_FRAME ()) window] makeKeyWindow];
unblock_input ();
return tem;
}
@ -1449,7 +1452,7 @@ - (NSRect) frame
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 @@ - (Lisp_Object)runDialogAt: (NSPoint)p
}
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 @@ Each ITEM is a cons cell (STRING . VALUE).
update menus there. */
trackingMenu = 1;
#endif
defsubr (&Sx_popup_dialog);
defsubr (&Sns_reset_menu);
defsubr (&Smenu_or_popup_active_p);

View file

@ -850,8 +850,8 @@ extern void find_and_call_menu_selection (struct frame *f,
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);

1121
src/term.c

File diff suppressed because it is too large Load diff

View file

@ -194,6 +194,9 @@ struct tty_display_info
/* 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. */

View file

@ -656,6 +656,14 @@ extern unsigned char *encode_terminal_code (struct glyph *, int,
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 */

View file

@ -62,6 +62,7 @@ static HANDLE prev_screen, cur_screen;
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 @@ w32con_move_cursor (struct frame *f, int row, int col)
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 @@ Wcm_clear (struct tty_display_info *tty)
}
/* 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
***********************************************************************/

View file

@ -5467,7 +5467,10 @@ show_hourglass (struct atimer *timer)
f = SELECTED_FRAME ();
if (!FRAME_W32_P (f))
return;
{
unblock_input ();
return;
}
w32_show_hourglass (f);
unblock_input ();

View file

@ -712,12 +712,17 @@ w32_console_read_socket (struct terminal *terminal,
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);

View file

@ -115,129 +115,34 @@ static int fill_in_menu (HMENU, widget_value *);
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
/* Decode the dialog items from what was specified. */
title = Fcar (contents);
CHECK_STRING (title);
{
/* 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;
list_of_panes (Fcons (contents, Qnil));
/* Decode the dialog items from what was specified. */
title = Fcar (contents);
CHECK_STRING (title);
/* Display them in a dialog box. */
block_input ();
selection = w32_dialog_show (f, 0, title, header, &error_name);
unblock_input ();
list_of_panes (Fcons (contents, Qnil));
discard_menu_items ();
FRAME_DISPLAY_INFO (f)->grabbed = 0;
/* 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 */
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 @@ w32_menu_show (struct frame *f, int x, int y, int for_click, int keymaps,
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 @@ w32_menu_show (struct frame *f, int x, int y, int for_click, int keymaps,
if (!NILP (subprefix_stack[j]))
entry = Fcons (subprefix_stack[j], entry);
}
unblock_input ();
return entry;
}
i += MENU_ITEMS_ITEM_LENGTH;
@ -947,9 +855,13 @@ w32_menu_show (struct frame *f, int x, int y, int for_click, int keymaps,
}
}
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 @@ syms_of_w32menu (void)
DEFSYM (Qdebug_on_next_call, "debug-on-next-call");
defsubr (&Smenu_or_popup_active_p);
#ifdef HAVE_MENUS
defsubr (&Sx_popup_dialog);
#endif
}
/*

View file

@ -264,6 +264,10 @@ extern int w32_kbd_mods_to_emacs (DWORD mods, WORD key);
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 @@ typedef char guichar_t;
#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);

View file

@ -5540,17 +5540,25 @@ the return value is nil. Otherwise the value is t. */)
|| 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
@ -5738,15 +5746,24 @@ the return value is nil. Otherwise the value is t. */)
|| 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. */

View file

@ -20584,7 +20584,128 @@ display_menu_bar (struct window *w)
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

View file

@ -192,149 +192,6 @@ mouse_position_for_popup (struct frame *f, int *x, int *y)
#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 @@ xmenu_show (struct frame *f, int x, int y, bool for_click, bool keymaps,
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 @@ xmenu_show (struct frame *f, int x, int y, bool for_click, bool keymaps,
if (!NILP (subprefix_stack[j]))
entry = Fcons (subprefix_stack[j], entry);
}
unblock_input ();
return entry;
}
i += MENU_ITEMS_ITEM_LENGTH;
@ -1864,9 +1724,13 @@ xmenu_show (struct frame *f, int x, int y, bool for_click, bool keymaps,
}
}
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 @@ xdialog_show (struct frame *f,
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 @@ xmenu_show (struct frame *f, int x, int y, bool for_click, bool keymaps,
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 @@ xmenu_show (struct frame *f, int x, int y, bool for_click, bool keymaps,
if (menu == NULL)
{
*error_name = "Can't create menu";
unblock_input ();
return Qnil;
}
@ -2314,6 +2216,7 @@ xmenu_show (struct frame *f, int x, int y, bool for_click, bool keymaps,
{
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 @@ xmenu_show (struct frame *f, int x, int y, bool for_click, bool keymaps,
{
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 @@ xmenu_show (struct frame *f, int x, int y, bool for_click, bool keymaps,
/* 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 @@ xmenu_show (struct frame *f, int x, int y, bool for_click, bool keymaps,
#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 @@ syms_of_xmenu (void)
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
}

View file

@ -1035,6 +1035,10 @@ extern void x_free_dpy_colors (Display *, Screen *, Colormap,
/* 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