5

I have menu-bar-open bound on f11 and menu-bar turned off, and because of that, f11 calls tmm-menubar, which is inconvenient and doesn't have mode-specific menu items for some reason (like org and tbl in org-mode). I want it to behave this way: make menu-bar visible, enable user to choose menu item, after that make menu-bar invisible again.

What is the most idiomatic and elegant way to to that?

I thought on writing advices, but Emacs developers usually recommend against it, as it causes problems for debug, and standard Emacs code does not include advices.

I use Emacs 24.1 in GUI.

Mirzhan Irkegulov
  • 17,660
  • 12
  • 105
  • 166
  • 2
    Advice definitely has the potential to cause confusion and make things more complex, and IIRC that is indeed one of the reasons Emacs' own code doesn't do it (but another obvious reason would be that Emacs' own code doesn't *need* to do it -- the original code can be changed if necessary) but as an end-user customising behaviour for their own needs, there's certainly nothing *wrong* with writing some advice (if no obviously better approach is available). I would presume that's why the facility was developed in the first place. – phils Jun 25 '12 at 04:36

4 Answers4

9

In Emacs-24 you can simply do this:

(global-set-key [f9] 'toggle-menu-bar-mode-from-frame)
  • Not sure about versions of Emacs older than 24.
  • Just be sure that f9 is really available in your installation.
Richard Gomes
  • 5,675
  • 2
  • 44
  • 50
  • How is this the most voted answer? It simply toggles the menu bar, which is just the first step of what the OP wants. – user643005 Nov 08 '18 at 16:56
4

If you're running a graphical Emacs session with menu-bar-mode disabled, then C-<mouse-3> should bring up the entire contents of the menu as a popup dialogue box. If you're running Emacs in a terminal, however, this definitely won't work; you haven't specified which is the case, so I'll try not to make assumptions. It's also possible to create custom mouse bindings (optionally, with keyboard modifiers) to the mouse-popup-menubar and/or mouse-popup-menubar-stuff functions, but ultimately that would only enable you to replicate behavior similar to the standard functionality that I've described above.

Due to the somewhat inflexible and global nature of menu-bar-mode (i.e., the fact that it applies across all Emacs frames and provides for relatively little customization via hooks, etc.), I think it would be very difficult to achieve precisely the behavior you desire with vanilla Emacs. It might be possible to write a custom function to temporarily enable menu-bar-mode and then use something like post-command-hook to disable it again after a selection is made, but I'm not certain. I'll try to investigate further if time allows.

Also, you might wish to look into third-party menu-bar packages, (q.v., the Menu Bar section of EmacsWiki).

Edit: I've hacked together a rather kludgy solution that you may find useful...

(add-hook
 'pre-command-hook
 (lambda ()
   (when (eq menu-bar-mode 42)
     (menu-bar-mode -1))))

(defun my-menu-bar-open ()
  (interactive)
  (unless menu-bar-mode
    (menu-bar-mode 1))
  (menu-bar-open)
  (setq menu-bar-mode 42))

I've tested this in a graphical session and it appears to simulate the behavior that you wanted, as long as you don't perform any action that Emacs registers as a command between executing my-menu-bar-open and making your selection (which is basically anything other than navigating the menu itself). The choice of 42 is a magic number (and a Douglas Adams homage) intended to minimize the risk that the hook function would be activated for more typical values of the menu-bar-mode variable. I don't claim that this is in any way elegant, but, in its decidedly ugly way, it does work. If you decide to use this, simply bind my-menu-bar-open to f11 (or whatever you prefer), i.e.:

(global-set-key [f11] 'my-menu-bar-open)

Alternatively, you can probably achieve very similar functionality by using pre-command-hook in an analogous fashion and instead advising menu-bar-open to perform a temporary toggle of menu-bar-mode.

Greg E.
  • 2,722
  • 1
  • 16
  • 22
2

A small improvement to Greg's answer, which keeps pre-command-hook clean:

(menu-bar-mode -1)

(defun my-menu-bar-open-after ()
  (remove-hook 'pre-command-hook 'my-menu-bar-open-after)
  (when (eq menu-bar-mode 42)
    (menu-bar-mode -1)))

(defun my-menu-bar-open (&rest args)
  (interactive)
  (let ((open menu-bar-mode))
    (unless open
      (menu-bar-mode 1))
    (funcall 'menu-bar-open args)
    (unless open
      (setq menu-bar-mode 42)
      (add-hook 'pre-command-hook 'my-menu-bar-open-after))))

(global-set-key [f10] 'my-menu-bar-open)
Lluís
  • 21
  • 1
0

I have tested this in GNU Emacs 25.2 and 26.3:

(menu-bar-mode -1)

(advice-add 'menu-bar-open
            :around
            (lambda (orig-fun &rest args)
              (menu-bar-mode 1)
              (apply orig-fun args)
              (menu-bar-mode -1)))

Resulting behaviour (assuming that menu-bar-open is bound to F10, which is the default):

  • The menu bar is not shown by default.
  • If you press F10, the menu bar will be shown.
  • Once you leave the menu bar, the menu bar will be gone until the next time you press F10.

Note that this is more like a hack than a proper solution.

Flux
  • 9,805
  • 5
  • 46
  • 92