elput: introduce gesture passing

In order to have that working on Xorg, this requires the libinput group
hack if you are not session leader.
For now this only has swipe bindings, other gestures can follow.
This commit is contained in:
Marcel Hollerbach 2021-03-24 16:07:27 +01:00
parent 72f19cc9fa
commit 8493a38876
8 changed files with 364 additions and 12 deletions

View File

@ -47,6 +47,9 @@ typedef struct _Elput_Pointer Elput_Pointer;
/* opaque structure to represent a touch device */
typedef struct _Elput_Touch Elput_Touch;
/* opaque structure to represent swipe data */
typedef struct _Elput_Swipe_Gesture Elput_Swipe_Gesture;
/* structure to represent event for seat capability changes */
typedef struct _Elput_Event_Seat_Caps
{
@ -131,6 +134,7 @@ EAPI extern int ELPUT_EVENT_MODIFIERS_SEND;
EAPI extern int ELPUT_EVENT_DEVICE_CHANGE;
EAPI extern int ELPUT_EVENT_SESSION_ACTIVE;
/** @since 1.19 */
EAPI extern int ELPUT_EVENT_POINTER_MOTION;
@ -201,6 +205,19 @@ EAPI int elput_shutdown(void);
*/
EAPI Elput_Manager *elput_manager_connect(const char *seat, unsigned int tty);
/**
* Create an input manager on the specified seat. Only gesture events are emitted. Nothing else.
*
* @param seat
* @param tty
*
* @return A Elput_Manager on success, NULL on failure
*
* @ingroup Elput_Manager_Group
*/
EAPI Elput_Manager *elput_manager_connect_gestures(const char *seat, unsigned int tty);
/**
* Disconnect an input manager
*
@ -726,6 +743,93 @@ EAPI Eina_Stringshare *elput_seat_name_get(const Elput_Seat *seat);
* @since 1.20
*/
EAPI Elput_Manager *elput_seat_manager_get(const Elput_Seat *seat);
/**
* @defgroup Elput_Gestures Elput gesture accessors
*
* Functions for accessing details of gesture events.
* The structure pointers can only be accessed within the events that emit them.
*/
/**
* A swipe gesture has began.
* ELPUT_EVENT_SWIPE_UPDATE and finally a single ELPUT_EVENT_SWIPE_END event will be emitted.
*
* @ingroup Elput_Gestures
* @since 1.26
*/
EAPI extern int ELPUT_EVENT_SWIPE_BEGIN;
/**
* There is a change to a ongoing swipe gesture.
*
* @ingroup Elput_Gestures
* @since 1.26
*/
EAPI extern int ELPUT_EVENT_SWIPE_UPDATE;
/**
* A ongoing swipe gesture has ended.
* This ends the lifetime of this gesture.
*
* @ingroup Elput_Gestures
* @since 1.26
*/
EAPI extern int ELPUT_EVENT_SWIPE_END;
/**
* Get the difference of x position from the last event to this event.
*
* @param gesture The event, if NULL 0 is returned
*
* @ingroup Elput_Gestures
* @since 1.26
*/
EAPI double elput_swipe_dx_get(Elput_Swipe_Gesture *gesture);
/**
* Get the difference of y position from the last event to this event.
*
* @param gesture The event, if NULL 0 is returned
*
* @ingroup Elput_Gestures
* @since 1.26
*/
EAPI double elput_swipe_dy_get(Elput_Swipe_Gesture *gesture);
/**
* Get the finger_count for this gesture
*
* @param gesture The event, if NULL 0 is returned
*
* @ingroup Elput_Gestures
* @since 1.26
*/
EAPI int elput_swipe_finger_count_get(Elput_Swipe_Gesture *gesture);
/**
* Get the window in which this event is emitted.
*
* @param gesture The event, if NULL 0 is returned
*
* @ingroup Elput_Gestures
* @since 1.26
*/
EAPI int elput_swipe_window_get(Elput_Swipe_Gesture *gesture);
/**
* Get the device from which the gesture event is coming.
*
* This value is the same for the lifetime of a gesture
*
* @param gesture The event, if NULL, NULL is returned
*
* @ingroup Elput_Gestures
* @since 1.26
*/
EAPI Elput_Device *elput_swipe_device_get(Elput_Swipe_Gesture *gesture);
# endif
# undef EAPI

View File

@ -14,6 +14,9 @@ EAPI int ELPUT_EVENT_DEVICE_CHANGE = 0;
EAPI int ELPUT_EVENT_SESSION_ACTIVE = 0;
EAPI int ELPUT_EVENT_POINTER_MOTION = 0;
EAPI int ELPUT_EVENT_SWITCH = 0;
EAPI int ELPUT_EVENT_SWIPE_BEGIN = 0;
EAPI int ELPUT_EVENT_SWIPE_UPDATE = 0;
EAPI int ELPUT_EVENT_SWIPE_END = 0;
EAPI int
elput_init(void)
@ -40,6 +43,9 @@ elput_init(void)
ELPUT_EVENT_SESSION_ACTIVE = ecore_event_type_new();
ELPUT_EVENT_POINTER_MOTION = ecore_event_type_new();
ELPUT_EVENT_SWITCH = ecore_event_type_new();
ELPUT_EVENT_SWIPE_BEGIN = ecore_event_type_new();
ELPUT_EVENT_SWIPE_UPDATE = ecore_event_type_new();
ELPUT_EVENT_SWIPE_END = ecore_event_type_new();
return _elput_init_count;

View File

@ -0,0 +1,78 @@
#include <elput_private.h>
#define ACCESSOR(STRUCT_NAME, FIELD_NAME, TYPE, FALLBACK) \
EAPI TYPE \
elput_##STRUCT_NAME##_##FIELD_NAME##_get(Elput_Swipe_Gesture *gesture) \
{ \
EINA_SAFETY_ON_NULL_RETURN_VAL(gesture, FALLBACK); \
return gesture->FIELD_NAME; \
}
ACCESSOR(swipe, dy, double, 0.0f)
ACCESSOR(swipe, dx, double, 0.0f)
ACCESSOR(swipe, finger_count, int, 0)
ACCESSOR(swipe, window, int, 0)
ACCESSOR(swipe, device, Elput_Device*, NULL)
EAPI Elput_Manager*
elput_manager_connect_gestures(const char *seat, unsigned int tty)
{
Elput_Manager *em = elput_manager_connect(seat, tty);
if (em)
{
em->only_gesture_events = EINA_TRUE;
}
return em;
}
static void
_free_and_unref_device(void *userdata EINA_UNUSED, void *data)
{
Elput_Swipe_Gesture *gesture = data;
libinput_device_unref(gesture->device->device);
free(gesture);
}
static void
_eval_callback(int event, struct libinput_device *device, struct libinput_event_gesture *gesture)
{
Elput_Device *dev = libinput_device_get_user_data(device);
Elput_Swipe_Gesture *elput_gesture = calloc(1, sizeof(Elput_Swipe_Gesture));
elput_gesture->dx = libinput_event_gesture_get_dx(gesture);
elput_gesture->dy = libinput_event_gesture_get_dy(gesture);
elput_gesture->finger_count = libinput_event_gesture_get_finger_count(gesture);
elput_gesture->window = dev->seat->manager->window;
elput_gesture->device = dev;
libinput_device_ref(device);
ecore_event_add(event, elput_gesture, _free_and_unref_device, NULL);
}
int
_gesture_event_process(struct libinput_event *event)
{
struct libinput_device *dev;
int ret = 1;
dev = libinput_event_get_device(event);
switch (libinput_event_get_type(event))
{
case LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN:
_eval_callback(ELPUT_EVENT_SWIPE_BEGIN, dev, libinput_event_get_gesture_event(event));
break;
case LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE:
_eval_callback(ELPUT_EVENT_SWIPE_UPDATE, dev, libinput_event_get_gesture_event(event));
break;
case LIBINPUT_EVENT_GESTURE_SWIPE_END:
_eval_callback(ELPUT_EVENT_SWIPE_END, dev, libinput_event_get_gesture_event(event));
break;
default:
ret = 0;
break;
}
return ret;
}

View File

@ -301,20 +301,25 @@ _udev_process_event(struct libinput_event *event)
}
static void
_process_event(struct libinput_event *event)
_process_event(Elput_Manager *em, struct libinput_event *event)
{
if (_udev_process_event(event)) return;
if (_evdev_event_process(event)) return;
if (!em->only_gesture_events)
{
if (_evdev_event_process(event)) return;
}
if (_gesture_event_process(event)) return;
}
static void
_process_events(Elput_Input *ei)
_process_events(Elput_Manager *em)
{
struct libinput_event *event;
Elput_Input *ei = &em->input;
while ((ei->lib) && (event = libinput_get_event(ei->lib)))
{
_process_event(event);
_process_event(em, event);
libinput_event_destroy(event);
}
}
@ -322,14 +327,14 @@ _process_events(Elput_Input *ei)
static Eina_Bool
_cb_input_dispatch(void *data, Ecore_Fd_Handler *hdlr EINA_UNUSED)
{
Elput_Input *ei;
Elput_Manager *em;
ei = data;
em = data;
if ((ei->lib) && (libinput_dispatch(ei->lib) != 0))
if ((em->input.lib) && (libinput_dispatch(em->input.lib) != 0))
WRN("libinput failed to dispatch events");
_process_events(ei);
_process_events(em);
return EINA_TRUE;
}
@ -361,10 +366,10 @@ _elput_input_init_end(void *data, Ecore_Thread *eth EINA_UNUSED)
manager->input.hdlr =
ecore_main_fd_handler_add(libinput_get_fd(manager->input.lib),
ECORE_FD_READ, _cb_input_dispatch,
&manager->input, NULL, NULL);
manager, NULL, NULL);
if (manager->input.hdlr)
_process_events(&manager->input);
_process_events(manager);
else
{
ERR("Could not create input fd handler");
@ -431,7 +436,7 @@ _elput_input_enable(Elput_Manager *manager)
{
if (libinput_resume(manager->input.lib) != 0) return;
manager->input.suspended = EINA_FALSE;
_process_events(&manager->input);
_process_events(manager);
}
}
@ -444,7 +449,7 @@ _elput_input_disable(Elput_Manager *manager)
EINA_LIST_FOREACH(manager->input.seats, l, seat)
seat->pending_motion = 1;
if (manager->input.lib) libinput_suspend(manager->input.lib);
_process_events(&manager->input);
_process_events(manager);
manager->input.suspended = EINA_TRUE;
}

View File

@ -5,6 +5,7 @@ static Elput_Interface *_ifaces[] =
#ifdef HAVE_SYSTEMD
&_logind_interface,
#endif
&_root_interface,
NULL,
};

View File

@ -246,6 +246,13 @@ struct _Elput_Device
Eina_Bool invert_y : 1;
};
struct _Elput_Swipe_Gesture {
double dx, dy;
int finger_count;
int window;
Elput_Device *device;
};
struct _Elput_Manager
{
Elput_Interface *interface;
@ -282,6 +289,7 @@ struct _Elput_Manager
Elput_Input input;
Eina_Bool del : 1;
Eina_Bool only_gesture_events : 1;
};
typedef struct _Elput_Async_Open
@ -295,6 +303,7 @@ void _elput_input_enable(Elput_Manager *manager);
void _elput_input_disable(Elput_Manager *manager);
int _evdev_event_process(struct libinput_event *event);
int _gesture_event_process(struct libinput_event *event);
Elput_Device *_evdev_device_create(Elput_Seat *seat, struct libinput_device *device);
void _evdev_device_destroy(Elput_Device *edev);
void _evdev_keyboard_destroy(Elput_Keyboard *kbd);
@ -308,6 +317,7 @@ Elput_Keyboard *_evdev_keyboard_get(Elput_Seat *seat);
Elput_Touch *_evdev_touch_get(Elput_Seat *seat);
extern Elput_Interface _logind_interface;
extern Elput_Interface _root_interface;
void _keyboard_keymap_update(Elput_Seat *seat);
void _keyboard_group_update(Elput_Seat *seat);

