8

Scenario: I have several (more than 2) windows open. I actively work with two of them. How do I best jump from one window to another, and back, with one command?

I use ace-window; it's great but I don't want to press window number every time. I know about next-window / prev-window, but these are two different commands.

What I'm looking for is something that remembers what the previous windows was when I select another window, and gets back to it. Invoked repeatedly, it would switch between the last two windows, Alt-Tab-style.

Where do I look?

  • I use fn plus one of the arrow keys to go in any direction, including in and out of the minibuffer (if it is active) -- see the built-in library windmove. – lawlist Jan 11 '17 at 20:11
  • @lawlist: I know about windmove. What I'm looking for is a way not to think about the direction required, especially if the windows have a few other windows between them. – 9000 Jan 11 '17 at 20:20
6

One way to write your own command is to use the built in get-mru-window function.

For example:

(defun my-flip-window ()
  (interactive)
  (let ((win  (get-mru-window nil nil t)))
    (when win (select-window win))))

This looks for the most-recently-used window in the current frame that is not the currently selected window.

Here is a variation that works across visible frames:

(defun my-flip-window ()
  (interactive)
  (let ((win  (get-mru-window 'visible nil t)))
    (when win
      (select-frame-set-input-focus (window-frame win))
      (select-window win))))

As mentioned in the comments, here's a variation that works when there's only one window (switching to the most recent buffer):

(defun flip-window ()
  (interactive)
  (let ((win  (get-mru-window 'visible t t)))
    (if win
        (progn
          (select-frame-set-input-focus (window-frame win))
          (select-window win))
      (mode-line-other-buffer))))
  • 1
    Nailed it! This one is much better than the one I put together. Nice find on get-mru-window. – Dan Jan 11 '17 at 20:41
  • 1
    I ended up adding this to my config with an additional variation: when there is only one frame/window (get-mru-window returns nil), then call mode-line-other-buffer. That way I have one key that flips back and forth between two buffers in any window configuration. – glucas Jan 12 '17 at 18:29
  • Great. I love that last variation @glucas. Thank you. Here is how I wrote it and it works. Is that the best way to do it? (defun my-switch-to-previous-window () (interactive) (let ((win (get-mru-window nil nil t))) (if win (select-window win) (mode-line-other-buffer)))) – prosoitos May 6 at 19:53
6

If you are already using ace-window, then you can use the command aw-flip-window to flip back and forth between two windows. By default this is bound to n in the ace-window aw-dispatch-alist.

That means that you can invoke ace-window and hit n instead of a window number to flip back to the previous window. You could also bind aw-flip-window to some other key.

Note that this will only flip back to a window that was previously selected by ace-window. If you often switch windows with other commands you may want a more general solution.

4

Here's a simple command, lightly tested, that will switch you to the most recently visited window:

(defvar recent-window nil
  "The most recently visited window.")

(defun switch-to-recent-window ()
  "Switch to the most recently visited window, as stored in
`recent-window'."
  (interactive)
  (let ((current (car (window-list))))
    (if recent-window
        (select-window recent-window)
      (message (concat "No recent window selected, "
                       "so I'm setting this window "
                       "as the most recent.")))
    (setq recent-window current)))
  • Thank you! It works. Do you mind if I make a package out of it, with attribution? – 9000 Jan 11 '17 at 20:23
  • You're welcome. Sure, feel free to use it in a package, but be aware that the code in not (yet) very intelligent. If you switch to other windows with commands such as next-window or other-window, the change won't get picked up in the recent-window variable. There's no obvious hook to use, so fixing this part may involve defining advice for a whole bunch of other functions. – Dan Jan 11 '17 at 20:26
  • 1
    I think you could use buffer-list-update-hook, which is called when the active window changes (after select-window). That hook is called in other cases but could be used to keep track of the last window. – glucas Jan 11 '17 at 20:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.