/* 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.
but I don't want to make one now. */
CHECK_WINDOW (window);
+ /* Note that xw_popup_dialog can call menu code, so
+ Vmenu_updating_frame should be set (Bug#17891). */
+ eassert (f && FRAME_LIVE_P (f));
+ XSETFRAME (Vmenu_updating_frame, 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
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. */
}
}
-#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);
}