146
src/lib/elput/elput_root.c Normal file
View File

@ -0,0 +1,146 @@
#include "elput_private.h"
#include <grp.h>
#include <sys/types.h>
#include <pwd.h>
# ifdef major
# define MAJOR(x) major(x)
# else
# define MAJOR(x) ((((x) >> 8) & 0xfff) | (((x) >> 32) & ~0xfff))
# endif
static Eina_Bool
_user_part_of_input(void)
{
uid_t user = getuid();
struct passwd *user_pw = getpwuid(user);
gid_t *gids = NULL;
int number_of_groups = 0;
struct group *input_group = getgrnam("input");
EINA_SAFETY_ON_NULL_RETURN_VAL(user_pw, EINA_FALSE);
EINA_SAFETY_ON_NULL_RETURN_VAL(input_group, EINA_FALSE);
if (getgrouplist(user_pw->pw_name, getgid(), NULL, &number_of_groups) != -1)
{
ERR("Failed to enumerate groups of user");
return EINA_FALSE;
}
number_of_groups ++;
gids = alloca((number_of_groups) * sizeof(gid_t));
if (getgrouplist(user_pw->pw_name, getgid(), gids, &number_of_groups) == -1)
{
ERR("Failed to get groups of user");
return EINA_FALSE;
}
for (int i = 0; i < number_of_groups; ++i)
{
if (gids[i] == input_group->gr_gid)
return EINA_TRUE;
}
return EINA_FALSE;
}
static Eina_Bool
_root_connect(Elput_Manager **manager EINA_UNUSED, const char *seat EINA_UNUSED, unsigned int tty EINA_UNUSED)
{
Elput_Manager *em;
em = calloc(1, sizeof(Elput_Manager));
if (!em) return EINA_FALSE;
em->interface = &_root_interface;
em->seat = eina_stringshare_add(seat);
if (!_user_part_of_input())
{
free(em);
return EINA_FALSE;
}
*manager = em;
return EINA_TRUE;
}
static void
_root_disconnect(Elput_Manager *em EINA_UNUSED)
{
//Nothing to do here, there is no data to free
}
static int
_root_open(Elput_Manager *em EINA_UNUSED, const char *path, int flags)
{
struct stat st;
int ret, fd = -1;
int fl;
ret = stat(path, &st);
if (ret < 0) return -1;
if (!S_ISCHR(st.st_mode)) return -1;
fd = open(path, flags);
if (fd < 0) return fd;
if (MAJOR(st.st_rdev) == 226) //DRM_MAJOR
em->drm_opens++;
fl = fcntl(fd, F_GETFL);
if (fl < 0) goto err;
if (flags & O_NONBLOCK)
fl |= O_NONBLOCK;
ret = fcntl(fd, F_SETFL, fl);
if (ret < 0) goto err;
return fd;
err:
close(fd);
return -1;
}
static void
_root_open_async(Elput_Manager *em, const char *path, int flags)
{
int fd = _root_open(em, path, flags);
int ret;
while (1)
{
ret = write(em->input.pipe, &fd, sizeof(int));
if (ret < 0)
{
if ((errno == EAGAIN) || (errno == EINTR))
continue;
WRN("Failed to write to input pipe");
}
break;
}
close(em->input.pipe);
em->input.pipe = -1;
}
static void
_root_close(Elput_Manager *em EINA_UNUSED, int fd)
{
close(fd);
}
static Eina_Bool
_root_vt_set(Elput_Manager *em EINA_UNUSED, int vt EINA_UNUSED)
{
//Nothing to do here
return EINA_TRUE;
}
Elput_Interface _root_interface =
{
_root_connect,
_root_disconnect,
_root_open,
_root_open_async,
_root_close,
_root_vt_set,
};

View File

@ -11,7 +11,9 @@ elput_src = files([
'elput_evdev.c',
'elput_input.c',
'elput_logind.c',
'elput_root.c',
'elput_manager.c',
'elput_gestures.c',
'elput.c',
'elput_private.h'
])