Add support for event processing via XInput 2

* configure.ac: Add an option to use XInput 2 if available
* src/Makefile.in (XINPUT_LIBS, XINPUT_CFLAGS): New variables
(EMACS_CFLAGS): Add Xinput CFLAGS
(LIBES): Add XInput libs
* src/xmenu.c (popup_activated_flag): Expose flag if XInput 2 is
available
* src/xfns.c (x_window): Set XInput 2 event mask
* src/xterm.c (x_detect_focus_change): Handle XInput 2 GenericEvents
(handle_one_xevent): Handle XInput 2 events
(x_term_init): Ask the server for XInput 2 support and set xkb_desc if
available
(x_delete_terminal): Free XKB kb desc if it exists, and free XI2
devices if they exist
(x_free_xi_devices, x_init_master_valuators): New functions
(x_get_scroll_valuator_delta): New function
(init_xterm): Don't tell GTK to only use Core Input when built with
XInput 2 support
* src/xterm.h (struct x_display_info): Add fields for XKB and XI2
support
* src/gtkutil.c (xg_event_is_for_menubar): Handle XIDeviceEvents
(xg_is_menu_window): New function
(xg_event_is_for_scrollbar): Handle XIDeviceEvents
This commit is contained in:
oldosfan 2021-11-01 08:19:32 +08:00 committed by Po Lu
parent 68a2a3307d
commit 346cfc8124
8 changed files with 1308 additions and 7 deletions

View file

