emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

master 14d5145: Merge branch 'feature/tab-bar-events'


From: Juri Linkov
Subject: master 14d5145: Merge branch 'feature/tab-bar-events'
Date: Thu, 9 Sep 2021 03:53:12 -0400 (EDT)

branch: master
commit 14d5145441559bdbefd3a4188144217e01c033de
Merge: 8ac5510 3a8b8df
Author: Juri Linkov <juri@linkov.net>
Commit: Juri Linkov <juri@linkov.net>

    Merge branch 'feature/tab-bar-events'
---
 lisp/mouse.el    |   7 ++-
 lisp/tab-bar.el  | 172 +++++++++++++++++++++++++++++++++++--------------------
 src/dispextern.h |   4 +-
 src/keyboard.c   |   6 ++
 src/menu.c       |   9 ++-
 src/term.c       |  17 +-----
 src/termchar.h   |   4 +-
 src/w32inevt.c   |   6 +-
 src/w32term.c    |  20 ++++---
 src/xdisp.c      | 104 ++++++++++++++-------------------
 src/xterm.c      |  10 +++-
 11 files changed, 198 insertions(+), 161 deletions(-)

diff --git a/lisp/mouse.el b/lisp/mouse.el
index 7d3ed9a..8c6fb2c 100644
--- a/lisp/mouse.el
+++ b/lisp/mouse.el
@@ -1408,9 +1408,10 @@ its value is returned."
             ;; Mouse clicks in the fringe come with a position in
             ;; (nth 5).  This is useful but is not exactly where we clicked, so
             ;; don't look up that position's properties!
