setting the frame title

The 'frame title' (window title) that emacs uses in graphical environments defaults to something like emacs@hostname.

Of course emacs lets us customize this, by changing the value of frame-title-format. Emacs accepts many different things there, (see the documentation for frame-title-format and mode-line-format for that), but let's look at an example.

Instead of the default emacs@hostname, I find it more useful to include the name of the file I'm working on instead, or, in case of non-file buffers, the buffer name. To do this, I have something like the following in my .emacs:

(setq frame-title-format
  '("" invocation-name ": "(:eval (if (buffer-file-name)
                (abbreviate-file-name (buffer-file-name))

As you see, frame-title-format is a template for the items that are present in the title bar; i.e.. emacs concatenates the items in the list, and it supports various %-constructs, which are replaced with actual values; see below.

In addition to the %-constructs, you can use :eval to make emacs evaluate the expression whenever it wants to update the title bar.

invocation-name is the name of the emacs binary.

abbreviate-file-name replaces the home directory part in file names with ~; for very deep paths it might be nice to do some abbreviation as well as some shells do; this is left as an exercise to the reader :)

You can experiment with some other things to put in frame-title-format; use the :eval construct as above to use emacs-lisp functions, and the various %-specifiers which are replaced by certain values; the emacs documentation lists the following:

%b -- print buffer name.      %f -- print visited file name.
%F -- print frame name.
%* -- print %, * or hyphen.   %+ -- print *, % or hyphen.
      %& is like %*, but ignore read-only-ness.
      % means buffer is read-only and * means it is modified.
      For a modified read-only buffer, %* gives % and %+ gives *.
%s -- print process status.
%i -- print the size of the buffer.
%I -- like %i, but use k, M, G, etc., to abbreviate.
%p -- print percent of buffer above top of window, or Top, Bot or All.
%P -- print percent of buffer above bottom of window, perhaps plus Top,
      or print Bottom or All.
%n -- print Narrow if appropriate.
%t -- visited file is text or binary (if OS supports this distinction).
%z -- print mnemonics of keyboard, terminal, and buffer coding systems.
%Z -- like %z, but including the end-of-line format.
%e -- print error message about full memory.
%@ -- print @ or hyphen.  @ means that default-directory is on a
      remote machine.
%[ -- print one [ for each recursive editing level.  %] similar.
%% -- print %.   %- -- print infinitely many dashes.
Decimal digits after the % specify field width to which to pad.

So, if we'd like to include the host (system) name and some indication of the status of this buffer, we could do something like:

(setq frame-title-format
  '("emacs%@" (:eval (system-name)) ": " (:eval (if (buffer-file-name)
                (abbreviate-file-name (buffer-file-name))
                  "%b")) " [%*]"))

Of course, some of the information is available elsewhere already, but it might be clearer in the frame-title. Or not – there's a lot of room for tweaking and experimentation here.


be_slayed said...

Hmm... I would like to show the buffer name, but a lot of my files are deeply buried (and abbreviate-file-name apparently doesn't deal with this) and the title text ends up running out of "bar space".

Is there anyway to work with the "uniquified" buffer name instead?

be_slayed said...

OK, I figured out the answer to my own question. Just replace 'buffer-file-name' with 'buffer-name'.

Unknown said...

Thanks. I've wondering how to change the frame title but haven't had time to look into it. This article saved me a lot of time and effort.

Anonymous said...

I use the following, which I believe I grabbed from the comments in this very blog :)

;; titlebar = buffer unless filename
(setq frame-title-format '(buffer-name "%f" ("%b")))

Anonymous said...

I like to set the frame name to reflect the project I'm working on: "emacs (Project Name)". So I wrote this little function to do it:

(defun my-set-frame-name ()
"Prompt the user for a window title, and set the current
frame's title to that string."
(let ((title (read-string "Enter window title: " "emacs (")))
(if (string-match "\\`emacs ([^)]+\\'" title) ; no trailing close-paren
(setq title (concat title ")")))
(set-frame-name title)

It prompts me for a string to use as a frame title, and it defaults to a string that begins with "emacs (". I can type a project name there, or I can erase the "emacs (" part and type anything I want. If I forget to use a close parenthesis, the function adds it for me.

I have this assigned to a keystroke, and I use it almost every time I start emacs.

Samue1604 said...

I didn't knew about the :eval trick thanks!

Brian White said...

Thanks for this information. It has put me on the right path. I want to massage the value returned by %f so I tried the following:

(setq frame-title-format '("Hi " (:eval (mapconcat (lambda (x) (format "%s" x)) (last (message-box "%s" (split-string "%f" "/")) 3) "/"))))

If I replace %f with a literal string it works as I expect ut using %f just places the full path with filename like it didn't run my code at all. I do get the leading "Hi " though.

Any thoughts would be greatly appreciated!

Brian White said...

Sorry. I put a debug elisp statement in my last post. The real line of code I am trying to use is:

(setq frame-title-format '("Hi " (:eval (mapconcat (lambda (x) (format "%s" x)) (last (split-string "%f" "/") 3) "/"))))

Thanks for the help!

John said...

Thanks for explaining how to set the frame title. I wanted to take some screen shots and leave my machine name out of them and couldn't find how to do that.

Anonymous said...

Hi, this works great for me, except...

When I switch away from emacs, a short while later the window title reverts back to "emacs@hostname". If I switch back to emacs it then updates the title again. I'm using emacs 24 if that makes a difference.

djcb said...

@Anonymous: hmmmm, cannot reproduce that...

Anonymous said...

Okay, maybe it is just my window manager doing something silly. Thanks!