From: Po Lu Date: Tue, 17 Jan 2023 10:28:37 +0000 (+0800) Subject: Correctly handle touches on the tool bar X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=b9025c507a3a7dae4de19b18cafaa09b18183832;p=emacs.git Correctly handle touches on the tool bar * src/xterm.c (xi_link_touch_point): New argument `frame'. Set new field `touchpoint->frame' to it. (xi_unlink_touch_points): New function. (xi_disable_devices): Clear the tool bar device on frames whose tool bar device matches this field. (handle_one_xevent): If an XI_TouchBegin event lands on the tool bar, then simulate a pointer click. Ignore future events from that touchpoint from there onwards. (x_make_frame_invisible, x_free_frame_resources): Unlink touch points associated with the frame. * src/xterm.h (struct xi_touch_point_t): New field `frame'. (struct x_output): New fields for keeping track of tool bar touches. --- diff --git a/src/xterm.c b/src/xterm.c index 028bb7582c4..6ae7e97f45a 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -5750,7 +5750,8 @@ xi_device_from_id (struct x_display_info *dpyinfo, int deviceid) static void xi_link_touch_point (struct xi_device_t *device, - int detail, double x, double y) + int detail, double x, double y, + struct frame *frame) { struct xi_touch_point_t *touchpoint; @@ -5759,6 +5760,7 @@ xi_link_touch_point (struct xi_device_t *device, touchpoint->x = x; touchpoint->y = y; touchpoint->number = detail; + touchpoint->frame = frame; device->touchpoints = touchpoint; } @@ -5787,6 +5789,36 @@ xi_unlink_touch_point (int detail, return false; } +/* Unlink all touch points associated with the frame F. + This is done upon unmapping or destroying F's window, because + touch point delivery after that point is undefined. */ + +static void +xi_unlink_touch_points (struct frame *f) +{ + struct xi_device_t *device; + struct xi_touch_point_t **next, *last; + int i; + + for (i = 0; i < FRAME_DISPLAY_INFO (f)->num_devices; ++i) + { + device = &FRAME_DISPLAY_INFO (f)->devices[i]; + + /* Now unlink all touch points on DEVICE matching F. */ + + for (next = &device->touchpoints; (last = *next);) + { + if (last->frame == f) + { + *next = last->next; + xfree (last); + } + else + next = &last->next; + } + } +} + static struct xi_touch_point_t * xi_find_touch_point (struct xi_device_t *device, int detail) { @@ -13535,6 +13567,10 @@ xi_disable_devices (struct x_display_info *dpyinfo, #ifdef HAVE_XINPUT2_2 struct xi_touch_point_t *tem, *last; #endif +#if defined HAVE_XINPUT2_2 && !defined HAVE_EXT_TOOL_BAR + struct x_output *output; + Lisp_Object tail, frame; +#endif /* Don't pointlessly copy dpyinfo->devices if there are no devices to disable. */ @@ -13577,6 +13613,34 @@ xi_disable_devices (struct x_display_info *dpyinfo, tem = tem->next; xfree (last); } + +#ifndef HAVE_EXT_TOOL_BAR + + /* Now look through each frame on DPYINFO. If it has an + outstanding tool bar press for this device, release + the tool bar. */ + + FOR_EACH_FRAME (tail, frame) + { + if (!FRAME_X_P (XFRAME (frame)) + || (FRAME_DISPLAY_INFO (XFRAME (frame)) + != dpyinfo)) + continue; + + output = FRAME_OUTPUT_DATA (XFRAME (frame)); + + if (output->tool_bar_touch_device + == dpyinfo->devices[i].device_id) + { + if (XFRAME (frame)->last_tool_bar_item != -1 + && WINDOWP (XFRAME (frame)->tool_bar_window)) + handle_tool_bar_click (XFRAME (frame), 0, 0, + false, 0); + + output->tool_bar_touch_device = 0; + } + } +#endif #endif goto out; @@ -24209,6 +24273,48 @@ handle_one_xevent (struct x_display_info *dpyinfo, } #endif +#ifndef HAVE_EXT_TOOL_BAR + /* Is this a touch from a direct touch device that is in + the tool-bar? */ + if (device->direct_p + && WINDOWP (f->tool_bar_window) + && WINDOW_TOTAL_LINES (XWINDOW (f->tool_bar_window))) + { + Lisp_Object window; + int x = xev->event_x; + int y = xev->event_y; + + window = window_from_coordinates (f, x, y, 0, true, true); + /* Ignore button release events if the mouse + wasn't previously pressed on the tool bar. + We do this because otherwise selecting some + text with the mouse and then releasing it on + the tool bar doesn't stop selecting text, + since the tool bar eats the button up + event. */ + tool_bar_p = EQ (window, f->tool_bar_window); + + /* If this touch has started in the tool bar, do not + send it to Lisp. Instead, simulate a tool bar + click, releasing it once it goes away. */ + + if (tool_bar_p) + { + handle_tool_bar_click (f, x, y, true, 0); + + /* Record the device and the touch ID on the + frame. That way, Emacs knows when to dismiss + the tool bar click later. */ + + FRAME_OUTPUT_DATA (f)->tool_bar_touch_device + = device->device_id; + FRAME_OUTPUT_DATA (f)->tool_bar_touch_id = xev->detail; + + goto XI_OTHER; + } + } +#endif + if (!menu_bar_p && !tool_bar_p) { if (f && device->direct_p) @@ -24218,13 +24324,16 @@ handle_one_xevent (struct x_display_info *dpyinfo, x_catch_errors (dpyinfo->display); if (x_input_grab_touch_events) - XIAllowTouchEvents (dpyinfo->display, xev->deviceid, - xev->detail, xev->event, XIAcceptTouch); + XIAllowTouchEvents (dpyinfo->display, + xev->deviceid, + xev->detail, xev->event, + XIAcceptTouch); if (!x_had_errors_p (dpyinfo->display)) { - xi_link_touch_point (device, xev->detail, xev->event_x, - xev->event_y); + xi_link_touch_point (device, xev->detail, + xev->event_x, + xev->event_y, f); inev.ie.kind = TOUCHSCREEN_BEGIN_EVENT; inev.ie.timestamp = xev->time; @@ -24299,10 +24408,11 @@ handle_one_xevent (struct x_display_info *dpyinfo, for (touchpoint = device->touchpoints; touchpoint; touchpoint = touchpoint->next) { - arg = Fcons (list3i (lrint (touchpoint->x), - lrint (touchpoint->y), - lrint (touchpoint->number)), - arg); + if (touchpoint->frame == f) + arg = Fcons (list3i (lrint (touchpoint->x), + lrint (touchpoint->y), + lrint (touchpoint->number)), + arg); } if (source) @@ -24348,6 +24458,23 @@ handle_one_xevent (struct x_display_info *dpyinfo, } } + /* Now see if the touchpoint was previously on the tool bar. + If it was, release the tool bar. */ + + if (!f) + f = x_window_to_frame (dpyinfo, xev->event); + + if (f && (FRAME_OUTPUT_DATA (f)->tool_bar_touch_id + == xev->detail)) + { + if (f->last_tool_bar_item != -1) + handle_tool_bar_click (f, xev->event_x, xev->event_y, + false, 0); + + /* Now clear the tool bar device. */ + FRAME_OUTPUT_DATA (f)->tool_bar_touch_device = 0; + } + goto XI_OTHER; } @@ -28453,6 +28580,11 @@ x_make_frame_invisible (struct frame *f) block_input (); +#ifdef HAVE_XINPUT2_2 + /* Remove any touch points associated with F. */ + xi_unlink_touch_points (f); +#endif + /* Before unmapping the window, update the WM_SIZE_HINTS property to claim that the current position of the window is user-specified, rather than program-specified, so that when the window is mapped again, it will be @@ -28658,6 +28790,11 @@ x_free_frame_resources (struct frame *f) xi_handle_delete_frame (dpyinfo, f); #endif +#ifdef HAVE_XINPUT2_2 + /* Remove any touch points associated with F. */ + xi_unlink_touch_points (f); +#endif + /* If a display connection is dead, don't try sending more commands to the X server. */ if (dpyinfo->display) diff --git a/src/xterm.h b/src/xterm.h index d768ba7ff8d..28ae00ca190 100644 --- a/src/xterm.h +++ b/src/xterm.h @@ -257,10 +257,17 @@ struct xi_scroll_valuator_t 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; + + /* The frame associated with this touch point. */ + struct frame *frame; }; #endif @@ -1295,6 +1302,16 @@ struct x_output VisibilityFullyObscured, but is set to something else in handle_one_xevent. */ int visibility_state; + +#ifdef HAVE_XINPUT2_2 + /* The touch ID of the last touch point to have touched the tool + bar. */ + int tool_bar_touch_id; + + /* The device that last touched the tool bar. 0 if no device + touched the tool bar. */ + int tool_bar_touch_device; +#endif }; enum