Subject: bug#62562: 30.0.50; [PATCH] Some new SVG icons

From: Juri Linkov <[email-masked]>
Date: Tue, 02 May 2023 20:10:15 +0300

>>>> Looks nice! BTW, how could I apply a mouse-face to the buttons in the
>>>> tab-bar? I poked around and mouse-face doesn’t seem to take an effect?
>>>
>>> Currently mouse-face is not supported neither by define-icon not by tab-bar.
>>
>> Ah, I see.  How are the buttons implemented then?  If I move my
>> pointer on top of it, it shows the “pressed” face.  I’m trying to
>> style the buttons on the tab-bar.
>
> Mouse pointer hovering is handled in 'note_tab_bar_highlight' by using
> DRAW_IMAGE_SUNKEN.  But you could try to style the image attributes
> such as :margin and :ascent in define-icon.

The tab line has a different implementation - with own problems.

Currently when the icon from tabs/close.xpm is used, then hovering
the mouse pointer changes the background of this image to the
background color of mouse-face.

But when the new image symbols/cross_16.svg is used, then on hovering
the original background color is preserved in the svg image, not replaced
with the background color of mouse-face.

I have no idea why there is such idiosyncrasy for svg images
with transparent background.

If this is not an important detail then below is a patch that
adds the new svg images to the tab line as well.

Another problem is that by default the foreground of new svg images
is black.  To tone down the black color, add-face-text-property
was added to tab-bar-tab-name-format-default to use the shadow face
in the previous patch.

The same way to support grayed color for icons on the tab line the
following patch uses add-face-text-property in
tab-line-tab-name-format-default.

The third problem was that using 'define-icon' broke the tab-line
auto-scrolling feature, because for some reason 'define-icon'
sets 'rear-nonsticky' to t.  So the fix below is to override it
and set 'rear-nonsticky' to nil.

diff --git a/lisp/tab-line.el b/lisp/tab-line.el
index 1958f12975f..ca990726cbc 100644
--- a/lisp/tab-line.el
+++ b/lisp/tab-line.el
@@ -185,12 +205,19 @@ tab-line-new-button-show
   :group 'tab-line
   :version "27.1")
 
+(define-icon tab-line-new nil
+  `((image "symbols/plus_16.svg" "tabs/new.xpm"
+           :face shadow
+           :margin (2 . 0)
+           :ascent center)
+    (text " + "))
+  "Icon for creating a new tab."
+  :version "30.1"
+  :help-echo "New tab")
+
 (defvar tab-line-new-button
-  (propertize " + "
-              'display '(image :type xpm
-                               :file "tabs/new.xpm"
-                               :margin (2 . 0)
-                               :ascent center)
+  (propertize (icon-string 'tab-line-new)
+              'rear-nonsticky nil
               'keymap tab-line-add-map
               'mouse-face 'tab-line-highlight
               'help-echo "Click to add tab")
@@ -213,34 +240,53 @@ tab-line-close-button-show
   :group 'tab-line
   :version "27.1")
 
+(define-icon tab-line-close nil
+  `((image "symbols/cross_16.svg" "tabs/close.xpm"
+           :face shadow
+           :margin (2 . 0)
+           :ascent center)
+    (text " x"))
+  "Icon for closing the clicked tab."
+  :version "30.1"
+  :help-echo "Click to close tab")
+
 (defvar tab-line-close-button
-  (propertize " x"
-              'display '(image :type xpm
-                               :file "tabs/close.xpm"
-                               :margin (2 . 0)
-                               :ascent center)
+  (propertize (icon-string 'tab-line-close)
+              'rear-nonsticky nil ;; important to not break auto-scroll
               'keymap tab-line-tab-close-map
               'mouse-face 'tab-line-close-highlight
               'help-echo "Click to close tab")
   "Button for closing the clicked tab.")
 
+(define-icon tab-line-left nil
+  `((image "symbols/chevron_left_16.svg" "tabs/left-arrow.xpm"
+           :face shadow
+           :margin (2 . 0)
+           :ascent center)
+    (text " <"))
+  "Icon for scrolling horizontally to the left."
+  :version "30.1")
+
 (defvar tab-line-left-button
-  (propertize " <"
-              'display '(image :type xpm
-                               :file "tabs/left-arrow.xpm"
-                               :margin (2 . 0)
-                               :ascent center)
+  (propertize (icon-string 'tab-line-left)
+              'rear-nonsticky nil
               'keymap tab-line-left-map
               'mouse-face 'tab-line-highlight
               'help-echo "Click to scroll left")
   "Button for scrolling horizontally to the left.")
 
+(define-icon tab-line-right nil
+  `((image "symbols/chevron_right_16.svg" "tabs/right-arrow.xpm"
+           :face shadow
+           :margin (2 . 0)
+           :ascent center)
+    (text "> "))
+  "Icon for scrolling horizontally to the right."
+  :version "30.1")
+
 (defvar tab-line-right-button
-  (propertize "> "
-              'display '(image :type xpm
-                               :file "tabs/right-arrow.xpm"
-                               :margin (2 . 0)
-                               :ascent center)
+  (propertize (icon-string 'tab-line-right)
+              'rear-nonsticky nil
               'keymap tab-line-right-map
               'mouse-face 'tab-line-highlight
               'help-echo "Click to scroll right")
@@ -484,21 +541,27 @@ tab-line-tab-name-format-default
       (setf face (funcall fn tab tabs face buffer-p selected-p)))
     (apply 'propertize
            (concat (propertize (string-replace "%" "%%" name) ;; (bug#57848)
+                               'face face
                                'keymap tab-line-tab-map
                                'help-echo (if selected-p "Current tab"
                                             "Click to select tab")
                                ;; Don't turn mouse-1 into mouse-2 (bug#49247)
                                'follow-link 'ignore)
-                   (or (and (or buffer-p (assq 'buffer tab) (assq 'close tab))
-                            tab-line-close-button-show
-                            (not (eq tab-line-close-button-show
-                                     (if selected-p 'non-selected 'selected)))
-                            tab-line-close-button)
-                       ""))
+                   (let ((close (or (and (or buffer-p (assq 'buffer tab)
+                                             (assq 'close tab))
+                                         tab-line-close-button-show
+                                         (not (eq tab-line-close-button-show
+                                                  (if selected-p 'non-selected
+                                                    'selected)))
+                                         tab-line-close-button)
+                                    "")))
+                     (setq close (copy-sequence close))
+                     ;; Don't overwrite the icon face
+                     (add-face-text-property 0 (length close) face t close)
+                     close))
            `(
              tab ,tab
              ,@(if selected-p '(selected t))
-             face ,face
              mouse-face tab-line-highlight))))
 
 (defun tab-line-format-template (tabs)