gdk/x11: Implement XI2.4 touchpad gesture support

This commit is contained in:
Povilas Kanapickas
2021-12-02 23:19:09 +02:00
parent 2db8f64ca7
commit a1a2f8ab56
11 changed files with 239 additions and 7 deletions

View File

@ -244,6 +244,9 @@
/* Define to 1 if XInput 2.2 is available */ /* Define to 1 if XInput 2.2 is available */
#mesondefine XINPUT_2_2 #mesondefine XINPUT_2_2
/* Define to 1 if XInput 2.4 is available */
#mesondefine XINPUT_2_4
/* Enable large inode numbers on Mac OS X 10.5. */ /* Enable large inode numbers on Mac OS X 10.5. */
#ifndef _DARWIN_USE_64_BIT_INODE #ifndef _DARWIN_USE_64_BIT_INODE
# define _DARWIN_USE_64_BIT_INODE 1 # define _DARWIN_USE_64_BIT_INODE 1

View File

@ -300,6 +300,9 @@
/* Define to 1 if XInput 2.2 is available */ /* Define to 1 if XInput 2.2 is available */
/* #undef XINPUT_2_2 */ /* #undef XINPUT_2_2 */
/* Define to 1 if XInput 2.4 is available */
/* #undef XINPUT_2_4 */
/* Define to 1 if the X Window System is missing or not being used. */ /* Define to 1 if the X Window System is missing or not being used. */
/* #undef X_DISPLAY_MISSING */ /* #undef X_DISPLAY_MISSING */

View File

