From 202bae05ec3af12a3979e21fe967cb4a4c66f587 Mon Sep 17 00:00:00 2001 From: Marcel Hollerbach Date: Wed, 24 Mar 2021 16:07:27 +0100 Subject: 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. --- src/lib/elput/Elput.h | 26 ++++++++ src/lib/elput/elput_gestures.c | 99 ++++++++++++++++++++++++++++ src/lib/elput/elput_input.c | 29 ++++---- src/lib/elput/elput_manager.c | 1 + src/lib/elput/elput_private.h | 16 +++++ src/lib/elput/elput_root.c | 146 +++++++++++++++++++++++++++++++++++++++++ src/lib/elput/meson.build | 2 + 7 files changed, 307 insertions(+), 12 deletions(-) create mode 100644 src/lib/elput/elput_gestures.c create mode 100644 src/lib/elput/elput_root.c diff --git a/src/lib/elput/Elput.h b/src/lib/elput/Elput.h index 7a05f8e795..01f649ea46 100644 --- a/src/lib/elput/Elput.h +++ b/src/lib/elput/Elput.h @@ -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 diff --git a/src/lib/elput/elput_gestures.c b/src/lib/elput/elput_gestures.c new file mode 100644 index 0000000000..9aed338960 --- /dev/null +++ b/src/lib/elput/elput_gestures.c @@ -0,0 +1,99 @@ +#include + + +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; +} diff --git a/src/lib/elput/elput_input.c b/src/lib/elput/elput_input.c index 392b157b1b..1ec339fb4e 100644 --- a/src/lib/elput/elput_input.c +++ b/src/lib/elput/elput_input.c @@ -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; } diff --git a/src/lib/elput/elput_manager.c b/src/lib/elput/elput_manager.c index 93f39ea261..82335cd0a8 100644 --- a/src/lib/elput/elput_manager.c +++ b/src/lib/elput/elput_manager.c @@ -5,6 +5,7 @@ static Elput_Interface *_ifaces[] = #ifdef HAVE_SYSTEMD &_logind_interface, #endif + &_root_interface, NULL, }; diff --git a/src/lib/elput/elput_private.h b/src/lib/elput/elput_private.h index fd7d843d2e..a73eb7e7eb 100644 --- a/src/lib/elput/elput_private.h +++ b/src/lib/elput/elput_private.h @@ -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); diff --git a/src/lib/elput/elput_root.c b/src/lib/elput/elput_root.c new file mode 100644 index 0000000000..f07d46d0b1 --- /dev/null +++ b/src/lib/elput/elput_root.c @@ -0,0 +1,146 @@ +#include "elput_private.h" +#include +#include +#include + +# 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, +}; diff --git a/src/lib/elput/meson.build b/src/lib/elput/meson.build index 639840e424..0caf56f06d 100644 --- a/src/lib/elput/meson.build +++ b/src/lib/elput/meson.build @@ -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' ]) -- cgit v1.2.1