Long ago, I used XEmacs, and its buffer-local faces to highlight the active window and modeline. When I switched to Emacs, I was sad to see that it didn't have buffer-local and window-local faces. It does have a separate face for active and inactive modelines though.

Today I learned that Emacs 23 has a buffer-local face remapping feature. I'm using this to highlight the active buffer (not window):

;;; highlight-focus.el --- highlight the active buffer

;; Author: Amit J Patel <amitp@cs.stanford.edu>

;;; Commentary:
;; 
;; I find that I'm not good at tracking when focus changes across
;; apps, windows, and within a window. As much as possible, I try to
;; have all my applications somehow draw attention to what has
;; focus. In X11 I marked the focus in red. In Firefox I marked the
;; text fields in yellow. This Emacs package highlights the active
;; buffer. It's inspired by an earlier package I had written for
;; XEmacs, which changes the window color and modeline color for the
;; current window.
;;
;;; History:
;;
;; 2014-05-07: Updated to use the Emacs 24 focus-{in,out}-hook
;; 2013-05-10: Rewritten to use the Emacs 23 "remap faces" feature.
;; 2007-04-16: Initial version, temporarily highlighting the active buffer

;; Also see <https://github.com/emacsmirror/auto-dim-other-buffers>

;;; Code:

(require 'face-remap)
(defvar highlight-focus:last-buffer nil)
(defvar highlight-focus:cookie nil)
(defvar highlight-focus:background "white")
(defvar highlight-focus:app-has-focus t)

(defun highlight-focus:check ()
  "Check if focus has changed, and if so, update remapping."
  (let ((current-buffer (and highlight-focus:app-has-focus (current-buffer))))
    (unless (eq highlight-focus:last-buffer current-buffer)
      (when (and highlight-focus:last-buffer highlight-focus:cookie)
        (with-current-buffer highlight-focus:last-buffer
          (face-remap-remove-relative highlight-focus:cookie)))
      (setq highlight-focus:last-buffer current-buffer)
      (when current-buffer
        (setq highlight-focus:cookie
              (face-remap-add-relative 'default :background highlight-focus:background))))))

(defun highlight-focus:app-focus (state)
  (setq highlight-focus:app-has-focus state)
  (highlight-focus:check))

(defadvice other-window (after highlight-focus activate)
  (highlight-focus:check))
(defadvice select-window (after highlight-focus activate)
  (highlight-focus:check))
(defadvice select-frame (after highlight-focus activate)
  (highlight-focus:check))
(add-hook 'window-configuration-change-hook 'highlight-focus:check)

(add-hook 'focus-in-hook (lambda () (highlight-focus:app-focus t)))
(add-hook 'focus-out-hook (lambda () (highlight-focus:app-focus nil)))

(provide 'highlight-focus)

;;; highlight-focus.el ends here

There's some more tweaking I need to do but so far it seems to be working reasonably well.

Update: [2014-06-01] I updated the code to use Emacs 24.4's focus-in and focus-out hooks.

Update: [2017-10-26] Ram Krishnan has turned this into a package; see github/kriyative/highlight-focus.

Update: [2020-07-01] I now use and recommend auto-dim-other-buffers. It works really well, and is on MELPA!

Labels:

10 comments:

Unknown wrote at Thursday, October 23, 2014 at 3:27:00 PM PDT

Hi,

I've adapted your solution to have parts of my mode-line colored differently for active and inactive buffers. As long as there is no buffer dsiplayes in more than one window, it kind of works for me. But it also bothers me. So, have you ever figured out how to do this kind of thing not with different buffers but different windows?

Ciao, Marcus

Amit wrote at Thursday, October 23, 2014 at 4:54:00 PM PDT

Hi Marcus, no, sorry, I haven't figured out different windows. XEmacs had this feature — you could override faces for a buffer, a window, or a frame. GNU Emacs does not.

For the mode-line I use mode-line and mode-line-inactive faces. They do support per-window colors.

kriyative wrote at Wednesday, October 25, 2017 at 8:36:00 PM PDT

Hi -

I just discovered the very useful highlight-focus Elisp package - thanks for sharing it.

I didn't find a GitHub (or other public) repository for the code, so I created one for my own use - if you have a different repo I can contribute to, please let me know.

https://github.com/kriyative/highlight-focus

I also made a small change to allow rendering the highlight in ways other than changing the buffer/window background color. Hope others find that useful.

Thanks again.

Cheers,

-ram

Amit wrote at Thursday, October 26, 2017 at 8:29:00 AM PDT

Thank you Ram! I linked to your github repository at the end of the blog post.

kriyative wrote at Sunday, October 29, 2017 at 3:41:00 PM PDT

Amit - you're welcome. Do you have a preferred open source license you'd like to assign to this package? I can add to the repo in case anybody else is interested in using/extending the package.

Amit wrote at Sunday, October 29, 2017 at 3:54:00 PM PDT

Ram — I usually use MIT for things like this. It seems like the least hassle for people.

kriyative wrote at Sunday, October 29, 2017 at 6:02:00 PM PDT

Great - I've added the MIT license file.

mina86 wrote at Thursday, May 28, 2020 at 5:33:00 AM PDT

> Today I learned that Emacs 23 has a buffer-local face remapping feature. I'm using this to highlight the active buffer (not window)

FYI, starting with Emacs 27 this now supports per-window predicates. auto-dim-other-buffers takes advantage of that to highlight the active window.

Amit wrote at Monday, June 8, 2020 at 5:38:00 PM PDT

Thanks mina86! That's great news!

Amit wrote at Wednesday, July 1, 2020 at 8:42:00 PM PDT

mina86: I've switched to auto-dim-other-buffers and I've updated the blog post to link to it.