[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)
- [nongnu] elpa/auto-dim-other-buffers a066c32ada 40/82: Allow disabling “dimming on focus out” feature, (continued)
- [nongnu] elpa/auto-dim-other-buffers a066c32ada 40/82: Allow disabling “dimming on focus out” feature, ELPA Syncer, 2022/12/12
- [nongnu] elpa/auto-dim-other-buffers 8b1d8803b5 43/82: Fix Markdown formatting in README file, ELPA Syncer, 2022/12/12
- [nongnu] elpa/auto-dim-other-buffers e9c886fac5 42/82: Use even number of arguments for `setq', ELPA Syncer, 2022/12/12
- [nongnu] elpa/auto-dim-other-buffers 853523a854 50/82: Don't dim last buffer when switching to minibuffer or echo area., ELPA Syncer, 2022/12/12
- [nongnu] elpa/auto-dim-other-buffers efd617c999 60/82: Make sure current buffer is not dimmed when the mode is enabled, ELPA Syncer, 2022/12/12
- [nongnu] elpa/auto-dim-other-buffers e4ef0a93ca 66/82: Unconditionally undim selected buffer when focus is regained, ELPA Syncer, 2022/12/12
- [nongnu] elpa/auto-dim-other-buffers a87cf772ac 61/82: Dim only the last buffer when loosing focus, ELPA Syncer, 2022/12/12
- [nongnu] elpa/auto-dim-other-buffers 087baafa08 51/82: Move minibuffer check to the beginning of ‘adob--buffer-list-update-hook’, ELPA Syncer, 2022/12/12
- [nongnu] elpa/auto-dim-other-buffers bedeef9ea3 70/82: Support ‘adow-mode’ since the first Emacs 27 preview releases, ELPA Syncer, 2022/12/12
- [nongnu] elpa/auto-dim-other-buffers cad370fb6c 72/82: Preserve current-buffer, ELPA Syncer, 2022/12/12
- [nongnu] elpa/auto-dim-other-buffers 191d714ebb 68/82: Dim individual windows rather than buffers,
ELPA Syncer <=
- [nongnu] elpa/auto-dim-other-buffers ed9ebbcc52 74/82: Define Auto Dim Other Buffers customise group, ELPA Syncer, 2022/12/12
- [nongnu] elpa/auto-dim-other-buffers 0a103b09eb 73/82: Require 'face-remap to silence compilation warning, ELPA Syncer, 2022/12/12
- [nongnu] elpa/auto-dim-other-buffers a1c67bf557 81/82: Update screenshot animation and demo video link, ELPA Syncer, 2022/12/12
- [nongnu] elpa/auto-dim-other-buffers c9fe23d03c 79/82: Allow configuring which faces to alter; not just the ‘default’, ELPA Syncer, 2022/12/12
- [nongnu] elpa/auto-dim-other-buffers 8062977284 10/82: face is real face, ELPA Syncer, 2022/12/12
- [nongnu] elpa/auto-dim-other-buffers 7f332de332 17/82: oops, ELPA Syncer, 2022/12/12
- [nongnu] elpa/auto-dim-other-buffers 7502775f38 29/82: Use a shorter lighter for the mode., ELPA Syncer, 2022/12/12
- [nongnu] elpa/auto-dim-other-buffers b1562a1200 38/82: Wrap `adob--dim-all-buffers' into a lambda when adding as a hook, ELPA Syncer, 2022/12/12
- [nongnu] elpa/auto-dim-other-buffers b599ff6db9 57/82: Better clean up when disabling the mode; remove arg from dim-all-buffers, ELPA Syncer, 2022/12/12
- [nongnu] elpa/auto-dim-other-buffers 53dd9b68fb 59/82: Ignore all hidden buffers, ELPA Syncer, 2022/12/12