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:
parent
68a2a3307d
commit
346cfc8124
8 changed files with 1308 additions and 7 deletions
22
configure.ac
22
configure.ac
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 ();
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
78
src/xfns.c
78
src/xfns.c
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
1086
src/xterm.c
1086
src/xterm.c
File diff suppressed because it is too large
Load diff
42
src/xterm.h
42
src/xterm.h
|
@ -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;
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue