I have two frames opened in emacs (one in each monitor, but this is irrelevant). I would like to have a lisp function to switch the buffer in the other frame (in the other monitor), whose focus is in an arbitrary buffer. The buffer I want to switch to in the other frame has a process (say Python) that is already running. When doing this, I want to keep the final focus in the current frame and buffer I ran the lisp function. Only now the other frame will show the buffer with the process. How could I have a lisp function to do that?

Edited: I ended up doing this, but maybe there is a better way

(defun go-to-python-buffer ()
  "Create or visit a Python buffer."
  (if (null (process-live-p (get-process "Python"))) ; (note that this line is different for python b/c get-process return different types in that case)
        (split-window-sensibly (selected-window))
        (other-window 1)
      (split-window-sensibly (selected-window))
      (switch-to-buffer (process-buffer (get-process "Python")))
      (other-window -1)) ) )

(defun go-to-python-frame ()
  "Create or visit a Python buffer in another frame."
  ;; check if there is a python process already open, if not, start one
  (if (not (stringp (get-process "Python"))) ; (note that this line is different for R b/c get-process return different types in that case)
  (if (= (list-length (frame-list)) 1)
      ;; if there is just one frame, create another, put the focus, and show the buffer with the python process
        (switch-to-buffer-other-frame (process-buffer (get-process "Python")))
        (other-window-or-frame -1))
      ;; if there is another frame already open, show the python buffer, and keep the focus
      (select-frame (next-frame))
      (switch-to-buffer (process-buffer (get-process "Python")) )
      (other-window-or-frame -1))))
  • Does your frames have dedicated names to help us target the right one? E.g., a frame for processes, a frame for code, a frame for email, a frame for calendar, etc. -- (let ((a (make-frame '((name . "TODAY")))) (b (make-frame '((name . "TOMORROW"))))) (message "a: %s | b: %s" a b ))
    – lawlist
    Dec 28, 2016 at 22:11
  • They don't, but we can give them arbitrary names when they are created, as you did.
    – Diogo
    Dec 28, 2016 at 23:36

1 Answer 1


Start from emacs -q, switch to the *scratch* buffer, copy and paste the example below to the *scratch* buffer, place the cursor immediately following the last closing parenthesis, and press: C-x C-e (aka eval-last-sexp). Then type M-x my-example


  • Step #1:  Create or retrieve the process buffer (in this example we use run-python).

[The default behavior when run-python is executed is to display the process buffer in another window on the existing frame. This example does not seek to alter the default behavior -- e.g., we are not deleting windows; we are not seeking to prevent windows from being split.]

  • Step #2:  Make a new frame named MISCELLANEOUS.

  • Step #3:  Make a new frame named PROCESSES.

  • Step #4:  Cycle through all existing frames looking for the frame named PROCESSES.

  • Step #5:  Display the process buffer in the largest window on the frame named PROCESSES.

  • Step #6:  Select the original frame where the user was just before starting this example.

  • Step #7:  Sit for just three (3) seconds and quickly observe what happened.

  • Step #8:  Clean up the example by deleting the frame named MISCELLANEOUS.

  • Step #9:  Clean up the example by deleting the frame named PROCESSES.

  • Step #10:  Display a message thanking the user for trying out this example.

(defun my-example ()
"Example for @Diogo."
  (let ((python-buffer
            (require 'python)
            (or (python-shell-get-buffer)
                (process-buffer (run-python)))))
        (original-frame (selected-frame))
        (a (make-frame '((name . "MISCELLANEOUS")
                         (height . 20)
                         (width . 80)
                         (top . 0)
                         (left . 625))))
        (b (make-frame '((name . "PROCESSES")
                         (height . 20)
                         (width . 80)
                         (top . 400)
                         (left . 625))))
        (frame-list (frame-list)))
    (catch 'break
        (lambda (frame)
          (let ((frame-name
                  (cdr (assq 'name (frame-parameters frame)))))
            (when (and python-buffer (equal frame-name "PROCESSES"))
              (throw 'break (progn
                (with-selected-frame frame
                   (unless (get-buffer-window python-buffer)
                    (set-window-buffer (get-largest-window) python-buffer))))))))
      ;; Just in case there was an error above, throw a break.
      (throw 'break nil))
    (select-frame original-frame 'norecord)
    (raise-frame original-frame)
    (sit-for 3)
    (delete-frame a)
    (delete-frame b)
    (message "Thank you for testing this example.")))
  • it works, but the other frame closes, and if there is a second frame already open, it does not use it. I ended up doing something in those lines that I posted in the edited question.
    – Diogo
    Dec 29, 2016 at 23:17
  • I've added a 10-step analysis to explain what this example does. If you need additional assistance, please let me know.
    – lawlist
    Dec 29, 2016 at 23:56

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.