Subject: Re: bug#68765: 30.0.50; Adding window-tool-bar package.

From: Jared Finder <[email-masked]>
Date: Sat, 01 Jun 2024 21:17:58 -0700

Thank you for all the feedback.  Updated patch attached.

On 2024-05-26 11:40, Eli Zaretskii wrote:
>> Date: Sun, 26 May 2024 09:20:56 -0700
>> From: Jared Finder <[email-masked]>
>> Cc: [email-masked], [email-masked], [email-masked],
>>  [email-masked]
>> 
>> >> +@findex global-window-tool-bar-mode
>> >> +  The command @code{global-window-tool-bar-mode} toggles the display
>> >> of
>> >> +a tool bar at the top of each window.  When enabled, multiple windows
>> >> +can display their own tool bar simultaneously.  To conserve space, a
>> >> +window tool bar is only shown if the tool bar for that window's
>> >> current
>> >> +buffer is different from the global (default) tool bar.  The most
>> >> common
>> >> +way a buffer has a different tool bar is due to its major mode, so
>> >> you
>> >> +can think of the window tool bar as showing a major mode's tool bar
>> >> if
>> >> +it exists.
>> >
>> > So, let me understand what happens under this global mode.  By
>> > default, the frame's tool bar changes according to the major mode of
>> > the buffer shown in the frame's selected window.  As a very frequent
>> > example, entering the minibuffer from a buffer whose mode is, say,
>> > Dired or Rmail or Info, changes the tool bar.  When that happens, some
>> > windows which previously didn't display their tool bar because it was
>> > identical to the frame's tool bar will now display their tool bars.
>> > Right?  And when you exit the minibuffer, those window-specific tool
>> > bars will again disappear, right?  Wouldn't that cause annoying
>> > flickering of the display?  (I know that setting
>> > tool-bar-always-show-default non-nil can prevent that, but I'm asking
>> > about the default behavior.)
>> 
>> No, this is not the behavior.  The window tool bar displays that
>> buffer's binding of <tool-bar>.  The window tool bar is displayed in 
>> the
>> tab line of each window and doesn't pay attention to what the current
>> buffer or window is.
> 
> But this means that the following text:
> 
>>>                                                  To conserve space,
>>> a window tool bar is only shown if the tool bar for that window's
>>> current buffer is different from the global (default) tool bar
> 
> is at least inaccurate.  Specifically, if the frame's global tool bar
> changes as result of some command, the identity of the tool bars of
> windows to that of the frame is not re-examined.  So if some window
> decided that its tool bar is not to be displayed, it will remain
> undisplayed until that window shows a different buffer or its buffer
> changes its major mode.  Is that correct?  If not, why not?

Your understanding here is accurate.  I consider this behavior a bug 
that I'd like to fix (in normal use it rarely happens).  I suppose I 
could use add-variable-watcher to detect all changes to tool-bar-map and 
update tool bar visibility.  I'd like to make sure to do this correctly 
and not cause a significant performance hit.

Should such a temporary limitation be documented in the manual?  I added 
a section to describe this limitation to my patch, but I don't know if 
it is appropriate.

> Or maybe I don't understand well enough what you mean by "The window
> tool bar is displayed in the tab line of each window and doesn't pay
> attention to what the current buffer or window is."  You are using
> here terminology that is confusing: there's no "current window" in
> Emacs, only the "selected window", and it is unclear whether by
> "current buffer" you mean the global current buffer (the one returned
> by the function current-buffer) or the buffer shown in a window (since
> you also say "the window's current buffer", another term that we do
> not use).

Thanks for helping me here with terminology here.  Looking over the 
manual, it seems the proper terms are "current buffer", "selected 
window", and "buffer displayed in a window".  I have updated my patch to 
use these terms.

