diff --git a/meson.build b/meson.build index 6a6daaa1..1e3066c9 100644 --- a/meson.build +++ b/meson.build @@ -345,6 +345,8 @@ install_headers('src/libinput.h') src_libinput = src_libfilter + [ 'src/libinput.c', 'src/libinput.h', + 'src/libinput-private-config.c', + 'src/libinput-private-config.h', 'src/libinput-private.h', 'src/evdev.c', 'src/evdev.h', @@ -670,6 +672,8 @@ if get_option('tests') config_h.set10('HAVE_LIBSYSTEMD', dep_libsystemd.found()) litest_sources = [ + 'src/libinput-private-config.c', + 'src/libinput-private-config.h', 'test/litest.h', 'test/litest-int.h', 'test/litest-device-absinfo-override.c', diff --git a/src/evdev-mt-touchpad-gestures.c b/src/evdev-mt-touchpad-gestures.c index 8c239bd7..b4fc7edb 100644 --- a/src/evdev-mt-touchpad-gestures.c +++ b/src/evdev-mt-touchpad-gestures.c @@ -1185,17 +1185,59 @@ tp_gesture_are_gestures_enabled(struct tp_dispatch *tp) return (!tp->semi_mt && tp->num_slots > 1); } +static enum libinput_config_status +tp_gesture_set_hold_enabled(struct libinput_device *device, + enum libinput_config_hold_state enabled) +{ + struct evdev_dispatch *dispatch = evdev_device(device)->dispatch; + struct tp_dispatch *tp = tp_dispatch(dispatch); + + if (!tp_gesture_are_gestures_enabled(tp)) + return LIBINPUT_CONFIG_STATUS_UNSUPPORTED; + + tp->gesture.hold_enabled = (enabled == LIBINPUT_CONFIG_HOLD_ENABLED); + + return LIBINPUT_CONFIG_STATUS_SUCCESS; +} + +static enum libinput_config_hold_state +tp_gesture_is_hold_enabled(struct libinput_device *device) +{ + struct evdev_dispatch *dispatch = evdev_device(device)->dispatch; + struct tp_dispatch *tp = tp_dispatch(dispatch); + + return tp->gesture.hold_enabled ? LIBINPUT_CONFIG_HOLD_ENABLED : + LIBINPUT_CONFIG_HOLD_DISABLED; +} + +static enum libinput_config_hold_state +tp_gesture_get_hold_default(struct libinput_device *device) +{ + struct evdev_dispatch *dispatch = evdev_device(device)->dispatch; + struct tp_dispatch *tp = tp_dispatch(dispatch); + + return tp_gesture_are_gestures_enabled(tp) ? + LIBINPUT_CONFIG_HOLD_ENABLED : + LIBINPUT_CONFIG_HOLD_DISABLED; +} + void tp_init_gesture(struct tp_dispatch *tp) { char timer_name[64]; + tp->gesture.config.set_hold_enabled = tp_gesture_set_hold_enabled; + tp->gesture.config.get_hold_enabled = tp_gesture_is_hold_enabled; + tp->gesture.config.get_hold_default = tp_gesture_get_hold_default; + tp->device->base.config.gesture = &tp->gesture.config; + /* two-finger scrolling is always enabled, this flag just * decides whether we detect pinch. semi-mt devices are too * unreliable to do pinch gestures. */ tp->gesture.enabled = tp_gesture_are_gestures_enabled(tp); tp->gesture.state = GESTURE_STATE_NONE; + tp->gesture.hold_enabled = tp_gesture_are_gestures_enabled(tp); snprintf(timer_name, sizeof(timer_name), diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h index a58ca7f7..2e849706 100644 --- a/src/evdev-mt-touchpad.h +++ b/src/evdev-mt-touchpad.h @@ -346,6 +346,7 @@ struct tp_dispatch { } accel; struct { + struct libinput_device_config_gesture config; bool enabled; bool started; unsigned int finger_count; @@ -358,6 +359,7 @@ struct tp_dispatch { double prev_scale; double angle; struct device_float_coords center; + bool hold_enabled; } gesture; struct { diff --git a/src/libinput-private-config.c b/src/libinput-private-config.c new file mode 100644 index 00000000..bd5cde3a --- /dev/null +++ b/src/libinput-private-config.c @@ -0,0 +1,75 @@ +/* + * Copyright © 2021 Red Hat, Inc. + * Copyright © 2021 José Expósito + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "config.h" + +#include "libinput-private-config.h" +#include "libinput-private.h" + +int +libinput_device_config_gesture_hold_is_available(struct libinput_device *device) +{ + if (!libinput_device_has_capability(device, + LIBINPUT_DEVICE_CAP_GESTURE)) + return 0; + + if (!device->config.gesture->get_hold_default(device)) + return 0; + + return 1; +} + +enum libinput_config_status +libinput_device_config_gesture_set_hold_enabled(struct libinput_device *device, + enum libinput_config_hold_state enable) +{ + if (enable != LIBINPUT_CONFIG_HOLD_ENABLED && + enable != LIBINPUT_CONFIG_HOLD_DISABLED) + return LIBINPUT_CONFIG_STATUS_INVALID; + + if (!libinput_device_config_gesture_hold_is_available(device)) { + return enable ? LIBINPUT_CONFIG_STATUS_UNSUPPORTED : + LIBINPUT_CONFIG_STATUS_SUCCESS; + } + + return device->config.gesture->set_hold_enabled(device, enable); +} + +enum libinput_config_hold_state +libinput_device_config_gesture_get_hold_enabled(struct libinput_device *device) +{ + if (!libinput_device_config_gesture_hold_is_available(device)) + return LIBINPUT_CONFIG_HOLD_DISABLED; + + return device->config.gesture->get_hold_enabled(device); +} + +enum libinput_config_hold_state +libinput_device_config_gesture_get_hold_default_enabled(struct libinput_device *device) +{ + if (!libinput_device_config_gesture_hold_is_available(device)) + return LIBINPUT_CONFIG_HOLD_DISABLED; + + return device->config.gesture->get_hold_default(device); +} diff --git a/src/libinput-private-config.h b/src/libinput-private-config.h new file mode 100644 index 00000000..d1d6c8ea --- /dev/null +++ b/src/libinput-private-config.h @@ -0,0 +1,111 @@ +/* + * Copyright © 2021 Red Hat, Inc. + * Copyright © 2021 José Expósito + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef LIBINPUT_PRIVATE_CONFIG_H +#define LIBINPUT_PRIVATE_CONFIG_H + +#include "config.h" + +#include "libinput.h" + +enum libinput_config_hold_state { + /** Hold gestures are to be disabled, or are currently disabled */ + LIBINPUT_CONFIG_HOLD_DISABLED, + /** Hold gestures are to be enabled, or are currently disabled */ + LIBINPUT_CONFIG_HOLD_ENABLED, +}; + +/** + * @ingroup config + * + * Check whether a device can perform hold gestures. + * + * @param device The device to configure + * @return Non-zero if a device can perform hold gestures, zero otherwise. + * + * @see libinput_device_config_gesture_set_hold_enabled + * @see libinput_device_config_gesture_get_hold_enabled + * @see libinput_device_config_gesture_get_hold_default_enabled + */ +int +libinput_device_config_gesture_hold_is_available(struct libinput_device *device); + +/** + * @ingroup config + * + * Enable or disable hold gestures on this device. + * + * @param device The device to configure + * @param enable @ref LIBINPUT_CONFIG_HOLD_ENABLED to enable hold gestures or + * @ref LIBINPUT_CONFIG_HOLD_DISABLED to disable them + * + * @return A config status code. Disabling hold gestures on a device that does + * not support them always succeeds. + * + * @see libinput_device_config_gesture_hold_is_available + * @see libinput_device_config_gesture_get_hold_enabled + * @see libinput_device_config_gesture_get_hold_default_enabled + */ +enum libinput_config_status +libinput_device_config_gesture_set_hold_enabled(struct libinput_device *device, + enum libinput_config_hold_state enable); + +/** + * @ingroup config + * + * Check if hold gestures are enabled on this device. If the device does not + * support hold gestures, this function always returns @ref + * LIBINPUT_CONFIG_HOLD_DISABLED. + * + * @param device The device to configure + * + * @retval LIBINPUT_CONFIG_HOLD_ENABLED If hold gestures are currently enabled + * @retval LIBINPUT_CONFIG_HOLD_DISABLED If hold gestures are currently disabled + * + * @see libinput_device_config_gesture_hold_is_available + * @see libinput_device_config_gesture_set_hold_enabled + * @see libinput_device_config_gesture_get_hold_default_enabled + */ +enum libinput_config_hold_state +libinput_device_config_gesture_get_hold_enabled(struct libinput_device *device); + +/** + * @ingroup config + * + * Return the default setting for whether hold gestures are enabled on this + * device. + * + * @param device The device to configure + * @retval LIBINPUT_CONFIG_HOLD_ENABLED If hold gestures are enabled by default + * @retval LIBINPUT_CONFIG_HOLD_DISABLED If hold gestures are disabled by + * default + * + * @see libinput_device_config_gesture_hold_is_available + * @see libinput_device_config_gesture_set_hold_enabled + * @see libinput_device_config_gesture_get_hold_enabled + */ +enum libinput_config_hold_state +libinput_device_config_gesture_get_hold_default_enabled(struct libinput_device *device); + +#endif /* LIBINPUT_PRIVATE_CONFIG_H */ diff --git a/src/libinput-private.h b/src/libinput-private.h index 8c7b77dd..172035ab 100644 --- a/src/libinput-private.h +++ b/src/libinput-private.h @@ -38,6 +38,7 @@ #include "linux/input.h" #include "libinput.h" +#include "libinput-private-config.h" #include "libinput-util.h" #include "libinput-version.h" @@ -307,6 +308,13 @@ struct libinput_device_config_rotation { unsigned int (*get_default_angle)(struct libinput_device *device); }; +struct libinput_device_config_gesture { + enum libinput_config_status (*set_hold_enabled)(struct libinput_device *device, + enum libinput_config_hold_state enabled); + enum libinput_config_hold_state (*get_hold_enabled)(struct libinput_device *device); + enum libinput_config_hold_state (*get_hold_default)(struct libinput_device *device); +}; + struct libinput_device_config { struct libinput_device_config_tap *tap; struct libinput_device_config_calibration *calibration; @@ -319,6 +327,7 @@ struct libinput_device_config { struct libinput_device_config_middle_emulation *middle_emulation; struct libinput_device_config_dwt *dwt; struct libinput_device_config_rotation *rotation; + struct libinput_device_config_gesture *gesture; }; struct libinput_device_group { diff --git a/test/litest.h b/test/litest.h index 53676521..fbd0746d 100644 --- a/test/litest.h +++ b/test/litest.h @@ -37,6 +37,7 @@ #include "check-double-macros.h" +#include "libinput-private-config.h" #include "libinput-util.h" #include "quirks.h" @@ -1162,6 +1163,30 @@ litest_sendevents_ext_mouse(struct litest_device *dev) litest_assert_int_eq(status, expected); } +static inline void +litest_enable_hold_gestures(struct libinput_device *device) +{ + enum libinput_config_status status, expected; + + expected = LIBINPUT_CONFIG_STATUS_SUCCESS; + status = libinput_device_config_gesture_set_hold_enabled(device, + LIBINPUT_CONFIG_HOLD_ENABLED); + + litest_assert_int_eq(status, expected); +} + +static inline void +litest_disable_hold_gestures(struct libinput_device *device) +{ + enum libinput_config_status status, expected; + + expected = LIBINPUT_CONFIG_STATUS_SUCCESS; + status = libinput_device_config_gesture_set_hold_enabled(device, + LIBINPUT_CONFIG_HOLD_DISABLED); + + litest_assert_int_eq(status, expected); +} + static inline bool litest_touchpad_is_external(struct litest_device *dev) { diff --git a/test/test-gestures.c b/test/test-gestures.c index cf378389..21f53baf 100644 --- a/test/test-gestures.c +++ b/test/test-gestures.c @@ -1160,6 +1160,78 @@ START_TEST(gestures_swipe_3fg_unaccel) } END_TEST +START_TEST(gestures_hold_config_default_disabled) +{ + struct litest_device *dev = litest_current_device(); + struct libinput_device *device = dev->libinput_device; + + ck_assert_int_eq(libinput_device_config_gesture_hold_is_available(device), + 0); + ck_assert_int_eq(libinput_device_config_gesture_get_hold_default_enabled(device), + LIBINPUT_CONFIG_HOLD_DISABLED); + ck_assert_int_eq(libinput_device_config_gesture_get_hold_default_enabled(device), + LIBINPUT_CONFIG_HOLD_DISABLED); +} +END_TEST + +START_TEST(gestures_hold_config_default_enabled) +{ + struct litest_device *dev = litest_current_device(); + struct libinput_device *device = dev->libinput_device; + + ck_assert_int_eq(libinput_device_config_gesture_hold_is_available(device), + 1); + ck_assert_int_eq(libinput_device_config_gesture_get_hold_default_enabled(device), + LIBINPUT_CONFIG_HOLD_ENABLED); + ck_assert_int_eq(libinput_device_config_gesture_get_hold_enabled(device), + LIBINPUT_CONFIG_HOLD_ENABLED); +} +END_TEST + +START_TEST(gestures_hold_config_set_invalid) +{ + struct litest_device *dev = litest_current_device(); + struct libinput_device *device = dev->libinput_device; + + ck_assert_int_eq(libinput_device_config_gesture_set_hold_enabled(device, -1), + LIBINPUT_CONFIG_STATUS_INVALID); + ck_assert_int_eq(libinput_device_config_gesture_set_hold_enabled(device, 2), + LIBINPUT_CONFIG_STATUS_INVALID); +} +END_TEST + +START_TEST(gestures_hold_config_is_available) +{ + struct litest_device *dev = litest_current_device(); + struct libinput_device *device = dev->libinput_device; + + ck_assert_int_eq(libinput_device_config_gesture_hold_is_available(device), + 1); + ck_assert_int_eq(libinput_device_config_gesture_get_hold_enabled(device), + LIBINPUT_CONFIG_HOLD_ENABLED); + ck_assert_int_eq(libinput_device_config_gesture_set_hold_enabled(device, LIBINPUT_CONFIG_HOLD_DISABLED), + LIBINPUT_CONFIG_STATUS_SUCCESS); + ck_assert_int_eq(libinput_device_config_gesture_get_hold_enabled(device), + LIBINPUT_CONFIG_HOLD_DISABLED); +} +END_TEST + +START_TEST(gestures_hold_config_is_not_available) +{ + struct litest_device *dev = litest_current_device(); + struct libinput_device *device = dev->libinput_device; + + ck_assert_int_eq(libinput_device_config_gesture_hold_is_available(device), + 0); + ck_assert_int_eq(libinput_device_config_gesture_get_hold_enabled(device), + LIBINPUT_CONFIG_HOLD_DISABLED); + ck_assert_int_eq(libinput_device_config_gesture_set_hold_enabled(device, LIBINPUT_CONFIG_HOLD_ENABLED), + LIBINPUT_CONFIG_STATUS_UNSUPPORTED); + ck_assert_int_eq(libinput_device_config_gesture_set_hold_enabled(device, LIBINPUT_CONFIG_HOLD_DISABLED), + LIBINPUT_CONFIG_STATUS_SUCCESS); +} +END_TEST + TEST_COLLECTION(gestures) { struct range cardinals = { N, N + NCARDINALS }; @@ -1182,6 +1254,12 @@ TEST_COLLECTION(gestures) litest_add(gestures_time_usec, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH); + litest_add(gestures_hold_config_default_disabled, LITEST_TOUCHPAD|LITEST_SEMI_MT, LITEST_ANY); + litest_add(gestures_hold_config_default_enabled, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH|LITEST_SEMI_MT); + litest_add(gestures_hold_config_set_invalid, LITEST_TOUCHPAD, LITEST_ANY); + litest_add(gestures_hold_config_is_available, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH|LITEST_SEMI_MT); + litest_add(gestures_hold_config_is_not_available, LITEST_TOUCHPAD|LITEST_SEMI_MT, LITEST_ANY); + /* Timing-sensitive test, valgrind is too slow */ if (!RUNNING_ON_VALGRIND) litest_add(gestures_swipe_3fg_unaccel, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);