]> git.eshelyaron.com Git - emacs.git/commitdiff
Support mouse events clicked on the tab bar but outside of any tab (bug#41343)
authorJuri Linkov <juri@linkov.net>
Mon, 13 Sep 2021 08:14:32 +0000 (11:14 +0300)
committerJuri Linkov <juri@linkov.net>
Mon, 13 Sep 2021 08:15:10 +0000 (11:15 +0300)
* lisp/tab-bar.el (tab-bar--key-to-number): Return non-nil non-numeric t
when no tab is used.  Return nil for current-tab.
(tab-bar-mouse-select-tab, tab-bar-mouse-close-tab): Do nothing
when tab-bar--key-to-number returns non-nil non-numeric t
for click events outside of any tab.
(tab-bar-mouse-context-menu): Add context menu when mouse is clicked
outside of tabs.  Add "Duplicate" alongside with "Close" to the menu
used when mouse is clicked on a tab.
(toggle-tab-bar-mode-from-frame, toggle-frame-tab-bar): Move code
closer to 'tab-bar-show'.

* src/xdisp.c (handle_tab_bar_click): Return Qtab_bar with empty list
when mouse is clicked on the tab bar but outside of any tab.

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

index 2684ff998b7f06e7a57dc25197a9882382ad1037..e0eb62c887ec165491ac7cd82017b5b9d9bcb7b7 100644 (file)
@@ -113,7 +113,6 @@ For easier selection of tabs by their numbers, consider customizing
   :group 'tab-bar
   :version "27.1")
 
-\f
 (defun tab-bar--define-keys ()
   "Install key bindings for switching between tabs if the user has configured them."
   (when tab-bar-select-tab-modifiers
@@ -224,10 +223,15 @@ a list of frames to update."
       (tab-bar--define-keys)
     (tab-bar--undefine-keys)))
 
