diff --git a/lisp/menu-bar.el b/lisp/menu-bar.el index 28ab60f1d2d..f58da54e32f 100644 --- a/lisp/menu-bar.el +++ b/lisp/menu-bar.el @@ -2691,53 +2691,64 @@ popup-menu (filter (when (symbolp map) (plist-get (get map 'menu-prop) :filter)))) (if filter (funcall filter (symbol-function map)) map))))) - (frame (selected-frame)) + (frame (if (and (eq (framep (selected-frame)) t) (frame-parent) + from-menu-bar + (zerop (or (frame-parameter nil 'menu-bar-lines) 0))) + ;; If the selected frame is a tty child frame + ;; without its own menu bar and we are called from + ;; the menu bar, the menu bar must be on the root + ;; frame of the selected frame. + (frame-root-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 - (key-binding (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-ignore-too-long (car map) mouse-click)) - (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))) + (with-selected-frame frame + (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 + (key-binding (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-ignore-too-long (car map) mouse-click)) + (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)) @@ -2808,14 +2819,27 @@ menu-bar-open If FRAME is nil or not given, use the selected frame." (interactive (list nil (prefix-numeric-value current-prefix-arg))) - (let ((type (framep (or frame (selected-frame))))) + (let* ((type (framep (or frame (selected-frame)))) + root + (frame (if (and (eq type t) (frame-parent frame) + (null tty-menu-open-use-tmm) + (zerop (or (frame-parameter frame 'menu-bar-lines) 0)) + (setq root (frame-root-frame)) + (not (zerop + (or (frame-parameter root 'menu-bar-lines) 0)))) + ;; If FRAME is a tty child frame without its own + ;; menu bar, 'tty-menu-open-use-tmm' is false and + ;; FRAME's root frame has a menu bar, use that root + ;; frame's menu bar. + root + frame))) (cond ((eq type 'x) (x-menu-bar-open frame)) ((eq type 'w32) (w32-menu-bar-open frame)) ((eq type 'haiku) (haiku-menu-bar-open frame)) ((eq type 'pgtk) (pgtk-menu-bar-open frame)) ((and (null tty-menu-open-use-tmm) - (not (zerop (or (frame-parameter nil 'menu-bar-lines) 0)))) + (not (zerop (or (frame-parameter frame 'menu-bar-lines) 0)))) ;; Make sure the menu bar is up to date. One situation where ;; this is important is when this function is invoked by name ;; via M-x, in which case the menu bar includes the "Minibuf" @@ -2831,7 +2855,7 @@ menu-bar-open (current-local-map) (vector 'menu-bar menu)) (cdar (minor-mode-key-binding (vector 'menu-bar menu))) (mouse-menu-bar-map)) - (posn-at-x-y x 0 nil t) nil t))) + (posn-at-x-y x 0 frame t) nil t))) (t (with-selected-frame (or frame (selected-frame)) (tmm-menubar)))))) diff --git a/src/xdisp.c b/src/xdisp.c index 0497490928f..5f7a4dcbeb4 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -1147,7 +1147,7 @@ #define THIN_SPACE_WIDTH 1 struct glyph_matrix *, ptrdiff_t, ptrdiff_t, int, int); static bool cursor_row_fully_visible_p (struct window *, bool, bool, bool); -static bool update_menu_bar (struct frame *, bool, bool); +static bool update_menu_bar (struct frame *, bool, bool, struct window *); static bool try_window_reusing_current_matrix (struct window *); static int try_window_id (struct window *); static void maybe_produce_line_number (struct it *); @@ -14050,13 +14050,32 @@ prepare_menu_bars (void) /* True means that update_menu_bar has run its hooks so any further calls to update_menu_bar shouldn't do so again. */ bool menu_bar_hooks_run = false; + struct window *sw = XWINDOW (selected_window); + struct frame *sf = WINDOW_XFRAME (sw); + struct frame *rf = NULL; + + if (FRAME_PARENT_FRAME (sf) && !FRAME_WINDOW_P (sf) + && FRAME_MENU_BAR_LINES (sf) == 0 + && FRAME_MENU_BAR_LINES (rf = root_frame (sf)) != 0 + && NILP (Fdefault_value (Qtty_menu_open_use_tmm))) + /* If the selected window's frame is a tty child frame without + menu bar, that frame's root frame has a menu bar and + 'tty-menu-open-use-tmm' is nil, update the menu bar of the + root frame from the selected window. */ + sf = rf; + else + { + sf = NULL; + sw = NULL; + } record_unwind_save_match_data (); FOR_EACH_FRAME (tail, frame) { struct frame *f = XFRAME (frame); - struct window *w = XWINDOW (FRAME_SELECTED_WINDOW (f)); + struct window *w + = sf == f ? sw : XWINDOW (FRAME_SELECTED_WINDOW (f)); /* Ignore tooltip frame. */ if (FRAME_TOOLTIP_P (f)) @@ -14068,8 +14087,8 @@ prepare_menu_bars (void) && !XBUFFER (w->contents)->text->redisplay) continue; - if (!FRAME_PARENT_FRAME (f)) - menu_bar_hooks_run = update_menu_bar (f, false, menu_bar_hooks_run); + menu_bar_hooks_run + = update_menu_bar (f, false, menu_bar_hooks_run, w); update_tab_bar (f, false); #ifdef HAVE_WINDOW_SYSTEM @@ -14081,10 +14100,21 @@ prepare_menu_bars (void) } else { - struct frame *sf = SELECTED_FRAME (); + struct window *sw = XWINDOW (selected_window); + struct frame *sf = WINDOW_XFRAME (sw); + struct frame *rf = NULL; + + if (FRAME_PARENT_FRAME (sf) && !FRAME_WINDOW_P (sf) + && FRAME_MENU_BAR_LINES (sf) == 0 + && FRAME_MENU_BAR_LINES (rf = root_frame (sf)) != 0 + && NILP (Fdefault_value (Qtty_menu_open_use_tmm))) + /* If the selected window's frame is a tty child frame without + menu bar, that frame's root frame has a menu bar and + 'tty-menu-open-use-tmm' is nil, update the menu bar of the + root frame from the selected window. */ + sf = rf; - if (!FRAME_PARENT_FRAME (sf)) - update_menu_bar (sf, true, false); + update_menu_bar (sf, true, false, sw); update_tab_bar (sf, true); #ifdef HAVE_WINDOW_SYSTEM @@ -14106,20 +14136,14 @@ prepare_menu_bars (void) updated value of this flag, to pass to the next call. */ static bool -update_menu_bar (struct frame *f, bool save_match_data, bool hooks_run) +update_menu_bar (struct frame *f, bool save_match_data, bool hooks_run, struct window *w) { - Lisp_Object window; - struct window *w; - /* If called recursively during a menu update, do nothing. This can happen when, for instance, an activate-menubar-hook causes a redisplay. */ if (inhibit_menubar_update) return hooks_run; - window = FRAME_SELECTED_WINDOW (f); - w = XWINDOW (window); - if (FRAME_WINDOW_P (f) ? #ifdef HAVE_EXT_MENU_BAR @@ -21076,24 +21100,33 @@ redisplay_window (Lisp_Object window, bool just_this_one_p) /* When we reach a frame's selected window, redo the frame's menu bar, tool bar, tab-bar, and the frame's title. */ - if (update_mode_line - && EQ (FRAME_SELECTED_WINDOW (f), window)) + if (update_mode_line && EQ (FRAME_SELECTED_WINDOW (f), window)) { - bool redisplay_menu_p; - if (FRAME_WINDOW_P (f)) { #ifdef HAVE_EXT_MENU_BAR - redisplay_menu_p = FRAME_EXTERNAL_MENU_BAR (f); + if (FRAME_EXTERNAL_MENU_BAR (f)) + display_menu_bar (w); #else - redisplay_menu_p = FRAME_MENU_BAR_LINES (f) > 0; + if (FRAME_MENU_BAR_LINES (f) > 0) + display_menu_bar (w); #endif } else - redisplay_menu_p = FRAME_MENU_BAR_LINES (f) > 0; + { + struct frame *rf = NULL; - if (redisplay_menu_p) - display_menu_bar (w); + if (FRAME_PARENT_FRAME (f) + && FRAME_MENU_BAR_LINES (f) == 0 + && FRAME_MENU_BAR_LINES (rf = root_frame (f)) != 0 + && NILP (Fdefault_value (Qtty_menu_open_use_tmm))) + /* If F is a tty child frame without menu bar, that frame's root + frame has a menu bar and 'tty-menu-open-use-tmm' is nil, + display the menu bar of the root frame's selected window. */ + display_menu_bar (XWINDOW (FRAME_SELECTED_WINDOW (rf))); + else if (FRAME_MENU_BAR_LINES (f) > 0) + display_menu_bar (w); + } #ifdef HAVE_WINDOW_SYSTEM if (FRAME_WINDOW_P (f)) @@ -38443,6 +38476,7 @@ syms_of_xdisp (void) DEFSYM (Qnhdrag, "nhdrag"); DEFSYM (Qvdrag, "vdrag"); DEFSYM (Qhourglass, "hourglass"); + DEFSYM (Qtty_menu_open_use_tmm, "tty-menu-open-use-tmm"); }