WIP: 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 only swipe bindings.
This commit is contained in:
Marcel Hollerbach 2021-03-24 16:07:27 +01:00
parent 49ac4121cf
commit 202bae05ec
7 changed files with 307 additions and 12 deletions

View File

@ -47,6 +47,8 @@ typedef struct _Elput_Pointer Elput_Pointer;
/* opaque structure to represent a touch device */
typedef struct _Elput_Touch Elput_Touch;
typedef struct _Elput_Swipe_Gesture Elput_Swipe_Gesture;
/* structure to represent event for seat capability changes */
typedef struct _Elput_Event_Seat_Caps
{
@ -201,6 +203,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 +741,17 @@ 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);
typedef void (*Elput_Swipe_Gesture_Callback)(void *data, Elput_Device *dev, Elput_Swipe_Gesture *gesture);
EAPI double elput_swipe_dx_get(Elput_Swipe_Gesture *gesture);
EAPI double elput_swipe_dy_get(Elput_Swipe_Gesture *gesture);
EAPI int elput_swipe_finger_count_get(Elput_Swipe_Gesture *gesture);
EAPI void elput_manager_swipe_gesture_listen(Elput_Manager *em,
Elput_Swipe_Gesture_Callback begin, void *begin_data,
Elput_Swipe_Gesture_Callback update, void *update_data,
Elput_Swipe_Gesture_Callback end, void *end_data);
# endif
# undef EAPI

View File

@ -0,0 +1,99 @@
#include <elput_private.h>
EAPI double
elput_swipe_dx_get(Elput_Swipe_Gesture *gesture)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(gesture, 0.0f);
return gesture->dx;
}
EAPI double
elput_swipe_dy_get(Elput_Swipe_Gesture *gesture)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(gesture, 0.0f);
return gesture->dy;
}
EAPI int
elput_swipe_finger_count_get(Elput_Swipe_Gesture *gesture)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(gesture, 0);
return gesture->finger_count;
}
EAPI void
elput_manager_swipe_gesture_listen(Elput_Manager *em,
Elput_Swipe_Gesture_Callback begin, void *begin_data,
Elput_Swipe_Gesture_Callback update, void *update_data,
Elput_Swipe_Gesture_Callback end, void *end_data)
{
EINA_SAFETY_ON_NULL_RETURN(em);
em->swipe_callback.begin.cb = begin;
em->swipe_callback.begin.data = begin_data;
em->swipe_callback.end.cb = end;
em->swipe_callback.end.data = end_data;
em->swipe_callback.update.cb = update;
em->swipe_callback.update.data = update_data;
}
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
_eval_callback(Elput_Gesture_Swipe_Callback *callback, struct libinput_device *device, struct libinput_event_gesture *gesture)
{
Elput_Device *dev;
Elput_Swipe_Gesture elput_gesture = {
libinput_event_gesture_get_dx(gesture),
libinput_event_gesture_get_dy(gesture),
libinput_event_gesture_get_finger_count(gesture),
};
if (!callback->cb) return;
dev = libinput_device_get_user_data(device);
callback->cb(callback->data, dev, &elput_gesture);
}
int
_gesture_event_process(struct libinput_event *event)
{
Elput_Manager *em;
struct libinput *lib;
struct libinput_device *dev;
int ret = 1;
lib = libinput_event_get_context(event);
dev = libinput_event_get_device(event);
em = libinput_get_user_data(lib);
switch (libinput_event_get_type(event))
{
case LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN:
_eval_callback(&em->swipe_callback.begin, dev, libinput_event_get_gesture_event(event));
break;
case LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE:
_eval_callback(&em->swipe_callback.update, dev, libinput_event_get_gesture_event(event));
break;
case LIBINPUT_EVENT_GESTURE_SWIPE_END:
_eval_callback(&em->swipe_callback.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,16 @@ struct _Elput_Device
Eina_Bool invert_y : 1;
};
typedef struct {
Elput_Swipe_Gesture_Callback cb;
void *data;
} Elput_Gesture_Swipe_Callback;
struct _Elput_Swipe_Gesture {
double dx, dy;
int finger_count;
};
struct _Elput_Manager
{
Elput_Interface *interface;
@ -257,6 +267,9 @@ struct _Elput_Manager
int vt_fd;
Ecore_Event_Handler *vt_hdlr;
uint32_t window;
struct {
Elput_Gesture_Swipe_Callback begin, update, end;
} swipe_callback;
int pending_ptr_x;
int pending_ptr_y;
@ -282,6 +295,7 @@ struct _Elput_Manager
Elput_Input input;
Eina_Bool del : 1;
Eina_Bool only_gesture_events : 1;
};
typedef struct _Elput_Async_Open
@ -295,6 +309,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 +323,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'
])