Subject: bug#77715: [PATCH] Add ring-bell functions for mode line and header line.

From: Elijah Gabe Pérez <[email-masked]>
Date: Thu, 10 Apr 2025 21:01:33 -0600

Drew Adams via "Bug reports for GNU Emacs, the Swiss army knife of text
editors" <[email-masked]> writes:

> I wrote:
>
>> When Emacs dings it's typically due to a user error.
>> 
>> Where do you see the error message? In the echo area.
>> 
>> Putting the attention-grabbing "flash" or whatever
>> in the echo area draws your attention to it, where
>> you see the msg telling you what happened.
>> 
>> Why draw or keep the user's attention _away_ from
>> that message? The user error might have little or
>> nothing to do with the text at the cursor of the
>> selected window.
>> 
>> Draw the user's attention _from_ there to the helpful
>> message.
>
> `visible-bell' has been around forever. Flashing
> the entire frame (or as the Emacs manual says, "the
> whole screen") is overkill, and it doesn't direct
> your attention to the error message. Similar problem
> with the alternatives I think you're considering,
> even if they're less overkill than `visible-bell'
> behavior.
>
> A modest attention-grabber, out of the way in the 
> echo area is better, IMO.

I think these features could coexist together, it wouldn't hurt.

Flash the mode (or header) line for bell it is something that people
have wanted to have, see packages such as mode-line-bell, doom-themes
(both in MELPA), and nano-bell.

I made my own implementation of echo-bell:
>From af63c6ba42160de07c75cf3e2c483551798678b8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?El=C3=ADas=20Gabriel=20P=C3=A9rez?= <[email-masked]>
Date: Thu, 10 Apr 2025 11:38:21 -0600
Subject: [PATCH] Add ring-bell function for flash faces.  (bug#77715)

New function for flash mode line, header line or echo area once
whether `ring-bell-function' is called.
* lisp/faces.el (flash-line): New faces.
* lisp/simple.el (flash-line-length): New user option.
(flash-header-line-bell-function, flash-header-line-bell-function)
(flash-echo-area-bell-function): New functions.
---
 etc/NEWS       | 20 ++++++++++++++++++++
 lisp/faces.el  | 14 ++++++++++++++
 lisp/simple.el | 35 +++++++++++++++++++++++++++++++++++
 3 files changed, 69 insertions(+)

diff --git a/etc/NEWS b/etc/NEWS
index c08b0052639..4affd9c9d40 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -1716,6 +1716,26 @@ change their face if the current line exceeds the 'fill-column'.  The
 new face 'display-fill-column-indicator-warning-face' is used to
 highlight the fill-column indicators.  By default this is disabled.
 
+---
+*** New function 'flash-mode-line-bell-function'.
+This function when called will flash current mode line briefly.
+Intended to be used in 'ring-bell-function'.
+
+---
+*** New function 'flash-header-line-bell-function'.
+This function when called will flash current header line briefly.
+Intended to be used in 'ring-bell-function'.
+
+---
+*** New function 'flash-echo-area-bell-function'.
+This function when called will flash current echo area briefly.
+Intended to be used in 'ring-bell-function'.
+
+---
+*** New user option 'flash-line-length'.
+This option controls length for flash the mode line, header line or
+echo area.
+
 
 * New Modes and Packages in Emacs 31.1
 
diff --git a/lisp/faces.el b/lisp/faces.el
index dbc0a2e04f6..cc1767fa41d 100644
--- a/lisp/faces.el
+++ b/lisp/faces.el
@@ -2745,6 +2745,20 @@ mode-line-inactive
   :group 'mode-line-faces
   :group 'basic-faces)
 
+(defface flash-line
+  '((((class color) (min-colors 88))
+     :box (:line-width -1 :color "brown" :style nil)
+     :background "red3" :foreground "white")
+    (((class color grayscale) (min-colors 88))
+     :box (:line-width -1 :style nil)
+     :background "grey10" :foreground "white")
+    (t
+     :inherit error :inverse-video t))
+  "Basic face for flash mode line or header line."
+  :version "31.1"
+  :group 'mode-line-faces
+  :group 'basic-faces)
+
 (defface mode-line-highlight
   '((((supports :box t) (class color grayscale) (min-colors 88))
      :box (:line-width 2 :color "grey40" :style released-button))
diff --git a/lisp/simple.el b/lisp/simple.el
index 7037158df8d..6a8ea94cf14 100644
--- a/lisp/simple.el
+++ b/lisp/simple.el
@@ -9383,6 +9383,41 @@ auto-save-mode
   (and (< buffer-saved-size 0)
        (setq buffer-saved-size 0)))
 
+(defcustom flash-line-length 0.05
+  "Length (in seconds) used for control mode line and header line flash time.
+This length is used by `flash-header-line-bell-function',
+`flash-mode-line-bell-function' and `flash-echo-area-bell-function'."
+  :type 'float
+  :version "31.1")
+
+(defun flash-mode-line-bell-function ()
+  "Flash current mode line as ring a bell.
+Intended to be used in `ring-bell-function'."
+  (when-let* (flash-line-length ; Ensure time is non-nil
+              (cookie (face-remap-add-relative 'mode-line-active 'flash-line)))
+    (run-with-timer flash-line-length nil
+                    #'face-remap-remove-relative
+                    cookie)))
+
+(defun flash-header-line-bell-function ()
+  "Flash current header line as ring a bell.
+Intended to be used in `ring-bell-function'."
+  (when-let* (flash-line-length ; Ensure time is non-nil
+              (cookie (face-remap-add-relative 'header-line-active 'flash-line)))
+    (run-with-timer flash-line-length nil
+                    #'face-remap-remove-relative
+                    cookie)))
+
+(defun flash-echo-area-bell-function ()
+  "Flash echo area as ring a bell.
+Intended to be used in `ring-bell-function'."
+  (message
+   (propertize "ring!"
+               'display `(space . (:align-to right))
+               'face 'flash-line))
+  (sit-for flash-line-length)
+  (message ""))
+
 (defgroup paren-blinking nil
   "Blinking matching of parens and expressions."
   :prefix "blink-matching-"
-- 
2.49.0

-- 
                                          - E.G via GNU Emacs and Org.