@ -1167,13 +1167,23 @@ if test "x$enable_x11_backend" = xyes; then
AC_DEFINE(XINPUT_2_2, 1, [Define to 1 if XInput 2.2 is available]), AC_DEFINE(XINPUT_2_2, 1, [Define to 1 if XInput 2.2 is available]),
have_xinput2_2=no, have_xinput2_2=no,
[[#include <X11/extensions/XInput2.h>]])]) [[#include <X11/extensions/XInput2.h>]])])
LIBS="$gtk_save_LIBS"
if test "x$have_xinput2_2" = "xyes"; then if test "x$have_xinput2_2" = "xyes"; then
X_EXTENSIONS="$X_EXTENSIONS XI2.2" X_EXTENSIONS="$X_EXTENSIONS XI2.2"
else else
X_EXTENSIONS="$X_EXTENSIONS XI2" X_EXTENSIONS="$X_EXTENSIONS XI2"
fi fi
AC_CHECK_MEMBER([XIGesturePinchEvent.type],
have_xinput2_4=yes
AC_DEFINE(XINPUT_2_4, 1, [Define to 1 if XInput 2.4 is available]),
have_xinput2_4=no,
[[#include <X11/extensions/XInput2.h>]])
if test "x$have_xinput2_4" = "xyes"; then
X_EXTENSIONS="$X_EXTENSIONS XI2.4"
fi
LIBS="$gtk_save_LIBS"
fi fi
AS_IF([test "x$have_xinput2" != "xyes"], AS_IF([test "x$have_xinput2" != "xyes"],

View File

@ -160,7 +160,7 @@ do_gestures (GtkWidget *do_widget)
gtk_container_add (GTK_CONTAINER (window), drawing_area); gtk_container_add (GTK_CONTAINER (window), drawing_area);
gtk_widget_add_events (drawing_area, gtk_widget_add_events (drawing_area,
GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
GDK_POINTER_MOTION_MASK | GDK_TOUCH_MASK); GDK_POINTER_MOTION_MASK | GDK_TOUCH_MASK | GDK_TOUCHPAD_GESTURE_MASK);
g_signal_connect (drawing_area, "draw", g_signal_connect (drawing_area, "draw",
G_CALLBACK (drawing_area_draw), NULL); G_CALLBACK (drawing_area_draw), NULL);

View File

@ -43,7 +43,8 @@ struct _GdkSeatDefaultPrivate
GDK_ENTER_NOTIFY_MASK | \ GDK_ENTER_NOTIFY_MASK | \
GDK_LEAVE_NOTIFY_MASK | \ GDK_LEAVE_NOTIFY_MASK | \
GDK_PROXIMITY_IN_MASK | \ GDK_PROXIMITY_IN_MASK | \
GDK_PROXIMITY_OUT_MASK) GDK_PROXIMITY_OUT_MASK | \
GDK_TOUCHPAD_GESTURE_MASK)
G_DEFINE_TYPE_WITH_PRIVATE (GdkSeatDefault, gdk_seat_default, GDK_TYPE_SEAT) G_DEFINE_TYPE_WITH_PRIVATE (GdkSeatDefault, gdk_seat_default, GDK_TYPE_SEAT)

View File

@ -1286,7 +1286,7 @@ get_native_device_event_mask (GdkWindow *private,
if (gdk_window_is_toplevel (private) || if (gdk_window_is_toplevel (private) ||
mask & GDK_BUTTON_PRESS_MASK) mask & GDK_BUTTON_PRESS_MASK)
mask |= mask |=
GDK_TOUCH_MASK | GDK_TOUCH_MASK | GDK_TOUCHPAD_GESTURE_MASK |
GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_MASK |
GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
GDK_SCROLL_MASK; GDK_SCROLL_MASK;

View File

@ -61,7 +61,6 @@ struct _GdkX11DeviceXI2Class
G_DEFINE_TYPE (GdkX11DeviceXI2, gdk_x11_device_xi2, GDK_TYPE_DEVICE) G_DEFINE_TYPE (GdkX11DeviceXI2, gdk_x11_device_xi2, GDK_TYPE_DEVICE)
static void gdk_x11_device_xi2_finalize (GObject *object); static void gdk_x11_device_xi2_finalize (GObject *object);
static void gdk_x11_device_xi2_get_property (GObject *object, static void gdk_x11_device_xi2_get_property (GObject *object,
guint prop_id, guint prop_id,
@ -762,6 +761,20 @@ _gdk_x11_device_xi2_translate_event_mask (GdkX11DeviceManagerXI2 *device_manager
} }
#endif /* XINPUT_2_2 */ #endif /* XINPUT_2_2 */
#ifdef XINPUT_2_4
/* XInput 2.4 includes multitouch support */
if (minor >= 4 &&
event_mask & GDK_TOUCHPAD_GESTURE_MASK)
{
XISetMask (mask, XI_GesturePinchBegin);
XISetMask (mask, XI_GesturePinchUpdate);
XISetMask (mask, XI_GesturePinchEnd);
XISetMask (mask, XI_GestureSwipeBegin);
XISetMask (mask, XI_GestureSwipeUpdate);
XISetMask (mask, XI_GestureSwipeEnd);
}
#endif
return mask; return mask;
} }
@ -810,6 +823,36 @@ _gdk_x11_device_xi2_translate_state (XIModifierState *mods_state,
return state; return state;
} }
#ifdef XINPUT_2_4
guint
_gdk_x11_device_xi2_gesture_type_to_phase (int evtype, int flags)
{
switch (evtype)
{
case XI_GesturePinchBegin:
case XI_GestureSwipeBegin:
return GDK_TOUCHPAD_GESTURE_PHASE_BEGIN;
case XI_GesturePinchUpdate:
case XI_GestureSwipeUpdate:
return GDK_TOUCHPAD_GESTURE_PHASE_UPDATE;
case XI_GesturePinchEnd:
if (flags & XIGesturePinchEventCancelled)
return GDK_TOUCHPAD_GESTURE_PHASE_CANCEL;
return GDK_TOUCHPAD_GESTURE_PHASE_END;
case XI_GestureSwipeEnd:
if (flags & XIGestureSwipeEventCancelled)
return GDK_TOUCHPAD_GESTURE_PHASE_CANCEL;
return GDK_TOUCHPAD_GESTURE_PHASE_END;
default:
g_assert_not_reached ();
return GDK_TOUCHPAD_GESTURE_PHASE_END;
}
}
#endif /* XINPUT_2_4 */
void void
_gdk_x11_device_xi2_add_scroll_valuator (GdkX11DeviceXI2 *device, _gdk_x11_device_xi2_add_scroll_valuator (GdkX11DeviceXI2 *device,
guint n_valuator, guint n_valuator,

View File

@ -48,7 +48,7 @@ _gdk_x11_device_manager_new (GdkDisplay *display)
int major, minor; int major, minor;
major = 2; major = 2;
minor = 3; minor = 4;
if (!_gdk_disable_multidevice && if (!_gdk_disable_multidevice &&
XIQueryVersion (xdisplay, &major, &minor) != BadRequest) XIQueryVersion (xdisplay, &major, &minor) != BadRequest)

View File

@ -1335,6 +1335,26 @@ get_event_window (GdkEventTranslator *translator,
} }
} }
break; break;
#ifdef XINPUT_2_4
case XI_GesturePinchBegin:
case XI_GesturePinchUpdate:
case XI_GesturePinchEnd:
{
XIGesturePinchEvent *xev = (XIGesturePinchEvent *) ev;
window = gdk_x11_window_lookup_for_display (display, xev->event);
}
break;
case XI_GestureSwipeBegin:
case XI_GestureSwipeUpdate:
case XI_GestureSwipeEnd:
{
XIGestureSwipeEvent *xev = (XIGestureSwipeEvent *) ev;
window = gdk_x11_window_lookup_for_display (display, xev->event);
}
break;
#endif /* XINPUT_2_4 */
case XI_Enter: case XI_Enter:
case XI_Leave: case XI_Leave:
case XI_FocusIn: case XI_FocusIn:
@ -1950,6 +1970,144 @@ gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
break; break;
#endif /* XINPUT_2_2 */ #endif /* XINPUT_2_2 */
#ifdef XINPUT_2_4
case XI_GesturePinchBegin:
case XI_GesturePinchUpdate:
case XI_GesturePinchEnd:
{
XIGesturePinchEvent *xev = (XIGesturePinchEvent *) ev;
#ifdef G_ENABLE_DEBUG
const char* event_name = "";
switch (xev->evtype)
{
case XI_GesturePinchBegin:
event_name = "begin";
break;
case XI_GesturePinchUpdate:
event_name = "update";
break;
case XI_GesturePinchEnd:
event_name = "end";
break;
}
#endif
GDK_NOTE(EVENTS,
g_message ("pinch gesture %s:\twindow %ld\n\tfinger_count: %u%s",
event_name,
xev->event,
xev->detail,
xev->flags & XIGesturePinchEventCancelled ? "\n\tcancelled" : ""));
event->touchpad_pinch.type = GDK_TOUCHPAD_PINCH;
event->touchpad_pinch.phase =
_gdk_x11_device_xi2_gesture_type_to_phase (xev->evtype, xev->flags);
event->touchpad_pinch.window = window;
event->touchpad_pinch.time = xev->time;
event->touchpad_pinch.x = (gdouble) xev->event_x / scale;
event->touchpad_pinch.y = (gdouble) xev->event_y / scale;
event->touchpad_pinch.x_root = (gdouble) xev->root_x / scale;
event->touchpad_pinch.y_root = (gdouble) xev->root_y / scale;
event->touchpad_pinch.dx = xev->delta_x;
event->touchpad_pinch.dy = xev->delta_y;
event->touchpad_pinch.scale = xev->scale;
event->touchpad_pinch.angle_delta = xev->delta_angle * G_PI / 180;
event->touchpad_pinch.n_fingers = xev->detail;
device = g_hash_table_lookup (device_manager->id_table,
GUINT_TO_POINTER (xev->deviceid));
gdk_event_set_device (event, device);
source_device = g_hash_table_lookup (device_manager->id_table,
GUINT_TO_POINTER (xev->sourceid));
gdk_event_set_source_device (event, source_device);
gdk_event_set_seat (event, gdk_device_get_seat (device));
event->touchpad_pinch.state = _gdk_x11_device_xi2_translate_state (&xev->mods, NULL, &xev->group);
if (xev->evtype == XI_GesturePinchBegin || xev->evtype == XI_GesturePinchEnd)
{
if (!set_screen_from_root (display, event, xev->root))
{
return_val = FALSE;
break;
}
}
if (ev->evtype == XI_GesturePinchBegin)
set_user_time (event);
}
break;
case XI_GestureSwipeBegin:
case XI_GestureSwipeUpdate:
case XI_GestureSwipeEnd:
{
XIGestureSwipeEvent *xev = (XIGestureSwipeEvent *) ev;
#ifdef G_ENABLE_DEBUG
const char* event_name = "";
switch (xev->evtype)
{
case XI_GestureSwipeBegin:
event_name = "begin";
break;
case XI_GestureSwipeUpdate:
event_name = "update";
break;
case XI_GestureSwipeEnd:
event_name = "end";
break;
}
#endif
GDK_NOTE(EVENTS,
g_message ("swipe gesture %s:\twindow %ld\n\tfinger_count: %u%s",
event_name,
xev->event,
xev->detail,
xev->flags & XIGestureSwipeEventCancelled ? "\n\tcancelled" : ""));
event->touchpad_swipe.type = GDK_TOUCHPAD_SWIPE;
event->touchpad_pinch.phase =
_gdk_x11_device_xi2_gesture_type_to_phase (xev->evtype, xev->flags);
event->touchpad_swipe.window = window;
event->touchpad_swipe.time = xev->time;
event->touchpad_swipe.x = (gdouble) xev->event_x / scale;
event->touchpad_swipe.y = (gdouble) xev->event_y / scale;
event->touchpad_swipe.x_root = (gdouble) xev->root_x / scale;
event->touchpad_swipe.y_root = (gdouble) xev->root_y / scale;
event->touchpad_swipe.dx = xev->delta_x;
event->touchpad_swipe.dy = xev->delta_y;
event->touchpad_swipe.n_fingers = xev->detail;
device = g_hash_table_lookup (device_manager->id_table,
GUINT_TO_POINTER (xev->deviceid));
gdk_event_set_device (event, device);
source_device = g_hash_table_lookup (device_manager->id_table,
GUINT_TO_POINTER (xev->sourceid));
gdk_event_set_source_device (event, source_device);
gdk_event_set_seat (event, gdk_device_get_seat (device));
event->touchpad_swipe.state = _gdk_x11_device_xi2_translate_state (&xev->mods, NULL, &xev->group);
if (xev->evtype == XI_GestureSwipeBegin || xev->evtype == XI_GestureSwipeEnd)
{
if (!set_screen_from_root (display, event, xev->root))
{
return_val = FALSE;
break;
}
}
if (ev->evtype == XI_GestureSwipeBegin)
set_user_time (event);
}
break;
#endif /* XINPUT_2_4 */
case XI_Enter: case XI_Enter:
case XI_Leave: case XI_Leave:
{ {
@ -2078,7 +2236,8 @@ gdk_x11_device_manager_xi2_get_handled_events (GdkEventTranslator *translator)
GDK_BUTTON3_MOTION_MASK | GDK_BUTTON3_MOTION_MASK |
GDK_BUTTON_MOTION_MASK | GDK_BUTTON_MOTION_MASK |
GDK_FOCUS_CHANGE_MASK | GDK_FOCUS_CHANGE_MASK |
GDK_TOUCH_MASK); GDK_TOUCH_MASK |
GDK_TOUCHPAD_GESTURE_MASK);
} }
static void static void

View File

@ -230,6 +230,11 @@ guchar * _gdk_x11_device_xi2_translate_event_mask (GdkX11DeviceManagerXI2 *devic
guint _gdk_x11_device_xi2_translate_state (XIModifierState *mods_state, guint _gdk_x11_device_xi2_translate_state (XIModifierState *mods_state,
XIButtonState *buttons_state, XIButtonState *buttons_state,
XIGroupState *group_state); XIGroupState *group_state);
#ifdef XINPUT_2_4
guint _gdk_x11_device_xi2_gesture_type_to_phase (int evtype, int flags);
#endif
gint _gdk_x11_device_xi2_get_id (GdkX11DeviceXI2 *device); gint _gdk_x11_device_xi2_get_id (GdkX11DeviceXI2 *device);
void _gdk_device_xi2_unset_scroll_valuators (GdkX11DeviceXI2 *device); void _gdk_device_xi2_unset_scroll_valuators (GdkX11DeviceXI2 *device);

View File

@ -629,6 +629,14 @@ if x11_enabled
endif endif
endif endif
has_gesture_pinch_event = cc.has_member('XIGesturePinchEvent', 'type', dependencies: xi_dep,
prefix: '''#include <X11/Xlib.h>
#include <X11/extensions/XInput2.h>''')
if has_gesture_pinch_event
cdata.set('XINPUT_2_4', 1)
endif
enable_xinerama = get_option('xinerama') enable_xinerama = get_option('xinerama')
if enable_xinerama != 'no' if enable_xinerama != 'no'
want_xinerama = enable_xinerama == 'yes' want_xinerama = enable_xinerama == 'yes'