emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[nongnu] elpa/auto-dim-other-buffers 191d714ebb 68/82: Dim individual wi


From: ELPA Syncer
Subject: [nongnu] elpa/auto-dim-other-buffers 191d714ebb 68/82: Dim individual windows rather than buffers
Date: Mon, 12 Dec 2022 20:58:46 -0500 (EST)

branch: elpa/auto-dim-other-buffers
commit 191d714ebb314e65db9bb89050163024f2b9f339
Author: Michal Nazarewicz <mina86@mina86.com>
Commit: Michal Nazarewicz <mina86@mina86.com>

    Dim individual windows rather than buffers
    
    It has been long standing bug where ‘auto-dim-other-buffers’ would not
    dim windows if they displayed selected buffer.  I.e. if a buffer was
    shown in multiple windows, and one of those windows was selected, all
    of them would be highlighted.
    
    This is now fixed so long as the mode is used in Emacs 27.1 or newer.
    Even if a buffer is displayed in multiple windows, only window with
    focus will be undimmed.
    
    This is thanks to ‘:filtered (:window …)’ face predicate introduced in
    27.1 which allows to activate or deactivated based on window
    properties.
    
    Fixes: https://github.com/mina86/auto-dim-other-buffers.el/issues/16
    Fixes: https://github.com/mina86/auto-dim-other-buffers.el/issues/19
---
 README.md                 |  23 ++--
 auto-dim-other-buffers.el | 259 +++++++++++++++++++++++++++++++++++-----------
 2 files changed, 214 insertions(+), 68 deletions(-)