@ -487,6 +487,7 @@ OPTION_DEFAULT_ON([modules],[don't compile with dynamic modules support])
OPTION_DEFAULT_ON([threads],[don't compile with elisp threading support])
OPTION_DEFAULT_OFF([native-compilation],[compile with Emacs Lisp native compiler support])
OPTION_DEFAULT_OFF([cygwin32-native-compilation],[use native compilation on 32-bit Cygwin])
OPTION_DEFAULT_OFF([xinput2],[use version 2.0 the X Input Extension for input])
AC_ARG_WITH([file-notification],[AS_HELP_STRING([--with-file-notification=LIB],
[use a file notification library (LIB one of: yes, inotify, kqueue, gfile, w32, no)])],
@ -4237,6 +4238,26 @@ fi
AC_SUBST(XFIXES_CFLAGS)
AC_SUBST(XFIXES_LIBS)
## Use XInput 2.0 if available
HAVE_XINPUT2=no
if test "${HAVE_X11}" = "yes" && test "${with_xinput2}" != "no"; then
EMACS_CHECK_MODULES([XINPUT], [xi])
if test $HAVE_XINPUT = yes; then
# Now check for XInput2.h
AC_CHECK_HEADER(X11/extensions/XInput2.h,
[AC_CHECK_LIB(Xi, XIGrabButton, HAVE_XINPUT2=yes)])
fi
if test $HAVE_XINPUT2 = yes; then
AC_DEFINE(HAVE_XINPUT2, 1, [Define to 1 if the X Input Extension version 2.0 is present.])
if test "$USE_GTK_TOOLKIT" = "GTK2"; then
AC_MSG_WARN([You are building Emacs with GTK+ 2 and the X Input Extension version 2.
This might lead to problems if your version of GTK+ is not built with support for XInput 2.])
fi
fi
fi
AC_SUBST(XINPUT_CFLAGS)
AC_SUBST(XINPUT_LIBS)
### Use Xdbe (-lXdbe) if available
HAVE_XDBE=no
if test "${HAVE_X11}" = "yes"; then
@ -5994,6 +6015,7 @@ AS_ECHO([" Does Emacs use -lXaw3d? ${HAVE_XAW3D
Does Emacs support legacy unexec dumping? ${with_unexec}
Which dumping strategy does Emacs use? ${with_dumping}
Does Emacs have native lisp compiler? ${HAVE_NATIVE_COMP}
Does Emacs use version 2 of the the X Input Extension? ${HAVE_XINPUT2}
"])
if test -n "${EMACSDATA}"; then

View file

@ -258,6 +258,9 @@ XINERAMA_CFLAGS = @XINERAMA_CFLAGS@
XFIXES_LIBS = @XFIXES_LIBS@
XFIXES_CFLAGS = @XFIXES_CFLAGS@
XINPUT_LIBS = @XINPUT_LIBS@
XINPUT_CFLAGS = @XINPUT_CFLAGS@
XDBE_LIBS = @XDBE_LIBS@
XDBE_CFLAGS = @XDBE_CFLAGS@
@ -374,7 +377,7 @@ EMACS_CFLAGS=-Demacs $(MYCPPFLAGS) -I. -I$(srcdir) \
$(GNUSTEP_CFLAGS) $(CFLAGS_SOUND) $(RSVG_CFLAGS) $(IMAGEMAGICK_CFLAGS) \
$(PNG_CFLAGS) $(LIBXML2_CFLAGS) $(LIBGCCJIT_CFLAGS) $(DBUS_CFLAGS) \
$(XRANDR_CFLAGS) $(XINERAMA_CFLAGS) $(XFIXES_CFLAGS) $(XDBE_CFLAGS) \
$(WEBKIT_CFLAGS) $(WEBP_CFLAGS) $(LCMS2_CFLAGS) \
$(WEBKIT_CFLAGS) $(WEBP_CFLAGS) $(LCMS2_CFLAGS) $(XINPUT_CFLAGS) \
$(SETTINGS_CFLAGS) $(FREETYPE_CFLAGS) $(FONTCONFIG_CFLAGS) \
$(HARFBUZZ_CFLAGS) $(LIBOTF_CFLAGS) $(M17N_FLT_CFLAGS) $(DEPFLAGS) \
$(LIBSYSTEMD_CFLAGS) $(JSON_CFLAGS) \
@ -524,7 +527,7 @@ LIBES = $(LIBS) $(W32_LIBS) $(LIBS_GNUSTEP) $(LIBX_BASE) $(LIBIMAGE) \
$(FREETYPE_LIBS) $(FONTCONFIG_LIBS) $(HARFBUZZ_LIBS) $(LIBOTF_LIBS) $(M17N_FLT_LIBS) \
$(LIBGNUTLS_LIBS) $(LIB_PTHREAD) $(GETADDRINFO_A_LIBS) $(LCMS2_LIBS) \
$(NOTIFY_LIBS) $(LIB_MATH) $(LIBZ) $(LIBMODULES) $(LIBSYSTEMD_LIBS) \
$(JSON_LIBS) $(LIBGMP) $(LIBGCCJIT_LIBS)
$(JSON_LIBS) $(LIBGMP) $(LIBGCCJIT_LIBS) $(XINPUT_LIBS)
## FORCE it so that admin/unidata can decide whether this file is
## up-to-date. Although since charprop depends on bootstrap-emacs,

View file

@ -47,6 +47,10 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
#include <gdk/gdkkeysyms.h>
#ifdef HAVE_XINPUT2
#include <X11/extensions/XInput2.h>
#endif
#ifdef HAVE_XFT
#include <X11/Xft/Xft.h>
#endif
@ -839,6 +843,23 @@ my_log_handler (const gchar *log_domain, GLogLevelFlags log_level,
}
#endif
#if defined HAVE_GTK3 && defined HAVE_XINPUT2
bool
xg_is_menu_window (Display *dpy, Window wdesc)
{
GtkWidget *gwdesc = xg_win_to_widget (dpy, wdesc);
if (GTK_IS_WINDOW (gwdesc))
{
GtkWidget *fw = gtk_bin_get_child (GTK_BIN (gwdesc));
if (GTK_IS_MENU (fw))
return true;
}
return false;
}
#endif
/* Make a geometry string and pass that to GTK. It seems this is the
only way to get geometry position right if the user explicitly
asked for a position when starting Emacs.
@ -3589,6 +3610,18 @@ xg_event_is_for_menubar (struct frame *f, const XEvent *event)
if (! x->menubar_widget) return 0;
#ifdef HAVE_XINPUT2
XIDeviceEvent *xev = (XIDeviceEvent *) event->xcookie.data;
if (event->type == GenericEvent) /* XI_ButtonPress or XI_ButtonRelease */
{
if (! (xev->event_x >= 0
&& xev->event_x < FRAME_PIXEL_WIDTH (f)
&& xev->event_y >= 0
&& xev->event_y < FRAME_MENUBAR_HEIGHT (f)))
return 0;
}
else
#endif
if (! (event->xbutton.x >= 0
&& event->xbutton.x < FRAME_PIXEL_WIDTH (f)
&& event->xbutton.y >= 0
@ -3597,7 +3630,12 @@ xg_event_is_for_menubar (struct frame *f, const XEvent *event)
return 0;
gdpy = gdk_x11_lookup_xdisplay (FRAME_X_DISPLAY (f));
gw = gdk_x11_window_lookup_for_display (gdpy, event->xbutton.window);
#ifdef HAVE_XINPUT2
if (event->type == GenericEvent)
gw = gdk_x11_window_lookup_for_display (gdpy, xev->event);
else
#endif
gw = gdk_x11_window_lookup_for_display (gdpy, event->xbutton.window);
if (! gw) return 0;
gevent.any.window = gw;
gevent.any.type = GDK_NOTHING;
@ -4244,7 +4282,20 @@ xg_event_is_for_scrollbar (struct frame *f, const XEvent *event)
{
bool retval = 0;
#ifdef HAVE_XINPUT2
XIDeviceEvent *xev = (XIDeviceEvent *) event->xcookie.data;
if (f && ((FRAME_DISPLAY_INFO (f)->supports_xi2
&& event->type == GenericEvent
&& (event->xgeneric.extension
== FRAME_DISPLAY_INFO (f)->xi2_opcode)
&& ((event->xgeneric.evtype == XI_ButtonPress
&& xev->detail < 4)
|| (event->xgeneric.evtype == XI_Motion)))
|| (event->type == ButtonPress
&& event->xbutton.button < 4)))
#else
if (f && event->type == ButtonPress && event->xbutton.button < 4)
#endif /* HAVE_XINPUT2 */
{
/* Check if press occurred outside the edit widget. */
GdkDisplay *gdpy = gdk_x11_lookup_xdisplay (FRAME_X_DISPLAY (f));
@ -4262,10 +4313,29 @@ xg_event_is_for_scrollbar (struct frame *f, const XEvent *event)
gwin = gdk_display_get_window_at_pointer (gdpy, NULL, NULL);
#endif
retval = gwin != gtk_widget_get_window (f->output_data.x->edit_widget);
#ifdef HAVE_XINPUT2
GtkWidget *grab = gtk_grab_get_current ();
if (event->type == GenericEvent
&& event->xgeneric.evtype == XI_Motion)
retval = retval || (grab && GTK_IS_SCROLLBAR (grab));
#endif
}
#ifdef HAVE_XINPUT2
else if (f && ((FRAME_DISPLAY_INFO (f)->supports_xi2
&& event->type == GenericEvent
&& (event->xgeneric.extension
== FRAME_DISPLAY_INFO (f)->xi2_opcode)
&& ((event->xgeneric.evtype == XI_ButtonRelease
&& xev->detail < 4)
|| (event->xgeneric.evtype == XI_Motion)))
|| ((event->type == ButtonRelease
&& event->xbutton.button < 4)
|| event->type == MotionNotify)))
#else
else if (f
&& ((event->type == ButtonRelease && event->xbutton.button < 4)
|| event->type == MotionNotify))
#endif /* HAVE_XINPUT2 */
{
/* If we are releasing or moving the scroll bar, it has the grab. */
GtkWidget *w = gtk_grab_get_current ();

View file

@ -192,6 +192,10 @@ extern Lisp_Object xg_get_page_setup (void);
extern void xg_print_frames_dialog (Lisp_Object);
#endif
#if defined HAVE_GTK3 && defined HAVE_XINPUT2
extern bool xg_is_menu_window (Display *dpy, Window);
#endif
/* Mark all callback data that are Lisp_object:s during GC. */
extern void xg_mark_data (void);

View file

@ -57,6 +57,10 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
#include <X11/extensions/Xdbe.h>
#endif
#ifdef HAVE_XINPUT2
#include <X11/extensions/XInput2.h>
#endif
#ifdef USE_X_TOOLKIT
#include <X11/Shell.h>
@ -3074,6 +3078,43 @@ x_window (struct frame *f, long window_prompting)
class_hints.res_class = SSDATA (Vx_resource_class);
XSetClassHint (FRAME_X_DISPLAY (f), XtWindow (shell_widget), &class_hints);
#ifdef HAVE_XINPUT2
if (FRAME_DISPLAY_INFO (f)->supports_xi2)
{
XIEventMask mask;
ptrdiff_t l = XIMaskLen (XI_LASTEVENT);
unsigned char *m;
mask.mask = m = alloca (l);
memset (m, 0, l);
mask.mask_len = l;
mask.deviceid = XIAllMasterDevices;
XISetMask (m, XI_ButtonPress);
XISetMask (m, XI_ButtonRelease);
XISetMask (m, XI_KeyPress);
XISetMask (m, XI_KeyRelease);
XISetMask (m, XI_Motion);
XISetMask (m, XI_Enter);
XISetMask (m, XI_Leave);
XISetMask (m, XI_FocusIn);
XISetMask (m, XI_FocusOut);
XISetMask (m, XI_DeviceChanged);
XISelectEvents (FRAME_X_DISPLAY (f),
FRAME_X_WINDOW (f),
&mask, 1);
mask.deviceid = XIAllDevices;
memset (m, 0, l);
XISetMask (m, XI_PropertyEvent);
XISetMask (m, XI_HierarchyChanged);
XISelectEvents (FRAME_X_DISPLAY (f),
FRAME_X_WINDOW (f),
&mask, 1);
}
#endif
#ifdef HAVE_X_I18N
FRAME_XIC (f) = NULL;
if (use_xim)
@ -3254,6 +3295,43 @@ x_window (struct frame *f)
}
#endif /* HAVE_X_I18N */
#ifdef HAVE_XINPUT2
if (FRAME_DISPLAY_INFO (f)->supports_xi2)
{
XIEventMask mask;
ptrdiff_t l = XIMaskLen (XI_LASTEVENT);
unsigned char *m;
mask.mask = m = alloca (l);
memset (m, 0, l);
mask.mask_len = l;
mask.deviceid = XIAllMasterDevices;
XISetMask (m, XI_ButtonPress);
XISetMask (m, XI_ButtonRelease);
XISetMask (m, XI_KeyPress);
XISetMask (m, XI_KeyRelease);
XISetMask (m, XI_Motion);
XISetMask (m, XI_Enter);
XISetMask (m, XI_Leave);
XISetMask (m, XI_FocusIn);
XISetMask (m, XI_FocusOut);
XISetMask (m, XI_DeviceChanged);
XISelectEvents (FRAME_X_DISPLAY (f),
FRAME_X_WINDOW (f),
&mask, 1);
mask.deviceid = XIAllDevices;
memset (m, 0, l);
XISetMask (m, XI_PropertyEvent);
XISetMask (m, XI_HierarchyChanged);
XISelectEvents (FRAME_X_DISPLAY (f),
FRAME_X_WINDOW (f),
&mask, 1);
}
#endif
validate_x_resource_name ();
class_hints.res_name = SSDATA (Vx_resource_name);

View file

@ -105,7 +105,11 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
/* Flag which when set indicates a dialog or menu has been posted by
Xt on behalf of one of the widget sets. */
#ifndef HAVE_XINPUT2
static int popup_activated_flag;
#else
int popup_activated_flag;
#endif
#ifdef USE_X_TOOLKIT

File diff suppressed because it is too large Load diff

View file

@ -88,6 +88,10 @@ typedef GtkWidget *xt_or_gtk_widget;
#include <X11/Xlib-xcb.h>
#endif
#ifdef HAVE_XKB
#include <X11/XKBlib.h>
#endif
#include "dispextern.h"
#include "termhooks.h"
@ -163,6 +167,26 @@ struct color_name_cache_entry
char *name;
};
#ifdef HAVE_XINPUT2
struct xi_scroll_valuator_t
{
bool invalid_p;
double current_value;
double emacs_value;
double increment;
int number;
int horizontal;
};
struct xi_device_t
{
int device_id;
int scroll_valuator_count;
struct xi_scroll_valuator_t *valuators;
};
#endif
Status x_parse_color (struct frame *f, const char *color_name,
XColor *color);
@ -474,6 +498,19 @@ struct x_display_info
#ifdef HAVE_XDBE
bool supports_xdbe;
#endif
#ifdef HAVE_XINPUT2
bool supports_xi2;
int xi2_version;
int xi2_opcode;
int num_devices;
struct xi_device_t *devices;
#endif
#ifdef HAVE_XKB
XkbDescPtr xkb_desc;
#endif
};
#ifdef HAVE_X_I18N
@ -481,6 +518,11 @@ struct x_display_info
extern bool use_xim;
#endif
#ifdef HAVE_XINPUT2
/* Defined in xmenu.c. */
extern int popup_activated_flag;
#endif
/* This is a chain of structures for all the X displays currently in use. */
extern struct x_display_info *x_display_list;