+\f
+;;; Key bindings
+
 (defun tab-bar--key-to-number (key)
-  (let ((key-name (format "%S" key)))
-    (when (string-prefix-p "tab-" key-name)
-      (string-to-number (string-replace "tab-" "" key-name)))))
+  (unless (eq key 'current-tab)
+    (let ((key-name (format "%S" key)))
+      (if (string-prefix-p "tab-" key-name)
+          (string-to-number (string-replace "tab-" "" key-name))
+        t))))
 
 (defun tab-bar--event-to-item (posn)
   (if (posn-window posn)
@@ -246,37 +250,59 @@ a list of frames to update."
            (lambda (key binding)
              (when (eq (car-safe binding) 'menu-item)
                (when (> (+ column (length (nth 1 binding))) x-position)
-                 (throw 'done (list
-                               key (nth 2 binding)
-                               (get-text-property
-                                (- x-position column) 'close-tab (nth 1 binding)))))
+                 (throw 'done (list key (nth 2 binding)
+                                    (get-text-property
+                                     (- x-position column)
+                                     'close-tab (nth 1 binding)))))
                (setq column (+ column (length (nth 1 binding))))))
            keymap))))))
 
 (defun tab-bar-mouse-select-tab (event)
   (interactive "e")
-  (let ((item (tab-bar--event-to-item (event-start event))))
+  (let* ((item (tab-bar--event-to-item (event-start event)))
+         (tab-number (tab-bar--key-to-number (nth 0 item))))
     (if (nth 2 item)
-        (tab-bar-close-tab (tab-bar--key-to-number (nth 0 item)))
+        (unless (eq tab-number t)
+          (tab-bar-close-tab tab-number))
       (if (functionp (nth 1 item))
           (call-interactively (nth 1 item))
-        (tab-bar-select-tab (tab-bar--key-to-number (nth 0 item)))))))
+        (unless (eq tab-number t)
+          (tab-bar-select-tab tab-number))))))
 
 (defun tab-bar-mouse-close-tab (event)
   (interactive "e")
-  (let ((item (tab-bar--event-to-item (event-start event))))
-    (tab-bar-close-tab (tab-bar--key-to-number (nth 0 item)))))
+  (let* ((item (tab-bar--event-to-item (event-start event)))
+         (tab-number (tab-bar--key-to-number (nth 0 item))))
+    (unless (eq tab-number t)
+      (tab-bar-close-tab tab-number))))
 
 (defun tab-bar-mouse-context-menu (event)
   (interactive "e")
   (let* ((item (tab-bar--event-to-item (event-start event)))
          (tab-number (tab-bar--key-to-number (nth 0 item)))
-         (menu (make-sparse-keymap "Context Menu")))
-
-    (define-key-after menu [close]
-      `(menu-item "Close" (lambda () (interactive)
-                            (tab-bar-close-tab ,tab-number))
-                  :help "Close the tab"))
+         (menu (make-sparse-keymap (propertize "Context Menu" 'hide t))))
+
+    (cond
+     ((eq tab-number t)
+      (define-key-after menu [new-tab]
+        '(menu-item "New tab" tab-bar-new-tab
+                    :help "Create a new tab"))
+      (when tab-bar-closed-tabs
+        (define-key-after menu [undo-close]
+          '(menu-item "Reopen closed tab" tab-bar-undo-close-tab
+                      :help "Undo closing the tab"))))
+
+     (t
+      (define-key-after menu [duplicate-tab]
+        `(menu-item "Duplicate" (lambda () (interactive)
+                                  (tab-bar-duplicate-tab
+                                   nil ;; TODO: add ,tab-number
+                                   ))
+                    :help "Duplicate the tab"))
+      (define-key-after menu [close]
+        `(menu-item "Close" (lambda () (interactive)
+                              (tab-bar-close-tab ,tab-number))
+                    :help "Close the tab"))))
 
     (popup-menu menu event)))
 
@@ -290,31 +316,6 @@ a list of frames to update."
                      (event-end event))))))
     (tab-bar-move-tab-to to from)))
 
-(defun toggle-tab-bar-mode-from-frame (&optional arg)
-  "Toggle tab bar on or off, based on the status of the current frame.
-Used in the Show/Hide menu, to have the toggle reflect the current frame.
-See `tab-bar-mode' for more information."
-  (interactive (list (or current-prefix-arg 'toggle)))
-  (if (eq arg 'toggle)
-      (tab-bar-mode (if (> (frame-parameter nil 'tab-bar-lines) 0) 0 1))
-    (tab-bar-mode arg)))
-
-(defun toggle-frame-tab-bar (&optional frame)
-  "Toggle tab bar of the selected frame.
-When calling from Lisp, use the optional argument FRAME to toggle
-the tab bar on that frame.
-This is useful if you want to enable the tab bar individually
-on each new frame when the global `tab-bar-mode' is disabled,
-or if you want to disable the tab bar individually on each
-new frame when the global `tab-bar-mode' is enabled, by using
-
-  (add-hook 'after-make-frame-functions 'toggle-frame-tab-bar)"
-  (interactive)
-  (set-frame-parameter frame 'tab-bar-lines
-                       (if (> (frame-parameter frame 'tab-bar-lines) 0) 0 1))
-  (set-frame-parameter frame 'tab-bar-lines-keep-state
-                       (not (frame-parameter frame 'tab-bar-lines-keep-state))))
-
 (defvar tab-bar-map
   (let ((map (make-sparse-keymap)))
     (define-key map [down-mouse-1] 'tab-bar-mouse-select-tab)
@@ -351,6 +352,32 @@ Its main job is to show tabs in the tab bar
 and to bind mouse events to the commands."
   (tab-bar-make-keymap-1))
 
+\f
+(defun toggle-tab-bar-mode-from-frame (&optional arg)
+  "Toggle tab bar on or off, based on the status of the current frame.
+Used in the Show/Hide menu, to have the toggle reflect the current frame.
+See `tab-bar-mode' for more information."
+  (interactive (list (or current-prefix-arg 'toggle)))
+  (if (eq arg 'toggle)
+      (tab-bar-mode (if (> (frame-parameter nil 'tab-bar-lines) 0) 0 1))
+    (tab-bar-mode arg)))
+
+(defun toggle-frame-tab-bar (&optional frame)
+  "Toggle tab bar of the selected frame.
+When calling from Lisp, use the optional argument FRAME to toggle
+the tab bar on that frame.
+This is useful if you want to enable the tab bar individually
+on each new frame when the global `tab-bar-mode' is disabled,
+or if you want to disable the tab bar individually on each
+new frame when the global `tab-bar-mode' is enabled, by using
+
+  (add-hook 'after-make-frame-functions 'toggle-frame-tab-bar)"
+  (interactive)
+  (set-frame-parameter frame 'tab-bar-lines
+                       (if (> (frame-parameter frame 'tab-bar-lines) 0) 0 1))
+  (set-frame-parameter frame 'tab-bar-lines-keep-state
+                       (not (frame-parameter frame 'tab-bar-lines-keep-state))))
+
 \f
 (defcustom tab-bar-show t
   "Defines when to show the tab bar.
@@ -1224,8 +1251,7 @@ where argument addressing is absolute."
 
 (defun tab-bar-duplicate-tab (&optional arg)
   "Duplicate the current tab to ARG positions to the right.
-If a negative ARG, duplicate the tab to ARG positions to the left.
-If ARG is zero, duplicate the tab in place of the current tab."
+ARG has the same meaning as in `tab-bar-new-tab'."
   (interactive "P")
   (let ((tab-bar-new-tab-choice nil)
         (tab-bar-new-tab-group t))
index 45c7090fc004848e0dbd2958205d585416d12d75..d30a68570f06c0b437d62277eb0715875e6e8cd0 100644 (file)
@@ -13774,7 +13774,7 @@ handle_tab_bar_click (struct frame *f, int x, int y, bool down_p,
   frame_to_window_pixel_xy (w, &x, &y);
   ts = get_tab_bar_item (f, x, y, &glyph, &hpos, &vpos, &prop_idx, &close_p);
   if (ts == -1)
-    return Qnil;
+    return Fcons (Qtab_bar, Qnil);
 
   /* If item is disabled, do nothing.  */
   enabled_p = AREF (f->tab_bar_items, prop_idx + TAB_BAR_ITEM_ENABLED_P);