/* Platform-independent code for terminal communications.
-Copyright (C) 1986, 1988, 1993-1994, 1996, 1999-2013 Free Software
+Copyright (C) 1986, 1988, 1993-1994, 1996, 1999-2014 Free Software
Foundation, Inc.
This file is part of GNU Emacs.
#include "termhooks.h"
#include "blockinput.h"
#include "dispextern.h"
+#include "buffer.h"
#ifdef USE_X_TOOLKIT
#include "../lwlib/lwlib.h"
static bool
have_boxes (void)
{
-#if defined (USE_X_TOOLKIT) || defined (USE_GTK) || defined (HAVE_NTGUI)
+#if defined (USE_X_TOOLKIT) || defined (USE_GTK) || defined (HAVE_NTGUI) || defined(HAVE_NS)
if (FRAME_WINDOW_P (XFRAME (Vmenu_updating_frame)))
return 1;
#endif
item_string = concat2 (prefix, item_string);
}
- if (FRAME_TERMCAP_P (XFRAME (Vmenu_updating_frame))
+ if ((FRAME_TERMCAP_P (XFRAME (Vmenu_updating_frame))
+ || FRAME_MSDOS_P (XFRAME (Vmenu_updating_frame)))
&& !NILP (map))
/* Indicate visually that this is a submenu. */
item_string = concat2 (item_string, build_string (" >"));
}
#endif /* HAVE_NS */
+ptrdiff_t
+menu_item_width (const unsigned char *str)
+{
+ ptrdiff_t len;
+ const unsigned 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 (SDATA (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
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;
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;
keybinding equivalents, but we don't do that any more anyway. */
return Qnil;
-#ifdef HAVE_MENUS
{
bool get_current_pos_p = 0;
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);
XSETFRAME (Vmenu_updating_frame, f);
}
-#endif /* HAVE_MENUS */
/* Now parse the lisp menus. */
record_unwind_protect_void (unuse_menu_items);
unbind_to (specpdl_count, Qnil);
-#ifdef HAVE_MENUS
#ifdef HAVE_WINDOW_SYSTEM
/* Hide a previous tip, if any. */
if (!FRAME_TERMCAP_P (f))
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). */
if (FRAME_X_P (f) || FRAME_MSDOS_P (f))
selection = xmenu_show (f, xpos, ypos, for_click,
- keymaps, title, &error_name,
- last_event_timestamp);
+ keymaps, title, &error_name);
else
#endif
+#ifndef MSDOS
if (FRAME_TERMCAP_P (f))
- selection = tty_menu_show (f, xpos, ypos, for_click,
- keymaps, title, &error_name);
+ {
+ ptrdiff_t count1 = SPECPDL_INDEX ();
+
+ /* Avoid crashes if, e.g., another client will connect while we
+ are in a menu. */
+ temporarily_switch_to_single_kboard (f);
+ selection = tty_menu_show (f, xpos, ypos, for_click, keymaps, title,
+ kbd_menu_navigation, &error_name);
+ unbind_to (count1, Qnil);
+ }
+#endif
#ifdef HAVE_NS
unbind_to (specpdl_count, Qnil);
FRAME_DISPLAY_INFO (f)->grabbed = 0;
#endif
-#endif /* HAVE_MENUS */
-
UNGCPRO;
if (error_name) error ("%s", error_name);
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.
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 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)
+#ifdef HAVE_NTGUI
if (FRAME_W32_P (f))
- return w32_popup_dialog (f, header, contents);
- else
+ {
+ Lisp_Object selection = w32_popup_dialog (f, header, contents);
+
+ if (!EQ (selection, Qunsupported__w32_dialog))
+ return selection;
+ }
#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;
- int frame_width, frame_height;
+ Lisp_Object x, y, frame, newpos, prompt;
+ int x_coord, y_coord;
+ prompt = Fcar (contents);
if (FRAME_WINDOW_P (f))
{
- frame_width = FRAME_PIXEL_WIDTH (f);
- frame_height = FRAME_PIXEL_HEIGHT (f);
+ x_coord = FRAME_PIXEL_WIDTH (f);
+ y_coord = FRAME_PIXEL_HEIGHT (f);
}
else
{
- frame_width = FRAME_COLS (f);
- frame_height = FRAME_LINES (f);
+ 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, frame_width / 2);
- XSETINT (y, frame_height / 2);
+ XSETINT (x, x_coord / 2);
+ XSETINT (y, y_coord / 2);
newpos = list2 (list2 (x, y), frame);
- return Fx_popup_menu (newpos,
- list2 (Fcar (contents), contents));
+ return Fx_popup_menu (newpos, list2 (prompt, contents));
}
}
-#endif /* HAVE_MENUS */
-
void
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);
}