From ed5dcfbd60c6c37b06c64395df3d4c9b11293f24 Mon Sep 17 00:00:00 2001 From: Marcel Hollerbach Date: Wed, 24 Mar 2021 16:04:48 +0100 Subject: [PATCH] gesture_recognition: Rework to use elput With this: - Support for gestures in X *and* wayland. Wayland does not require the libinput group hack - Hotplugging support thanks to udev support This requires a new rebuild of efl. --- src/bin/e_bindings.c | 14 + src/bin/e_bindings.h | 2 + .../e_int_config_swipebindings.c | 47 ++- src/modules/gesture_recognition/e_mod_main.c | 313 ++++++++---------- src/modules/gesture_recognition/meson.build | 2 +- 5 files changed, 194 insertions(+), 184 deletions(-) diff --git a/src/bin/e_bindings.c b/src/bin/e_bindings.c index 08a19c336..9c53e1121 100644 --- a/src/bin/e_bindings.c +++ b/src/bin/e_bindings.c @@ -21,6 +21,7 @@ static Eina_List *acpi_bindings = NULL; static Eina_List *swipe_bindings = NULL; static unsigned int bindings_disabled = 0; +static int gesture_capable_devices = 0; static E_Bindings_Swipe_Live_Update live_update; static E_Bindings_Swipe_Live_Update live_update_data; @@ -1613,6 +1614,19 @@ _e_bindings_edge_cb_timer(void *data) return ECORE_CALLBACK_CANCEL; } + +E_API void +e_bindings_gesture_capable_devices_set(int number) +{ + gesture_capable_devices = number; +} + +E_API int +e_bindings_gesture_capable_devices_get(void) +{ + return gesture_capable_devices; +} + E_API void e_bindings_swipe_add(E_Binding_Context ctxt, double direction, double length, unsigned int fingers, double error, const char *action, const char *params) { diff --git a/src/bin/e_bindings.h b/src/bin/e_bindings.h index b65fabe38..40a048050 100644 --- a/src/bin/e_bindings.h +++ b/src/bin/e_bindings.h @@ -224,6 +224,8 @@ E_API E_Action* e_bindings_swipe_handle(E_Binding_Context ctxt, E_Object *ob E_API Eina_Inarray/**/* e_bindings_swipe_find_candidates(E_Binding_Context ctxt, double direction, double lenght, unsigned int fingers); E_API void e_bindings_swipe_live_update_hook_set(E_Bindings_Swipe_Live_Update update, void *data); E_API E_Bindings_Swipe_Live_Update e_bindings_swipe_live_update_hook_get(void); +E_API void e_bindings_gesture_capable_devices_set(int number); +E_API int e_bindings_gesture_capable_devices_get(void); E_API void* e_bindings_swipe_live_update_hook_data_get(void); E_API int e_bindings_evas_modifiers_convert(Evas_Modifier *modifiers); diff --git a/src/modules/conf_bindings/e_int_config_swipebindings.c b/src/modules/conf_bindings/e_int_config_swipebindings.c index 90c5ced93..a982e58d3 100644 --- a/src/modules/conf_bindings/e_int_config_swipebindings.c +++ b/src/modules/conf_bindings/e_int_config_swipebindings.c @@ -276,12 +276,12 @@ _action_change_cb(void *data) static int _swipe_binding_sort_cb(E_Config_Binding_Swipe *a, E_Config_Binding_Swipe *b) { - int finger_diff = (a->fingers == b->fingers)*-1; + int finger_diff = a->fingers - b->fingers; if (!finger_diff) { return a->direction - b->direction; } - return finger_diff; + return finger_diff*-1; } static void @@ -950,6 +950,38 @@ _basic_create_widgets(E_Config_Dialog *cfd, Evas *evas, E_Config_Dialog_Data *cf return o; } +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; +} E_Config_Dialog * e_int_config_swipebindings(Evas_Object *parent EINA_UNUSED, const char *params) @@ -966,13 +998,22 @@ e_int_config_swipebindings(Evas_Object *parent EINA_UNUSED, const char *params) v->basic.create_widgets = _basic_create_widgets; v->override_auto_apply = 1; + if (!_user_part_of_input()) + { + e_module_dialog_show(NULL, "Gesture Recognition", "Your user is not part of the input group, libinput cannot be used."); + } + + if (e_bindings_gesture_capable_devices_get() == 0) + { + e_module_dialog_show(NULL, "Gesture Recognition", "No devices detected that are capable of gesture recognition."); + } + cfd = e_config_dialog_new(NULL, _("Swipe Bindings Settings"), "E", "keyboard_and_mouse/swipe_bindings", "enlightenment/swipes", 0, v, NULL); if ((params) && (params[0])) { cfd->cfdata->params = eina_stringshare_add(params); -// _add_swipe_binding_cb(cfd->cfdata, NULL); } return cfd; diff --git a/src/modules/gesture_recognition/e_mod_main.c b/src/modules/gesture_recognition/e_mod_main.c index b1ddbf988..aad0144a5 100644 --- a/src/modules/gesture_recognition/e_mod_main.c +++ b/src/modules/gesture_recognition/e_mod_main.c @@ -1,9 +1,9 @@ #include #include -#include #include #include #include +#include E_API E_Module_Api e_modapi = { @@ -11,9 +11,8 @@ E_API E_Module_Api e_modapi = "Gesture Recognition" }; -static struct libinput *gesture_recognition_ctx; -static Ecore_Fd_Handler *fd_listener; static Eina_Hash *active_gestures; +static Elput_Manager *manager; typedef struct { Eina_Vector2 pos; @@ -23,45 +22,8 @@ typedef struct { } visuals; } Swipe_Stats; -static int -open_restricted(const char *path, int flags, void *user_data EINA_UNUSED) -{ - int fd = open(path, flags); - return fd < 0 ? -errno : fd; -} - -static void -close_restricted(int fd, void *user_data EINA_UNUSED) -{ - close(fd); -} - -static const struct libinput_interface interface = { - .open_restricted = open_restricted, - .close_restricted = close_restricted, -}; - -static void -_find_all_touch_input_devices(const char *path, struct libinput *li) -{ - Eina_File_Direct_Info *info; - Eina_Iterator *input_devies = eina_file_direct_ls(path); - - EINA_ITERATOR_FOREACH(input_devies, info) - { - struct libinput_device *dev = libinput_path_add_device(li, info->path); - - if (!dev) continue; - - if (!libinput_device_has_capability(dev, LIBINPUT_DEVICE_CAP_GESTURE)) - { - libinput_path_remove_device(dev); - } - } -} - static Swipe_Stats* -_find_swipe_gesture_recognizition(struct libinput_device *dev) +_find_swipe_gesture_recognizition(Elput_Device *dev) { Swipe_Stats *stats = eina_hash_find(active_gestures, dev); @@ -69,7 +31,7 @@ _find_swipe_gesture_recognizition(struct libinput_device *dev) } static Swipe_Stats* -_start_swipe_gesture_recognizition(struct libinput_device *dev) +_start_swipe_gesture_recognizition(Elput_Device *dev) { Swipe_Stats *stats = _find_swipe_gesture_recognizition(dev); @@ -103,7 +65,7 @@ _start_swipe_gesture_recognizition(struct libinput_device *dev) } static void -_end_swipe_gesture_recognizition(struct libinput_device *dev) +_end_swipe_gesture_recognizition(Elput_Device *dev) { eina_hash_del_by_key(active_gestures, dev); } @@ -118,137 +80,6 @@ _config_angle(Eina_Vector2 pos) return res; } -static Eina_Bool -_cb_input_dispatch(void *data, Ecore_Fd_Handler *hdlr EINA_UNUSED) -{ - struct libinput *li = data; - struct libinput_event *event; - - if (libinput_dispatch(li) != 0) - printf("Failed to dispatch libinput events"); - - while((event = libinput_get_event(li))) - { - E_Bindings_Swipe_Live_Update live_update = e_bindings_swipe_live_update_hook_get(); - - enum libinput_event_type type = libinput_event_get_type(event); - struct libinput_device *dev = libinput_event_get_device(event); - if (type == LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN) - { - struct libinput_event_gesture *gesture = libinput_event_get_gesture_event(event); - - Swipe_Stats *stats = _start_swipe_gesture_recognizition(dev); - stats->fingers = libinput_event_gesture_get_finger_count(gesture); - stats->pos.x = stats->pos.y = 0; - } - else if (type == LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE) - { - struct libinput_event_gesture *gesture = libinput_event_get_gesture_event(event); - Swipe_Stats *stats = _find_swipe_gesture_recognizition(dev); - - stats->pos.x += libinput_event_gesture_get_dx(gesture); - stats->pos.y += libinput_event_gesture_get_dy(gesture); - if (live_update) - { - live_update(e_bindings_swipe_live_update_hook_data_get(), EINA_FALSE, _config_angle(stats->pos), eina_vector2_length_get(&stats->pos), 0.8, stats->fingers); - } - else if (stats->visuals.win) - { - Eina_Inarray *res = e_bindings_swipe_find_candidates(E_BINDING_CONTEXT_NONE, _config_angle (stats->pos), eina_vector2_length_get(&stats->pos), stats->fingers); - E_Binding_Swipe_Candidate *itr; - double total = 0.0f; - unsigned int len = 0; - - EINA_INARRAY_FOREACH(res, itr) - { - total += itr->acceptance; - len ++; - } - - if (len > 0) - { - char text_buffer[1000]; - - snprintf(text_buffer, sizeof(text_buffer), "%d gestures possible", len); - elm_progressbar_value_set(stats->visuals.visuals, total/len); - elm_object_text_set(stats->visuals.visuals, text_buffer); - } - else - { - elm_progressbar_value_set(stats->visuals.visuals, 0.0f); - elm_object_text_set(stats->visuals.visuals, "No gesture found"); - } - - eina_inarray_free(res); - } - } - else if (type == LIBINPUT_EVENT_GESTURE_SWIPE_END) - { - Swipe_Stats *stats = _find_swipe_gesture_recognizition(dev); - - if (live_update) - live_update(e_bindings_swipe_live_update_hook_data_get(), EINA_TRUE, _config_angle(stats->pos), eina_vector2_length_get(&stats->pos), 0.8, stats->fingers); - else - e_bindings_swipe_handle(E_BINDING_CONTEXT_NONE, NULL, _config_angle(stats->pos), eina_vector2_length_get(&stats->pos), stats->fingers); - - _end_swipe_gesture_recognizition(dev); - } - libinput_event_destroy(event); - } - return EINA_TRUE; -} - -static void -_setup_libinput(void) -{ - gesture_recognition_ctx = libinput_path_create_context(&interface, NULL); - - _find_all_touch_input_devices("/dev/input/", gesture_recognition_ctx); - - fd_listener = ecore_main_fd_handler_add(libinput_get_fd(gesture_recognition_ctx), ECORE_FD_READ, _cb_input_dispatch, gesture_recognition_ctx, NULL, NULL); -} - - -static void -_tear_down_libinput(void) -{ - ecore_main_fd_handler_del(fd_listener); - libinput_unref(gesture_recognition_ctx); -} - -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 void _stats_free(void *ptr) { @@ -258,17 +89,135 @@ _stats_free(void *ptr) free(stats); } +static void +_apply_visual_changes(Swipe_Stats *stats) +{ + E_Bindings_Swipe_Live_Update live_update = e_bindings_swipe_live_update_hook_get(); + if (live_update) + { + live_update(e_bindings_swipe_live_update_hook_data_get(), EINA_FALSE, _config_angle(stats->pos), eina_vector2_length_get(&stats->pos), 0.8, stats->fingers); + } + else if (stats->visuals.win) + { + Eina_Inarray *res = e_bindings_swipe_find_candidates(E_BINDING_CONTEXT_NONE, _config_angle (stats->pos), eina_vector2_length_get(&stats->pos), stats->fingers); + E_Binding_Swipe_Candidate *itr; + double total = 0.0f; + unsigned int len = 0; + + EINA_INARRAY_FOREACH(res, itr) + { + total += itr->acceptance; + len ++; + } + + if (len > 0) + { + char text_buffer[1000]; + + snprintf(text_buffer, sizeof(text_buffer), "%d gestures possible", len); + elm_progressbar_value_set(stats->visuals.visuals, total/len); + elm_object_text_set(stats->visuals.visuals, text_buffer); + } + else + { + elm_progressbar_value_set(stats->visuals.visuals, 0.0f); + elm_object_text_set(stats->visuals.visuals, "No gesture found"); + } + + eina_inarray_free(res); + } +} + +static Eina_Bool +_swipe_cb(void *data EINA_UNUSED, int type, void *event) +{ + Elput_Swipe_Gesture *gesture = event; + Elput_Device *dev = elput_swipe_device_get(gesture); + + if (type == ELPUT_EVENT_SWIPE_BEGIN) + { + Swipe_Stats *stats = _start_swipe_gesture_recognizition(dev); + stats->fingers = elput_swipe_finger_count_get(gesture); + stats->pos.x = stats->pos.y = 0; + } + else if (type == ELPUT_EVENT_SWIPE_UPDATE) + { + Swipe_Stats *stats = _find_swipe_gesture_recognizition(dev); + + stats->pos.x += elput_swipe_dx_get(gesture); + stats->pos.y += elput_swipe_dy_get(gesture); + + _apply_visual_changes(stats); + } + else if (type == ELPUT_EVENT_SWIPE_END) + { + E_Bindings_Swipe_Live_Update live_update = e_bindings_swipe_live_update_hook_get(); + Swipe_Stats *stats = _find_swipe_gesture_recognizition(dev); + + if (live_update) + live_update(e_bindings_swipe_live_update_hook_data_get(), EINA_TRUE, _config_angle(stats->pos), eina_vector2_length_get(&stats->pos), 0.8, stats->fingers); + else + e_bindings_swipe_handle(E_BINDING_CONTEXT_NONE, NULL, _config_angle(stats->pos), eina_vector2_length_get(&stats->pos), stats->fingers); + + _end_swipe_gesture_recognizition(dev); + } + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_debug(void *data EINA_UNUSED, int type EINA_UNUSED, void *event EINA_UNUSED) +{ + Elput_Event_Seat_Caps *caps = event; + const Eina_List *node, *devices = elput_seat_devices_get(caps->seat); + Elput_Device *device; + int number_of_gesture_devices = 0; + + EINA_LIST_FOREACH(devices, node, device) + { + if (elput_device_caps_get(device) & ELPUT_DEVICE_CAPS_GESTURE) + { + number_of_gesture_devices++; + } + } + e_bindings_gesture_capable_devices_set(number_of_gesture_devices); + return ECORE_CALLBACK_PASS_ON; +} + +static void +_init_for_x11(E_Module *m EINA_UNUSED) +{ + const char *device = NULL; + + elput_init(); + device = getenv("XDG_SEAT"); + if (!device) device = "seat0"; + manager = elput_manager_connect_gestures(device, 0); + elput_input_init(manager); +} + +static void +_shutdown_for_x11(void) +{ + elput_manager_disconnect(manager); + manager = NULL; + elput_shutdown(); +} + + E_API int e_modapi_init(E_Module *m EINA_UNUSED) { - if (!_user_part_of_input()) + if (e_comp->comp_type == E_PIXMAP_TYPE_X) { - e_module_dialog_show(m, "Gesture Recognition", "Your user is not part of the input group, libinput cannot be used."); - - return 0; + _init_for_x11(m); } + active_gestures = eina_hash_pointer_new(_stats_free); - _setup_libinput(); + + ecore_event_handler_add(ELPUT_EVENT_SWIPE_BEGIN, _swipe_cb, NULL); + ecore_event_handler_add(ELPUT_EVENT_SWIPE_UPDATE, _swipe_cb, NULL); + ecore_event_handler_add(ELPUT_EVENT_SWIPE_END, _swipe_cb, NULL); + ecore_event_handler_add(ELPUT_EVENT_SEAT_CAPS, _debug, NULL); return 1; } @@ -276,7 +225,11 @@ e_modapi_init(E_Module *m EINA_UNUSED) E_API int e_modapi_shutdown(E_Module *m EINA_UNUSED) { - _tear_down_libinput(); + if (e_comp->comp_type == E_PIXMAP_TYPE_X) + { + _shutdown_for_x11(); + } + return 1; } diff --git a/src/modules/gesture_recognition/meson.build b/src/modules/gesture_recognition/meson.build index 55a7301ea..0bd6b50ef 100644 --- a/src/modules/gesture_recognition/meson.build +++ b/src/modules/gesture_recognition/meson.build @@ -1,4 +1,4 @@ src = files( 'e_mod_main.c', ) -deps += [dependency('libinput')] +deps += [dependency('elput')]