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.

Labels:

2 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.