Single Function to Center Emacs Window on Screen

Fellow Emacs-user Göktuğ Kayaalp condensed my frame centering stuff into one function as I mentioned one could do, and then improved it by adding a condition for full-screen frames. This is probably the last post on this topic, ever, because what else could be said. Right?!

It’s so nice, I want to share the code, reformatted a bit. And Göktuğ didn’t add the binding of frame to selected-frame as a fallback, so I added that back in, plus longer docs.

(defun my/frame-recenter (&optional frame)
  "Center FRAME on the screen.
FRAME can be a frame name, a terminal name, or a frame.
If FRAME is omitted or nil, use currently selected frame."
  (unless (eq 'maximised (frame-parameter nil 'fullscreen))
    (let* ((frame (or (and (boundp 'frame)
           (frame-w (frame-pixel-width frame))
           (frame-h (frame-pixel-height frame))
           ;; frame-monitor-workarea returns (x y width height) for the monitor
           (monitor-w (nth 2 (frame-monitor-workarea frame)))
           (monitor-h (nth 3 (frame-monitor-workarea frame)))
           (center (list (/ (- monitor-w frame-w) 2)
                         (/ (- monitor-h frame-h) 2))))
      (apply 'set-frame-position (flatten-list (list frame center))))))

(add-hook 'after-init-hook #'my/frame-recenter)
(add-hook 'after-make-frame-functions #'my/frame-recenter)

Update 2021-11-06: I noticed that some time after I began using Emacs 28, (and (boundp 'frame) frame) caused trouble and would fall-back to selected-frame too often. A working solution to auto-center a frame after making it is to omit the boundp check and just write this: (let* ((frame (or frame (selected-frame))) ...; this will fall-back to the selected frame if the frame parameter is not passed.

I wasn’t aware that instead of add-to-list a hook for after-make-frame-functions would do the job, too. That’s what you get from following some of the docs on the web to the letter. The after-init-hook is a great addition, too.

Since I have this auto-centering functionality in place, I find myself opening and closing new frames quite a lot. For most of 2020, I have been using a single frame, often in full-screen mode, and then have been splitting panes and experimenting with workspaces and tabs. Using the macOS windowing system instead integrates much easier with the rest of my computer life. (Though I still envy the Linux folks with their tiling window managers who use multiple tabs in emacs. Looks so tidy!)

You can also run this function in the terminal no problem. It will just exit with t and you won’t see any effect. The important part is that there are no errors when you’re not in a GUI.

See also: