diff options
| author | shipmints | 2025-02-22 05:13:05 -0500 |
|---|---|---|
| committer | Juri Linkov | 2025-03-06 20:37:44 +0200 |
| commit | efd483cf0ecde3b0545a9eb39cc3fa9483fad76c (patch) | |
| tree | b133b0feb7052c057ac1767012bc78884a5745a8 | |
| parent | 63cc542b9402ad0a794f4e05790366bd580b8bd1 (diff) | |
| download | emacs-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/NEWS | 6 | ||||
| -rw-r--r-- | lisp/tab-bar.el | 18 | ||||
| -rw-r--r-- | src/xdisp.c | 131 |
3 files changed, 137 insertions, 18 deletions
| @@ -290,6 +290,12 @@ specified by external means. | |||
| 290 | This hook allows you to control which tab-bar tabs are auto-resized. | 290 | This 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 | ||
| 295 | hovers 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'. |
| 294 | This hook allows you to operate on a reopened tab. | 300 | This 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. |
| 894 | Each function is called with three arguments: the name returned | 909 | Each function is called with three arguments: the name returned |
| 895 | by the previously called modifier, the tab and its number. | 910 | 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." | |||
| 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); |