>> > Btw, what exactly is the meaning of "the tool bar of the window is
>> > different from the global tool bar"?  How are tool bars compared?  For
>> > example, a button on the tool bar can have the :visible attribute,
>> > which will cause the icon not to appear under some conditions -- will
>> > a tool bar with that icon on display be considered "different" from a
>> > tool bar where the icon is not shown due to :visible conditions?
>> 
>> It's specifically using the following test:
>> 
>> (eq tool-bar-map
>>      (default-value 'tool-bar-map))
> 
> So a frame's tool bar can completely change its look due to :visible,
> and Emacs will still consider it "equal" to the tool bar of some
> window where those :visible conditions yield a completely different
> look?  Does that make sense?

 From a functionality standpoint, I think it makes a lot of sense.  It's 
about if there's a major mode specific tool bar, not just if the list of 
buttons is different.  Major modes with custom tool bars are recommended 
to set tool-bar-map locally and that's what all customizations in core 
Emacs do.  An eq comparison properly catches this.

I have updated the patch to refer to the tool bar binding being 
different to try to communicate this.

> I'm beginning to think that the feature whereby we don't display the
> window's tool bar under some conditions "to conserve space" is more
> confusing and hard to document than is useful, and perhaps we should
> simply show the window's tool bar unconditionally?

I find it really useful to have this auto-show/hide behavior.  As I 
wrote in the docs, "you can think of the window tool bar as showing a 
major mode specific tool bar if it exists".  The most prominent other 
source of a custom tool bar is isearch.  Having no space taken up when 
editing a text file, then having the tool bar appear when I hit C-s 
lines up with what I see in many other programs.  I'd be sad to see this 
behavior removed.

> So what I would like us to say in the manual is that the value of
> window-tool-bar-format

Just to be clear -- there is no new line as you requested a while back. 
The mode just alters the value of tab-line-format.

> and of tab-line-format should produce what is
> expected from these lines: a row of tabs for tab-line and a row of
> icons for the tool bar.  The reader should understand that having a
> tab-line-format whose value is "%b %f", for example, makes no sense,
> although it will work.  (In general, most or all %-elements of mode
> line and header line make no sense in tab-line and tool bar.  It is
> hardly an accident that tab-line-format's value is just (:eval FUNC),
> in stark contrast to the value of mode-line-format and
> header-line-format in modes in which it is non-nil.)
> 
> Did I succeed to explain my concerns?

Yes, I think I understand.  I have updated my patch.

   -- MJF

From 7972068d46f7b40fb54a6e2b802fc65de973cf57 Mon Sep 17 00:00:00 2001
From: Jared Finder <[email-masked]>
Date: Mon, 20 May 2024 21:59:14 -0700
Subject: [PATCH] Adding documentation for window-tool-bar (bug#68765)

* doc/emacs/emacs.texi (Top):
* doc/emacs/frames.texi (Tool Bars):
* doc/emacs/glossary.texi (Glossary):
* doc/emacs/modes.texi (Minor Modes): Mention Window Tool Bar
and add xref.
* doc/emacs/windows.texi (Windows, Tab Line): New documentation.
* doc/lispref/elisp.texi (Top):
* doc/lispref/modes.texi (Mode Line Format, Mode Line Basics)
(Mode Line Data): Mention Tab Lines and add xref.
(Tab Lines): New documentation.
* etc/NEWS: Mention newly added variable
'tool-bar-always-show-default' and new package 'window-tool-bar'
---
 doc/emacs/emacs.texi    |  1 +
 doc/emacs/frames.texi   | 14 ++++++++---
 doc/emacs/glossary.texi | 10 +++++---
 doc/emacs/modes.texi    |  4 +++
 doc/emacs/windows.texi  | 50 ++++++++++++++++++++++++++++++++++++
 doc/lispref/elisp.texi  |  1 +
 doc/lispref/modes.texi  | 56 ++++++++++++++++++++++++++++++-----------
 etc/NEWS                | 14 +++++++++++
 8 files changed, 128 insertions(+), 22 deletions(-)

diff --git a/doc/emacs/emacs.texi b/doc/emacs/emacs.texi
index 7d77f13ab21..8246041fb95 100644
--- a/doc/emacs/emacs.texi
+++ b/doc/emacs/emacs.texi
@@ -529,6 +529,7 @@ Top
 * Temporary Displays::  Displaying non-editable buffers.
 * Window Convenience::  Convenience functions for window handling.
 * Tab Line::            Window tab line.
+* Window Tool Bar::     A tool bar that is attached to windows.
 
 Displaying a Buffer in a Window
 
diff --git a/doc/emacs/frames.texi b/doc/emacs/frames.texi
index 6c62fde4ffb..8028a516e66 100644
--- a/doc/emacs/frames.texi
+++ b/doc/emacs/frames.texi
@@ -1295,16 +1295,22 @@ Menu Bars
 @node Tool Bars
 @section Tool Bars
 @cindex tool bar mode
+@cindex tool bar, attached to frame
 @cindex mode, Tool Bar
 @cindex icons, toolbar
 
-  On graphical displays, Emacs puts a @dfn{tool bar} at the top of
-each frame, just below the menu bar.  This is a row of icons which you
-can click on with the mouse to invoke various commands.
+  On graphical displays, Emacs puts a @dfn{tool bar} at the top of each
+frame, just below the menu bar.  This is a row of icons which you can
+click on with the mouse to invoke various commands.  Emacs can also
+optionally display a tool bar at the top of each window (@pxref{Window
+Tool Bar}).
 
+@vindex tool-bar-always-show-default
   The global (default) tool bar contains general commands.  Some major
 modes define their own tool bars; whenever a buffer with such a major
-mode is current, the mode's tool bar replaces the global tool bar.
+mode is current, the mode's tool bar replaces the global tool bar.  To
+prevent this replacement from happening, customize the variable
+@code{tool-bar-always-show-default}.
 
 @findex tool-bar-mode
 @vindex tool-bar-mode
diff --git a/doc/emacs/glossary.texi b/doc/emacs/glossary.texi
index 344e4831f36..b30e1d789fc 100644
--- a/doc/emacs/glossary.texi
+++ b/doc/emacs/glossary.texi
@@ -1436,10 +1436,12 @@ Glossary
 for your favorite set of faces (q.v.).
 
 @item Tool Bar
-The tool bar is a line (sometimes multiple lines) of icons at the top
-of an Emacs frame.  Clicking on one of these icons executes a command.
-You can think of this as a graphical relative of the menu bar (q.v.).
-@xref{Tool Bars}.
+The tool bar is a line (sometimes multiple lines) of icons at the top of
+an Emacs frame.  Clicking on one of these icons executes a command.  You
+can think of this as a graphical relative of the menu bar (q.v.).
+@xref{Tool Bars}.  There is also a window tool bar that behaves
+similarly, but is at the top of an Emacs window.  @xref{Window Tool
+Bar}.
 
 @anchor{Glossary---Tooltips}
 @item Tooltips
diff --git a/doc/emacs/modes.texi b/doc/emacs/modes.texi
index 2776dc72a27..253042b28a3 100644
--- a/doc/emacs/modes.texi
+++ b/doc/emacs/modes.texi
@@ -295,6 +295,10 @@ Minor Modes
 but the tool bar is only displayed on graphical terminals.  @xref{Tool
 Bars}.
 
+@item
+Window Tool Bar mode gives windows a tool bar when it is different from
+the default tool bar.  @xref{Window Tool Bar}.
+
 @item
 Tab Bar mode gives each frame a tab bar.  @xref{Tab Bars}.
 
diff --git a/doc/emacs/windows.texi b/doc/emacs/windows.texi
index ad2225b5922..8ab832d7cc7 100644
--- a/doc/emacs/windows.texi
+++ b/doc/emacs/windows.texi
@@ -22,6 +22,7 @@ Windows
 * Displaying Buffers::  How Emacs picks a window for displaying a buffer.
 * Window Convenience::  Convenience functions for window handling.
 * Tab Line::            Window tab line.
+* Window Tool Bar::     A tool bar that is attached to windows.
 @end menu
 
 @node Basic Window
@@ -689,3 +690,52 @@ Tab Line
 switch between window configurations containing several windows with buffers,
 tabs on the Tab Line at the top of each window are used to switch
 between buffers in the window.
+
+
+@node Window Tool Bar
+@section Window Tool Bar
+
+@cindex window tool bar
+@cindex mode, window tool bar
+@cindex tool bar, attached to window
+
+@findex global-window-tool-bar-mode
+  The command @code{global-window-tool-bar-mode} toggles the display of
+a tool bar at the top of each window.  When enabled, multiple windows
+can display their own tool bar simultaneously.  To conserve space, a
+window tool bar is only shown if the tool bar for the window's displayed
+buffer has a different binding from the global (default) tool bar.  The
+most common way a buffer has a different binding is due to its major
+mode, so you can think of the window tool bar as showing a major mode
+specific tool bar if it exists.
+
+There is a limitation with how this mode detects that there is a major
+mode specific tool bar.  This check is only made when entering a major
+mode.  If the global or major mode specific tool bar binding is changed
+while Window Tool Bar mode is enabled and the window tool bar is not
+showing, re-entering the major mode, like by running @kbd{M-x
+normal-mode}, will cause the window tool bar to show correctly.
+
+@findex window-tool-bar-mode
+If you want to toggle the display of a window tool bar for only some
+buffers, run the command @code{window-tool-bar-mode} in those buffers.
+This is useful to put in a mode hook.  For example, if you want the window
+tool bar to appear only for buffers that do not represent files and have
+a custom tool bar, you could add the following code to your init file
+(@pxref{Init File}):
+
+@example
+(add-hook 'special-mode-hook 'window-tool-bar-mode)
+@end example
+
+Emacs can also display a single tool bar at the top of frames
+(@pxref{Tool Bars}).  When showing a tool bar at the top of frames as
+well as windows, you may want to have the frame tool bar not change
+based on the current buffer's major mode.  This can be done by
+customizing the variable @code{tool-bar-always-show-default}.
+
+Note that the window tool bar displays in the same space as the tab
+line, so only one of these can be display at a time unless you customize
+the value of @code{tab-line-format} in Lisp.  In this case, add
+@code{(:eval (window-tool-bar-string))} to @code{tab-line-format}.
+@xref{Mode Line Format,,, elisp, The Emacs Lisp Reference Manual}.
diff --git a/doc/lispref/elisp.texi b/doc/lispref/elisp.texi
index 339272d1f05..1059d0dcf61 100644
--- a/doc/lispref/elisp.texi
+++ b/doc/lispref/elisp.texi
@@ -925,6 +925,7 @@ Top
 * %-Constructs::            Putting information into a mode line.
 * Properties in Mode::      Using text properties in the mode line.
 * Header Lines::            Like a mode line, but at the top.
+* Tab Lines::               A line that is above the header line.
 * Emulating Mode Line::     Formatting text as the mode line would.
 
 Font Lock Mode
diff --git a/doc/lispref/modes.texi b/doc/lispref/modes.texi
index cf67b319924..f3d4f5347b3 100644
--- a/doc/lispref/modes.texi
+++ b/doc/lispref/modes.texi
@@ -2074,14 +2074,14 @@ Mode Line Format
 line at the bottom, which displays status information about the buffer
 displayed in the window.  The mode line contains information about the
 buffer, such as its name, associated file, depth of recursive editing,
-and major and minor modes.  A window can also have a @dfn{header
-line}, which is much like the mode line but appears at the top of the
-window.
+and major and minor modes.  A window can also have a @dfn{header line}
+and a @dfn{tab line}, which are much like the mode line but they appear
+at the top of the window.
 
-  This section describes how to control the contents of the mode line
-and header line.  We include it in this chapter because much of the
-information displayed in the mode line relates to the enabled major and
-minor modes.
+  This section describes how to control the contents of the mode line,
+header line, and tab line.  We include it in this chapter because much
+of the information displayed in the mode line relates to the enabled
+major and minor modes.
 
 @menu
 * Base: Mode Line Basics.       Basic ideas of mode line control.
@@ -2091,6 +2091,7 @@ Mode Line Format
 * %-Constructs::                Putting information into a mode line.
 * Properties in Mode::          Using text properties in the mode line.
 * Header Lines::                Like a mode line, but at the top.
+* Tab Lines::                   A line that is above the header line.
 * Emulating Mode Line::         Formatting text as the mode line would.
 @end menu
 
@@ -2101,11 +2102,13 @@ Mode Line Basics
 variable @code{mode-line-format} (@pxref{Mode Line Top}).  This variable
 holds a @dfn{mode line construct}: a template that controls what is
 displayed on the buffer's mode line.  The value of
-@code{header-line-format} specifies the buffer's header line in the same
-way.  All windows for the same buffer use the same
-@code{mode-line-format} and @code{header-line-format} unless a
-@code{mode-line-format} or @code{header-line-format} parameter has been
-specified for that window (@pxref{Window Parameters}).
+@code{header-line-format} and @code{tab-line-format} specifies the
+buffer's header line and tab line in the same way.  All windows for the
+same buffer use the same @code{mode-line-format},
+@code{header-line-format}, and @code{tab-line-format} unless a
+@code{mode-line-format}, @code{header-line-format}, or
+@code{tab-line-format} parameter has been specified for that window
+(@pxref{Window Parameters}).
 
   For efficiency, Emacs does not continuously recompute each window's
 mode line and header line.  It does so when circumstances appear to call
@@ -2167,8 +2170,8 @@ Mode Line Data
 @dfn{mode line construct}, made up of lists, strings, symbols, and
 numbers kept in buffer-local variables.  Each data type has a specific
 meaning for the mode line appearance, as described below.  The same data
-structure is used for constructing frame titles (@pxref{Frame Titles})
-and header lines (@pxref{Header Lines}).
+structure is used for constructing frame titles (@pxref{Frame Titles}),
+header lines (@pxref{Header Lines}), and tab lines (@pxref{Tab Lines}).
 
   A mode line construct may be as simple as a fixed string of text,
 but it usually specifies how to combine fixed strings with variables'
@@ -2816,6 +2819,31 @@ Header Lines
 header line at once; if it has a mode line, then it does not display a
 header line.
 
+@node Tab Lines
+@subsection Window Tab Lines
+@cindex tab line (of a window)
+@cindex window tab line
+
+  A window can have a @dfn{tab line} at the top.  If both the tab line
+and header line are visible, the tab line appears above the header line.
+The tab line feature is controlled like the mode line feature, except
+that it's controlled by @code{tab-line-format}.  Unlike the mode line,
+the tab line is only expected to be used to display a list of tabs
+(@pxref{Tab Line,,, emacs, The GNU Emacs Manual}) or the window
+tool bar (@pxref{Window Tool Bar,,, emacs, The GNU Emacs Manual}):
+
+@defvar tab-line-format
+This variable, local in every buffer, specifies how to display the tab
+line, for windows displaying the buffer.  The format of the value is the
+same as for @code{mode-line-format} (@pxref{Mode Line Data}).  It is
+normally @code{nil}, so that ordinary buffers have no tab line.
+@end defvar
+
+@defun window-tab-line-height &optional window
+This function returns the height in pixels of @var{window}'s tab line.
+@var{window} must be a live window, and defaults to the selected window.
+@end defun
+
 @node Emulating Mode Line
 @subsection Emulating Mode Line Formatting
 
diff --git a/etc/NEWS b/etc/NEWS
index d72ef5b5bef..6202a0cb2a8 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -240,6 +240,12 @@ window systems other than Nextstep.
 When this minor mode is enabled, buttons representing modifier keys
 are displayed along the tool bar.
 
++++
+** New user option 'tool-bar-always-show-default'.
+When non-nil, the tool bar at the top of a frame does not show buffer
+local customization of the tool bar.  This is convenient when using the
+newly added 'global-window-tool-bar-mode'.  The default value is nil.
+
 +++
 ** "d" in the mode line now indicates that the window is dedicated.
 Windows have always been able to be dedicated to a specific buffer;
@@ -1877,6 +1883,14 @@ than regular expressions, but less complexity than context-free
 grammars.  The Info manual "(elisp) Parsing Expression Grammars" has
 documentation and examples.
 
++++
+** New package Window-Tool-Bar.
+This provides a new minor mode, 'window-tool-bar-mode'.  When this minor
+mode is enabled, a tool bar is displayed at the top of a window if the
+buffer in the window has a buffer local tool bar, commonly from its
+major mode.  The global minor mode 'global-window-tool-bar-mode' enables
+this minor mode in all buffers.
+
 
 * Incompatible Lisp Changes in Emacs 30.1
 
-- 
2.39.2