At work, I have a dual-monitor setup and, naturally, both of them are fullscreened to emacs. I have bindings to switch between the two frames with other-frame, but sometimes I just want particular content on the screen directly in front of me. (One is off to the side.) How can I rotate window configurations among frames (in this case, effectively swapping them)?

  • To clarify, you want to keep the window configurations themselves, but change the frame in which each window configuration is displayed? (I believe you've confused things by referring to "windows" and other-window when you meant "frames" and other-frame?)
    – phils
    Nov 13, 2014 at 22:16
  • @phils Oh yes, my mistake. Long day. Nov 13, 2014 at 22:27
  • 1
    FWIW, I think this would ideally be dealt with at the window manager level; as it's a problem which can apply to more than just Emacs. (Not that an Emacs-specific solution isn't useful too, mind.)
    – phils
    Nov 13, 2014 at 22:39
  • 2
    How about just using set-frame-position and change the positions of both frames after gathering the current values? gnu.org/software/emacs/manual/html_node/elisp/…
    – lawlist
    Nov 14, 2014 at 0:36
  • @lawlist That's another way of thinking about it :) Nov 14, 2014 at 0:37

1 Answer 1


Try swapping window states of root windows of the frames in question:

(defun swap-frames (a b)
  "Swap window states of root windows of two frames."
  (let ((state-a (window-state-get (frame-root-window a)))
        (state-b (window-state-get (frame-root-window b))))
  (window-state-put state-a (frame-root-window b))
  (window-state-put state-b (frame-root-window a))))

(defun swap-two-frames ()
  "Swap states of the first two frames in frame-list."
  (swap-frames (nth 0 (frame-list)) (nth 1 (frame-list))))

Here's one way to generalize this to implement cyclic rotation of window states.

(defun apply-window-states (states windows)
  "Apply states in STATES to all WINDOWS by calling
  (when (< (length states) (length windows))
    (error "not enough window states to apply to all windows"))
  (when windows
    (window-state-put (car states) (car windows))
    (apply-window-states (cdr states) (cdr windows))))

This helper function just calls window-state-put for all pairs of provided states and windows.

(There must be a better way to do this. Does Emacs Lisp have zip? If it does, we could just map over the result of zipping lists of states and windows and remove this function.)

Now I can define

(defun rotate-frames (arg)
  "Cyclically rotate window states through all frames.
Use the prefix argument to switch direction."
  (interactive "P")
  (let* ((windows (mapcar (lambda (f) (frame-root-window f)) (frame-list)))
         (states (mapcar (lambda (w) (window-state-get w)) windows)))
    (if (not arg)
        ;; cycle in one direction
          (apply-window-states (cdr states) (butlast windows))
          (window-state-put (car states) (car (last windows))))
      ;; cycle in the other direction
      (apply-window-states (butlast states) (cdr windows))
      (window-state-put (car (last states)) (car windows)))))

Finally, set some key bindings.

(global-set-key (kbd "S-<right>") #'rotate-frames)
(global-set-key (kbd "S-<left>") (lambda () (interactive) (rotate-frames t)))

I like it. I might actually use this myself. :-)

  • Is there any way to extend this to rotate states through all frames? Nov 13, 2014 at 22:26
  • @SeanAllred: Yes, certainly. I'll update the answer when I find a moment later today. Nov 13, 2014 at 22:29
  • @SeanAllred: I updated the answer. (I think it's pretty neat!) Nov 14, 2014 at 3:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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