-           (and pt (not (memq (posn-area pos) '(left-fringe right-fringe
-                                                 left-margin right-margin)))
-                (get-char-property pt property w))))
+            (and pt (not (memq (posn-area pos)
+                               '(left-fringe right-fringe
+                                 left-margin right-margin tab-bar)))
+                 (get-char-property pt property w))))
     (get-char-property pos property)))
 
 (defun mouse-on-link-p (pos)
diff --git a/lisp/tab-bar.el b/lisp/tab-bar.el
index cde9a32..63b1f15 100644
--- a/lisp/tab-bar.el
+++ b/lisp/tab-bar.el
@@ -27,10 +27,7 @@
 ;; bindings for the global tab bar.
 
 ;; The normal global binding for [tab-bar] (below) uses the value of
-;; `tab-bar-map' as the actual keymap to define the tab bar.  Modes
-;; may either bind items under the [tab-bar] prefix key of the local
-;; map to add to the global bar or may set `tab-bar-map'
-;; buffer-locally to override it.
+;; `tab-bar-map' as the actual keymap to define the tab bar.
 
 ;;; Code:
 
@@ -224,31 +221,71 @@ a list of frames to update."
       (tab-bar--define-keys)
     (tab-bar--undefine-keys)))
 
-(defun tab-bar-handle-mouse (event)
-  "Text-mode emulation of switching tabs on the tab bar.
-This command is used when you click the mouse in the tab bar
-on a console which has no window system but does have a mouse."
+(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)))))
+
+(defun tab-bar--event-to-item (posn)
+  (if (posn-window posn)
+      (let ((caption (car (posn-string posn))))
+        (when caption
+          (get-text-property 0 'menu-item caption)))
+    ;; Text-mode emulation of switching tabs on the tab bar.
+    ;; This code is used when you click the mouse in the tab bar
+    ;; on a console which has no window system but does have a mouse.
+    (let* ((x-position (car (posn-x-y posn)))
+           (keymap (lookup-key (cons 'keymap (nreverse (current-active-maps))) 
[tab-bar]))
+           (column 0))
+      (when x-position
+        (catch 'done
+          (map-keymap
+           (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)))))
+               (setq column (+ column (length (nth 1 binding))))))
+           keymap))))))
+
+(defun tab-bar-mouse-select-tab (event)
   (interactive "e")
-  (let* ((x-position (car (posn-x-y (event-start event))))
-         (keymap (lookup-key (cons 'keymap (nreverse (current-active-maps))) 
[tab-bar]))
-         (column 0))
-    (when x-position
-      (unless (catch 'done
-                (map-keymap
-                 (lambda (key binding)
-                   (when (eq (car-safe binding) 'menu-item)
-                     (when (> (+ column (length (nth 1 binding))) x-position)
-                       (if (get-text-property (- x-position column) 'close-tab 
(nth 1 binding))
-                           (let* ((close-key (vector (intern (format "C-%s" 
key))))
-                                  (close-def (lookup-key keymap close-key)))
-                             (when close-def
-                               (call-interactively close-def)))
-                         (call-interactively (nth 2 binding)))
-                       (throw 'done t))
-                     (setq column (+ column (length (nth 1 binding))))))
-                 keymap))
-        ;; Clicking anywhere outside existing tabs will add a new tab
-        (tab-bar-new-tab)))))
+  (let ((item (tab-bar--event-to-item (event-start event))))
+    (if (nth 2 item)
+        (tab-bar-close-tab (tab-bar--key-to-number (nth 0 item)))
+      (if (functionp (nth 1 item))
+          (call-interactively (nth 1 item))
+        (tab-bar-select-tab (tab-bar--key-to-number (nth 0 item)))))))
+
+(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)))))
+
+(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"))
+
+    (popup-menu menu event)))
+
+(defun tab-bar-mouse-move-tab (event)
+  (interactive "e")
+  (let ((from (tab-bar--key-to-number
+               (nth 0 (tab-bar--event-to-item
+                       (event-start event)))))
+        (to (tab-bar--key-to-number
+             (nth 0 (tab-bar--event-to-item
+                     (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.
@@ -275,24 +312,41 @@ new frame when the global `tab-bar-mode' is enabled, by 
using
   (set-frame-parameter frame 'tab-bar-lines-keep-state
                        (not (frame-parameter frame 
'tab-bar-lines-keep-state))))
 
-(defvar tab-bar-map (make-sparse-keymap)
-  "Keymap for the tab bar.
-Define this locally to override the global tab bar.")
+(defvar tab-bar-map
+  (let ((map (make-sparse-keymap)))
+    (define-key map [down-mouse-1] 'tab-bar-mouse-select-tab)
+    (define-key map [drag-mouse-1] 'tab-bar-mouse-move-tab)
+    (define-key map [mouse-1] 'ignore)
+    (define-key map [down-mouse-2] 'tab-bar-mouse-close-tab)
+    (define-key map [mouse-2] 'ignore)
+    (define-key map [down-mouse-3] 'tab-bar-mouse-context-menu)
+
+    (define-key map [mouse-4]     'tab-previous)
+    (define-key map [mouse-5]     'tab-next)
+    (define-key map [wheel-up]    'tab-previous)
+    (define-key map [wheel-down]  'tab-next)
+    (define-key map [wheel-left]  'tab-previous)
+    (define-key map [wheel-right] 'tab-next)
+
+    (define-key map [S-mouse-4]     'tab-bar-move-tab-backward)
+    (define-key map [S-mouse-5]     'tab-bar-move-tab)
+    (define-key map [S-wheel-up]    'tab-bar-move-tab-backward)
+    (define-key map [S-wheel-down]  'tab-bar-move-tab)
+    (define-key map [S-wheel-left]  'tab-bar-move-tab-backward)
+    (define-key map [S-wheel-right] 'tab-bar-move-tab)
+
+    map)
+  "Keymap for the commands used on the tab bar.")
 
 (global-set-key [tab-bar]
                 `(menu-item ,(purecopy "tab bar") ignore
                             :filter tab-bar-make-keymap))
 
-(defconst tab-bar-keymap-cache (make-hash-table :weakness t :test 'equal))
-
 (defun tab-bar-make-keymap (&optional _ignore)
   "Generate an actual keymap from `tab-bar-map'.
-Its main job is to show tabs in the tab bar."
-  (if (= 1 (length tab-bar-map))
-      (tab-bar-make-keymap-1)
-    (let ((key (cons (frame-terminal) tab-bar-map)))
-      (or (gethash key tab-bar-keymap-cache)
-          (puthash key tab-bar-map tab-bar-keymap-cache)))))
+Its main job is to show tabs in the tab bar
+and to bind mouse events to the commands."
+  (tab-bar-make-keymap-1))
 
 
 (defcustom tab-bar-show t
@@ -610,19 +664,12 @@ You can hide these buttons by customizing 
`tab-bar-format' and removing
      `((,(intern (format "tab-%i" i))
         menu-item
         ,(funcall tab-bar-tab-name-format-function tab i)
-        ,(or
-          (alist-get 'binding tab)
-          `(lambda ()
-             (interactive)
-             (tab-bar-select-tab ,i)))
+        ,(alist-get 'binding tab)
         :help "Click to visit tab"))))
-   `((,(if (eq (car tab) 'current-tab) 'C-current-tab (intern (format 
"C-tab-%i" i)))
-      menu-item ""
-      ,(or
-        (alist-get 'close-binding tab)
-        `(lambda ()
-           (interactive)
-           (tab-bar-close-tab ,i)))))))
+   (when (alist-get 'close-binding tab)
+     `((,(if (eq (car tab) 'current-tab) 'C-current-tab (intern (format 
"C-tab-%i" i)))
+        menu-item ""
+        ,(alist-get 'close-binding tab))))))
 
 (defun tab-bar-format-tabs ()
   (let ((i 0))
@@ -762,9 +809,7 @@ on the tab bar instead."
 
 (defun tab-bar-make-keymap-1 ()
   "Generate an actual keymap from `tab-bar-map', without caching."
-  (append
-   '(keymap (mouse-1 . tab-bar-handle-mouse))
-   (tab-bar-format-list tab-bar-format)))
+  (append tab-bar-map (tab-bar-format-list tab-bar-format)))
 
 
 ;; Some window-configuration parameters don't need to be persistent.
@@ -868,11 +913,13 @@ ARG counts from 1.  Negative ARG counts tabs from the end 
of the tab bar."
     (let ((key (event-basic-type last-command-event)))
       (setq arg (if (and (characterp key) (>= key ?1) (<= key ?9))
                     (- key ?0)
-                  1))))
+                  0))))
 
   (let* ((tabs (funcall tab-bar-tabs-function))
          (from-index (tab-bar--current-tab-index tabs))
-         (to-index (if (< arg 0) (+ (length tabs) (1+ arg)) arg))
+         (to-index (cond ((< arg 0) (+ (length tabs) (1+ arg)))
+                         ((zerop arg) (1+ from-index))
+                         (t arg)))
          (to-index (1- (max 1 (min to-index (length tabs))))))
 
     (unless (eq from-index to-index)
@@ -1016,6 +1063,12 @@ where argument addressing is absolute."
          (to-index (mod (+ from-index arg) (length tabs))))
     (tab-bar-move-tab-to (1+ to-index) (1+ from-index))))
 
+(defun tab-bar-move-tab-backward (&optional arg)
+  "Move the current tab ARG positions to the left.
+Like `tab-bar-move-tab', but moves in the opposite direction."
+  (interactive "p")
+  (tab-bar-move-tab (- (or arg 1))))
+
 (defun tab-bar-move-tab-to-frame (arg &optional from-frame from-index to-frame 
to-index)
   "Move tab from FROM-INDEX position to new position at TO-INDEX.
 FROM-INDEX defaults to the current tab index.
@@ -2080,11 +2133,8 @@ Used in `repeat-mode'.")
 
 (defvar tab-bar-move-repeat-map
   (let ((map (make-sparse-keymap)))
-    (define-key map "m" 'tab-move)
-    (define-key map "M" (lambda ()
-                          (interactive)
-                          (setq repeat-map 'tab-bar-move-repeat-map)
-                          (tab-move -1)))
+    (define-key map "m" 'tab-bar-move-tab)
+    (define-key map "M" 'tab-bar-move-tab-backward)
     map)
   "Keymap to repeat tab move key sequences `C-x t m m M'.
 Used in `repeat-mode'.")
diff --git a/src/dispextern.h b/src/dispextern.h
index 33fcaa4..f4c7575 100644
--- a/src/dispextern.h
+++ b/src/dispextern.h
@@ -3415,8 +3415,8 @@ extern void get_glyph_string_clip_rect (struct 
glyph_string *,
                                         NativeRectangle *nr);
 extern Lisp_Object find_hot_spot (Lisp_Object, int, int);
 
-extern void handle_tab_bar_click (struct frame *,
-                                   int, int, bool, int);
+extern Lisp_Object handle_tab_bar_click (struct frame *,
+                                        int, int, bool, int);
 extern void handle_tool_bar_click (struct frame *,
                                    int, int, bool, int);
 
diff --git a/src/keyboard.c b/src/keyboard.c
index 4b0e4a1..ac8c6b0 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -5654,6 +5654,12 @@ make_lispy_event (struct input_event *event)
 
            position = make_lispy_position (f, event->x, event->y,
                                            event->timestamp);
+
+           if (CONSP (event->arg) && EQ (XCAR (event->arg), Qtab_bar))
+             {
+               XSETCAR (XCDR (position), Qtab_bar);
+               position = nconc2 (position, Fcons (XCDR (event->arg), Qnil));
+             }
          }
 #ifndef USE_TOOLKIT_SCROLL_BARS
        else
diff --git a/src/menu.c b/src/menu.c
index d43360e..1aafa78 100644
--- a/src/menu.c
+++ b/src/menu.c
@@ -1127,9 +1127,12 @@ x_popup_menu_1 (Lisp_Object position, Lisp_Object menu)
 
     /* Decode the first argument: find the window and the coordinates.  */
     if (EQ (position, Qt)
-       || (CONSP (position) && (EQ (XCAR (position), Qmenu_bar)
-                                || EQ (XCAR (position), Qtab_bar)
-                                || EQ (XCAR (position), Qtool_bar))))
+       || (CONSP (position)
+           && (EQ (XCAR (position), Qmenu_bar)
+               || EQ (XCAR (position), Qtab_bar)
+               || (CONSP (XCDR (position))
+                   && EQ (XCAR (XCDR (position)), Qtab_bar))
+               || EQ (XCAR (position), Qtool_bar))))
       {
        get_current_pos_p = 1;
       }
diff --git a/src/term.c b/src/term.c
index 6651b96..7d9fe8c 100644
--- a/src/term.c
+++ b/src/term.c
@@ -2575,21 +2575,8 @@ handle_one_term_event (struct tty_display_info *tty, 
Gpm_Event *event)
     {
       f->mouse_moved = 0;
       term_mouse_click (&ie, event, f);
-      /* eassert (ie.kind == MOUSE_CLICK_EVENT); */
-      if (tty_handle_tab_bar_click (f, event->x, event->y,
-                                    (ie.modifiers & down_modifier) != 0, &ie))
-        {
-          /* eassert (ie.kind == MOUSE_CLICK_EVENT
-           *          || ie.kind == TAB_BAR_EVENT); */
-          /* tty_handle_tab_bar_click stores 2 events in the event
-             queue, so we are done here.  */
-          /* FIXME: Actually, `tty_handle_tab_bar_click` returns true
-             without storing any events, when
-             (ie.modifiers & down_modifier) != 0  */
-          count += 2;
-          return count;
-        }
-      /* eassert (ie.kind == MOUSE_CLICK_EVENT); */
+      ie.arg = tty_handle_tab_bar_click (f, event->x, event->y,
+                                        (ie.modifiers & down_modifier) != 0, 
&ie);
       kbd_buffer_store_event (&ie);
       count++;
     }
diff --git a/src/termchar.h b/src/termchar.h
index f50c1bf..7ab9337 100644
--- a/src/termchar.h
+++ b/src/termchar.h
@@ -234,7 +234,7 @@ extern struct tty_display_info *tty_list;
 #define CURTTY() FRAME_TTY (SELECTED_FRAME())
 
 struct input_event;
-extern bool tty_handle_tab_bar_click (struct frame *, int, int, bool,
-                                     struct input_event *);
+extern Lisp_Object tty_handle_tab_bar_click (struct frame *, int, int, bool,
+                                            struct input_event *);
 
 #endif /* EMACS_TERMCHAR_H */
diff --git a/src/w32inevt.c b/src/w32inevt.c
index 1255072..9a69b32 100644
--- a/src/w32inevt.c
+++ b/src/w32inevt.c
@@ -586,9 +586,8 @@ do_mouse_event (MOUSE_EVENT_RECORD *event,
       int x = event->dwMousePosition.X;
       int y = event->dwMousePosition.Y;
       struct frame *f = get_frame ();
-      if (tty_handle_tab_bar_click (f, x, y, (button_state & mask) != 0,
-                                   emacs_ev))
-       return 0;       /* tty_handle_tab_bar_click adds the event to queue */
+      emacs_ev->arg = tty_handle_tab_bar_click (f, x, y, (button_state & mask) 
!= 0,
+                                               emacs_ev);
 
       emacs_ev->modifiers |= ((button_state & mask)
                              ? down_modifier : up_modifier);
@@ -597,7 +596,6 @@ do_mouse_event (MOUSE_EVENT_RECORD *event,
       XSETFASTINT (emacs_ev->x, x);
       XSETFASTINT (emacs_ev->y, y);
       XSETFRAME (emacs_ev->frame_or_window, f);
-      emacs_ev->arg = Qnil;
 
       return 1;
     }
diff --git a/src/w32term.c b/src/w32term.c
index ebd6723..9ee3b1e 100644
--- a/src/w32term.c
+++ b/src/w32term.c
@@ -168,8 +168,8 @@ int w32_keyboard_codepage;
 int w32_message_fd = -1;
 #endif /* CYGWIN */
 
-static void w32_handle_tab_bar_click (struct frame *,
-                                      struct input_event *);
+static Lisp_Object w32_handle_tab_bar_click (struct frame *,
+                                            struct input_event *);
 static void w32_handle_tool_bar_click (struct frame *,
                                        struct input_event *);
 static void w32_define_cursor (Window, Emacs_Cursor);
@@ -3687,17 +3687,17 @@ w32_mouse_position (struct frame **fp, int insist, 
Lisp_Object *bar_window,
    frame-relative coordinates X/Y.  EVENT_TYPE is either ButtonPress
    or ButtonRelease.  */
 
-static void
+static Lisp_Object
 w32_handle_tab_bar_click (struct frame *f, struct input_event *button_event)
 {
   int x = XFIXNAT (button_event->x);
   int y = XFIXNAT (button_event->y);
 
   if (button_event->modifiers & down_modifier)
-    handle_tab_bar_click (f, x, y, 1, 0);
+    return handle_tab_bar_click (f, x, y, 1, 0);
   else
-    handle_tab_bar_click (f, x, y, 0,
-                          button_event->modifiers & ~up_modifier);
+    return handle_tab_bar_click (f, x, y, 0,
+                                button_event->modifiers & ~up_modifier);
 }
 
 
@@ -5189,6 +5189,7 @@ w32_read_socket (struct terminal *terminal,
          {
             /* If we decide we want to generate an event to be seen
                by the rest of Emacs, we put it here.  */
+           Lisp_Object tab_bar_arg = Qnil;
            bool tab_bar_p = 0;
            bool tool_bar_p = 0;
            int button = 0;
@@ -5211,12 +5212,12 @@ w32_read_socket (struct terminal *terminal,
 
                     if (EQ (window, f->tab_bar_window))
                       {
-                        w32_handle_tab_bar_click (f, &inev);
+                        tab_bar_arg = w32_handle_tab_bar_click (f, &inev);
                         tab_bar_p = 1;
                       }
                   }
 
-                if (tab_bar_p
+                if ((tab_bar_p && NILP (tab_bar_arg))
                    || (dpyinfo->w32_focus_frame
                        && f != dpyinfo->w32_focus_frame
                        /* This does not help when the click happens in
@@ -5224,6 +5225,9 @@ w32_read_socket (struct terminal *terminal,
                        && !frame_ancestor_p (f, dpyinfo->w32_focus_frame)))
                  inev.kind = NO_EVENT;
 
+                 if (!NILP (tab_bar_arg))
+                   inev.arg = tab_bar_arg;
+
                 /* Is this in the tool-bar?  */
                 if (WINDOWP (f->tool_bar_window)
                     && WINDOW_TOTAL_LINES (XWINDOW (f->tool_bar_window)))
diff --git a/src/xdisp.c b/src/xdisp.c
index b2fcc16..45c7090 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -13759,7 +13759,7 @@ get_tab_bar_item (struct frame *f, int x, int y, struct 
glyph **glyph,
    false for button release.  MODIFIERS is event modifiers for button
    release.  */
 
-void
+Lisp_Object
 handle_tab_bar_click (struct frame *f, int x, int y, bool down_p,
                      int modifiers)
 {
@@ -13773,16 +13773,13 @@ 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
-      /* If the button is released on a tab other than the one where
-        it was pressed, don't generate the tab-bar button click event.  */
-      || (ts != 0 && !down_p))
-    return;
+  if (ts == -1)
+    return Qnil;
 
   /* If item is disabled, do nothing.  */
   enabled_p = AREF (f->tab_bar_items, prop_idx + TAB_BAR_ITEM_ENABLED_P);
   if (NILP (enabled_p))
-    return;
+    return Qnil;
 
   if (down_p)
     {
@@ -13793,24 +13790,24 @@ handle_tab_bar_click (struct frame *f, int x, int y, 
bool down_p,
     }
   else
     {
-      Lisp_Object key, frame;
-      struct input_event event;
-      EVENT_INIT (event);
-
       /* Show item in released state.  */
       if (!NILP (Vmouse_highlight))
        show_mouse_face (hlinfo, DRAW_IMAGE_RAISED);
-
-      key = AREF (f->tab_bar_items, prop_idx + TAB_BAR_ITEM_KEY);
-
-      XSETFRAME (frame, f);
-      event.kind = TAB_BAR_EVENT;
-      event.frame_or_window = frame;
-      event.arg = key;
-      event.modifiers = close_p ? ctrl_modifier | modifiers : modifiers;
-      kbd_buffer_store_event (&event);
       f->last_tab_bar_item = -1;
     }
+
+  Lisp_Object caption =
+    Fcopy_sequence (AREF (f->tab_bar_items, prop_idx + TAB_BAR_ITEM_CAPTION));
+
+  AUTO_LIST2 (props, Qmenu_item,
+             list3 (AREF (f->tab_bar_items, prop_idx + TAB_BAR_ITEM_KEY),
+                    AREF (f->tab_bar_items, prop_idx + TAB_BAR_ITEM_BINDING),
+                    close_p ? Qt : Qnil));
+
+  Fadd_text_properties (make_fixnum (0), make_fixnum (SCHARS (caption)),
+                       props, caption);
+
+  return Fcons (Qtab_bar, Fcons (caption, make_fixnum (0)));
 }
 
 
@@ -13908,7 +13905,7 @@ note_tab_bar_highlight (struct frame *f, int x, int y)
 
 /* Find the tab-bar item at X coordinate and return its information.  */
 static Lisp_Object
-tty_get_tab_bar_item (struct frame *f, int x, int *idx, ptrdiff_t *end)
+tty_get_tab_bar_item (struct frame *f, int x, int *prop_idx, bool *close_p)
 {
   ptrdiff_t clen = 0;
 
@@ -13921,8 +13918,11 @@ tty_get_tab_bar_item (struct frame *f, int x, int 
*idx, ptrdiff_t *end)
       clen += SCHARS (caption);
       if (x < clen)
        {
-         *idx = i;
-         *end = clen;
+         *prop_idx = i;
+         *close_p = !NILP (Fget_text_property (make_fixnum (SCHARS (caption)
+                                                            - (clen - x)),
+                                               Qclose_tab,
+                                               caption));
          return caption;
        }
     }
@@ -13934,61 +13934,45 @@ tty_get_tab_bar_item (struct frame *f, int x, int 
*idx, ptrdiff_t *end)
    structure, store it in keyboard queue, and return true; otherwise
    return false.  MODIFIERS are event modifiers for generating the tab
    release event.  */
-bool
+Lisp_Object
 tty_handle_tab_bar_click (struct frame *f, int x, int y, bool down_p,
                          struct input_event *event)
 {
   /* Did they click on the tab bar?  */
   if (y < FRAME_MENU_BAR_LINES (f)
       || y >= FRAME_MENU_BAR_LINES (f) + FRAME_TAB_BAR_LINES (f))
-    return false;
+    return Qnil;
 
   /* Find the tab-bar item where the X,Y coordinates belong.  */
   int prop_idx;
-  ptrdiff_t clen;
-  Lisp_Object caption = tty_get_tab_bar_item (f, x, &prop_idx, &clen);
+  bool close_p;
+  Lisp_Object caption = tty_get_tab_bar_item (f, x, &prop_idx, &close_p);
 
   if (NILP (caption))
-    return false;
+    return Qnil;
 
   if (NILP (AREF (f->tab_bar_items,
                  prop_idx * TAB_BAR_ITEM_NSLOTS + TAB_BAR_ITEM_ENABLED_P)))
-    return false;
+    return Qnil;
 
   if (down_p)
     f->last_tab_bar_item = prop_idx;
   else
-    {
-      /* Force reset of up_modifier bit from the event modifiers.  */
-      if (event->modifiers & up_modifier)
-        event->modifiers &= ~up_modifier;
-
-      /* Generate a TAB_BAR_EVENT event.  */
-      Lisp_Object frame;
-      Lisp_Object key = AREF (f->tab_bar_items,
-                             prop_idx * TAB_BAR_ITEM_NSLOTS
-                             + TAB_BAR_ITEM_KEY);
-      /* Kludge alert: we assume the last two characters of a tab
-        label are " x", and treat clicks on those 2 characters as a
-        Close Tab command.  */
-      eassert (STRINGP (caption));
-      int lastc = SSDATA (caption)[SCHARS (caption) - 1];
-      bool close_p = false;
-      if ((x == clen - 1 || (clen > 1 && x == clen - 2)) && lastc == 'x')
-       close_p = true;
-
-      event->code = 0;
-      XSETFRAME (frame, f);
-      event->kind = TAB_BAR_EVENT;
-      event->frame_or_window = frame;
-      event->arg = key;
-      if (close_p)
-       event->modifiers |= ctrl_modifier;
-      kbd_buffer_store_event (event);
-      f->last_tab_bar_item = -1;
-    }
+    f->last_tab_bar_item = -1;
 
-  return true;
+  caption = Fcopy_sequence (caption);
+
+  AUTO_LIST2 (props, Qmenu_item,
+             list3 (AREF (f->tab_bar_items, prop_idx * TAB_BAR_ITEM_NSLOTS
+                          + TAB_BAR_ITEM_KEY),
+                    AREF (f->tab_bar_items, prop_idx * TAB_BAR_ITEM_NSLOTS
+                          + TAB_BAR_ITEM_BINDING),
+                    close_p ? Qt : Qnil));
+
+  Fadd_text_properties (make_fixnum (0), make_fixnum (SCHARS (caption)),
+                       props, caption);
+
+  return Fcons (Qtab_bar, Fcons (caption, make_fixnum (0)));
 }
 
 
@@ -33569,7 +33553,7 @@ note_mouse_highlight (struct frame *f, int x, int y)
          && y < FRAME_MENU_BAR_LINES (f) + FRAME_TAB_BAR_LINES (f)))
     {
       int prop_idx;
-      ptrdiff_t ignore;
+      bool ignore;
       Lisp_Object caption = tty_get_tab_bar_item (f, x, &prop_idx, &ignore);
 
       if (!NILP (caption))
diff --git a/src/xterm.c b/src/xterm.c
index b478eff..4c1754a 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -9169,6 +9169,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
       {
         /* If we decide we want to generate an event to be seen
            by the rest of Emacs, we put it here.  */
+        Lisp_Object tab_bar_arg = Qnil;
         bool tab_bar_p = false;
         bool tool_bar_p = false;
 
@@ -9217,8 +9218,8 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                 window = window_from_coordinates (f, x, y, 0, true, true);
                 tab_bar_p = EQ (window, f->tab_bar_window);
 
-                if (tab_bar_p && event->xbutton.button < 4)
-                 handle_tab_bar_click
+                if (tab_bar_p)
+                 tab_bar_arg = handle_tab_bar_click
                    (f, x, y, event->xbutton.type == ButtonPress,
                     x_x_to_emacs_modifiers (dpyinfo, event->xbutton.state));
               }
@@ -9242,7 +9243,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
               }
 #endif /* !USE_GTK */
 
-            if (!tab_bar_p && !tool_bar_p)
+            if (!(tab_bar_p && NILP (tab_bar_arg)) && !tool_bar_p)
 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
               if (! popup_activated ())
 #endif
@@ -9260,6 +9261,9 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                     }
                   else
                     x_construct_mouse_click (&inev.ie, &event->xbutton, f);
+
+                 if (!NILP (tab_bar_arg))
+                   inev.ie.arg = tab_bar_arg;
                 }
             if (FRAME_X_EMBEDDED_P (f))
               xembed_send_message (f, event->xbutton.time,



reply via email to

[Prev in Thread] Current Thread [Next in Thread]