diff --git a/README.md b/README.md
index 34614b20d7..dc68937957 100644
--- a/README.md
+++ b/README.md
@@ -2,14 +2,16 @@
 
 
[![MELPA](https://melpa.org/packages/auto-dim-other-buffers-badge.svg)](https://melpa.org/#/auto-dim-other-buffers)
 
-The `auto-dim-other-buffers-mode` is a global minor mode which
-makes non-current buffer less prominent making it more apparent
-which window has a focus.
+The `auto-dim-other-buffers-mode` is a global minor mode which makes
+windows without focus less prominent.  With many windows in a frame,
+the idea is that this mode helps recognise which is the selected
+window by providing a non-intrusive but still noticeable visual
+indicator.
 
 ![Demo](screenshot.gif)
 
-The preferred way to install the mode is by installing a package
-form MELPA:
+The preferred way to install the mode is by grabbing
+`auto-dim-other-buffers` package form MELPA:
 
     M-x package-install RET auto-dim-other-buffers RET
 
@@ -29,6 +31,11 @@ To configure how dimmed buffers look like, customise
 
     M-x customize-face RET auto-dim-other-buffers-face RET
 
-The `auto-dim-other-buffers-mode` is a global minor mode which
-makes non-current buffer less prominent making it more apparent
-which window has a focus.
+More customisation can be found in `auto-dim-other-buffers`
+customisation group which can be accessed with:
+
+    M-x customize-group RET auto-dim-other-buffers RET
+
+Note that despite it’s name, since Emacs 27.1 the mode operates on *windows*
+rather than buffers.  I.e. selected window is highlighted and all other
+windows are dimmed even if they display the same buffer.
diff --git a/auto-dim-other-buffers.el b/auto-dim-other-buffers.el
index 90972fd23a..b3ea2a3766 100644
--- a/auto-dim-other-buffers.el
+++ b/auto-dim-other-buffers.el
@@ -1,15 +1,8 @@
-;;; auto-dim-other-buffers.el --- Makes non-current buffers less prominent -*- 
lexical-binding: t -*-
-
-;; Copyright 2013 Steven Degutis
-;; Copyright 2013-2017 Google Inc.
-;; Copyright 2014 Justin Talbott
-;; Copyright 2018-2020 Michał Nazarewicz
-
-;; Author: Steven Degutis
-;;     Michal Nazarewicz <mina86@mina86.com>
+;;; auto-dim-other-buffers.el --- Makes windows without focus less prominent 
-*- lexical-binding: t -*-
+;; Author: Michal Nazarewicz <mina86@mina86.com>
 ;; Maintainer: Michal Nazarewicz <mina86@mina86.com>
 ;; URL: https://github.com/mina86/auto-dim-other-buffers.el
-;; Version: 1.9.6
+;; Version: 2.0
 
 ;; This file is not part of GNU Emacs.
 
@@ -28,12 +21,13 @@
 
 ;;; Commentary:
 
-;; The `auto-dim-other-buffers-mode' is a global minor mode which
-;; makes non-current buffer less prominent making it more apparent
-;; which window has a focus.
+;; The ‘auto-dim-other-buffers-mode’ is a global minor mode which makes windows
+;; without focus less prominent.  With many windows in a frame, the idea is 
that
+;; this mode helps recognise which is the selected window by providing
+;; a non-intrusive but still noticeable visual indicator.
 
-;; The preferred way to install the mode is by installing a package
-;; form MELPA:
+;; The preferred way to install the mode is by grabbing 
‘auto-dim-other-buffers’
+;; package form MELPA:
 ;;
 ;;     M-x package-install RET auto-dim-other-buffers RET
 
@@ -53,15 +47,27 @@
 ;;
 ;;     M-x customize-face RET auto-dim-other-buffers-face RET
 
+;; More customisation can be found in ‘auto-dim-other-buffers’ customisation
+;; group which can be accessed with:
+;;
+;;     M-x customize-group RET auto-dim-other-buffers RET
+
+;; Note that despite it’s name, since Emacs 27.1 the mode operates on *windows*
+;; rather than buffers.  I.e. selected window is highlighted and all other
+;; windows are dimmed even if they display the same buffer.  In older Emacs
+;; versions the mode falls back to the old behaviour where all windows
+;; displaying selected buffer are highlighted.  This historic behaviour is 
where
+;; the mode gets its name from.
+
 ;;; Code:
 
 (defface auto-dim-other-buffers-face
   '((((background light)) :background "#eff") (t :background "#122"))
-  "Face (presumably dimmed somehow) for non-current buffers."
+  "Face (presumably dimmed somehow) for non-selected window."
   :group 'auto-dim-other-buffers)
 
 (defcustom auto-dim-other-buffers-dim-on-focus-out t
-  "Whether to dim all buffers when a frame looses focus."
+  "Whether to dim all windows when frame looses focus."
   :type 'boolean
   :group 'auto-dim-other-buffers)
 
@@ -70,47 +76,147 @@
   :type 'boolean
   :group 'auto-dim-other-buffers)
 
+
+(defconst adob--adow-mode (not (version< emacs-version "27.1"))
+  "Whether Emacs supports :filtered faces.
+If t, the code will run in ‘auto dim other window’ mode (hence
+‘adow-mode’) which operates on windows rather than buffers.  To
+operate on windows, Emacs must support :filtered face predicate
+which has been added in Emacs 27.1.")
+
+(defconst adob--remap-face
+  (if adob--adow-mode
+      '(:filtered (:window adob--dim t) auto-dim-other-buffers-face)
+    'auto-dim-other-buffers-face)
+  "Face to use when adding relative face remapping.
+Depending on whether Emacs supports :filtered predicate, this
+will or will not use it.  See ‘adob--adow-mode’.")
+
 (defvar adob--last-buffer nil
-  "Selected buffer before command finished.")
+  "Last selected buffer which, i.e. buffer which is currently not dimmed.")
+(defvar adob--last-window nil
+  "Last selected buffer which, i.e. window which is currently not dimmed.
+This is only used in adow mode (i.e. if ‘adob--adow-mode’).")
 
 (defun adob--never-dim-p (buffer)
   "Return whether to never dim BUFFER.
-Currently, no hidden buffers (ones whose name starts with a space) are dimmed."
+Currently, no hidden buffers (ones whose name starts with a space) are dimmed.
+This is only used outside of adow-mode (i.e. if not ‘adob--adow-mode’)."
   (eq t (compare-strings " " 0 1 (buffer-name buffer) 0 1)))
 
 (defvar-local adob--face-mode-remapping nil
-  "Current remapping cookie for `auto-dim-other-buffers-mode'.")
+  "Current face remapping cookie for `auto-dim-other-buffers-mode'.")
+
+(defun adob--remap-face (buffer object)
+  "Make sure face remapping is active in BUFFER.
 
-(defun adob--dim-buffer ()
-  "Dim current buffer if not already dimmed."
-  (when (not adob--face-mode-remapping)
+Does not preserve current buffer and changes it to BUFFER if new
+remapping had to be added.
+
+If face remapping had to be added, force update of OBJECT which
+can be a window (which forces update of only that window) or
+a buffer (which forces update of all windows displaying that
+buffer).  To keep track of the face remapping, update
+‘adob--face-mode-remapping’.
+
+Return non-nil if new remapping has been added; nil if it was
+already active in current buffer."
+  (unless (buffer-local-value 'adob--face-mode-remapping buffer)
+    (set-buffer buffer)
+    (force-window-update object)
     (setq adob--face-mode-remapping
-          (face-remap-add-relative 'default 'auto-dim-other-buffers-face))
-    (force-window-update (current-buffer))))
+          (face-remap-add-relative 'default adob--remap-face))))
+
+(defun adob--unmap-face (buffer object)
+  "Make sure face remapping is inactive in BUFFER.
 
-(defun adob--undim-buffer ()
-  "Undim current buffer if dimmed."
-  (when adob--face-mode-remapping
+Does not preserve current buffer and changes it to BUFFER if new
+remapping had to be added.
+
+If face remapping had to be removed, force update of OBJECT which
+can be a window (which forces update of only that window) or
+a buffer (which forces update of all windows displaying that
+buffer).  To keep track of the face remapping, update
+‘adob--face-mode-remapping’.
+
+Return t if remapping has been removed; nil if it was not active
+in current buffer."
+  (when (buffer-local-value 'adob--face-mode-remapping buffer)
+    (set-buffer buffer)
     (face-remap-remove-relative adob--face-mode-remapping)
     (setq adob--face-mode-remapping nil)
-    (force-window-update (current-buffer))))
+    (force-window-update object)
+    t))
+
+(defun adob--dim-buffer (buffer &optional except-in)
+  "Dim BUFFER if not already dimmed except in EXCEPT-IN window.
+
+Does not preserve current buffer and changes it to BUFFER if new
+remapping had to be added.
+
+EXCEPT-IN only works if the code is running in adow mode (see
+‘adob--adow-mode’) and it works by deactivating the dimmed face
+in specified window."
+  (when (adob--remap-face buffer buffer)
+    (dolist (wnd (and adob--adow-mode
+                      (get-buffer-window-list buffer 'n 'visible)))
+      (set-window-parameter wnd 'adob--dim (not (eq wnd except-in))))))
 
 (defun adob--update ()
-  "Make sure that selected buffer is not dimmed.
-Dim previously selected buffer if selection has changed."
-  (let ((buf (window-buffer)))
-    (unless (or (eq buf adob--last-buffer)
-                (and (not auto-dim-other-buffers-dim-on-switch-to-minibuffer)
-                     (minibufferp buf)))
-      ;; Selected buffer has changed.  Dim the old one and undim the new.
-      (save-current-buffer
-        (when (and (buffer-live-p adob--last-buffer)
-                   (not (adob--never-dim-p adob--last-buffer)))
-          (set-buffer adob--last-buffer)
-          (adob--dim-buffer))
-        (set-buffer buf)
-        (adob--undim-buffer)
-        (setq adob--last-buffer buf)))))
+  "Make sure that selected window is not dimmed.
+Dim previously selected window if selection has changed."
+  (when (or auto-dim-other-buffers-dim-on-switch-to-minibuffer
+            (not (window-minibuffer-p)))
+    (let* ((wnd (selected-window))
+           (buf (window-buffer wnd)))
+
+      ;; If window has changed, update old and new window’s parameters.
+      (when (and adob--adow-mode
+                 (not (eq wnd adob--last-window)))
+        (when (and (window-live-p adob--last-window)
+                   (not (window-minibuffer-p adob--last-window)))
+          (set-window-parameter adob--last-window 'adob--dim t)
+          (force-window-update adob--last-window))
+        (setq adob--last-window wnd)
+        (unless (window-minibuffer-p adob--last-window)
+          (set-window-parameter adob--last-window 'adob--dim nil)
+          (force-window-update adob--last-window)))
+
+      ;; If buffer has changed, update their status.
+      (unless (eq buf adob--last-buffer)
+        (save-current-buffer
+          (when (buffer-live-p adob--last-buffer)
+            (adob--dim-buffer adob--last-buffer wnd))
+          (setq adob--last-buffer buf)
+          (if adob--adow-mode
+              (adob--remap-face buf buf)
+            (adob--unmap-face buf buf)))))))
+
+(defun adob--rescan-windows ()
+  "Rescan all windows in selected frame and dim all non-selected windows."
+  (let* ((selected-window (selected-window))
+         (selected-buffer (window-buffer selected-window))
+         (windows (window-list nil 'n)))
+    (save-current-buffer
+      (while windows
+        (let* ((wnd (car windows))
+               (buf (window-buffer wnd)))
+          (setq windows (cdr windows))
+          (cond (adob--adow-mode
+                 ;; Update window’s ‘adob--dim’ parameter.  If it changes set
+                 ;; we’ll also later tell Emacs to redisplay the window.
+                 (let ((new (not (eq wnd selected-window))))
+                   (unless (eq new (window-parameter wnd 'adob--dim))
+                     (set-window-parameter wnd 'adob--dim new)
+                     (force-window-update wnd)))
+                 ;; In adow-mode, make sure that the buffer has remapped faces.
+                 (adob--remap-face buf wnd))
+                ;; Outside of adow-mode, add or remove face remapping depending
+                ;; on whether current buffer selected buffer or not.
+                ((eq buf selected-buffer)
+                 (adob--unmap-face buf wnd))
+                ((adob--never-dim-p buf)
+                 (adob--remap-face buf wnd))))))))
 
 (defun adob--buffer-list-update-hook ()
   "React to buffer list changes.
@@ -123,30 +229,53 @@ Otherwise, if a new buffer is displayed somewhere, dim 
it."
       ;; A new buffer is displayed somewhere but it’s not the selected one so
       ;; dim it.
       (unless (adob--never-dim-p current)
-        (adob--dim-buffer)))))
+        (adob--dim-buffer current)))))
 
 (defun adob--focus-out-hook ()
   "Dim all buffers if `auto-dim-other-buffers-dim-on-focus-out'."
-  (when (and auto-dim-other-buffers-dim-on-focus-out
-             (buffer-live-p adob--last-buffer)
-             (not (adob--never-dim-p adob--last-buffer)))
-    (with-current-buffer adob--last-buffer
-      (adob--dim-buffer))
-    (setq adob--last-buffer nil)))
+  (cond ((not (and auto-dim-other-buffers-dim-on-focus-out
+                   (buffer-live-p adob--last-buffer))))
+        ((and (window-live-p adob--last-window)
+              (not (window-minibuffer-p adob--last-window)))
+         (set-window-parameter adob--last-window 'adob--dim t)
+         (force-window-update adob--last-window)
+         (setq adob--last-buffer nil
+               adob--last-window nil))
+        ((not (or adob--adow-mode
+                  (adob--never-dim-p adob--last-buffer)))
+         (save-current-buffer (adob--dim-buffer adob--last-buffer))
+         (setq adob--last-buffer nil))))
 
 (defun adob--focus-change-hook ()
   "Based on focus status of selected frame dim or undim selected buffer.
 Do nothing if `auto-dim-other-buffers-dim-on-focus-out' is nil
 and frame’s doesn’t have focus."
+  ;; ‘after-focus-change-function’ has been added at the same time as
+  ;; ‘frame-focus-state’ function so if we’re here we know that function is
+  ;; defined.
   (if (with-no-warnings (frame-focus-state))
       (adob--update)
     (adob--focus-out-hook)))
 
 ;;;###autoload
 (define-minor-mode auto-dim-other-buffers-mode
-  "Visually makes non-current buffers less prominent"
+  "Visually makes windows without focus less prominent.
+
+Windows without input focus are made to look less prominent by
+applying ‘auto-dim-other-buffers-face’ to them.  With many
+windows in a frame, the idea is that this mode helps recognise
+which is the selected window by providing a non-intrusive but
+still noticeable visual indicator.
+
+Note that despite it’s name, since Emacs 27.1 this mode operates
+on *windows* rather than buffers.  In older versions of Emacs, if
+a buffer was displayed in multiple windows, none of them would be
+dimmed even though at most one could have focus.  This historic
+behaviour is where the mode gets its name from."
   :global t
+  ;; Add/remove all hooks
   (let ((callback (if auto-dim-other-buffers-mode #'add-hook #'remove-hook)))
+    (funcall callback 'window-configuration-change-hook #'adob--rescan-windows)
     (funcall callback 'buffer-list-update-hook #'adob--buffer-list-update-hook)
     ;; Prefer ‘after-focus-change-function’ (which was added in Emacs 27.1) to
     ;; ‘focus-out-hook’ and ‘focus-in-hook’.
@@ -161,19 +290,29 @@ and frame’s doesn’t have focus."
 
   (save-current-buffer
     (if auto-dim-other-buffers-mode
+        ;; Dim all except for the current buffer.  When running in adow mode,
+        ;; dim current buffer as well except for in selected window.  If not
+        ;; running in adow mode, don’t dim hidden buffers either (most notably
+        ;; we care about Minibuffer and Echo Area buffers).
         (progn
-          (setq adob--last-buffer (window-buffer))
+          (setq adob--last-buffer (window-buffer)
+                adob--last-window (if adob--adow-mode (selected-window)))
           (dolist (buffer (buffer-list))
-            (unless (or (eq buffer adob--last-buffer)
-                        (adob--never-dim-p buffer))
-              (set-buffer buffer)
-              (adob--dim-buffer))))
-      (setq adob--last-buffer nil)
+            (when (or adob--adow-mode
+                      (not (or (eq buffer adob--last-buffer)
+                               (adob--never-dim-p buffer))))
+              (adob--dim-buffer buffer adob--last-window))))
+
+      ;; Clean up by removing all face remaps.
+      (setq adob--last-buffer nil
+            adob--last-window nil)
       (dolist (buffer (buffer-list))
+        ;; Kill the local variable even if it’s already set to nil.  This is 
why
+        ;; we’re checking whether it’s a local variable rather than it’s value
+        ;; in the buffer.
         (when (local-variable-p 'adob--face-mode-remapping buffer)
           (set-buffer buffer)
-          (when adob--face-mode-remapping
-            (face-remap-remove-relative adob--face-mode-remapping))
+          (adob--unmap-face buffer buffer)
           (kill-local-variable 'adob--face-mode-remapping))))))
 
 (provide 'auto-dim-other-buffers)



reply via email to

[Prev in Thread] Current Thread [Next in Thread]