Simple Emacs Window Persistence

So I've been using Emacs for a long time now but most recently, I've started using the new NextStep/Cocoa support for Mac OS X. Basically, it replaces the old Carbon support with OS X's newer Cocoa APIs. The reason for doing this was an attempt to find an OS X Emacs application instead of using the terminal emacs implementation. Nothing was wrong with the terminal version but I wanted to have more flexibility, specifically with OS X's Spaces feature. One of the first things I noticed was, well, every time I opened Emacs.app, I had to reposition and resize my Emacs window because the maximize button didn't consume all available screen real estate. That being said, I whipped up a very simple alternative using Emacs Lisp (elisp). Below are the two elisp functions, one to persist your window geometry at Emacs close and another to load the geometry at Emacs startup, and the hooks to wire the functions up to the necessary hooks to have it all work:

  1. ;; Custom functions/hooks for persisting/loading frame geometry upon save/load
  2. (defun save-frameg ()
  3. "Gets the current frame's geometry and saves to ~/.emacs.frameg."
  4. (let ((frameg-font (frame-parameter (selected-frame) 'font))
  5. (frameg-left (frame-parameter (selected-frame) 'left))
  6. (frameg-top (frame-parameter (selected-frame) 'top))
  7. (frameg-width (frame-parameter (selected-frame) 'width))
  8. (frameg-height (frame-parameter (selected-frame) 'height))
  9. (frameg-file (expand-file-name "~/.emacs.frameg")))
  10. (with-temp-buffer
  11. ;; Turn off backup for this file
  12. (make-local-variable 'make-backup-files)
  13. (setq make-backup-files nil)
  14. (insert
  15. ";;; This file stores the previous emacs frame's geometry.\n"
  16. ";;; Last generated " (current-time-string) ".\n"
  17. "(setq initial-frame-alist\n"
  18. " '((font . \"" frameg-font "\")\n"
  19. (format " (top . %d)\n" (max frameg-top 0))
  20. (format " (left . %d)\n" (max frameg-left 0))
  21. (format " (width . %d)\n" (max frameg-width 0))
  22. (format " (height . %d)))\n" (max frameg-height 0)))
  23. (when (file-writable-p frameg-file)
  24. (write-file frameg-file)))))
  25.  
  26. (defun load-frameg ()
  27. "Loads ~/.emacs.frameg which should load the previous frame's geometry."
  28. (let ((frameg-file (expand-file-name "~/.emacs.frameg")))
  29. (when (file-readable-p frameg-file)
  30. (load-file frameg-file))))
  31.  
  32. ;; Special work to do ONLY when there is a window system being used
  33. (if window-system
  34. (progn
  35. (add-hook 'after-init-hook 'load-frameg)
  36. (add-hook 'kill-emacs-hook 'save-frameg)))

All you have to do is get this into your ~/.emacs file and things just work. What you'll notice is after you have this code in place, open Emacs, reposition your window and resize its geometry. Next time you open Emacs, it should remember the last window geometry/location.

Known Issues

  • This implementation does not work for new Emacs windows spawned from a running Emacs (If you know a hook I could use so that opening a new window will run load_frameg, let me know.)

Comments

Thank you, thank you, thank you!

You are welcome, you are welcome, you are welcome!