From: Po Lu Date: Tue, 18 Jul 2023 01:27:27 +0000 (+0800) Subject: Expose the ``cancellation'' of touch events to Lisp X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=9ad601e7d762f47d3469692b8135cc72b8301365;p=emacs.git Expose the ``cancellation'' of touch events to Lisp * doc/lispref/commands.texi (Touchscreen Events): * etc/NEWS: Describe new event parameter `canceled'. * src/keyboard.c (make_lispy_event) : If event->modifiers, set canceled to t. * src/termhooks.h (enum event_kind): Describe meaning of modifiers in TOUCHSCREEN_END_EVENTs. * src/xfns.c (setup_xi_event_mask): Select for XI_TouchOwnership. * src/xterm.c (xi_link_touch_point): Round X and Y and clear ownership. (xi_unlink_touch_point): Return 1 if the touch point is not owned by Emacs, 2 otherwise. (handle_one_xevent): Handle XI_TouchOwnership events and report ownership correctly. * src/xterm.h (enum xi_touch_ownership): New enum. Write commentary on XI touch sequence ownership. (struct xi_touch_point_t): Use integer X and Y. New field `ownership'. Adjust for alignment. --- diff --git a/doc/lispref/commands.texi b/doc/lispref/commands.texi index cd1745614eb..037f42124cc 100644 --- a/doc/lispref/commands.texi +++ b/doc/lispref/commands.texi @@ -2018,10 +2018,15 @@ position. @var{points} is a list of touch points containing the up-to-date positions of each touch point currently on the touchscreen. @cindex @code{touchscreen-end} event -@item (touchscreen-end @var{point}) +@item (touchscreen-end @var{point} @var{canceled}) This event is sent when @var{point} is no longer present on the display, because another program took the grab, or because the user raised the finger from the touchscreen. + +@var{canceled} is non-@code{nil} if the touch sequence has been +intercepted by another program (such as the window manager), and Emacs +should undo or avoid any editing commands that would otherwise result +from the touch sequence. @end table @node Focus Events diff --git a/etc/NEWS b/etc/NEWS index 3cfc36e10da..c50f560282a 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -615,6 +615,12 @@ provokes an error if used numerically. This user option names directories in which Emacs will treat all directory-local variables as safe. ++++ +** New parameter to 'touchscreen-end' events. +CANCEL non-nil establishes that the touch sequence has been +intercepted by programs such as window managers and should be ignored +with Emacs. + ** New variable 'inhibit-auto-fill' to temporarily prevent auto-fill. ** Functions and variables to transpose sexps diff --git a/src/keyboard.c b/src/keyboard.c index b61b1766856..41cda2e65de 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -6404,7 +6404,6 @@ make_lispy_event (struct input_event *event) } case TOUCHSCREEN_BEGIN_EVENT: - case TOUCHSCREEN_END_EVENT: { Lisp_Object x, y, id, position; struct frame *f = XFRAME (event->frame_or_window); @@ -6422,6 +6421,25 @@ make_lispy_event (struct input_event *event) Fcons (id, position)); } + case TOUCHSCREEN_END_EVENT: + { + Lisp_Object x, y, id, position; + struct frame *f = XFRAME (event->frame_or_window); + + id = event->arg; + x = event->x; + y = event->y; + + position = make_lispy_position (f, x, y, event->timestamp); + + return list3 (((event->kind + == TOUCHSCREEN_BEGIN_EVENT) + ? Qtouchscreen_begin + : Qtouchscreen_end), + Fcons (id, position), + event->modifiers ? Qt : Qnil); + } + case PINCH_EVENT: { Lisp_Object x, y, position; diff --git a/src/termhooks.h b/src/termhooks.h index ba04a6b7759..c8345c2715f 100644 --- a/src/termhooks.h +++ b/src/termhooks.h @@ -307,7 +307,11 @@ enum event_kind In TOUCHSCREEN_BEGIN_EVENT and TOUCHSCREEN_END_EVENT, ARG is the unique ID of the touchpoint, and X and Y are the frame-relative - positions of the touchpoint. */ + positions of the touchpoint. + + In TOUCHSCREEN_END_EVENT, non-0 modifiers means that the + touchpoint has been canceled. (See (elisp)Touchscreen + Events.) */ , TOUCHSCREEN_UPDATE_EVENT , TOUCHSCREEN_BEGIN_EVENT diff --git a/src/xfns.c b/src/xfns.c index fd4807fd5f5..55bcfb8e20e 100644 --- a/src/xfns.c +++ b/src/xfns.c @@ -4107,6 +4107,7 @@ setup_xi_event_mask (struct frame *f) XISetMask (m, XI_TouchBegin); XISetMask (m, XI_TouchUpdate); XISetMask (m, XI_TouchEnd); + XISetMask (m, XI_TouchOwnership); #if defined HAVE_XINPUT2_4 && defined USE_GTK3 if (FRAME_DISPLAY_INFO (f)->xi2_version >= 4) diff --git a/src/xterm.c b/src/xterm.c index 5cc2dfdae1d..130a2c93b64 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -5742,6 +5742,10 @@ xi_device_from_id (struct x_display_info *dpyinfo, int deviceid) #ifdef HAVE_XINPUT2_2 +/* Record a touch sequence with the identifier DETAIL from the given + FRAME on the specified DEVICE. Round X and Y and record them as + its current position. */ + static void xi_link_touch_point (struct xi_device_t *device, int detail, double x, double y, @@ -5751,19 +5755,28 @@ xi_link_touch_point (struct xi_device_t *device, touchpoint = xmalloc (sizeof *touchpoint); touchpoint->next = device->touchpoints; - touchpoint->x = x; - touchpoint->y = y; + touchpoint->x = lrint (x); + touchpoint->y = lrint (y); touchpoint->number = detail; touchpoint->frame = frame; + touchpoint->ownership = TOUCH_OWNERSHIP_NONE; device->touchpoints = touchpoint; } -static bool -xi_unlink_touch_point (int detail, - struct xi_device_t *device) +/* Free and remove the touch sequence with the identifier DETAIL. + DEVICE is the device in which the touch sequence should be + recorded. + + Value is 0 if no touch sequence by that identifier exists inside + DEVICE, 1 if a touch sequence has been found but is not owned by + Emacs, and 2 otherwise. */ + +static int +xi_unlink_touch_point (int detail, struct xi_device_t *device) { struct xi_touch_point_t *last, *tem; + enum xi_touch_ownership ownership; for (last = NULL, tem = device->touchpoints; tem; last = tem, tem = tem->next) @@ -5775,12 +5788,17 @@ xi_unlink_touch_point (int detail, else last->next = tem->next; + ownership = tem->ownership; xfree (tem); - return true; + + if (ownership == TOUCH_OWNERSHIP_SELF) + return 2; + + return 1; } } - return false; + return 0; } /* Unlink all touch points associated with the frame F. @@ -5813,6 +5831,10 @@ xi_unlink_touch_points (struct frame *f) } } +/* Return the data associated with a touch sequence DETAIL recorded by + `xi_link_touch_point' from DEVICE, or NULL if it can't be + found. */ + static struct xi_touch_point_t * xi_find_touch_point (struct xi_device_t *device, int detail) { @@ -24422,12 +24444,48 @@ handle_one_xevent (struct x_display_info *dpyinfo, goto XI_OTHER; } + case XI_TouchOwnership: + { + struct xi_device_t *device; + struct xi_touch_point_t *touchpoint; + XITouchOwnershipEvent *event; + + /* All grabbing clients have decided to reject ownership + of this touch sequence. */ + + event = (XITouchOwnershipEvent *) xi_event; + device = xi_device_from_id (dpyinfo, event->deviceid); + + if (!device || device->use == XIMasterPointer) + goto XI_OTHER; + + touchpoint = xi_find_touch_point (device, event->touchid); + + if (!touchpoint) + goto XI_OTHER; + + /* As a result, Emacs should complete whatever editing + operations result from this touch sequence. */ + touchpoint->ownership = TOUCH_OWNERSHIP_SELF; + } + case XI_TouchUpdate: { struct xi_device_t *device, *source; struct xi_touch_point_t *touchpoint; Lisp_Object arg = Qnil; + /* If flags & TouchPendingEnd, the touch sequence has + already ended, but some grabbing clients remain + undecided as to whether they will obtain ownership of + the touch sequence. + + Wait for them to make their decision, resulting in + TouchOwnership and TouchEnd events being sent. */ + + if (xev->flags & XITouchPendingEnd) + goto XI_OTHER; + device = xi_device_from_id (dpyinfo, xev->deviceid); source = xi_device_from_id (dpyinfo, xev->sourceid); x_display_set_last_user_time (dpyinfo, xev->time, @@ -24439,7 +24497,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, detached, and master pointers may also represent dependent touch devices. */ - if (!device) + if (!device || device->use == XIMasterPointer) goto XI_OTHER; touchpoint = xi_find_touch_point (device, xev->detail); @@ -24447,12 +24505,12 @@ handle_one_xevent (struct x_display_info *dpyinfo, if (!touchpoint /* Don't send this event if nothing has changed either. */ - || (touchpoint->x == (int) xev->event_x - && touchpoint->y == (int) xev->event_y)) + || (touchpoint->x == lrint (xev->event_x) + && touchpoint->y == lrint (xev->event_y))) goto XI_OTHER; - touchpoint->x = xev->event_x; - touchpoint->y = xev->event_y; + touchpoint->x = lrint (xev->event_x); + touchpoint->y = lrint (xev->event_y); f = x_window_to_frame (dpyinfo, xev->event); @@ -24466,8 +24524,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, touchpoint; touchpoint = touchpoint->next) { if (touchpoint->frame == f) - arg = Fcons (list3i (lrint (touchpoint->x), - lrint (touchpoint->y), + arg = Fcons (list3i (touchpoint->x, touchpoint->y, lrint (touchpoint->number)), arg); } @@ -24484,7 +24541,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, case XI_TouchEnd: { struct xi_device_t *device, *source; - bool unlinked_p; + int state; device = xi_device_from_id (dpyinfo, xev->deviceid); source = xi_device_from_id (dpyinfo, xev->sourceid); @@ -24500,9 +24557,9 @@ handle_one_xevent (struct x_display_info *dpyinfo, if (!device || device->use == XIMasterPointer) goto XI_OTHER; - unlinked_p = xi_unlink_touch_point (xev->detail, device); + state = xi_unlink_touch_point (xev->detail, device); - if (unlinked_p) + if (state) { f = x_window_to_frame (dpyinfo, xev->event); @@ -24510,6 +24567,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, { inev.ie.kind = TOUCHSCREEN_END_EVENT; inev.ie.timestamp = xev->time; + inev.ie.modifiers = state != 2; XSETFRAME (inev.ie.frame_or_window, f); XSETINT (inev.ie.x, lrint (xev->event_x)); diff --git a/src/xterm.h b/src/xterm.h index 34a713ea2ca..c7db54e2bcf 100644 --- a/src/xterm.h +++ b/src/xterm.h @@ -255,19 +255,71 @@ struct xi_scroll_valuator_t #ifdef HAVE_XINPUT2_2 +/* Enum describing the ownership of a touch point. + + The input extension allows other clients to intercept touch + sequences destined for a client window through passively grabbing + for touch events on a parent window. + + When a passive touch grab for an XI_TouchBegin event activates, one + grabbing client is designated the ``owner'' of the touch sequence + started by the grabbed event. Touch events are then delivered to + both the grabbing client and other clients that have selected for + touch events on the subwindow. + + The X server will not deliver TouchEnd events to clients other than + the owner until one grabbing client decides to take over processing + the touch event sequence, or no more grabbing clients remain. + Instead, a TouchUpdate event with the TouchPendingEnd flag is sent, + and the TouchEnd event is postponed until the decision is made and + all XI_TouchOwnership events are sent. + + If the owner decides to take over processing the touch sequence, an + XI_TouchEnd event is delivered to all other clients receiving + events for the current touch sequence, who are then expected to + cancel or undo any actions which have taken place in reaction to + events from that sequence. + + If the owner decides to relinquish ownership over the touch + sequence, the X server looks for another grabbing client, and + transfers touch ownership to that client instead. Nothing changes + from the perspective of clients who have merely selected for events + from the subwindow, while an XI_TouchEnd event is delivered to the + old owner, and an XI_TouchOwnership event is delivered to the new + owner. + + If all grabbing clients reject ownership over the touch sequence, + the X server delivers an XI_TouchOwnership event to the client that + has selected for touch events on the subwindow, the only client + that will receive events for this touch sequence from this time + forward. */ + +enum xi_touch_ownership + { + /* Emacs doesn't own this touch sequence. */ + TOUCH_OWNERSHIP_NONE, + + /* Emacs owns this touch sequence. */ + TOUCH_OWNERSHIP_SELF, + }; + struct xi_touch_point_t { - /* The next touch point in this list. */ - struct xi_touch_point_t *next; - /* The touchpoint detail. */ int number; - /* The last known X and Y position of the touchpoint. */ - double x, y; + /* Whether or not Emacs has ``exclusive'' access to this touch + point. */ + enum xi_touch_ownership ownership; + + /* The last known rounded X and Y positions of the touchpoint. */ + int x, y; /* The frame associated with this touch point. */ struct frame *frame; + + /* The next touch point in this list. */ + struct xi_touch_point_t *next; }; #endif