Is there a way to control which window Emacs opens new buffers in?

I'm using sr-speedbar with emacs, and I often have the frame split into 2-3 different windows, and whenever I click on a file in sr-speedbar, it always opens the new buffer in the lowest window. I'm trying to keep the lower-rightmost window as a relatively small ansi-term, and emacs keeps insisting on opening new buffers in the small term window rather than in the much larger area that I'd like to use for editing buffers.

Is there some way that I can configure the buffer-creation logic to prefer higher windows over lower windows?

I've already tried taking my lowest window and marking it as protected, and that just made emacs split it into two unreasonably small portions. Then I tried enabling window-size-fixed and instead of making emacs open the buffer above that window, it just gave me an error that the window was too small to be split. Good I guess that it stopped clobbering my lowest window, but dumb that it stops me from opening new buffers instead.

Ideally, I'd like to be able to force emacs to select the upper-right-most window for displaying newly-created buffers, not attempt to split the lower-right-most window.


I assume you're using Emacs 24; I have not tested this answer in any earlier version, and do not know when the concept of dedicated windows was added to Emacs. I've seen mentions of its use which date from 2011, so I assume Emacs 23 (at least) also has the capability.

You can prevent Emacs from opening a new buffer in a given window by dedicating the window to its buffer.

In the simplest case, you can do this by selecting the window you wish to dedicate, ensuring it currently displays the buffer to which you wish to dedicate it, and then doing M-: (set-window-dedicated-p (selected-window) t). This will prevent Emacs considering the window so modified when deciding in which window to show a buffer. To remove the dedication, evaluate the same expression, replacing the second argument with nil.

You can prevent Emacs from attempting to split a window which displays a given buffer setting the buffer-local variable window-size-fixed to a non-nil value.

In the simplest case, you can do this by selecting the window and doing M-: (setq window-size-fixed t). To fix only the height or width of windows displaying the buffer, evaluate the same expression, passing 'height or 'width as the second argument; to remove the restriction, replace the second argument with nil.

In the general case, I found your problem interesting enough to hack up a solution, which you can drop into your load path, (require), and use:

;;; dedicate-windows-manually.el --- Manually (un)dedicate windows

;; Copyright (C) 2013 Aaron Miller
;; <[email protected]>

;; This program is free software; you can redistribute it and/or
;; modify it under the terms of the GNU General Public License as
;; published by the Free Software Foundation; either version 2 of
;; the License, or (at your option) any later version.

;; This program is distributed in the hope that it will be
;; useful, but WITHOUT ANY WARRANTY; without even the implied
;; warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
;; PURPOSE.  See the GNU General Public License for more details.

;; You should have received a copy of the GNU General Public
;; License along with this program; if not, write to the Free
;; Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
;; MA 02111-1307 USA

;;; Commentary:

;; Introduction
;; ============

;; The functions here defined allow you to manually dedicate and
;; undedicate windows, that is, prevent `set-window-buffer' from
;; considering them when selecting a window in which to display a
;; given buffer.

;; Windows dedicated in this fashion will also be protected from
;; splitting by setting `window-size-fixed'.

;; Installation
;; ============

;; Place this file in your load path; then, place the following
;; command somewhere in your initialization file:

;; (require 'dedicate-windows-manually)

;; Now you can use M-x dedicate-window to dedicate the selected window
;; to its currently displayed buffer, M-x undedicate-window to release
;; a dedication so applied, and M-x dedicate-window-toggle to switch
;; between the states.

;; These functions will operate only on manually dedicated or
;; undedicated windows; that is, M-x dedicate-window will not dedicate
;; a window which is already dedicated (i.e. "(window-dedicated-p
;; window) -> t", and M-x undedicate-window will not undedicate a
;; window which was not dedicated by way of M-x dedicate-window.

;; If you find yourself frequently doing M-x dedicate-window-toggle,
;; you might wish to place something like this in your init file:

;; (global-set-key (kbd "C-x 4 C-d") 'dedicate-window-toggle)

;; Bugs:
;; * Changing the lighter string while you have windows dedicated is
;;   probably not a good idea.
;; * I should certainly find a better way to change the mode line.

;;; Code:

(defcustom dedicated-window-lighter-string " [D]"
  "A string, propertized with `dedicated-window-lighter-face', prepended
to the mode line of manually dedicated windows.")

(defvar dedicated-windows-by-hand nil
  "A list of windows known to have been manually dedicated. Windows not
in this list will not be undedicated by `undedicate-window'.")

(defun dedicate-window-was-by-hand-p (window)
  (let ((result nil))
    (loop for w in dedicated-windows-by-hand
          collect (if (eq w window) (setq result t)))
    result))

(defun dedicate-window (&optional window flag)
  "Dedicate a window to its buffer, and prevent it from being split.

Optional argument WINDOW, if non-nil, should specify a window. Otherwise,
or when called interactively, the currently selected window is used.

Optional argument FLAG, if non-nil, will be passed verbatim to
`set-window-dedicated-p'."
  (interactive nil)
  (if (eq nil window) (setq window (selected-window)))
  (if (eq nil flag) (setq flag t))
  (if (window-dedicated-p window)
      (message "Window is already dedicated.")
    (progn
      (add-to-list 'dedicated-windows-by-hand window)
      (setq mode-line-format
            (append `(,dedicated-window-lighter-string) mode-line-format))
      (setq window-size-fixed t)
      (set-window-dedicated-p window flag))))

(defun undedicate-window (&optional window)
  "Un-dedicate a window from its buffer.

Optional argument WINDOW, if non-nil, should specify a window listed in
`dedicated-windows-by-hand'. Otherwise, or when called interactively,
the currently selected window is used.

If WINDOW is not in `dedicated-windows-by-hand', a complaint will be
issued and nothing will be done."
  (interactive nil)
  (if (eq nil window) (setq window (selected-window)))
  (if (not (window-dedicated-p window))
      (message "Window is not dedicated.")
    (if (not (dedicate-window-was-by-hand-p window))
        (message "Window is not dedicated by hand.")
      (progn
        (setq dedicated-windows-by-hand
              (remove window dedicated-windows-by-hand))
        (setq mode-line-format
              (remove dedicated-window-lighter-string mode-line-format))
        (setq window-size-fixed nil)
        (set-window-dedicated-p window nil)))))

(defun dedicate-window-toggle (&optional window)
  "Toggle a window's manual buffer dedication state.

Optional argument WINDOW, if non-nil, should specify a window. Otherwise,
or when called interactively, the value of `selected-window' is used."
  (interactive nil)
  (if (eq nil window) (setq window (selected-window)))
  (if (window-dedicated-p window)
      (undedicate-window window)
    (dedicate-window window)))

(provide 'dedicate-windows-manually)

;;; dedicate-windows-manually.el ends here

In recent Emacs releases option display-buffer-alist was added. It provides fine-grained control over buffer display, windows used, etc. However, because it lets you do so many things it is also quite complex and difficult to describe. Consult the documentation: C-h v display-buffer-alist.