8

Is there an Emacs face that can be used to control the colour of inactive buffer names?

Normally when setting the face mode-line-buffer-id all windows are affected.

In this example the mode-line has a light background, so I set mode-line-buffer-id to a much darker #333.

mode-line with dark buffer-id on light background

The idea is to invert the colour combination for for mode-line-inactive.

While this is possible for most of the text in the mode-line of inactive windows, the buffer names becomes unreadable since it's still controlled by the mode-line-buffer-id face.

mode-line-inactive with dark buffer-id on dark background

I believe that setting mode-line-inactive to a lighter background would work around the problem, but that's not the result I wish to achieve.

2

4 Answers 4

3

I'm not sure whether you're still looking for an answer or not but this was the only result I got on Google while trying to do this myself.

Anyways for whatever reason Emacs calls this distant-foreground so the only thing you really need to do is add :distant-foreground $colour-of-choice to your face.

1

Here's a variation on another answer that might help. This example remaps mode-line-buffer-id to be green in inactive buffers.

(defun toggle-mode-line-buffer-id-face (window)
  "Update the `mode-line-buffer-id' face in WINDOW dependening on
whether the window is selected."
  (with-current-buffer (window-buffer window)
(if (eq (current-buffer) (window-buffer (selected-window)))
    (face-remap-reset-base 'mode-line-buffer-id)
  (face-remap-set-base 'mode-line-buffer-id '(:foreground "green")))))

(add-hook 'buffer-list-update-hook (lambda () (walk-windows #'toggle-mode-line-buffer-id-face nil t)))

Update: As noted in the comments, this does not entirely solve the problem. When you have several visible windows visiting the same buffer, they will all share the same face.

2
  • Unfortunately, a buffer can be visible in more than one window, where one could be active and one inactive. Jun 2, 2016 at 7:54
  • True, face remapping applies to the buffer and not the window.
    – glucas
    Jun 2, 2016 at 10:24
1

This is a variation of the other answers, with this one distinguishing between active and inactive windows. If a buffer is visible in more than one window, only the active window will have ml-active-window-face and the other windows will all have ml-inactive-window-face.

(defvar ml-selected-window nil)

(defun ml-record-selected-window ()
  (setq ml-selected-window (selected-window)))

(defun ml-update-all ()
  (force-mode-line-update t))

(add-hook 'post-command-hook 'ml-record-selected-window)

(add-hook 'buffer-list-update-hook 'ml-update-all)

(defface ml-active-window-face
   '((t (:foreground "red")))
   "Face for active buffer identification.")

(defface ml-inactive-window-face
   '((t (:foreground "green")))
   "Face for inactive buffer identification.")

(defun ml-propertized-buffer-identification (fmt)
  "Return a list suitable for `mode-line-buffer-identification'.
FMT is a format specifier such as \"%12b\".  This function adds
text properties for face, help-echo, and local-map to it."
  (list (propertize fmt
        'face
          (if (eq ml-selected-window (selected-window))
            'ml-active-window-face
            'ml-inactive-window-face)
        'help-echo
        (purecopy "Buffer name
mouse-1: Previous buffer\nmouse-3: Next buffer")
        'mouse-face 'mode-line-highlight
        'local-map mode-line-buffer-identification-keymap)))

(setq-default mode-line-buffer-identification
  '(:eval (ml-propertized-buffer-identification "%12b")))

Example

0

I'm not sure it is possible. It seems that the mode line is updated only when its window is selected (testing using calls to message bears this out). And the code that does this is C code, not Lisp.

You can use a conditional expression in the definition of mode-line-buffer-identification, so that the face to use is computed dynamically. But I don't know of any function or variable that you can use to test whether a given window has an inactive mode-line.

You cannot use selected-window, for example, because that always points to the window with the active mode-line.

Here is an example of dynamic updating that is based on the buffer name. It is not what you want, but it at least shows you what you can do. If you can come up with a way to test whether the window being updated is selected then you could substitute that for the buffer-name test. (But my impression is that only the selected window gets its mode-line updated.)

(setq-default mode-line-buffer-identification
              '(:eval
                (list (propertize "%b"
                       'face (if ;; NOPE (eq (selected-window) (get-buffer-window (current-buffer)))
                                 (eq (current-buffer) (get-buffer "some-buffer"))
                                 'mode-line-buffer-id
                               'some-other-face)
                       'help-echo "Buffer name mouse-1: Previous buffer\nmouse-3: Next buffer"
                       'mouse-face 'mode-line-highlight
                       'local-map mode-line-buffer-identification-keymap))))

Another thing you might try is advising function format-mode-line. It does apparently distinguish a window with an active mode-line from one with an inactive mode-line. But it too is coded in C, so I doubt you will get very far with advising it. It tests C variable Qmode_line_inactive, FWIW.

I'd suggest asking this question on one of the Emacs mailing lists (e.g. [email protected]), if you don't get a satisfactory answer here. Seems like it could be good to be able to do what you request. +1 for the question, in any case.

1
  • 1
    Just to complete Drew's answer, active buffer detection and specific mode-line-buffer-id faces for active and inactive buffers is done in powerline. If you want to investigate the code, a good starting point is the function powerline-default-theme defined in powerline-themes.el
    – deb0ch
    May 31, 2016 at 18:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.