From 63dfbda7df0df5b054f8f95b79673672c267de54 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sat, 5 Oct 2013 18:42:17 +0300 Subject: [PATCH] Fix menu drop by mouse click; new primitive menu-bar-menu-at-x-y. --- src/keyboard.c | 92 +++++++++++++++++++++++++++++--------------------- src/menu.c | 54 +++++++++++++++++++++++++++++ 2 files changed, 107 insertions(+), 39 deletions(-) diff --git a/src/keyboard.c b/src/keyboard.c index a595742ace8..6fd1e9b9c67 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -5406,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. @@ -5557,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; - - /* Find the menu bar item under `column'. */ - item = Qnil; - items = FRAME_MENU_BAR_ITEMS (f); - for (i = 0; i < ASIZE (items); i += 4) + pixel_to_glyph_coords (f, XINT (event->x), XINT (event->y), + &column, &row, NULL, 1); + + /* In the non-toolkit version, clicks on the menu bar + are ordinary button events in the event buffer. + Distinguish them, and invoke the menu. + + (In the toolkit version, the toolkit handles the + menu bar and Emacs doesn't know about it until + after the user makes a selection.) */ + if (row >= 0 && row < FRAME_MENU_BAR_LINES (f) + && (event->modifiers & down_modifier)) { - Lisp_Object pos, string; - string = AREF (items, i + 1); - pos = AREF (items, i + 3); - if (NILP (string)) - break; - if (column >= XINT (pos) - && column < XINT (pos) + SCHARS (string)) + Lisp_Object items, item; + + /* Find the menu bar item under `column'. */ + item = Qnil; + items = FRAME_MENU_BAR_ITEMS (f); + for (i = 0; i < ASIZE (items); i += 4) { - item = AREF (items, i); - break; + Lisp_Object pos, string; + string = AREF (items, i + 1); + pos = AREF (items, i + 3); + if (NILP (string)) + break; + if (column >= XINT (pos) + && column < XINT (pos) + SCHARS (string)) + { + item = AREF (items, i); + break; + } } - } - /* ELisp manual 2.4b says (x y) are window relative but - code says they are frame-relative. */ - position = list4 (event->frame_or_window, - Qmenu_bar, - Fcons (event->x, event->y), - make_number (event->timestamp)); + /* 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); + 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); diff --git a/src/menu.c b/src/menu.c index 3f7aa0c33c3..690955ca0ad 100644 --- a/src/menu.c +++ b/src/menu.c @@ -1035,6 +1035,59 @@ find_and_return_menu_selection (struct frame *f, bool keymaps, void *client_data } #endif /* HAVE_NS */ +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 global-map [menu-bar SYMBOL]) + +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); + 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 && col < XINT (pos) + SCHARS (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 @@ -1527,4 +1580,5 @@ syms_of_menu (void) #ifdef HAVE_MENUS defsubr (&Sx_popup_dialog); #endif + defsubr (&Smenu_bar_menu_at_x_y); } -- 2.39.2