diff options
| author | Juri Linkov | 2021-09-05 20:16:33 +0300 |
|---|---|---|
| committer | Juri Linkov | 2021-09-05 20:16:33 +0300 |
| commit | 794fdce55d097f2b58ce37818edffb2deef7b9de (patch) | |
| tree | 42c14ae6326ae151f3e943d264074a2671ccda98 | |
| parent | ad9c57f54ae3eea9e5b2fe9264e9edb8b2ed1857 (diff) | |
| download | emacs-794fdce55d097f2b58ce37818edffb2deef7b9de.tar.gz emacs-794fdce55d097f2b58ce37818edffb2deef7b9de.zip | |
Improve tab-bar event handling (bug#41343)
* lisp/tab-bar.el (tab-bar--key-to-number): Rename from tab--key-to-number.
(tab-bar--event-to-item): New function from tab-bar-handle-mouse.
(tab-bar-mouse-select-tab, tab-bar-mouse-close-tab)
(tab-bar-mouse-context-menu, tab-bar-mouse-move-tab):
Use tab-bar--event-to-item.
* src/menu.c (x_popup_menu_1): Handle Qtab_bar in the second list element.
* src/xdisp.c (tty_get_tab_bar_item): Change arg 'end' to bool 'close_p'.
(tty_get_tab_bar_item): Detect if the close button was clicked.
(tty_handle_tab_bar_click): Return a list with caption that has
text properties.
| -rw-r--r-- | lisp/tab-bar.el | 96 | ||||
| -rw-r--r-- | src/menu.c | 9 | ||||
| -rw-r--r-- | src/w32term.c | 10 | ||||
| -rw-r--r-- | src/xdisp.c | 44 | ||||
| -rw-r--r-- | src/xterm.c | 10 |
5 files changed, 82 insertions, 87 deletions
diff --git a/lisp/tab-bar.el b/lisp/tab-bar.el index ef7babb87b1..aac7bb5d106 100644 --- a/lisp/tab-bar.el +++ b/lisp/tab-bar.el | |||
| @@ -221,61 +221,53 @@ a list of frames to update." | |||
| 221 | (tab-bar--define-keys) | 221 | (tab-bar--define-keys) |
| 222 | (tab-bar--undefine-keys))) | 222 | (tab-bar--undefine-keys))) |
| 223 | 223 | ||
| 224 | (defun tab--key-to-number (key) | 224 | (defun tab-bar--key-to-number (key) |
| 225 | (unless (or (null key) (eq key 'current-tab)) | 225 | (let ((key-name (format "%S" key))) |
| 226 | (string-to-number | 226 | (when (string-prefix-p "tab-" key-name) |
| 227 | (string-replace "tab-" "" (format "%S" key))))) | 227 | (string-to-number (string-replace "tab-" "" key-name))))) |
| 228 | 228 | ||
| 229 | (defun tab-bar-handle-mouse (event) | 229 | (defun tab-bar--event-to-item (posn) |
| 230 | "Text-mode emulation of switching tabs on the tab bar. | 230 | (if (posn-window posn) |
| 231 | This command is used when you click the mouse in the tab bar | 231 | (let ((caption (car (posn-string posn)))) |
| 232 | on a console which has no window system but does have a mouse." | 232 | (when caption |
| 233 | (interactive "e") | 233 | (get-text-property 0 'menu-item caption))) |
| 234 | (let* ((x-position (car (posn-x-y (event-start event)))) | 234 | ;; Text-mode emulation of switching tabs on the tab bar. |
| 235 | (keymap (lookup-key (cons 'keymap (nreverse (current-active-maps))) [tab-bar])) | 235 | ;; This code is used when you click the mouse in the tab bar |
| 236 | (column 0)) | 236 | ;; on a console which has no window system but does have a mouse. |
| 237 | (when x-position | 237 | (let* ((x-position (car (posn-x-y posn))) |
| 238 | (unless (catch 'done | 238 | (keymap (lookup-key (cons 'keymap (nreverse (current-active-maps))) [tab-bar])) |
| 239 | (map-keymap | 239 | (column 0)) |
| 240 | (lambda (key binding) | 240 | (when x-position |
| 241 | (when (eq (car-safe binding) 'menu-item) | 241 | (catch 'done |
| 242 | (when (> (+ column (length (nth 1 binding))) x-position) | 242 | (map-keymap |
| 243 | (if (get-text-property | 243 | (lambda (key binding) |
| 244 | (- x-position column) 'close-tab (nth 1 binding)) | 244 | (when (eq (car-safe binding) 'menu-item) |
| 245 | (tab-bar-close-tab (tab--key-to-number key)) | 245 | (when (> (+ column (length (nth 1 binding))) x-position) |
| 246 | (if (nth 2 binding) | 246 | (throw 'done (list |
| 247 | (call-interactively (nth 2 binding)) | 247 | key (nth 2 binding) |
| 248 | (tab-bar-select-tab (tab--key-to-number key)))) | 248 | (get-text-property |
| 249 | (throw 'done t)) | 249 | (- x-position column) 'close-tab (nth 1 binding))))) |
| 250 | (setq column (+ column (length (nth 1 binding)))))) | 250 | (setq column (+ column (length (nth 1 binding)))))) |
| 251 | keymap)) | 251 | keymap)))))) |
| 252 | ;; Clicking anywhere outside existing tabs will add a new tab | ||
| 253 | (tab-bar-new-tab))))) | ||
| 254 | 252 | ||
| 255 | (defun tab-bar-mouse-select-tab (event) | 253 | (defun tab-bar-mouse-select-tab (event) |
| 256 | (interactive "e") | 254 | (interactive "e") |
| 257 | (if (posn-window (event-start event)) | 255 | (let ((item (tab-bar--event-to-item (event-start event)))) |
| 258 | (let* ((caption (car (posn-string (event-start event)))) | 256 | (if (nth 2 item) |
| 259 | (item (and caption (get-text-property 0 'menu-item caption)))) | 257 | (tab-bar-close-tab (tab-bar--key-to-number (nth 0 item))) |
| 260 | (if (nth 2 item) | 258 | (if (functionp (nth 1 item)) |
| 261 | (tab-bar-close-tab (tab--key-to-number (nth 0 item))) | 259 | (call-interactively (nth 1 item)) |
| 262 | (if (functionp (nth 1 item)) | 260 | (tab-bar-select-tab (tab-bar--key-to-number (nth 0 item))))))) |
| 263 | (call-interactively (nth 1 item)) | ||
| 264 | (tab-bar-select-tab (tab--key-to-number (nth 0 item)))))) | ||
| 265 | ;; TTY | ||
| 266 | (tab-bar-handle-mouse event))) | ||
| 267 | 261 | ||
| 268 | (defun tab-bar-mouse-close-tab (event) | 262 | (defun tab-bar-mouse-close-tab (event) |
| 269 | (interactive "e") | 263 | (interactive "e") |
| 270 | (let* ((caption (car (posn-string (event-start event)))) | 264 | (let ((item (tab-bar--event-to-item (event-start event)))) |
| 271 | (item (and caption (get-text-property 0 'menu-item caption)))) | 265 | (tab-bar-close-tab (tab-bar--key-to-number (nth 0 item))))) |
| 272 | (tab-bar-close-tab (tab--key-to-number (nth 0 item))))) | ||
| 273 | 266 | ||
| 274 | (defun tab-bar-mouse-context-menu (event) | 267 | (defun tab-bar-mouse-context-menu (event) |
| 275 | (interactive "e") | 268 | (interactive "e") |
| 276 | (let* ((caption (car (posn-string (event-start event)))) | 269 | (let* ((item (tab-bar--event-to-item (event-start event))) |
| 277 | (item (and caption (get-text-property 0 'menu-item caption))) | 270 | (tab-number (tab-bar--key-to-number (nth 0 item))) |
| 278 | (tab-number (tab--key-to-number (nth 0 item))) | ||
| 279 | (menu (make-sparse-keymap "Context Menu"))) | 271 | (menu (make-sparse-keymap "Context Menu"))) |
| 280 | 272 | ||
| 281 | (define-key-after menu [close] | 273 | (define-key-after menu [close] |
| @@ -287,12 +279,12 @@ on a console which has no window system but does have a mouse." | |||
| 287 | 279 | ||
| 288 | (defun tab-bar-mouse-move-tab (event) | 280 | (defun tab-bar-mouse-move-tab (event) |
| 289 | (interactive "e") | 281 | (interactive "e") |
| 290 | (let* ((caption (car (posn-string (event-start event)))) | 282 | (let ((from (tab-bar--key-to-number |
| 291 | (item (and caption (get-text-property 0 'menu-item caption))) | 283 | (nth 0 (tab-bar--event-to-item |
| 292 | (from (tab--key-to-number (nth 0 item))) | 284 | (event-start event))))) |
| 293 | (caption (car (posn-string (event-end event)))) | 285 | (to (tab-bar--key-to-number |
| 294 | (item (and caption (get-text-property 0 'menu-item caption))) | 286 | (nth 0 (tab-bar--event-to-item |
| 295 | (to (tab--key-to-number (nth 0 item)))) | 287 | (event-end event)))))) |
| 296 | (tab-bar-move-tab-to to from))) | 288 | (tab-bar-move-tab-to to from))) |
| 297 | 289 | ||
| 298 | (defun toggle-tab-bar-mode-from-frame (&optional arg) | 290 | (defun toggle-tab-bar-mode-from-frame (&optional arg) |
diff --git a/src/menu.c b/src/menu.c index 3b1d7402571..990a74b92e3 100644 --- a/src/menu.c +++ b/src/menu.c | |||
| @@ -1127,9 +1127,12 @@ x_popup_menu_1 (Lisp_Object position, Lisp_Object menu) | |||
| 1127 | 1127 | ||
| 1128 | /* Decode the first argument: find the window and the coordinates. */ | 1128 | /* Decode the first argument: find the window and the coordinates. */ |
| 1129 | if (EQ (position, Qt) | 1129 | if (EQ (position, Qt) |
| 1130 | || (CONSP (position) && (EQ (XCAR (position), Qmenu_bar) | 1130 | || (CONSP (position) |
| 1131 | || EQ (XCAR (position), Qtab_bar) | 1131 | && (EQ (XCAR (position), Qmenu_bar) |
| 1132 | || EQ (XCAR (position), Qtool_bar)))) | 1132 | || EQ (XCAR (position), Qtab_bar) |
| 1133 | || (CONSP (XCDR (position)) | ||
| 1134 | && EQ (XCAR (XCDR (position)), Qtab_bar)) | ||
| 1135 | || EQ (XCAR (position), Qtool_bar)))) | ||
| 1133 | { | 1136 | { |
| 1134 | get_current_pos_p = 1; | 1137 | get_current_pos_p = 1; |
| 1135 | } | 1138 | } |
diff --git a/src/w32term.c b/src/w32term.c index c9570b0c670..aca4739a2e3 100644 --- a/src/w32term.c +++ b/src/w32term.c | |||
| @@ -5186,7 +5186,7 @@ w32_read_socket (struct terminal *terminal, | |||
| 5186 | { | 5186 | { |
| 5187 | /* If we decide we want to generate an event to be seen | 5187 | /* If we decide we want to generate an event to be seen |
| 5188 | by the rest of Emacs, we put it here. */ | 5188 | by the rest of Emacs, we put it here. */ |
| 5189 | Lisp_Object tab_bar_key = Qnil; | 5189 | Lisp_Object tab_bar_arg = Qnil; |
| 5190 | bool tab_bar_p = 0; | 5190 | bool tab_bar_p = 0; |
| 5191 | bool tool_bar_p = 0; | 5191 | bool tool_bar_p = 0; |
| 5192 | int button = 0; | 5192 | int button = 0; |
| @@ -5209,12 +5209,12 @@ w32_read_socket (struct terminal *terminal, | |||
| 5209 | 5209 | ||
| 5210 | if (EQ (window, f->tab_bar_window)) | 5210 | if (EQ (window, f->tab_bar_window)) |
| 5211 | { | 5211 | { |
| 5212 | tab_bar_key = w32_handle_tab_bar_click (f, &inev); | 5212 | tab_bar_arg = w32_handle_tab_bar_click (f, &inev); |
| 5213 | tab_bar_p = 1; | 5213 | tab_bar_p = 1; |
| 5214 | } | 5214 | } |
| 5215 | } | 5215 | } |
| 5216 | 5216 | ||
| 5217 | if ((tab_bar_p && NILP (tab_bar_key)) | 5217 | if ((tab_bar_p && NILP (tab_bar_arg)) |
| 5218 | || (dpyinfo->w32_focus_frame | 5218 | || (dpyinfo->w32_focus_frame |
| 5219 | && f != dpyinfo->w32_focus_frame | 5219 | && f != dpyinfo->w32_focus_frame |
| 5220 | /* This does not help when the click happens in | 5220 | /* This does not help when the click happens in |
| @@ -5222,8 +5222,8 @@ w32_read_socket (struct terminal *terminal, | |||
| 5222 | && !frame_ancestor_p (f, dpyinfo->w32_focus_frame))) | 5222 | && !frame_ancestor_p (f, dpyinfo->w32_focus_frame))) |
| 5223 | inev.kind = NO_EVENT; | 5223 | inev.kind = NO_EVENT; |
| 5224 | 5224 | ||
| 5225 | if (!NILP (tab_bar_key)) | 5225 | if (!NILP (tab_bar_arg)) |
| 5226 | inev.arg = tab_bar_key; | 5226 | inev.arg = tab_bar_arg; |
| 5227 | 5227 | ||
| 5228 | /* Is this in the tool-bar? */ | 5228 | /* Is this in the tool-bar? */ |
| 5229 | if (WINDOWP (f->tool_bar_window) | 5229 | if (WINDOWP (f->tool_bar_window) |
diff --git a/src/xdisp.c b/src/xdisp.c index 4a5ab172cc1..91f9bb98e6f 100644 --- a/src/xdisp.c +++ b/src/xdisp.c | |||
| @@ -13891,7 +13891,7 @@ note_tab_bar_highlight (struct frame *f, int x, int y) | |||
| 13891 | 13891 | ||
| 13892 | /* Find the tab-bar item at X coordinate and return its information. */ | 13892 | /* Find the tab-bar item at X coordinate and return its information. */ |
| 13893 | static Lisp_Object | 13893 | static Lisp_Object |
| 13894 | tty_get_tab_bar_item (struct frame *f, int x, int *idx, ptrdiff_t *end) | 13894 | tty_get_tab_bar_item (struct frame *f, int x, int *prop_idx, bool *close_p) |
| 13895 | { | 13895 | { |
| 13896 | ptrdiff_t clen = 0; | 13896 | ptrdiff_t clen = 0; |
| 13897 | 13897 | ||
| @@ -13904,8 +13904,11 @@ tty_get_tab_bar_item (struct frame *f, int x, int *idx, ptrdiff_t *end) | |||
| 13904 | clen += SCHARS (caption); | 13904 | clen += SCHARS (caption); |
| 13905 | if (x < clen) | 13905 | if (x < clen) |
| 13906 | { | 13906 | { |
| 13907 | *idx = i; | 13907 | *prop_idx = i; |
| 13908 | *end = clen; | 13908 | *close_p = !NILP (Fget_text_property (make_fixnum (SCHARS (caption) |
| 13909 | - (clen - x)), | ||
| 13910 | Qclose_tab, | ||
| 13911 | caption)); | ||
| 13909 | return caption; | 13912 | return caption; |
| 13910 | } | 13913 | } |
| 13911 | } | 13914 | } |
| @@ -13928,8 +13931,8 @@ tty_handle_tab_bar_click (struct frame *f, int x, int y, bool down_p, | |||
| 13928 | 13931 | ||
| 13929 | /* Find the tab-bar item where the X,Y coordinates belong. */ | 13932 | /* Find the tab-bar item where the X,Y coordinates belong. */ |
| 13930 | int prop_idx; | 13933 | int prop_idx; |
| 13931 | ptrdiff_t clen; | 13934 | bool close_p; |
| 13932 | Lisp_Object caption = tty_get_tab_bar_item (f, x, &prop_idx, &clen); | 13935 | Lisp_Object caption = tty_get_tab_bar_item (f, x, &prop_idx, &close_p); |
| 13933 | 13936 | ||
| 13934 | if (NILP (caption)) | 13937 | if (NILP (caption)) |
| 13935 | return Qnil; | 13938 | return Qnil; |
| @@ -13941,24 +13944,21 @@ tty_handle_tab_bar_click (struct frame *f, int x, int y, bool down_p, | |||
| 13941 | if (down_p) | 13944 | if (down_p) |
| 13942 | f->last_tab_bar_item = prop_idx; | 13945 | f->last_tab_bar_item = prop_idx; |
| 13943 | else | 13946 | else |
| 13944 | { | 13947 | f->last_tab_bar_item = -1; |
| 13945 | f->last_tab_bar_item = -1; | ||
| 13946 | } | ||
| 13947 | 13948 | ||
| 13948 | /* Generate a TAB_BAR_EVENT event. */ | 13949 | caption = Fcopy_sequence (caption); |
| 13949 | Lisp_Object key = AREF (f->tab_bar_items, | ||
| 13950 | prop_idx * TAB_BAR_ITEM_NSLOTS | ||
| 13951 | + TAB_BAR_ITEM_KEY); | ||
| 13952 | /* Kludge alert: we assume the last two characters of a tab | ||
| 13953 | label are " x", and treat clicks on those 2 characters as a | ||
| 13954 | Close Tab command. */ | ||
| 13955 | eassert (STRINGP (caption)); | ||
| 13956 | int lastc = SSDATA (caption)[SCHARS (caption) - 1]; | ||
| 13957 | bool close_p = false; | ||
| 13958 | if ((x == clen - 1 || (clen > 1 && x == clen - 2)) && lastc == 'x') | ||
| 13959 | close_p = true; | ||
| 13960 | 13950 | ||
| 13961 | return list3 (Qtab_bar, key, close_p ? Qt : Qnil); | 13951 | AUTO_LIST2 (props, Qmenu_item, |
| 13952 | list3 (AREF (f->tab_bar_items, prop_idx * TAB_BAR_ITEM_NSLOTS | ||
| 13953 | + TAB_BAR_ITEM_KEY), | ||
| 13954 | AREF (f->tab_bar_items, prop_idx * TAB_BAR_ITEM_NSLOTS | ||
| 13955 | + TAB_BAR_ITEM_BINDING), | ||
| 13956 | close_p ? Qt : Qnil)); | ||
| 13957 | |||
| 13958 | Fadd_text_properties (make_fixnum (0), make_fixnum (SCHARS (caption)), | ||
| 13959 | props, caption); | ||
| 13960 | |||
| 13961 | return Fcons (Qtab_bar, Fcons (caption, make_fixnum (0))); | ||
| 13962 | } | 13962 | } |
| 13963 | 13963 | ||
| 13964 | 13964 | ||
| @@ -33524,7 +33524,7 @@ note_mouse_highlight (struct frame *f, int x, int y) | |||
| 33524 | && y < FRAME_MENU_BAR_LINES (f) + FRAME_TAB_BAR_LINES (f))) | 33524 | && y < FRAME_MENU_BAR_LINES (f) + FRAME_TAB_BAR_LINES (f))) |
| 33525 | { | 33525 | { |
| 33526 | int prop_idx; | 33526 | int prop_idx; |
| 33527 | ptrdiff_t ignore; | 33527 | bool ignore; |
| 33528 | Lisp_Object caption = tty_get_tab_bar_item (f, x, &prop_idx, &ignore); | 33528 | Lisp_Object caption = tty_get_tab_bar_item (f, x, &prop_idx, &ignore); |
| 33529 | 33529 | ||
| 33530 | if (!NILP (caption)) | 33530 | if (!NILP (caption)) |
diff --git a/src/xterm.c b/src/xterm.c index 57229d3d616..846b67b069f 100644 --- a/src/xterm.c +++ b/src/xterm.c | |||
| @@ -9166,7 +9166,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, | |||
| 9166 | { | 9166 | { |
| 9167 | /* If we decide we want to generate an event to be seen | 9167 | /* If we decide we want to generate an event to be seen |
| 9168 | by the rest of Emacs, we put it here. */ | 9168 | by the rest of Emacs, we put it here. */ |
| 9169 | Lisp_Object tab_bar_key = Qnil; | 9169 | Lisp_Object tab_bar_arg = Qnil; |
| 9170 | bool tab_bar_p = false; | 9170 | bool tab_bar_p = false; |
| 9171 | bool tool_bar_p = false; | 9171 | bool tool_bar_p = false; |
| 9172 | 9172 | ||
| @@ -9216,7 +9216,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, | |||
| 9216 | tab_bar_p = EQ (window, f->tab_bar_window); | 9216 | tab_bar_p = EQ (window, f->tab_bar_window); |
| 9217 | 9217 | ||
| 9218 | if (tab_bar_p) | 9218 | if (tab_bar_p) |
| 9219 | tab_bar_key = handle_tab_bar_click | 9219 | tab_bar_arg = handle_tab_bar_click |
| 9220 | (f, x, y, event->xbutton.type == ButtonPress, | 9220 | (f, x, y, event->xbutton.type == ButtonPress, |
| 9221 | x_x_to_emacs_modifiers (dpyinfo, event->xbutton.state)); | 9221 | x_x_to_emacs_modifiers (dpyinfo, event->xbutton.state)); |
| 9222 | } | 9222 | } |
| @@ -9240,7 +9240,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, | |||
| 9240 | } | 9240 | } |
| 9241 | #endif /* !USE_GTK */ | 9241 | #endif /* !USE_GTK */ |
| 9242 | 9242 | ||
| 9243 | if (!(tab_bar_p && NILP (tab_bar_key)) && !tool_bar_p) | 9243 | if (!(tab_bar_p && NILP (tab_bar_arg)) && !tool_bar_p) |
| 9244 | #if defined (USE_X_TOOLKIT) || defined (USE_GTK) | 9244 | #if defined (USE_X_TOOLKIT) || defined (USE_GTK) |
| 9245 | if (! popup_activated ()) | 9245 | if (! popup_activated ()) |
| 9246 | #endif | 9246 | #endif |
| @@ -9259,8 +9259,8 @@ handle_one_xevent (struct x_display_info *dpyinfo, | |||
| 9259 | else | 9259 | else |
| 9260 | x_construct_mouse_click (&inev.ie, &event->xbutton, f); | 9260 | x_construct_mouse_click (&inev.ie, &event->xbutton, f); |
| 9261 | 9261 | ||
| 9262 | if (!NILP (tab_bar_key)) | 9262 | if (!NILP (tab_bar_arg)) |
| 9263 | inev.ie.arg = tab_bar_key; | 9263 | inev.ie.arg = tab_bar_arg; |
| 9264 | } | 9264 | } |
| 9265 | if (FRAME_X_EMBEDDED_P (f)) | 9265 | if (FRAME_X_EMBEDDED_P (f)) |
| 9266 | xembed_send_message (f, event->xbutton.time, | 9266 | xembed_send_message (f, event->xbutton.time, |