emacsmenuelispmenubar

Dynamically show/hide menu bar in Emacs


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.


Solution

  • 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.