[x11] Use barriers to trap the pointer in the window

This should be a much friendlier way of "grabbing" input, though I
suspect that using raw keyboard events will result in a keyboard grab,
which is part of the reason for wanting a friendly grab.

There does seem to be a problem with the mouse sneaking out of the
top-right and bottom-left corners. I currently suspect a bug in the X
server, but further investigation is needed.
This commit is contained in:
Bill Currie 2021-11-22 13:16:05 +09:00
parent 3af078b77a
commit 3ac6d2aa22
6 changed files with 149 additions and 13 deletions

View file

@ -53,6 +53,26 @@ if test "x$HAVE_XI2" != xno; then
fi
AC_SUBST(XI2_LIBS)
dnl Check for XInput2 support
AC_ARG_ENABLE(xfixes,
[ --disable-xfixes do not use Xorg Xfixes extension],
HAVE_XFIXES=$enable_xfixes, HAVE_XFIXES=auto)
if test "x$HAVE_XFIXES" != xno; then
save_CPPFLAGS="$CPPFLAGS"
CPPFLAGS="$X_CFLAGS $CPPFLAGS"
AC_CHECK_HEADER(X11/extensions/Xfixes.h,
dnl Make sure the library works
[AC_CHECK_LIB(Xi, XIQueryVersion,
AC_DEFINE(HAVE_XFIXES, 1, [Define if you have the Xorg Xfixes extension])
XFIXES_LIBS="-lXfixes",,
[$X_LIBS -lXext -lX11 $X_EXTRA_LIBS]
)],,
[#include <X11/Xlib.h>]
)
CPPFLAGS="$save_CPPFLAGS"
fi
AC_SUBST(XFIXES_LIBS)
dnl Check for DGA support
AC_ARG_ENABLE(dga,
[ --disable-dga do not use XFree86 DGA extension],

View file

@ -41,7 +41,7 @@
#define X11_KEY_MASK (KeyPressMask | KeyReleaseMask)
#define X11_MOUSE_MASK (ButtonPressMask | ButtonReleaseMask \
| PointerMotionMask)
#define X11_FOCUS_MASK (FocusChangeMask | EnterWindowMask)
#define X11_FOCUS_MASK (FocusChangeMask | EnterWindowMask | LeaveWindowMask)
#define X11_INPUT_MASK (X11_KEY_MASK | X11_MOUSE_MASK | X11_FOCUS_MASK)
#define X11_MASK (X11_WINDOW_MASK | X11_FOCUS_MASK | PointerMotionMask)

View file

@ -64,6 +64,9 @@
#ifdef HAVE_XI2
# include <X11/extensions/XInput2.h>
#endif
#ifdef HAVE_XFIXES
# include <X11/extensions/Xfixes.h>
#endif
#include "QF/cdaudio.h"
#include "QF/cmd.h"
@ -140,9 +143,16 @@ static IE_key_event_t x11_key;
static int input_grabbed = 0;
static int xi_opcode;
static int xf_opcode;
static PointerBarrier x11_left_barrier;
static PointerBarrier x11_right_barrier;
static PointerBarrier x11_top_barrier;
static PointerBarrier x11_bottom_barrier;
static int x11_have_xi;
static int x11_fd;
static int x11_driver_handle = -1;
static int x11_event_handler_id;
static qboolean x11_have_pointer;
static void
dga_on (void)
@ -211,6 +221,7 @@ in_paste_buffer_f (void)
static void
enter_notify (XEvent *event)
{
x11_have_pointer = true;
x_time = event->xcrossing.time;
x11_mouse.x = event->xmotion.x;
@ -220,6 +231,12 @@ enter_notify (XEvent *event)
}
}
static void
leave_notify (XEvent *event)
{
x11_have_pointer = false;
}
static void
XLateKey (XKeyEvent *ev, int *k, int *u)
{
@ -905,6 +922,21 @@ xi_raw_button_resease (void *event)
xi_raw_button (event, 0);
}
static void
xi_barrier_hit (void *event)
{
__auto_type be = *(XIBarrierEvent *) event;
if (!x11_have_pointer || !input_grabbed) {
XIBarrierReleasePointer (x_disp, be.deviceid, be.barrier, be.eventid);
}
}
static void
xi_barrier_leave (void *event)
{
}
static void
event_generic (XEvent *event)
{
@ -913,6 +945,8 @@ event_generic (XEvent *event)
[XI_RawMotion] = xi_raw_motion,
[XI_RawButtonPress] = xi_raw_button_press,
[XI_RawButtonRelease] = xi_raw_button_resease,
[XI_BarrierHit] = xi_barrier_hit,
[XI_BarrierLeave] = xi_barrier_leave,
};
XGenericEventCookie *cookie = &event->xcookie;
@ -957,10 +991,14 @@ grab_error (int code, const char *device)
static void
in_x11_grab_input (void *data, int grab)
{
return;//FIXME
if (!x_disp || !x_win)
return;
if (xf_opcode) {
input_grabbed = grab;
return;
}
if (vid_fullscreen)
grab = grab || vid_fullscreen->int_val;
@ -1207,17 +1245,36 @@ in_x11_check_xi2 (void)
Sys_MaskPrintf (SYS_vid, "in_x11_check_xi2: Xlib return bad: %d\n",
ret);
}
Sys_MaskPrintf (SYS_vid, "XI2 supported: version %d.%d\n", major, minor);
Sys_MaskPrintf (SYS_vid, "XI2 supported: version %d.%d, op: %d\n",
major, minor, xi_opcode);
if (!XQueryExtension (x_disp, "XFIXES", &xf_opcode, &event, &error)) {
Sys_MaskPrintf (SYS_vid, "X fixes extenions not available.\n");
return 0;
}
major = 5, minor = 0;
if (!XFixesQueryVersion (x_disp, &major, &minor)
|| (major * 10 + minor) < 50) {
Sys_MaskPrintf (SYS_vid, "Need X fixes 5.0.\n");
return 0;
}
Sys_MaskPrintf (SYS_vid, "XFixes supported: version %d.%d, op: %d\n",
major, minor, xf_opcode);
return 1;
}
static void
in_x11_xi_select_events (void)
{
//Raw events do not have target windows, so must specify the root
//window
//XISelectEvents(x_disp, x_root, &evmask, 1);
//XFlush (x_disp);
byte mask[(XI_LASTEVENT + 7) / 8] = {};
XIEventMask evmask = {
.deviceid = XIAllMasterDevices,
.mask_len = sizeof (mask),
.mask = mask,
};
XISetMask (mask, XI_BarrierHit);
XISetMask (mask, XI_BarrierLeave);
XISelectEvents (x_disp, x_win, &evmask, 1);
}
static void
@ -1251,6 +1308,61 @@ in_x11_xi_setup_grabs (void)
// 0, &evmask, 1, &modif);
}
static void
in_x11_setup_barriers (int xpos, int ypos, int xlen, int ylen)
{
if (x11_left_barrier > 0) {
XFixesDestroyPointerBarrier (x_disp, x11_left_barrier);
}
if (x11_right_barrier > 0) {
XFixesDestroyPointerBarrier (x_disp, x11_right_barrier);
}
if (x11_top_barrier > 0) {
XFixesDestroyPointerBarrier (x_disp, x11_top_barrier);
}
if (x11_bottom_barrier > 0) {
XFixesDestroyPointerBarrier (x_disp, x11_bottom_barrier);
}
int lx = xpos;
int ty = ypos;
int rx = xpos + xlen - 1;
int by = ypos + ylen - 1;
x11_left_barrier = XFixesCreatePointerBarrier (x_disp, x_win,
lx, ty-1, lx, by+1,
BarrierPositiveX, 0, 0);
x11_right_barrier = XFixesCreatePointerBarrier (x_disp, x_win,
rx, ty-1, rx, by+1,
BarrierNegativeX, 0, 0);
x11_top_barrier = XFixesCreatePointerBarrier (x_disp, x_win,
lx-1, ty, rx+1, ty,
BarrierPositiveY, 0, 0);
x11_bottom_barrier = XFixesCreatePointerBarrier (x_disp, x_win,
lx-1, by, rx+1, by,
BarrierNegativeY, 0, 0);
}
static void
x11_app_window (const IE_event_t *ie_event)
{
__auto_type aw = ie_event->app_window;
in_x11_setup_barriers (aw.xpos, aw.ypos, aw.xlen, aw.ylen);
}
static int
x11_event_handler (const IE_event_t *ie_event, void *unused)
{
static void (*handlers[ie_event_count]) (const IE_event_t *ie_event) = {
[ie_app_window] = x11_app_window,
};
if (ie_event->type < 0 || ie_event->type >= ie_event_count
|| !handlers[ie_event->type]) {
return 0;
}
handlers[ie_event->type] (ie_event);
return 1;
}
long
IN_X11_Preinit (void)
{
@ -1259,12 +1371,15 @@ IN_X11_Preinit (void)
long event_mask = X11_INPUT_MASK;
x11_event_handler_id = IE_Add_Handler (x11_event_handler, 0);
X11_AddEvent (KeyPress, &event_key);
X11_AddEvent (KeyRelease, &event_key);
X11_AddEvent (FocusIn, &event_focusin);
X11_AddEvent (FocusOut, &event_focusout);
X11_AddEvent (SelectionNotify, &selection_notify);
X11_AddEvent (EnterNotify, &enter_notify);
X11_AddEvent (LeaveNotify, &leave_notify);
if (!COM_CheckParm ("-nomouse")) {
if ((x11_have_xi = in_x11_check_xi2 ())) {

View file

@ -134,8 +134,8 @@ nq_x11_libs= \
$(nq_client_LIBS)
nq_x11_SOURCES= nq/source/sys_unix.c
nq_x11_LDADD= $(nq_x11_libs) \
$(VIDMODE_LIBS) $(DGA_LIBS) $(XI2_LIBS) $(X_LIBS) -lX11 \
$(X_EXTRA_LIBS) $(X_SHM_LIB) $(NET_LIBS) $(DL_LIBS)
$(VIDMODE_LIBS) $(DGA_LIBS) ${XFIXES_LIBS} $(XI2_LIBS) $(X_LIBS) \
-lX11 $(X_EXTRA_LIBS) $(X_SHM_LIB) $(NET_LIBS) $(DL_LIBS)
nq_x11_LDFLAGS= $(common_ldflags)
nq_x11_DEPENDENCIES= $(nq_x11_libs)

View file

@ -161,8 +161,9 @@ qw_client_x11_libs= \
$(qw_client_LIBS)
qw_client_x11_SOURCES= qw/source/cl_sys_unix.c
qw_client_x11_LDADD= $(qw_client_x11_libs) \
$(VIDMODE_LIBS) $(DGA_LIBS) $(XI2_LIBS) $(X_LIBS) -lX11 \
$(X_EXTRA_LIBS) $(X_SHM_LIB) $(NET_LIBS) $(LIBCURL_LIBS) $(DL_LIBS)
$(VIDMODE_LIBS) $(DGA_LIBS) ${XFIXES_LIBS} $(XI2_LIBS) $(X_LIBS) \
-lX11 $(X_EXTRA_LIBS) $(X_SHM_LIB) $(NET_LIBS) $(LIBCURL_LIBS) \
$(DL_LIBS)
qw_client_x11_LDFLAGS= $(common_ldflags)
qw_client_x11_DEPENDENCIES= $(qw_client_x11_libs)

View file

@ -115,8 +115,8 @@ qwaq_x11_libs= \
$(qwaq_client_libs)
ruamoko_qwaq_qwaq_x11_SOURCES=ruamoko/qwaq/builtins/qwaq.c ruamoko/qwaq/builtins/qwaq-bi.c
ruamoko_qwaq_qwaq_x11_LDADD= $(qwaq_x11_libs) $(QWAQ_LIBS) \
$(VIDMODE_LIBS) $(DGA_LIBS) $(XI2_LIBS) $(X_LIBS) -lX11 \
$(X_EXTRA_LIBS) $(X_SHM_LIB) $(DL_LIBS)
$(VIDMODE_LIBS) $(DGA_LIBS) ${XFIXES_LIBS} $(XI2_LIBS) $(X_LIBS) \
-lX11 $(X_EXTRA_LIBS) $(X_SHM_LIB) $(DL_LIBS)
ruamoko_qwaq_qwaq_x11_LDFLAGS=
ruamoko_qwaq_qwaq_x11_DEPENDENCIES= $(qwaq_x11_libs) $(QWAQ_DEPS)