aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPo Lu2023-05-16 15:54:50 +0800
committerPo Lu2023-05-16 15:54:50 +0800
commitbb8bf9203ed33de0bb269c8ff69067aa7b3a692a (patch)
tree9aeb35760a2997f734b3f706048e381300b514c1
parent44da7d75ed3fa6322d64d66d250bc78e91636ff5 (diff)
downloademacs-bb8bf9203ed33de0bb269c8ff69067aa7b3a692a.tar.gz
emacs-bb8bf9203ed33de0bb269c8ff69067aa7b3a692a.zip
Add touchscreen support to the tab bar
* lisp/menu-bar.el (popup-menu-normalize-position): Normalize `touchscreen-begin' events correctly. * lisp/tab-bar.el (tab-bar-mouse-context-menu): New argument POSN. Use it if specified. (touch-screen-track-tap, tab-bar-handle-timeout) (tab-bar-touchscreen-begin): New functions. (tab-bar-map): Bind [tab-bar touchscreen-begin]. * lisp/touch-screen.el (touch-screen-track-drag): Fix doc string. * src/dispextern.h: Export `get_tab_bar_item_kbd'. * src/keyboard.c (coords_in_tab_bar_window): New function. (make_lispy_event): Adjust touchscreen begin event mouse position list for tab bar. * src/xdisp.c (tab_bar_item_info): Allow CLOSE_P to be NULL. (get_tab_bar_item): Adjust doc string. (get_tab_bar_item_kbd): New function.
-rw-r--r--lisp/menu-bar.el15
-rw-r--r--lisp/tab-bar.el83
-rw-r--r--lisp/touch-screen.el2
-rw-r--r--src/dispextern.h1
-rw-r--r--src/keyboard.c71
-rw-r--r--src/xdisp.c61
6 files changed, 211 insertions, 22 deletions
diff --git a/lisp/menu-bar.el b/lisp/menu-bar.el
index 949d805465d..da002a46621 100644
--- a/lisp/menu-bar.el
+++ b/lisp/menu-bar.el
@@ -2669,20 +2669,25 @@ FROM-MENU-BAR, if non-nil, means we are dropping one of menu-bar's menus."
2669POSITION can be an event, a posn- value, a value having the 2669POSITION can be an event, a posn- value, a value having the
2670form ((XOFFSET YOFFSET) WINDOW), or nil. 2670form ((XOFFSET YOFFSET) WINDOW), or nil.
2671If nil, the current mouse position is used, or nil if there is no mouse." 2671If nil, the current mouse position is used, or nil if there is no mouse."
2672 (pcase position 2672 (cond
2673 ;; nil -> mouse cursor position 2673 ;; nil -> mouse cursor position
2674 ('nil 2674 ((eq position nil)
2675 (let ((mp (mouse-pixel-position))) 2675 (let ((mp (mouse-pixel-position)))
2676 (list (list (cadr mp) (cddr mp)) (car mp)))) 2676 (list (list (cadr mp) (cddr mp)) (car mp))))
2677 ;; Value returned from `event-end' or `posn-at-point'. 2677 ;; Value returned from `event-end' or `posn-at-point'.
2678 ((pred posnp) 2678 ((posnp position)
2679 (let ((xy (posn-x-y position))) 2679 (let ((xy (posn-x-y position)))
2680 (list (list (car xy) (cdr xy)) 2680 (list (list (car xy) (cdr xy))
2681 (posn-window position)))) 2681 (posn-window position))))
2682 ;; `touchscreen-begin' or `touchscreen-end' event.
2683 ((or (eq (car-safe position) 'touchscreen-begin)
2684 (eq (car-safe position) 'touchscreen-end))
2685 position)
2682 ;; Event. 2686 ;; Event.
2683 ((pred eventp) 2687 ((eventp position)
2684 (popup-menu-normalize-position (event-end position))) 2688 (popup-menu-normalize-position (event-end position)))
2685 (_ position))) 2689 ;; Some other value.
2690 (t position)))
2686 2691
2687(defcustom tty-menu-open-use-tmm nil 2692(defcustom tty-menu-open-use-tmm nil
2688 "If non-nil, \\[menu-bar-open] on a TTY will invoke `tmm-menubar'. 2693 "If non-nil, \\[menu-bar-open] on a TTY will invoke `tmm-menubar'.
diff --git a/lisp/tab-bar.el b/lisp/tab-bar.el
index 9d703b5d048..1a33eda0866 100644
--- a/lisp/tab-bar.el
+++ b/lisp/tab-bar.el
@@ -341,10 +341,12 @@ only when you click on its \"x\" close button."
341 (unless (eq tab-number t) 341 (unless (eq tab-number t)
342 (tab-bar-close-tab tab-number)))) 342 (tab-bar-close-tab tab-number))))
343 343
344(defun tab-bar-mouse-context-menu (event) 344(defun tab-bar-mouse-context-menu (event &optional posn)
345 "Pop up the context menu for the tab on which you click." 345 "Pop up the context menu for the tab on which you click.
346EVENT is a mouse or touch screen event. POSN is nil or the
347position of EVENT."
346 (interactive "e") 348 (interactive "e")
347 (let* ((item (tab-bar--event-to-item (event-start event))) 349 (let* ((item (tab-bar--event-to-item (or posn (event-start event))))
348 (tab-number (tab-bar--key-to-number (nth 0 item))) 350 (tab-number (tab-bar--key-to-number (nth 0 item)))
349 (menu (make-sparse-keymap (propertize "Context Menu" 'hide t)))) 351 (menu (make-sparse-keymap (propertize "Context Menu" 'hide t))))
350 352
@@ -397,6 +399,78 @@ at the mouse-down event to the position at mouse-up event."
397 (tab-bar-move-tab-to 399 (tab-bar-move-tab-to
398 (if (null to) (1+ (tab-bar--current-tab-index)) to) from)))) 400 (if (null to) (1+ (tab-bar--current-tab-index)) to) from))))
399 401
402
403
404;;; Tab bar touchscreen support.
405
406(declare-function touch-screen-track-tap "touch-screen.el")
407
408(defun tab-bar-handle-timeout ()
409 "Handle a touch-screen timeout on the tab bar.
410Beep, then throw to `context-menu' and return."
411 (beep)
412 (throw 'context-menu 'context-menu))
413
414(defun tab-bar-touchscreen-begin (event)
415 "Handle a touchscreen begin EVENT on the tab bar.
416
417Determine where the touch was made. If it was made on a tab
418itself, start a timer set to go off after a certain amount of
419time, and wait for the touch point to be released, and either
420display a context menu or select a tab as appropriate.
421
422Otherwise, if it was made on a button, close or create a tab as
423appropriate."
424 (interactive "e")
425 (let* ((posn (cdadr event))
426 (item (tab-bar--event-to-item posn))
427 (number (tab-bar--key-to-number (car item)))
428 timer)
429 (when (eq (catch 'context-menu
430 (cond ((integerp number)
431 ;; The touch began on a tab. Start a context
432 ;; menu timer and start tracking the tap.
433 (unwind-protect
434 (progn
435 (setq timer (run-at-time touch-screen-delay nil
436 #'tab-bar-handle-timeout))
437 ;; Now wait for the tap to complete.
438 (when (touch-screen-track-tap event)
439 ;; And select the tab, or close it,
440 ;; depending on whether or not the
441 ;; close button was pressed.
442 (if (caddr item)
443 (tab-bar-close-tab number)
444 (tab-bar-select-tab number))))
445 ;; Cancel the timer.
446 (cancel-timer timer)))
447 ((and (memq (car item) '(add-tab history-back
448 history-forward))
449 (functionp (cadr item)))
450 ;; This is some kind of button. Wait for the
451 ;; tap to complete and press it.
452 (when (touch-screen-track-tap event)
453 (call-interactively (cadr item))))
454 (t
455 ;; The touch began on the tab bar itself.
456 ;; Start a context menu timer and start
457 ;; tracking the tap, but don't do anything
458 ;; afterwards.
459 (unwind-protect
460 (progn
461 (setq timer (run-at-time touch-screen-delay nil
462 #'tab-bar-handle-timeout))
463 ;; Now wait for the tap to complete.
464 (touch-screen-track-tap event))
465 ;; Cancel the timer.
466 (cancel-timer timer)))))
467 'context-menu)
468 ;; Display the context menu in response to a time out waiting
469 ;; for the tap to complete.
470 (tab-bar-mouse-context-menu event posn))))
471
472
473
400(defvar-keymap tab-bar-map 474(defvar-keymap tab-bar-map
401 :doc "Keymap for the commands used on the tab bar." 475 :doc "Keymap for the commands used on the tab bar."
402 "<down-mouse-1>" #'tab-bar-mouse-down-1 476 "<down-mouse-1>" #'tab-bar-mouse-down-1
@@ -418,7 +492,8 @@ at the mouse-down event to the position at mouse-up event."
418 "S-<wheel-up>" #'tab-bar-move-tab-backward 492 "S-<wheel-up>" #'tab-bar-move-tab-backward
419 "S-<wheel-down>" #'tab-bar-move-tab 493 "S-<wheel-down>" #'tab-bar-move-tab
420 "S-<wheel-left>" #'tab-bar-move-tab-backward 494 "S-<wheel-left>" #'tab-bar-move-tab-backward
421 "S-<wheel-right>" #'tab-bar-move-tab) 495 "S-<wheel-right>" #'tab-bar-move-tab
496 "<touchscreen-begin>" #'tab-bar-touchscreen-begin)
422 497
423(global-set-key [tab-bar] 498(global-set-key [tab-bar]
424 `(menu-item ,(purecopy "tab bar") ,(make-sparse-keymap) 499 `(menu-item ,(purecopy "tab bar") ,(make-sparse-keymap)
diff --git a/lisp/touch-screen.el b/lisp/touch-screen.el
index 31d46b062ed..a7fa5b4829c 100644
--- a/lisp/touch-screen.el
+++ b/lisp/touch-screen.el
@@ -529,7 +529,7 @@ otherwise, return t once the `touchscreen-end' event arrives."
529 529
530(defun touch-screen-track-drag (event update &optional data) 530(defun touch-screen-track-drag (event update &optional data)
531 "Track a single drag starting from EVENT. 531 "Track a single drag starting from EVENT.
532EVENT should be a `touchscreen-end' event. 532EVENT should be a `touchscreen-begin' event.
533 533
534Read touch screen events until a `touchscreen-end' event is 534Read touch screen events until a `touchscreen-end' event is
535received with the same ID as in EVENT. For each 535received with the same ID as in EVENT. For each
diff --git a/src/dispextern.h b/src/dispextern.h
index 36e998070a4..402972d33d9 100644
--- a/src/dispextern.h
+++ b/src/dispextern.h
@@ -3528,6 +3528,7 @@ extern void get_glyph_string_clip_rect (struct glyph_string *,
3528 NativeRectangle *nr); 3528 NativeRectangle *nr);
3529extern Lisp_Object find_hot_spot (Lisp_Object, int, int); 3529extern Lisp_Object find_hot_spot (Lisp_Object, int, int);
3530 3530
3531extern int get_tab_bar_item_kbd (struct frame *, int, int, int *, bool *);
3531extern Lisp_Object handle_tab_bar_click (struct frame *, 3532extern Lisp_Object handle_tab_bar_click (struct frame *,
3532 int, int, bool, int); 3533 int, int, bool, int);
3533extern void handle_tool_bar_click (struct frame *, 3534extern void handle_tool_bar_click (struct frame *,
diff --git a/src/keyboard.c b/src/keyboard.c
index 6e63cd71f30..c0d201f72ad 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -5875,6 +5875,25 @@ coords_in_menu_bar_window (struct frame *f, int x, int y)
5875 5875
5876#endif 5876#endif
5877 5877
5878/* Return whether or not the coordinates X and Y are inside the
5879 tab-bar window of the given frame F. */
5880
5881static bool
5882coords_in_tab_bar_window (struct frame *f, int x, int y)
5883{
5884 struct window *window;
5885
5886 if (!WINDOWP (f->tab_bar_window))
5887 return false;
5888
5889 window = XWINDOW (f->tab_bar_window);
5890
5891 return (y >= WINDOW_TOP_EDGE_Y (window)
5892 && x >= WINDOW_LEFT_EDGE_X (window)
5893 && y <= WINDOW_BOTTOM_EDGE_Y (window)
5894 && x <= WINDOW_RIGHT_EDGE_X (window));
5895}
5896
5878/* Given a struct input_event, build the lisp event which represents 5897/* Given a struct input_event, build the lisp event which represents
5879 it. If EVENT is 0, build a mouse movement event from the mouse 5898 it. If EVENT is 0, build a mouse movement event from the mouse
5880 movement buffer, which should have a movement event in it. 5899 movement buffer, which should have a movement event in it.
@@ -6522,11 +6541,14 @@ make_lispy_event (struct input_event *event)
6522 case TOUCHSCREEN_END_EVENT: 6541 case TOUCHSCREEN_END_EVENT:
6523 { 6542 {
6524 Lisp_Object x, y, id, position; 6543 Lisp_Object x, y, id, position;
6525 struct frame *f = XFRAME (event->frame_or_window); 6544 struct frame *f;
6545 int tab_bar_item;
6546 bool close;
6526#if defined HAVE_WINDOW_SYSTEM && !defined HAVE_EXT_MENU_BAR 6547#if defined HAVE_WINDOW_SYSTEM && !defined HAVE_EXT_MENU_BAR
6527 int column, row, dummy; 6548 int column, row, dummy;
6528#endif 6549#endif /* defined HAVE_WINDOW_SYSTEM && !defined HAVE_EXT_MENU_BAR */
6529 6550
6551 f = XFRAME (event->frame_or_window);
6530 id = event->arg; 6552 id = event->arg;
6531 x = event->x; 6553 x = event->x;
6532 y = event->y; 6554 y = event->y;
@@ -6589,10 +6611,53 @@ make_lispy_event (struct input_event *event)
6589 6611
6590 return Qnil; 6612 return Qnil;
6591 } 6613 }
6592#endif 6614#endif /* defined HAVE_WINDOW_SYSTEM && !defined HAVE_EXT_MENU_BAR */
6593 6615
6594 position = make_lispy_position (f, x, y, event->timestamp); 6616 position = make_lispy_position (f, x, y, event->timestamp);
6595 6617
6618#ifdef HAVE_WINDOW_SYSTEM
6619
6620 /* Now check if POSITION lies on the tab bar. If so, look up
6621 the corresponding tab bar item's propertized string as the
6622 OBJECT. */
6623
6624 if (coords_in_tab_bar_window (f, XFIXNUM (event->x),
6625 XFIXNUM (event->y))
6626 /* `get_tab_bar_item_kbd' returns 0 if the item was
6627 previously highlighted, 1 otherwise, and -1 if there is
6628 no tab bar item. */
6629 && get_tab_bar_item_kbd (f, XFIXNUM (event->x),
6630 XFIXNUM (event->y), &tab_bar_item,
6631 &close) >= 0)
6632 {
6633 /* First, obtain the propertized string. */
6634 x = Fcopy_sequence (AREF (f->tab_bar_items,
6635 (tab_bar_item
6636 + TAB_BAR_ITEM_CAPTION)));
6637
6638 /* Next, add the key binding. */
6639 AUTO_LIST2 (y, Qmenu_item, list3 (AREF (f->tab_bar_items,
6640 (tab_bar_item
6641 + TAB_BAR_ITEM_KEY)),
6642 AREF (f->tab_bar_items,
6643 (tab_bar_item
6644 + TAB_BAR_ITEM_BINDING)),
6645 close ? Qt : Qnil));
6646
6647 /* And add the new properties to the propertized string. */
6648 Fadd_text_properties (make_fixnum (0),
6649 make_fixnum (SCHARS (x)),
6650 y, x);
6651
6652 /* Set the position to 0. */
6653 x = Fcons (x, make_fixnum (0));
6654
6655 /* Finally, add the OBJECT. */
6656 position = nconc2 (position, Fcons (x, Qnil));
6657 }
6658
6659#endif /* HAVE_WINDOW_SYSTEM */
6660
6596 return list2 (((event->kind 6661 return list2 (((event->kind
6597 == TOUCHSCREEN_BEGIN_EVENT) 6662 == TOUCHSCREEN_BEGIN_EVENT)
6598 ? Qtouchscreen_begin 6663 ? Qtouchscreen_begin
diff --git a/src/xdisp.c b/src/xdisp.c
index 89b1ae77e6f..09b1cc616f2 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -14584,21 +14584,32 @@ tab_bar_item_info (struct frame *f, struct glyph *glyph,
14584 Qmenu_item, f->current_tab_bar_string); 14584 Qmenu_item, f->current_tab_bar_string);
14585 if (! FIXNUMP (prop)) 14585 if (! FIXNUMP (prop))
14586 return false; 14586 return false;
14587
14587 *prop_idx = XFIXNUM (prop); 14588 *prop_idx = XFIXNUM (prop);
14588 14589
14589 *close_p = !NILP (Fget_text_property (make_fixnum (charpos), 14590 if (close_p)
14590 Qclose_tab, 14591 *close_p = !NILP (Fget_text_property (make_fixnum (charpos),
14591 f->current_tab_bar_string)); 14592 Qclose_tab,
14593 f->current_tab_bar_string));
14592 14594
14593 return true; 14595 return true;
14594} 14596}
14595 14597
14596 14598
14597/* Get information about the tab-bar item at position X/Y on frame F. 14599/* Get information about the tab-bar item at position X/Y on frame F's
14598 Return in *GLYPH a pointer to the glyph of the tab-bar item in 14600 tab bar window.
14599 the current matrix of the tab-bar window of F, or NULL if not 14601
14600 on a tab-bar item. Return in *PROP_IDX the index of the tab-bar 14602 Set *GLYPH to a pointer to the glyph of the tab-bar item in the
14601 item in F->tab_bar_items. Value is 14603 current matrix of the tab-bar window of F, or NULL if not on a
14604 tab-bar item. Return in *PROP_IDX the index of the tab-bar item in
14605 F->tab_bar_items.
14606
14607 Place the window-relative vpos of Y in *VPOS, and the
14608 window-relative hpos of X in *HPOS. If CLOSE_P, set it to whether
14609 or not the tab bar item represents a button that should close a
14610 tab.
14611
14612 Value is
14602 14613
14603 -1 if X/Y is not on a tab-bar item 14614 -1 if X/Y is not on a tab-bar item
14604 0 if X/Y is on the same item that was highlighted before. 14615 0 if X/Y is on the same item that was highlighted before.
@@ -14606,7 +14617,7 @@ tab_bar_item_info (struct frame *f, struct glyph *glyph,
14606 14617
14607static int 14618static int
14608get_tab_bar_item (struct frame *f, int x, int y, struct glyph **glyph, 14619get_tab_bar_item (struct frame *f, int x, int y, struct glyph **glyph,
14609 int *hpos, int *vpos, int *prop_idx, bool *close_p) 14620 int *hpos, int *vpos, int *prop_idx, bool *close_p)
14610{ 14621{
14611 struct window *w = XWINDOW (f->tab_bar_window); 14622 struct window *w = XWINDOW (f->tab_bar_window);
14612 int area; 14623 int area;
@@ -14624,6 +14635,38 @@ get_tab_bar_item (struct frame *f, int x, int y, struct glyph **glyph,
14624 return *prop_idx == f->last_tab_bar_item ? 0 : 1; 14635 return *prop_idx == f->last_tab_bar_item ? 0 : 1;
14625} 14636}
14626 14637
14638/* EXPORT:
14639
14640 Like `get_tab_bar_item'. However, don't return anything for GLYPH,
14641 HPOS, or VPOS, and treat X and Y as relative to F itself, as
14642 opposed to its tab bar window. */
14643
14644int
14645get_tab_bar_item_kbd (struct frame *f, int x, int y, int *prop_idx,
14646 bool *close_p)
14647{
14648 struct window *w;
14649 int area, vpos, hpos;
14650 struct glyph *glyph;
14651
14652 w = XWINDOW (f->tab_bar_window);
14653
14654 /* Convert X and Y to window coordinates. */
14655 frame_to_window_pixel_xy (w, &x, &y);
14656
14657 /* Find the glyph under X/Y. */
14658 glyph = x_y_to_hpos_vpos (w, x, y, &hpos, &vpos, 0,
14659 0, &area);
14660 if (glyph == NULL)
14661 return -1;
14662
14663 /* Get the start of this tab-bar item's properties in
14664 f->tab_bar_items. */
14665 if (!tab_bar_item_info (f, glyph, prop_idx, close_p))
14666 return -1;
14667
14668 return *prop_idx == f->last_tab_bar_item ? 0 : 1;
14669}
14627 14670
14628/* EXPORT: 14671/* EXPORT:
14629 Handle mouse button event on the tab-bar of frame F, at 14672 Handle mouse button event on the tab-bar of frame F, at