]> git.eshelyaron.com Git - emacs.git/commitdiff
mouse-face properties on tab-bar tab captions (bug#76394)
authorshipmints <shipmints@gmail.com>
Sat, 22 Feb 2025 10:13:05 +0000 (05:13 -0500)
committerEshel Yaron <me@eshelyaron.com>
Sun, 9 Mar 2025 10:20:06 +0000 (11:20 +0100)
* etc/NEWS: Announce 'tab-bar' 'mouse-face' support.

* src/xdisp.c (note_tab_bar_highlight): Handle mouse-face property.

* lisp/tab-bar.el
(tab-bar-tab-highlight): New face.
(tab-bar-tab-name-format-mouse-face): New function adds the 'mouse-face'
'tab-bar-tab-highlight' to the tab name.
(tab-bar-tab-name-format-functions): Add
'tab-bar-tab-name-format-mouse-face'.

(cherry picked from commit efd483cf0ecde3b0545a9eb39cc3fa9483fad76c)

lisp/tab-bar.el
src/xdisp.c

index d479b0c9f09683b735c3a475b97fdc24faa9b00d..a53b33686c10a56a8c428fbec0af0e4a069fbd2a 100644 (file)
   :version "28.1"
   :group 'tab-bar-faces)
 
+(defface tab-bar-tab-highlight
+  '((((class color) (min-colors 88))
+     :box (:line-width 1 :style released-button)
+     :background "grey85"
+     :foreground "black")
+    (t :inverse-video nil))
+  "Tab bar face for highlighting."
+  :version "31.1"
+  :group 'tab-bar-faces)
+
 \f
 
 (defvar tab-bar-mode-map (make-sparse-keymap)
@@ -886,10 +896,15 @@ It uses the function `tab-bar-tab-face-function'."
    0 (length name) (funcall tab-bar-tab-face-function tab) t name)
   name)
 
+(defun tab-bar-tab-name-format-mouse-face (name _tab _i)
+  "Apply the `mouse-face' `tab-bar-tab-highlight' to the tab name."
+  (propertize name 'mouse-face 'tab-bar-tab-highlight))
+
 (defcustom tab-bar-tab-name-format-functions
   '(tab-bar-tab-name-format-hints
     tab-bar-tab-name-format-close-button
-    tab-bar-tab-name-format-face)
+    tab-bar-tab-name-format-face
+    tab-bar-tab-name-format-mouse-face)
   "Functions called to modify the tab name.
 Each function is called with three arguments: the name returned
 by the previously called modifier, the tab and its number.
@@ -899,6 +914,7 @@ It should return the formatted tab name to display in the tab bar."
                   (function-item tab-bar-tab-name-format-hints)
                   (function-item tab-bar-tab-name-format-close-button)
                   (function-item tab-bar-tab-name-format-face)
+                  (function-item tab-bar-tab-name-format-mouse-face)
                   (function :tag "Custom function")))
   :group 'tab-bar
   :version "30.1")
index 2ecfeec215f91d223cb2b506413ab65eb42454b4..89e8841d8214dfbcd9d7ef2f250b2fc4c099da71 100644 (file)
@@ -15084,7 +15084,6 @@ handle_tab_bar_click (struct frame *f, int x, int y, bool down_p,
   return Fcons (Qtab_bar, Fcons (caption, make_fixnum (0)));
 }
 
-
 /* Possibly highlight a tab-bar item on frame F when mouse moves to
    tab-bar window-relative coordinates X/Y.  Called from
    note_mouse_highlight.  */
@@ -15096,8 +15095,7 @@ note_tab_bar_highlight (struct frame *f, int x, int y)
   struct window *w = XWINDOW (window);
   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
   int hpos, vpos;
-  struct glyph *glyph;
-  struct glyph_row *row;
+  struct glyph *glyph = NULL;
   int i;
   Lisp_Object enabled_p;
   int prop_idx;
@@ -15143,25 +15141,124 @@ note_tab_bar_highlight (struct frame *f, int x, int y)
 
   /* If tab-bar item is not enabled, don't highlight it.  */
   enabled_p = AREF (f->tab_bar_items, prop_idx + TAB_BAR_ITEM_ENABLED_P);
