When I close a frame, I'd like for its buffer to be killed.
If the buffer is displayed in other frames, the buffer should not be killed.
Do nothing if more than one buffer is displayed in a frame.
What's a good way to set this up?
If I've understood the question, here's a function that does what you want:
(defun maybe-delete-frame-buffer (frame) "When a dedicated FRAME is deleted, also kill its buffer. A dedicated frame contains a single window whose buffer is not displayed anywhere else." (let ((windows (window-list frame))) (when (eq 1 (length windows)) (let ((buffer (window-buffer (car windows)))) (when (eq 1 (length (get-buffer-window-list buffer nil t))) (kill-buffer buffer))))))
You can add it as a hook that gets called whenever a frame is closed using:
(add-to-list 'delete-frame-functions #'maybe-delete-frame-buffer)
Below is a function (tested, but not extensively) that meets your first requirement: it kills the current buffer when you close a frame UNLESS the buffer is also visible in another frame.
(defun kill-buffer-when-frame-delete-dwim (frame) "Kill current buffer unless it's visible in another frame besides current FRAME." (unless (delq nil (mapcar #'(lambda (x) (memq (current-buffer) (mapcar #'window-buffer x))) (mapcar #'window-list (delq frame (frame-list))))) (kill-buffer (current-buffer)))) (add-hook 'delete-frame-functions 'kill-buffer-when-frame-delete-dwim)
I'm unclear on the second requirement:
Here's a simple approach:
(defun close-frame-buffer (frame) (kill-buffer (window-buffer (frame-root-window frame)))) (add-hook 'delete-frame-functions 'close-frame-buffer)
It will kill a buffer even if it's open in another frame however.