1
0
mirror of https://git.savannah.gnu.org/git/emacs.git synced 2024-11-22 07:09:54 +00:00

Allow interacting with the tab line from a touch screen

* doc/emacs/frames.texi (Tab Bars): Explain how to interact with
the tab bar from a touch screen.
* doc/emacs/input.texi (Touchscreens): Document exactly what a
``long press'' is.
* doc/emacs/windows.texi (Tab Line): Likewise.
* lisp/tab-line.el (tab-line-tab-map, tab-line-add-map)
(tab-line-tab-close-map, tab-line-left-map, tab-line-right-map):
Bind `touchscreen-begin' to each command.
(tab-line-track-tap, tab-line-event-start): New functions.
(tab-line-hscroll-right, tab-line-hscroll-left, tab-line-new-tab)
(tab-line-select-tab, tab-line-close-tab): Use them.
This commit is contained in:
Po Lu 2023-05-18 16:09:00 +08:00
parent 074c0268fd
commit fdc0bf25b2
4 changed files with 138 additions and 64 deletions

View File

@ -1571,6 +1571,15 @@ the items that operate on the clicked tab. Dragging the tab with
wheel scrolling switches to the next or previous tab. Holding down
the @key{SHIFT} key during scrolling moves the tab to the left or right.
Touch screen input (@pxref{Other Input Devices}) can also be used to
operate on tabs. Long-pressing (@pxref{Touchscreens}) a tab will
display a context menu with items that operate on the tab that was
pressed, and long-pressing the tab bar itself will display a context
menu which lets you create and remove tabs; tapping a tab itself will
result in that tab's window configuration being selected, and tapping
a button on the tab bar will behave as if it was clicked with
@kbd{mouse-1}.
@findex tab-bar-history-mode
You can enable @code{tab-bar-history-mode} to remember window
configurations used in every tab, and later restore them.

View File

@ -51,17 +51,20 @@ window horizontally to follow (@pxref{Horizontal Scrolling}.)
@item
@cindex dragging, touchscreens
``Dragging'', meaning to place a tool on the display and leave it
there for a while before moving the tool around, will make Emacs set
the point to where the tool was and begin selecting text under the
tool as it moves around, much like what would happen if @code{mouse-1}
were to be held down. @xref{Mouse Commands}.
@cindex long-press, touchscreens
``Dragging'', meaning to perform a @dfn{long-press} (placing a tool
on the display and leaving it there for a while) before moving the
tool around, will make Emacs set the point to where the tool was and
begin selecting text under the tool as it moves around, much like what
would happen if @code{mouse-1} were to be held down. @xref{Mouse
Commands}.
@end itemize
@vindex touch-screen-delay
By default, Emacs considers a tool as having been left on the
display for a while after 0.7 seconds, but this can be changed by
customizing the variable @code{touch-screen-delay}.
display long enough to trigger a ``long-press'' after 0.7 seconds, but
this can be changed by customizing the variable
@code{touch-screen-delay}.
@node On-Screen Keyboards
@section Using Emacs with virtual keyboards

View File

@ -642,6 +642,13 @@ to the window-local tab line of buffers, and clicking on the @kbd{x}
icon of a tab deletes it. The mouse wheel on the tab line scrolls
the tabs horizontally.
Touch screen input (@pxref{Other Input Devices}) can also be used to
interact with the ``tab line''. Long-pressing (@pxref{Touchscreens})
a tab will display a context menu with items that operate on the tab
that was pressed; tapping a tab itself will result in switching to
that tab's buffer, and tapping a button on the tab line will behave as
if it was clicked with @kbd{mouse-1}.
Selecting the previous window-local tab is the same as typing @kbd{C-x
@key{LEFT}} (@code{previous-buffer}), selecting the next tab is the
same as @kbd{C-x @key{RIGHT}} (@code{next-buffer}). Both commands

View File

@ -137,33 +137,38 @@ function `tab-line-tab-face-group'."
(defvar-keymap tab-line-tab-map
:doc "Local keymap for `tab-line-mode' window tabs."
"<tab-line> <down-mouse-1>" #'tab-line-select-tab
"<tab-line> <mouse-2>" #'tab-line-close-tab
"<tab-line> <down-mouse-3>" #'tab-line-tab-context-menu
"<tab-line> <down-mouse-1>" #'tab-line-select-tab
"<tab-line> <mouse-2>" #'tab-line-close-tab
"<tab-line> <down-mouse-3>" #'tab-line-tab-context-menu
"<tab-line> <touchscreen-begin>" #'tab-line-select-tab
"RET" #'tab-line-select-tab)
(defvar-keymap tab-line-add-map
:doc "Local keymap to add `tab-line-mode' window tabs."
"<tab-line> <down-mouse-1>" #'tab-line-new-tab
"<tab-line> <down-mouse-2>" #'tab-line-new-tab
"<tab-line> <down-mouse-1>" #'tab-line-new-tab
"<tab-line> <down-mouse-2>" #'tab-line-new-tab
"<tab-line> <touchscreen-begin>" #'tab-line-new-tab
"RET" #'tab-line-new-tab)
(defvar-keymap tab-line-tab-close-map
:doc "Local keymap to close `tab-line-mode' window tabs."
"<tab-line> <mouse-1>" #'tab-line-close-tab
"<tab-line> <mouse-2>" #'tab-line-close-tab)
"<tab-line> <mouse-1>" #'tab-line-close-tab
"<tab-line> <mouse-2>" #'tab-line-close-tab
"<tab-line> <touchscreen-begin>" #'tab-line-close-tab)
(defvar-keymap tab-line-left-map
:doc "Local keymap to scroll `tab-line-mode' window tabs to the left."
"<tab-line> <down-mouse-1>" #'tab-line-hscroll-left
"<tab-line> <down-mouse-2>" #'tab-line-hscroll-left
"RET" #'tab-line-new-tab)
"<tab-line> <down-mouse-1>" #'tab-line-hscroll-left
"<tab-line> <down-mouse-2>" #'tab-line-hscroll-left
"<tab-line> <touchscreen-begin>" #'tab-line-hscroll-left
"RET" #'tab-line-new-tab)
(defvar-keymap tab-line-right-map
:doc "Local keymap to scroll `tab-line-mode' window tabs to the right."
"<tab-line> <down-mouse-1>" #'tab-line-hscroll-right
"<tab-line> <down-mouse-2>" #'tab-line-hscroll-right
"RET" #'tab-line-new-tab)
"<tab-line> <down-mouse-1>" #'tab-line-hscroll-right
"<tab-line> <down-mouse-2>" #'tab-line-hscroll-right
"<tab-line> <touchscreen-begin>" #'tab-line-hscroll-right
"RET" #'tab-line-new-tab)
(defcustom tab-line-new-tab-choice t
@ -326,6 +331,48 @@ or by `tab-line-tabs-buffer-groups'."
"Function to return a global list of buffers.
Used only for `tab-line-tabs-mode-buffers' and `tab-line-tabs-buffer-groups'.")
;;; Touch screen support.
(defun tab-line-track-tap (event &optional function)
"Track a tap starting from EVENT.
If EVENT is not a `touchscreen-begin' event, return t.
Otherwise, return t if the tap completes successfully, and nil if
the tap should be ignored.
If FUNCTION is specified and the tap does not complete within
`touch-screen-delay' seconds, display the appropriate context
menu by calling FUNCTION with EVENT, and return nil."
(if (not (eq (car-safe event) 'touchscreen-begin))
t
(let ((result (catch 'context-menu
(let (timer)
(unwind-protect
(progn
(when function
(setq timer
(run-at-time touch-screen-delay t
#'throw 'context-menu
'context-menu)))
(touch-screen-track-tap event))
(when timer
(cancel-timer timer)))))))
(cond ((eq result 'context-menu)
(prog1 nil
(funcall function event)))
(result t)))))
(defun tab-line-event-start (event)
"Like `event-start'.
However, return the correct mouse position list if EVENT is a
`touchscreen-begin' event."
(or (and (eq (car-safe event) 'touchscreen-begin)
(cdadr event))
(event-start event)))
(defun tab-line-tabs-buffer-list ()
(seq-filter (lambda (b) (and (buffer-live-p b)
(/= (aref (buffer-name b) 0) ?\s)))
@ -719,17 +766,21 @@ the selected tab visible."
"Scroll the tab line ARG positions to the right.
Interactively, ARG is the prefix numeric argument and defaults to 1."
(interactive (list current-prefix-arg last-nonmenu-event))
(let ((window (and (listp event) (posn-window (event-start event)))))
(tab-line-hscroll arg window)
(force-mode-line-update window)))
(when (tab-line-track-tap event)
(let ((window (and (listp event)
(posn-window (tab-line-event-start event)))))
(tab-line-hscroll arg window)
(force-mode-line-update window))))
(defun tab-line-hscroll-left (&optional arg event)
"Scroll the tab line ARG positions to the left.
Interactively, ARG is the prefix numeric argument and defaults to 1."
(interactive (list current-prefix-arg last-nonmenu-event))
(let ((window (and (listp event) (posn-window (event-start event)))))
(tab-line-hscroll (- (or arg 1)) window)
(force-mode-line-update window)))
(when (tab-line-track-tap event)
(let ((window (and (listp event)
(posn-window (tab-line-event-start event)))))
(tab-line-hscroll (- (or arg 1)) window)
(force-mode-line-update window))))
(defun tab-line-new-tab (&optional event)
@ -738,15 +789,16 @@ This command is usually invoked by clicking on the plus-shaped button
on the tab line. Switching to another buffer also adds a new tab
corresponding to the new buffer shown in the window."
(interactive (list last-nonmenu-event))
(if (functionp tab-line-new-tab-choice)
(funcall tab-line-new-tab-choice)
(let ((tab-line-tabs-buffer-groups mouse-buffer-menu-mode-groups))
(if (and (listp event)
(display-popup-menus-p)
(not tty-menu-open-use-tmm))
(mouse-buffer-menu event) ; like (buffer-menu-open)
;; tty menu doesn't support mouse clicks, so use tmm
(tmm-prompt (mouse-buffer-menu-keymap))))))
(when (tab-line-track-tap event)
(if (functionp tab-line-new-tab-choice)
(funcall tab-line-new-tab-choice)
(let ((tab-line-tabs-buffer-groups mouse-buffer-menu-mode-groups))
(if (and (listp event)
(display-popup-menus-p)
(not tty-menu-open-use-tmm))
(mouse-buffer-menu event) ; like (buffer-menu-open)
;; tty menu doesn't support mouse clicks, so use tmm
(tmm-prompt (mouse-buffer-menu-keymap)))))))
(defun tab-line-select-tab (&optional event)
"Switch to the buffer specified by the tab on which you click.
@ -754,16 +806,17 @@ This command maintains the original order of prev/next buffers.
So, for example, switching to a previous tab is equivalent to
using the `previous-buffer' command."
(interactive "e")
(let* ((posnp (event-start event))
(tab (tab-line--get-tab-property 'tab (car (posn-string posnp))))
(buffer (if (bufferp tab) tab (cdr (assq 'buffer tab)))))
(if buffer
(tab-line-select-tab-buffer buffer (posn-window posnp))
(let ((select (cdr (assq 'select tab))))
(when (functionp select)
(with-selected-window (posn-window posnp)
(funcall select)
(force-mode-line-update)))))))
(when (tab-line-track-tap event #'tab-line-tab-context-menu)
(let* ((posnp (tab-line-event-start event))
(tab (tab-line--get-tab-property 'tab (car (posn-string posnp))))
(buffer (if (bufferp tab) tab (cdr (assq 'buffer tab)))))
(if buffer
(tab-line-select-tab-buffer buffer (posn-window posnp))
(let ((select (cdr (assq 'select tab))))
(when (functionp select)
(with-selected-window (posn-window posnp)
(funcall select)
(force-mode-line-update))))))))
(defun tab-line-select-tab-buffer (buffer &optional window)
(let* ((window-buffer (window-buffer window))
@ -869,25 +922,27 @@ This command is usually invoked by clicking on the close button on the
right side of the tab. This command buries the buffer, so it goes out of
sight of the tab line."
(interactive (list last-nonmenu-event))
(let* ((posnp (and (listp event) (event-start event)))
(window (and posnp (posn-window posnp)))
(tab (tab-line--get-tab-property 'tab (car (posn-string posnp))))
(buffer (if (bufferp tab) tab (cdr (assq 'buffer tab))))
(close-function (unless (bufferp tab) (cdr (assq 'close tab)))))
(with-selected-window (or window (selected-window))
(cond
((functionp close-function)
(funcall close-function))
((eq tab-line-close-tab-function 'kill-buffer)
(kill-buffer buffer))
((eq tab-line-close-tab-function 'bury-buffer)
(if (eq buffer (current-buffer))
(bury-buffer)
(set-window-prev-buffers nil (assq-delete-all buffer (window-prev-buffers)))
(set-window-next-buffers nil (delq buffer (window-next-buffers)))))
((functionp tab-line-close-tab-function)
(funcall tab-line-close-tab-function tab)))
(force-mode-line-update))))
(when (tab-line-track-tap event)
(let* ((posnp (and (listp event)
(tab-line-event-start event)))
(window (and posnp (posn-window posnp)))
(tab (tab-line--get-tab-property 'tab (car (posn-string posnp))))
(buffer (if (bufferp tab) tab (cdr (assq 'buffer tab))))
(close-function (unless (bufferp tab) (cdr (assq 'close tab)))))
(with-selected-window (or window (selected-window))
(cond
((functionp close-function)
(funcall close-function))
((eq tab-line-close-tab-function 'kill-buffer)
(kill-buffer buffer))
((eq tab-line-close-tab-function 'bury-buffer)
(if (eq buffer (current-buffer))
(bury-buffer)
(set-window-prev-buffers nil (assq-delete-all buffer (window-prev-buffers)))
(set-window-next-buffers nil (delq buffer (window-next-buffers)))))
((functionp tab-line-close-tab-function)
(funcall tab-line-close-tab-function tab)))
(force-mode-line-update)))))
(defun tab-line-tab-context-menu (&optional event)
"Pop up the context menu for a tab-line tab."