+
   if (!NILP (enabled_p) && !NILP (Vmouse_highlight))
     {
-      /* Compute the x-position of the glyph.  In front and past the
-        image is a space.  We include this in the highlighted area.  */
+      struct glyph_row *row = NULL;
+      struct glyph *row_start_glyph = NULL;
+      struct glyph *tmp_glyph;
+      int total_pixel_width;
+      Lisp_Object string;
+      Lisp_Object mouse_face;
+      int mouse_face_id = -1;
+      int hpos0, hpos_caption;
+
       row = MATRIX_ROW (w->current_matrix, vpos);
-      for (i = x = 0; i < hpos; ++i)
-       x += row->glyphs[TEXT_AREA][i].pixel_width;
+      /* display_tab_bar does not yet support R2L.  */
+      eassert (!row->reversed_p);
+      row_start_glyph = row->glyphs[TEXT_AREA];
+
+      string = AREF (f->tab_bar_items, prop_idx + TAB_BAR_ITEM_CAPTION);
+      if (STRINGP (string))
+       {
+         /* Compute starting column of the tab-bar-item to adjust col
+            of the mouse face relative to row_start_glyph.
+
+            tab_bar_item_info does not contain the absolute starting
+            offset of the item.  We compute it by looking backwards
+            until we find a glyph that belongs to a previous tab bar
+            item, or if this is the first item.  */
+         hpos0 = hpos + 1;
+         int tmp_prop_idx;
+         bool tmp_bool;
+         for (tmp_glyph = glyph;
+              tmp_glyph >= row_start_glyph;
+              tmp_glyph--)
+           {
+             if (!tab_bar_item_info (f, tmp_glyph, &tmp_prop_idx, &tmp_bool)
+                 || tmp_prop_idx != prop_idx)
+               break; /* Just before the beginning of this item.  */
+             else
+               --hpos0;
+           }
 
-      /* Record this as the current active region.  */
-      hlinfo->mouse_face_beg_col = hpos;
-      hlinfo->mouse_face_beg_row = vpos;
-      hlinfo->mouse_face_beg_x = x;
-      hlinfo->mouse_face_past_end = false;
+         /* Offset into the caption vs. the row.  */
+         hpos_caption = hpos - hpos0;
 
-      hlinfo->mouse_face_end_col = hpos + 1;
-      hlinfo->mouse_face_end_row = vpos;
-      hlinfo->mouse_face_end_x = x + glyph->pixel_width;
-      hlinfo->mouse_face_window = window;
-      hlinfo->mouse_face_face_id = TAB_BAR_FACE_ID;
+         mouse_face = Fget_text_property (make_fixnum (hpos_caption),
+                                          Qmouse_face, string);
+         if (!NILP (mouse_face))
+           {
+             mouse_face_id = lookup_named_face (w, f, mouse_face, false);
+             if (mouse_face_id < 0)
+               mouse_face_id = compute_char_face (f, ' ', mouse_face);
+             draw = DRAW_MOUSE_FACE;
+           }
+       }
+
+      if (draw == DRAW_MOUSE_FACE)
+       {
+         Lisp_Object b, e;
+         ptrdiff_t begpos, endpos;
+         int beg_x, end_x;
+
+         /* Search for mouse-face boundaries.  */
+         b = Fprevious_single_property_change (make_fixnum (hpos_caption + 1),
+                                               Qmouse_face, string, Qnil);
+         if (NILP (b))
+           begpos = 0;
+         else
+           begpos = XFIXNUM (b);
+         e = Fnext_single_property_change (make_fixnum (begpos), Qmouse_face, string, Qnil);
+         if (NILP (e))
+           endpos = SCHARS (string);
+         else
+           endpos = XFIXNUM (e);
+
+         /* Compute the starting and ending pixel coordinates */
+         for (i = beg_x = 0;
+              i < hpos0 + begpos; ++i)
+           beg_x += row->glyphs[TEXT_AREA][i].pixel_width;
+         for (end_x = 0,
+                i = hpos0 + begpos;
+              i < hpos0 + endpos; ++i)
+           end_x += row->glyphs[TEXT_AREA][i].pixel_width;
+
+         if ( EQ (window, hlinfo->mouse_face_window)
+              && (hlinfo->mouse_face_beg_col <= hpos
+                  && hpos < hlinfo->mouse_face_end_col)
+              && hlinfo->mouse_face_beg_row == vpos )
+           return;
+
+         hlinfo->mouse_face_window = window;
+         hlinfo->mouse_face_face_id = mouse_face_id;
+         hlinfo->mouse_face_beg_row = vpos;
+         hlinfo->mouse_face_end_row = vpos;
+         hlinfo->mouse_face_past_end = false;
+         hlinfo->mouse_face_beg_col = hpos0 + begpos;
+         hlinfo->mouse_face_end_col = hpos0 + endpos;
+         hlinfo->mouse_face_beg_x   = beg_x;
+         hlinfo->mouse_face_end_x   = end_x;
+       }
+      else
+       {
+         /* Compute the x-position of the glyph.  In front and past the
+            image is a space.  We include this in the highlighted area.  */
+         for (i = x = 0; i < hpos; ++i)
+           x += row->glyphs[TEXT_AREA][i].pixel_width;
+         total_pixel_width = glyph->pixel_width;
+
+         hlinfo->mouse_face_face_id = TAB_BAR_FACE_ID;
+         hlinfo->mouse_face_beg_col = hpos;
+         hlinfo->mouse_face_beg_row = vpos;
+         hlinfo->mouse_face_beg_x = x;
+         hlinfo->mouse_face_past_end = false;
+
+         hlinfo->mouse_face_end_col = hpos + 1;
+         hlinfo->mouse_face_end_row = vpos;
+         hlinfo->mouse_face_end_x = x + total_pixel_width;
+         hlinfo->mouse_face_window = window;
+       }
 
       /* Display it as active.  */
       show_mouse_face (hlinfo, draw, true);