2

im trying to launch emacs with specific named frames and want each frame to have a specific buffer opened in a specific frame (ie have the frame named FM opned a dired buffer at `~/~)

this is my current state of my conf to try to achieve this:

*** create startup frames 
#+BEGIN_SRC emacs-lisp  :results none
(set-frame-name "MAIN")
(make-frame '((name . "FM")))
(make-frame '((name . "TERM"))) 
(make-frame '((name . "ORG")))




#+END_SRC
*** binds for frames 
#+BEGIN_SRC emacs-lisp  :results none
(global-set-key (kbd "s-a") (lambda () (interactive) (select-frame-by-name "MAIN")))
(global-set-key (kbd "s-s") (lambda () (interactive) (select-frame-by-name "TERM")))
(global-set-key (kbd "s-d") (lambda () (interactive) (select-frame-by-name "ORG"))) 
(global-set-key (kbd "s-z") (lambda () (interactive) (select-frame-by-name "FM"))) 
#+END_SRC
*** open in frames 
#+BEGIN_SRC emacs-lisp  :results none
(select-frame-by-name "FM") (dired-jump  "~/")
(select-frame-by-name "TERM") (eshell)
;; initial frame
(select-frame-by-name "MAIN") (find-file "~/org/files/agenda/TODO.org")

#+END_SRC

the frames are indeed generated and named correctly, yet i cany get the frames to open the correct buffer. im a bit at a loss.

  • Here is a link to a complex example that places specific buffers in certain frames, creating new frames if one with matching a specific frame name does not exist: stackoverflow.com/questions/18346785/… . It works for file-visiting buffers and also non-file-visiting buffers. It can be taken one step further by associating the buffer with the frame using a library such as frame-buffs by Alp Aker (or just the innards). – lawlist Sep 28 '18 at 14:57
1

Here is the simplified example I have inserted into my init.el (it omits keybindings for switching to the frames):

;; 0. for the main frame this hook is not called
(add-hook 'after-make-frame-functions
          (lambda (frame)
            (select-frame frame)
            (cond
             ((equal (frame-parameter frame 'name) "FM")
              (dired "~/"))
             ((equal (frame-parameter frame 'name) "TERM")
              (eshell)))))

(set-frame-name "MAIN")
;; 1. that is why we need to explicitly open the file needed here
(find-file "~/org/files/agenda/TODO.org")

(make-frame '((name . "FM")))
(make-frame '((name . "TERM")))

So it creates 3 frames for me (default one and 2 more).

  1. for the default frame you have to do "setup" right away.
  2. for other frames you create in init.el you should(?) use after-make-frame-functions hook and provide what you want to do with them there.
  • This works great @max Kim !..but..:)..seems not to work when i launch Emacs in daemon mode. i get this error: Unknown terminal type. any clue why? – zeltak Sep 28 '18 at 14:00
  • I am not sure. Try to remove (find-file "~/org/files/agenda/TODO.org"). Or maybe daemon mode has nothing to do with frames, because frames should be only created by emacsclient? – Maxim Kim Sep 28 '18 at 14:02
2

No need to fiddle with make-frame or hooks at all for this. Just use special-display-buffer-names to specify that those buffers get dedicated frames.

You can even give their frames particular parameters (e.g. different background colors), if you want.

For example:

(setq special-display-buffer-names
      (append '(("FM"   (background-color . "LightBlue"))
                ("ORG"  (background-color . "LightGreen"))
                ("TERM" (background-color . "LightPink")))
              special-display-buffer-names))

Or you can use the same frame parameters for all three and just set special-display-regexps to a regexp that matches (only) those buffer names:

(setq special-display-frame-alist
      (cons '(background-color . "LightBlue") special-display-frame-alist))
(setq special-display-regexps
      (concat "\\`" (regexp-opt '("FM" "ORG" "TERM")) "\\'"))

If you prefer, you can just use Customize to customize any of those options: special-display-buffer-names, special-display-regexps, and special-display-frame-alist. That's generally preferable (IMO) to adding code to your init file that does the same thing.

See the Elisp manual, node Dedicated Windows for more info about dedicated windows.


Special-display buffers are a handy way to do this kind of thing. Alternatively, you can fiddle with display-buffer-alist to do the same thing.

Note: Emacs considers special-display buffers "obsolete" since the more general mechanism of display-buffer-alist was implemented. (And they removed all mention of special-display from the manuals -- see below.) I don't consider special-display buffers to be obsolete or no longer useful just because you can do the same thing (and more) in a more complicated way. And I'm very glad that Emacs Dev made sure, with some encouragement, that the special-display code and doc strings have not been removed, and everything still works just fine, as always.


FYI, here is the Elisp manual doc (node Choosing Window) about special-display buffers from Emacs 23, before they removed it:

  • User Option: special-display-buffer-names

    A list of buffer names identifying buffers that should be displayed specially. If the name of BUFFER-OR-NAME is in this list, display-buffer handles the buffer specially. By default, special display means to give the buffer a dedicated frame.

    If an element is a list, instead of a string, then the CAR of that list is the buffer name, and the rest of that list says how to create the frame. There are two possibilities for the rest of that list (its CDR): It can be an alist, specifying frame parameters, or it can contain a function and arguments to give to it. (The function's first argument is always the buffer to be displayed; the arguments from the list come after that.)

    For example:

    (("myfile" (minibuffer) (menu-bar-lines . 0)))

    specifies to display a buffer named myfile in a dedicated frame with specified minibuffer and menu-bar-lines parameters.

    The list of frame parameters can also use the phony frame parameters same-frame and same-window. If the specified frame parameters include (same-window . VALUE) and VALUE is non-nil, that means to display the buffer in the current selected window. Otherwise, if they include (same-frame . VALUE) and VALUE is non-nil, that means to display the buffer in a new window in the currently selected frame.

  • User Option: special-display-regexps

    A list of regular expressions specifying buffers that should be displayed specially. If the buffer's name matches any of the regular expressions in this list, display-buffer handles the buffer specially. By default, special display means to give the buffer a dedicated frame.

    If an element is a list, instead of a string, then the CAR of the list is the regular expression, and the rest of the list says how to create the frame. See special-display-buffer-names above.

  • Function: special-display-p buffer-name

    This function returns non-nil if displaying a buffer named BUFFER-NAME with display-buffer would create a special frame. The value is t if it would use the default frame parameters, or else the specified list of frame parameters.

  • User Option: special-display-function

    This variable holds the function to call to display a buffer specially. It receives the buffer as an argument, and should return the window in which it is displayed. The default value of this variable is special-display-popup-frame, see below.

  • Function: special-display-popup-frame buffer &optional args

    This function tries to make BUFFER visible in a frame of its own. If BUFFER is already displayed in some window, it makes that window's frame visible and raises it. Otherwise, it creates a frame that is dedicated to BUFFER. The return value is the window used to display BUFFER.

    If ARGS is an alist, it specifies frame parameters for the new frame. If ARGS is a list whose CAR is a symbol, then (car ARGS) is called as a function to actually create and set up the frame; it is called with BUFFER as first argument, and (cdr ARGS) as additional arguments.

    This function always uses an existing window displaying BUFFER, whether or not it is in a frame of its own; but if you set up the above variables in your init file, before BUFFER was created, then presumably the window was previously made by this function.

  • User Option: special-display-frame-alist

    This variable holds frame parameters for special-display-popup-frame to use when it creates a frame.

  • thx for this very comprehensive response. this looks inline with what im aiming at. though how does one launch these special-display-buffers on startup (using emacs daemon if possible) to create 4 separate frames with pre defined buffers? – zeltak Sep 28 '18 at 15:07
  • You don't need to worry about creating the frames - they get created whenever you visit the buffers. If you want to create them initially, rather than interactively, just use any of switch-to-buffer, pop-to-buffer, display-buffer, find-file (if they are file buffers), dired (if they are directory buffers), etc. in your init file. It's enough to display the buffer to get it displayed in the dedicated frame you want. – Drew Sep 28 '18 at 15:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.