aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorshipmints2025-02-22 05:13:05 -0500
committerJuri Linkov2025-03-06 20:37:44 +0200
commitefd483cf0ecde3b0545a9eb39cc3fa9483fad76c (patch)
treeb133b0feb7052c057ac1767012bc78884a5745a8
parent63cc542b9402ad0a794f4e05790366bd580b8bd1 (diff)
downloademacs-efd483cf0ecde3b0545a9eb39cc3fa9483fad76c.tar.gz
emacs-efd483cf0ecde3b0545a9eb39cc3fa9483fad76c.zip
mouse-face properties on tab-bar tab captions (bug#76394)
* 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'.
-rw-r--r--etc/NEWS6
-rw-r--r--lisp/tab-bar.el18
-rw-r--r--src/xdisp.c131
3 files changed, 137 insertions, 18 deletions
diff --git a/etc/NEWS b/etc/NEWS
index 864bfbf595b..258f0dcc4ba 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -290,6 +290,12 @@ specified by external means.
290This hook allows you to control which tab-bar tabs are auto-resized. 290This hook allows you to control which tab-bar tabs are auto-resized.
291 291
292--- 292---
293*** 'mouse-face' properties are now supported on the 'tab-bar'.
294'tab-bar' tab "buttons" are now highlighted when the mouse pointer
295hovers over them. You can customize the new face
296'tab-bar-tab-highlight'.
297
298---
293*** New abnormal hook 'tab-bar-post-undo-close-tab-functions'. 299*** New abnormal hook 'tab-bar-post-undo-close-tab-functions'.
294This hook allows you to operate on a reopened tab. 300This hook allows you to operate on a reopened tab.
295 301
diff --git a/lisp/tab-bar.el b/lisp/tab-bar.el
index 9d804c4ed28..e7aa4841da0 100644
--- a/lisp/tab-bar.el
+++ b/lisp/tab-bar.el
@@ -85,6 +85,16 @@
85 :version "28.1" 85 :version "28.1"
86 :group 'tab-bar-faces) 86 :group 'tab-bar-faces)
87 87
88(defface tab-bar-tab-highlight
89 '((((class color) (min-colors 88))
90 :box (:line-width 1 :style released-button)
91 :background "grey85"
92 :foreground "black")
93 (t :inverse-video nil))
94 "Tab bar face for highlighting."
95 :version "31.1"
96 :group 'tab-bar-faces)
97
88 98
89 99
90(defvar tab-bar-mode-map (make-sparse-keymap) 100(defvar tab-bar-mode-map (make-sparse-keymap)
@@ -886,10 +896,15 @@ It uses the function `tab-bar-tab-face-function'."
886 0 (length name) (funcall tab-bar-tab-face-function tab) t name) 896 0 (length name) (funcall tab-bar-tab-face-function tab) t name)
887 name) 897 name)
888 898
899(defun tab-bar-tab-name-format-mouse-face (name _tab _i)
900 "Apply the `mouse-face' `tab-bar-tab-highlight' to the tab name."
901 (propertize name 'mouse-face 'tab-bar-tab-highlight))
902
889(defcustom tab-bar-tab-name-format-functions 903(defcustom tab-bar-tab-name-format-functions
890 '(tab-bar-tab-name-format-hints 904 '(tab-bar-tab-name-format-hints
891 tab-bar-tab-name-format-close-button 905 tab-bar-tab-name-format-close-button
892 tab-bar-tab-name-format-face) 906 tab-bar-tab-name-format-face
907 tab-bar-tab-name-format-mouse-face)
893 "Functions called to modify the tab name. 908 "Functions called to modify the tab name.
894Each function is called with three arguments: the name returned 909Each function is called with three arguments: the name returned
895by the previously called modifier, the tab and its number. 910by 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."
899 (function-item tab-bar-tab-name-format-hints) 914 (function-item tab-bar-tab-name-format-hints)
900 (function-item tab-bar-tab-name-format-close-button) 915 (function-item tab-bar-tab-name-format-close-button)
901 (function-item tab-bar-tab-name-format-face) 916 (function-item tab-bar-tab-name-format-face)
917 (function-item tab-bar-tab-name-format-mouse-face)
902 (function :tag "Custom function"))) 918 (function :tag "Custom function")))
903 :group 'tab-bar 919 :group 'tab-bar
904 :version "30.1") 920 :version "30.1")
diff --git a/src/xdisp.c b/src/xdisp.c
index a290664534e..ac654934e54 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -15084,7 +15084,6 @@ handle_tab_bar_click (struct frame *f, int x, int y, bool down_p,
15084 return Fcons (Qtab_bar, Fcons (caption, make_fixnum (0))); 15084 return Fcons (Qtab_bar, Fcons (caption, make_fixnum (0)));
15085} 15085}
15086 15086
15087
15088/* Possibly highlight a tab-bar item on frame F when mouse moves to 15087/* Possibly highlight a tab-bar item on frame F when mouse moves to
15089 tab-bar window-relative coordinates X/Y. Called from 15088 tab-bar window-relative coordinates X/Y. Called from
15090 note_mouse_highlight. */ 15089 note_mouse_highlight. */
@@ -15096,8 +15095,7 @@ note_tab_bar_highlight (struct frame *f, int x, int y)
15096 struct window *w = XWINDOW (window); 15095 struct window *w = XWINDOW (window);
15097 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f); 15096 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
15098 int hpos, vpos; 15097 int hpos, vpos;
15099 struct glyph *glyph; 15098 struct glyph *glyph = NULL;
15100 struct glyph_row *row;
15101 int i; 15099 int i;
15102 Lisp_Object enabled_p; 15100 Lisp_Object enabled_p;
15103 int prop_idx; 15101 int prop_idx;
@@ -15143,25 +15141,124 @@ note_tab_bar_highlight (struct frame *f, int x, int y)
15143 15141
15144 /* If tab-bar item is not enabled, don't highlight it. */ 15142 /* If tab-bar item is not enabled, don't highlight it. */
15145 enabled_p = AREF (f->tab_bar_items, prop_idx + TAB_BAR_ITEM_ENABLED_P); 15143 enabled_p = AREF (f->tab_bar_items, prop_idx + TAB_BAR_ITEM_ENABLED_P);
15144
15146 if (!NILP (enabled_p) && !NILP (Vmouse_highlight)) 15145 if (!NILP (enabled_p) && !NILP (Vmouse_highlight))
15147 { 15146 {
15148 /* Compute the x-position of the glyph. In front and past the 15147 struct glyph_row *row = NULL;
15149 image is a space. We include this in the highlighted area. */ 15148 struct glyph *row_start_glyph = NULL;
15149 struct glyph *tmp_glyph;
15150 int total_pixel_width;
15151 Lisp_Object string;
15152 Lisp_Object mouse_face;
15153 int mouse_face_id = -1;
15154 int hpos0, hpos_caption;
15155
15150 row = MATRIX_ROW (w->current_matrix, vpos); 15156 row = MATRIX_ROW (w->current_matrix, vpos);
15151 for (i = x = 0; i < hpos; ++i) 15157 /* display_tab_bar does not yet support R2L. */
15152 x += row->glyphs[TEXT_AREA][i].pixel_width; 15158 eassert (!row->reversed_p);
15159 row_start_glyph = row->glyphs[TEXT_AREA];
15160
15161 string = AREF (f->tab_bar_items, prop_idx + TAB_BAR_ITEM_CAPTION);
15162 if (STRINGP (string))
15163 {
15164 /* Compute starting column of the tab-bar-item to adjust col
15165 of the mouse face relative to row_start_glyph.
15166
15167 tab_bar_item_info does not contain the absolute starting
15168 offset of the item. We compute it by looking backwards
15169 until we find a glyph that belongs to a previous tab bar
15170 item, or if this is the first item. */
15171 hpos0 = hpos + 1;
15172 int tmp_prop_idx;
15173 bool tmp_bool;
15174 for (tmp_glyph = glyph;
15175 tmp_glyph >= row_start_glyph;
15176 tmp_glyph--)
15177 {
15178 if (!tab_bar_item_info (f, tmp_glyph, &tmp_prop_idx, &tmp_bool)
15179 || tmp_prop_idx != prop_idx)
15180 break; /* Just before the beginning of this item. */
15181 else
15182 --hpos0;
15183 }
15153 15184
15154 /* Record this as the current active region. */ 15185 /* Offset into the caption vs. the row. */
15155 hlinfo->mouse_face_beg_col = hpos; 15186 hpos_caption = hpos - hpos0;
15156 hlinfo->mouse_face_beg_row = vpos;
15157 hlinfo->mouse_face_beg_x = x;
15158 hlinfo->mouse_face_past_end = false;
15159 15187
15160 hlinfo->mouse_face_end_col = hpos + 1; 15188 mouse_face = Fget_text_property (make_fixnum (hpos_caption),
15161 hlinfo->mouse_face_end_row = vpos; 15189 Qmouse_face, string);
15162 hlinfo->mouse_face_end_x = x + glyph->pixel_width; 15190 if (!NILP (mouse_face))
15163 hlinfo->mouse_face_window = window; 15191 {
15164 hlinfo->mouse_face_face_id = TAB_BAR_FACE_ID; 15192 mouse_face_id = lookup_named_face (w, f, mouse_face, false);
15193 if (mouse_face_id < 0)
15194 mouse_face_id = compute_char_face (f, ' ', mouse_face);
15195 draw = DRAW_MOUSE_FACE;
15196 }
15197 }
15198
15199 if (draw == DRAW_MOUSE_FACE)
15200 {
15201 Lisp_Object b, e;
15202 ptrdiff_t begpos, endpos;
15203 int beg_x, end_x;
15204
15205 /* Search for mouse-face boundaries. */
15206 b = Fprevious_single_property_change (make_fixnum (hpos_caption + 1),
15207 Qmouse_face, string, Qnil);
15208 if (NILP (b))
15209 begpos = 0;
15210 else
15211 begpos = XFIXNUM (b);
15212 e = Fnext_single_property_change (make_fixnum (begpos), Qmouse_face, string, Qnil);
15213 if (NILP (e))
15214 endpos = SCHARS (string);
15215 else
15216 endpos = XFIXNUM (e);
15217
15218 /* Compute the starting and ending pixel coordinates */
15219 for (i = beg_x = 0;
15220 i < hpos0 + begpos; ++i)
15221 beg_x += row->glyphs[TEXT_AREA][i].pixel_width;
15222 for (end_x = 0,
15223 i = hpos0 + begpos;
15224 i < hpos0 + endpos; ++i)
15225 end_x += row->glyphs[TEXT_AREA][i].pixel_width;
15226
15227 if ( EQ (window, hlinfo->mouse_face_window)
15228 && (hlinfo->mouse_face_beg_col <= hpos
15229 && hpos < hlinfo->mouse_face_end_col)
15230 && hlinfo->mouse_face_beg_row == vpos )
15231 return;
15232
15233 hlinfo->mouse_face_window = window;
15234 hlinfo->mouse_face_face_id = mouse_face_id;
15235 hlinfo->mouse_face_beg_row = vpos;
15236 hlinfo->mouse_face_end_row = vpos;
15237 hlinfo->mouse_face_past_end = false;
15238 hlinfo->mouse_face_beg_col = hpos0 + begpos;
15239 hlinfo->mouse_face_end_col = hpos0 + endpos;
15240 hlinfo->mouse_face_beg_x = beg_x;
15241 hlinfo->mouse_face_end_x = end_x;
15242 }
15243 else
15244 {
15245 /* Compute the x-position of the glyph. In front and past the
15246 image is a space. We include this in the highlighted area. */
15247 for (i = x = 0; i < hpos; ++i)
15248 x += row->glyphs[TEXT_AREA][i].pixel_width;
15249 total_pixel_width = glyph->pixel_width;
15250
15251 hlinfo->mouse_face_face_id = TAB_BAR_FACE_ID;
15252 hlinfo->mouse_face_beg_col = hpos;
15253 hlinfo->mouse_face_beg_row = vpos;
15254 hlinfo->mouse_face_beg_x = x;
15255 hlinfo->mouse_face_past_end = false;
15256
15257 hlinfo->mouse_face_end_col = hpos + 1;
15258 hlinfo->mouse_face_end_row = vpos;
15259 hlinfo->mouse_face_end_x = x + total_pixel_width;
15260 hlinfo->mouse_face_window = window;
15261 }
15165 15262
15166 /* Display it as active. */ 15263 /* Display it as active. */
15167 show_mouse_face (hlinfo, draw, true); 15264 show_mouse_face (hlinfo, draw, true);