diff --git a/src/lib/elput/Elput.h b/src/lib/elput/Elput.h index 7a05f8e795..03f186a8c8 100644 --- a/src/lib/elput/Elput.h +++ b/src/lib/elput/Elput.h @@ -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 diff --git a/src/lib/elput/elput.c b/src/lib/elput/elput.c index 3c51bca1ff..6426e803e4 100644 --- a/src/lib/elput/elput.c +++ b/src/lib/elput/elput.c @@ -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; diff --git a/src/lib/elput/elput_gestures.c b/src/lib/elput/elput_gestures.c new file mode 100644 index 0000000000..baa67e9519 --- /dev/null +++ b/src/lib/elput/elput_gestures.c @@ -0,0 +1,78 @@ +#include + +#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; +} 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..9c613d9d57 100644 --- a/src/lib/elput/elput_private.h +++ b/src/lib/elput/elput_private.h @@ -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); 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' ])