diff --git a/configure.ac b/configure.ac index 13cf3a81..860324ac 100644 --- a/configure.ac +++ b/configure.ac @@ -1,7 +1,7 @@ AC_PREREQ([2.64]) m4_define([libinput_major_version], [0]) -m4_define([libinput_minor_version], [3]) +m4_define([libinput_minor_version], [4]) m4_define([libinput_micro_version], [0]) m4_define([libinput_version], [libinput_major_version.libinput_minor_version.libinput_micro_version]) @@ -30,7 +30,7 @@ AM_INIT_AUTOMAKE([1.11 foreign no-dist-gzip dist-xz]) # - If binary compatibility has been broken (eg removed or changed interfaces) # change to C+1:0:0 # - If the interface is the same as the previous version, change to C:R+1:A -LIBINPUT_LT_VERSION=2:0:0 +LIBINPUT_LT_VERSION=3:0:0 AC_SUBST(LIBINPUT_LT_VERSION) AM_SILENT_RULES([yes]) @@ -74,6 +74,21 @@ else fi AM_CONDITIONAL([HAVE_DOXYGEN], [test "x$have_doxygen" = "xyes"]) +AC_ARG_ENABLE(event-gui, + AS_HELP_STRING([--enable-event-gui], [Build the GUI event viewer (default=auto)]), + [build_eventgui="$enableval"], + [build_eventgui="auto"]) +PKG_CHECK_EXISTS([cairo glib-2.0 gtk+-3.0], [HAVE_GUILIBS="yes"], [HAVE_GUILIBS="no"]) + +if test "x$build_eventgui" = "xauto"; then + build_eventgui="$HAVE_GUILIBS" +fi +if test "x$build_eventgui" = "xyes"; then + PKG_CHECK_MODULES(CAIRO, [cairo]) + PKG_CHECK_MODULES(GTK, [glib-2.0 gtk+-3.0]) +fi +AM_CONDITIONAL(BUILD_EVENTGUI, [test "x$build_eventgui" = "xyes"]) + AC_ARG_ENABLE(tests, AS_HELP_STRING([--enable-tests], [Build the tests (default=auto)]), [build_tests="$enableval"], diff --git a/doc/libinput.doxygen.in b/doc/libinput.doxygen.in index f78b7cf9..9f931c34 100644 --- a/doc/libinput.doxygen.in +++ b/doc/libinput.doxygen.in @@ -1570,7 +1570,8 @@ INCLUDE_FILE_PATTERNS = # undefined via #undef or recursively expanded use the := operator # instead of the = operator. -PREDEFINED = LIBINPUT_ATTRIBUTE_PRINTF(f,a)= +PREDEFINED = LIBINPUT_ATTRIBUTE_PRINTF(f, a)= \ + LIBINPUT_ATTRIBUTE_DEPRECATED # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. diff --git a/src/evdev-mt-touchpad-buttons.c b/src/evdev-mt-touchpad-buttons.c index 45d5d703..2ac231c7 100644 --- a/src/evdev-mt-touchpad-buttons.c +++ b/src/evdev-mt-touchpad-buttons.c @@ -452,6 +452,7 @@ tp_button_handle_event(struct tp_dispatch *tp, enum button_event event, uint64_t time) { + struct libinput *libinput = tp->device->base.seat->libinput; enum button_state current = t->button.state; switch(t->button.state) { @@ -485,7 +486,8 @@ tp_button_handle_event(struct tp_dispatch *tp, } if (current != t->button.state) - log_debug("button state: from %s, event %s to %s\n", + log_debug(libinput, + "button state: from %s, event %s to %s\n", button_state_to_str(current), button_event_to_str(event), button_state_to_str(t->button.state)); @@ -538,11 +540,13 @@ tp_process_button(struct tp_dispatch *tp, const struct input_event *e, uint64_t time) { + struct libinput *libinput = tp->device->base.seat->libinput; uint32_t mask = 1 << (e->code - BTN_LEFT); /* Ignore other buttons on clickpads */ if (tp->buttons.is_clickpad && e->code != BTN_LEFT) { - log_bug_kernel("received %s button event on a clickpad\n", + log_bug_kernel(libinput, + "received %s button event on a clickpad\n", libevdev_event_code_get_name(EV_KEY, e->code)); return 0; } @@ -562,6 +566,7 @@ int tp_init_buttons(struct tp_dispatch *tp, struct evdev_device *device) { + struct libinput *libinput = tp->device->base.seat->libinput; struct tp_touch *t; int width, height; double diagonal; @@ -575,10 +580,12 @@ tp_init_buttons(struct tp_dispatch *tp, if (libevdev_has_event_code(device->evdev, EV_KEY, BTN_MIDDLE) || libevdev_has_event_code(device->evdev, EV_KEY, BTN_RIGHT)) { if (tp->buttons.is_clickpad) - log_bug_kernel("clickpad advertising right button\n"); + log_bug_kernel(libinput, + "clickpad advertising right button\n"); } else { if (!tp->buttons.is_clickpad) - log_bug_kernel("non clickpad without right button?\n"); + log_bug_kernel(libinput, + "non clickpad without right button?\n"); } absinfo_x = device->abs.absinfo_x; diff --git a/src/evdev-mt-touchpad-tap.c b/src/evdev-mt-touchpad-tap.c index 34bb0d0b..25412184 100644 --- a/src/evdev-mt-touchpad-tap.c +++ b/src/evdev-mt-touchpad-tap.c @@ -130,6 +130,7 @@ tp_tap_clear_timer(struct tp_dispatch *tp) static void tp_tap_idle_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t time) { + struct libinput *libinput = tp->device->base.seat->libinput; switch (event) { case TAP_EVENT_TOUCH: @@ -138,7 +139,8 @@ tp_tap_idle_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t break; case TAP_EVENT_RELEASE: case TAP_EVENT_MOTION: - log_bug_libinput("invalid event, no fingers are down\n"); + log_bug_libinput(libinput, + "invalid event, no fingers are down\n"); break; case TAP_EVENT_TIMEOUT: break; @@ -197,11 +199,13 @@ tp_tap_hold_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t static void tp_tap_tapped_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t time) { + struct libinput *libinput = tp->device->base.seat->libinput; switch (event) { case TAP_EVENT_MOTION: case TAP_EVENT_RELEASE: - log_bug_libinput("invalid event when fingers are up\n"); + log_bug_libinput(libinput, + "invalid event when fingers are up\n"); break; case TAP_EVENT_TOUCH: tp->tap.state = TAP_STATE_DRAGGING_OR_DOUBLETAP; @@ -426,7 +430,9 @@ tp_tap_dead_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t static void tp_tap_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t time) { + struct libinput *libinput = tp->device->base.seat->libinput; enum tp_tap_state current; + if (!tp->tap.enabled) return; @@ -477,7 +483,8 @@ tp_tap_handle_event(struct tp_dispatch *tp, enum tap_event event, uint64_t time) if (tp->tap.state == TAP_STATE_IDLE || tp->tap.state == TAP_STATE_DEAD) tp_tap_clear_timer(tp); - log_debug("tap state: %s → %s → %s\n", + log_debug(libinput, + "tap state: %s → %s → %s\n", tap_state_to_str(current), tap_event_to_str(event), tap_state_to_str(tp->tap.state)); diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index 787afa4c..ced92378 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -453,6 +453,8 @@ tp_post_twofinger_scroll(struct tp_dispatch *tp, uint64_t time) dx += tmpx; dy += tmpy; } + /* Stop spurious MOTION events at the end of scrolling */ + t->is_pointer = false; } if (nchanged == 0) @@ -464,35 +466,25 @@ tp_post_twofinger_scroll(struct tp_dispatch *tp, uint64_t time) tp_filter_motion(tp, &dx, &dy, time); /* Require at least three px scrolling to start */ - if (dy <= -3.0 || dy >= 3.0) { - tp->scroll.state = SCROLL_STATE_SCROLLING; - tp->scroll.direction |= (1 << LIBINPUT_POINTER_AXIS_VERTICAL_SCROLL); - } - if (dx <= -3.0 || dx >= 3.0) { - tp->scroll.state = SCROLL_STATE_SCROLLING; - tp->scroll.direction |= (1 << LIBINPUT_POINTER_AXIS_HORIZONTAL_SCROLL); - } + if (dy <= -3.0 || dy >= 3.0) + tp->scroll.direction |= (1 << LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL); - if (tp->scroll.state == SCROLL_STATE_NONE) - return; - - /* Stop spurious MOTION events at the end of scrolling */ - tp_for_each_touch(tp, t) - t->is_pointer = false; + if (dx <= -3.0 || dx >= 3.0) + tp->scroll.direction |= (1 << LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL); if (dy != 0.0 && - (tp->scroll.direction & (1 << LIBINPUT_POINTER_AXIS_VERTICAL_SCROLL))) { + (tp->scroll.direction & (1 << LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL))) { pointer_notify_axis(&tp->device->base, time, - LIBINPUT_POINTER_AXIS_VERTICAL_SCROLL, + LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL, dy); } if (dx != 0.0 && - (tp->scroll.direction & (1 << LIBINPUT_POINTER_AXIS_HORIZONTAL_SCROLL))) { + (tp->scroll.direction & (1 << LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL))) { pointer_notify_axis(&tp->device->base, time, - LIBINPUT_POINTER_AXIS_HORIZONTAL_SCROLL, + LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL, dx); } } @@ -500,22 +492,18 @@ tp_post_twofinger_scroll(struct tp_dispatch *tp, uint64_t time) static void tp_stop_scroll_events(struct tp_dispatch *tp, uint64_t time) { - if (tp->scroll.state == SCROLL_STATE_NONE) - return; - /* terminate scrolling with a zero scroll event */ - if (tp->scroll.direction & (1 << LIBINPUT_POINTER_AXIS_VERTICAL_SCROLL)) + if (tp->scroll.direction & (1 << LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL)) pointer_notify_axis(&tp->device->base, time, - LIBINPUT_POINTER_AXIS_VERTICAL_SCROLL, + LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL, 0); - if (tp->scroll.direction & (1 << LIBINPUT_POINTER_AXIS_HORIZONTAL_SCROLL)) + if (tp->scroll.direction & (1 << LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL)) pointer_notify_axis(&tp->device->base, time, - LIBINPUT_POINTER_AXIS_HORIZONTAL_SCROLL, + LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL, 0); - tp->scroll.state = SCROLL_STATE_NONE; tp->scroll.direction = 0; } @@ -732,7 +720,6 @@ static int tp_init_scroll(struct tp_dispatch *tp) { tp->scroll.direction = 0; - tp->scroll.state = SCROLL_STATE_NONE; return 0; } diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h index 0b1457db..7afb3c46 100644 --- a/src/evdev-mt-touchpad.h +++ b/src/evdev-mt-touchpad.h @@ -72,11 +72,6 @@ enum button_state { BUTTON_STATE_IGNORE, }; -enum scroll_state { - SCROLL_STATE_NONE, - SCROLL_STATE_SCROLLING -}; - enum tp_tap_state { TAP_STATE_IDLE = 4, TAP_STATE_TOUCH, @@ -192,7 +187,6 @@ struct tp_dispatch { } buttons; /* physical buttons */ struct { - enum scroll_state state; enum libinput_pointer_axis direction; } scroll; diff --git a/src/evdev-tablet.c b/src/evdev-tablet.c index 48f49fee..a6acca41 100644 --- a/src/evdev-tablet.c +++ b/src/evdev-tablet.c @@ -53,7 +53,8 @@ tablet_process_absolute(struct tablet_dispatch *tablet, case ABS_DISTANCE: axis = evcode_to_axis(e->code); if (axis == LIBINPUT_TABLET_AXIS_NONE) { - log_bug_libinput("Invalid ABS event code %#x\n", + log_bug_libinput(device->base.seat->libinput, + "Invalid ABS event code %#x\n", e->code); break; } @@ -62,7 +63,8 @@ tablet_process_absolute(struct tablet_dispatch *tablet, tablet_set_status(tablet, TABLET_AXES_UPDATED); break; default: - log_info("Unhandled ABS event code %#x\n", e->code); + log_info(device->base.seat->libinput, + "Unhandled ABS event code %#x\n", e->code); break; } } @@ -153,7 +155,8 @@ tablet_check_notify_axes(struct tablet_dispatch *tablet, tablet->axes[a] = normalize_tilt(absinfo); break; default: - log_bug_libinput("Invalid axis update: %d\n", a); + log_bug_libinput(device->base.seat->libinput, + "Invalid axis update: %d\n", a); break; } @@ -184,7 +187,8 @@ tablet_update_button(struct tablet_dispatch *tablet, mask = &tablet->button_state.stylus_buttons; button = evcode - BTN_TOUCH; } else { - log_info("Unhandled button %s (%#x)\n", + log_info(tablet->device->base.seat->libinput, + "Unhandled button %s (%#x)\n", libevdev_event_code_get_name(EV_KEY, evcode), evcode); return; } @@ -250,7 +254,8 @@ tablet_process_misc(struct tablet_dispatch *tablet, } break; default: - log_info("Unhandled MSC event code %s (%#x)\n", + log_info(device->base.seat->libinput, + "Unhandled MSC event code %s (%#x)\n", libevdev_event_code_get_name(EV_MSC, e->code), e->code); break; @@ -432,7 +437,8 @@ tablet_process(struct evdev_dispatch *dispatch, tablet_flush(tablet, device, time); break; default: - log_error("Unexpected event type %s (%#x)\n", + log_error(device->base.seat->libinput, + "Unexpected event type %s (%#x)\n", libevdev_event_type_get_name(e->type), e->type); break; diff --git a/src/evdev.c b/src/evdev.c index 42fe2de1..1aee4848 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -115,6 +115,7 @@ evdev_device_transform_y(struct evdev_device *device, static void evdev_flush_pending_event(struct evdev_device *device, uint64_t time) { + struct libinput *libinput = device->base.seat->libinput; struct motion_params motion; int32_t cx, cy; double x, y; @@ -147,7 +148,8 @@ evdev_flush_pending_event(struct evdev_device *device, uint64_t time) break; if (device->mt.slots[slot].seat_slot != -1) { - log_bug_kernel("%s: Driver sent multiple touch down for the " + log_bug_kernel(libinput, + "%s: Driver sent multiple touch down for the " "same slot", device->devnode); break; } @@ -196,7 +198,8 @@ evdev_flush_pending_event(struct evdev_device *device, uint64_t time) break; if (device->abs.seat_slot != -1) { - log_bug_kernel("%s: Driver sent multiple touch down for the " + log_bug_kernel(libinput, + "%s: Driver sent multiple touch down for the " "same slot", device->devnode); break; } @@ -310,8 +313,8 @@ evdev_process_key(struct evdev_device *device, &device->base, time, e->code, - e->value ? LIBINPUT_KEYBOARD_KEY_STATE_PRESSED : - LIBINPUT_KEYBOARD_KEY_STATE_RELEASED); + e->value ? LIBINPUT_KEY_STATE_PRESSED : + LIBINPUT_KEY_STATE_RELEASED); break; } } @@ -390,7 +393,7 @@ evdev_process_relative(struct evdev_device *device, pointer_notify_axis( base, time, - LIBINPUT_POINTER_AXIS_VERTICAL_SCROLL, + LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL, -1 * e->value * DEFAULT_AXIS_STEP_DISTANCE); break; case REL_HWHEEL: @@ -403,7 +406,7 @@ evdev_process_relative(struct evdev_device *device, pointer_notify_axis( base, time, - LIBINPUT_POINTER_AXIS_HORIZONTAL_SCROLL, + LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL, e->value * DEFAULT_AXIS_STEP_DISTANCE); break; default: @@ -591,6 +594,7 @@ configure_pointer_acceleration(struct evdev_device *device) static int evdev_configure_device(struct evdev_device *device) { + struct libinput *libinput = device->base.seat->libinput; struct libevdev *evdev = device->evdev; const struct input_absinfo *absinfo; struct input_absinfo fixed; @@ -696,7 +700,8 @@ evdev_configure_device(struct evdev_device *device) !libevdev_has_event_code(evdev, EV_KEY, BTN_TOOL_PEN) && (has_abs || has_mt)) { device->dispatch = evdev_mt_touchpad_create(device); - log_info("input device '%s', %s is a touchpad\n", + log_info(libinput, + "input device '%s', %s is a touchpad\n", device->devname, device->devnode); } else if (!libevdev_has_event_code(device->evdev, EV_KEY, BTN_TOOL_FINGER) && libevdev_has_event_code(device->evdev, EV_KEY, BTN_TOOL_PEN) && @@ -733,7 +738,8 @@ evdev_configure_device(struct evdev_device *device) device->seat_caps |= EVDEV_DEVICE_POINTER; - log_info("input device '%s', %s is a pointer caps =%s%s%s\n", + log_info(libinput, + "input device '%s', %s is a pointer caps =%s%s%s\n", device->devname, device->devnode, has_abs ? " absolute-motion" : "", has_rel ? " relative-motion": "", @@ -741,12 +747,14 @@ evdev_configure_device(struct evdev_device *device) } if (has_keyboard) { device->seat_caps |= EVDEV_DEVICE_KEYBOARD; - log_info("input device '%s', %s is a keyboard\n", + log_info(libinput, + "input device '%s', %s is a keyboard\n", device->devname, device->devnode); } if (has_touch && !has_button) { device->seat_caps |= EVDEV_DEVICE_TOUCH; - log_info("input device '%s', %s is a touch device\n", + log_info(libinput, + "input device '%s', %s is a touch device\n", device->devname, device->devnode); } @@ -769,7 +777,8 @@ evdev_device_create(struct libinput_seat *seat, * read. mtdev_get() also expects this. */ fd = open_restricted(libinput, devnode, O_RDWR | O_NONBLOCK); if (fd < 0) { - log_info("opening input device '%s' failed (%s).\n", + log_info(libinput, + "opening input device '%s' failed (%s).\n", devnode, strerror(-fd)); return NULL; } diff --git a/src/libinput-private.h b/src/libinput-private.h index 3630f74d..db78cca1 100644 --- a/src/libinput-private.h +++ b/src/libinput-private.h @@ -58,7 +58,11 @@ struct libinput { const struct libinput_interface *interface; const struct libinput_interface_backend *interface_backend; + + libinput_log_handler log_handler; + enum libinput_log_priority log_priority; void *user_data; + int refcount; }; typedef void (*libinput_seat_destroy_func) (struct libinput_seat *seat); @@ -97,17 +101,21 @@ struct libinput_tool { typedef void (*libinput_source_dispatch_t)(void *data); -#define log_debug(...) log_msg(LIBINPUT_LOG_PRIORITY_DEBUG, __VA_ARGS__) -#define log_info(...) log_msg(LIBINPUT_LOG_PRIORITY_INFO, __VA_ARGS__) -#define log_error(...) log_msg(LIBINPUT_LOG_PRIORITY_ERROR, __VA_ARGS__) -#define log_bug_kernel(...) log_msg(LIBINPUT_LOG_PRIORITY_ERROR, "kernel bug: " __VA_ARGS__) -#define log_bug_libinput(...) log_msg(LIBINPUT_LOG_PRIORITY_ERROR, "libinput bug: " __VA_ARGS__); -#define log_bug_client(...) log_msg(LIBINPUT_LOG_PRIORITY_ERROR, "client bug: " __VA_ARGS__); +#define log_debug(li_, ...) log_msg((li_), LIBINPUT_LOG_PRIORITY_DEBUG, __VA_ARGS__) +#define log_info(li_, ...) log_msg((li_), LIBINPUT_LOG_PRIORITY_INFO, __VA_ARGS__) +#define log_error(li_, ...) log_msg((li_), LIBINPUT_LOG_PRIORITY_ERROR, __VA_ARGS__) +#define log_bug_kernel(li_, ...) log_msg((li_), LIBINPUT_LOG_PRIORITY_ERROR, "kernel bug: " __VA_ARGS__) +#define log_bug_libinput(li_, ...) log_msg((li_), LIBINPUT_LOG_PRIORITY_ERROR, "libinput bug: " __VA_ARGS__); +#define log_bug_client(li_, ...) log_msg((li_), LIBINPUT_LOG_PRIORITY_ERROR, "client bug: " __VA_ARGS__); void -log_msg(enum libinput_log_priority priority, const char *format, ...); +log_msg(struct libinput *libinput, + enum libinput_log_priority priority, + const char *format, ...); + void -log_msg_va(enum libinput_log_priority priority, +log_msg_va(struct libinput *libinput, + enum libinput_log_priority priority, const char *format, va_list args); @@ -155,7 +163,7 @@ void keyboard_notify_key(struct libinput_device *device, uint32_t time, uint32_t key, - enum libinput_keyboard_key_state state); + enum libinput_key_state state); void pointer_notify_motion(struct libinput_device *device, diff --git a/src/libinput-util.h b/src/libinput-util.h index a1d6616e..fc8e8a08 100644 --- a/src/libinput-util.h +++ b/src/libinput-util.h @@ -23,6 +23,8 @@ #ifndef LIBINPUT_UTIL_H #define LIBINPUT_UTIL_H +#include + #include "libinput.h" void @@ -108,4 +110,10 @@ clear_bit(unsigned char *array, int bit) array[bit / 8] &= ~(1 << (bit % 8)); } +static inline void +msleep(unsigned int ms) +{ + usleep(ms * 1000); +} + #endif /* LIBINPUT_UTIL_H */ diff --git a/src/libinput.c b/src/libinput.c index 054d4fae..8010bc6e 100644 --- a/src/libinput.c +++ b/src/libinput.c @@ -56,7 +56,7 @@ struct libinput_event_keyboard { uint32_t time; uint32_t key; uint32_t seat_key_count; - enum libinput_keyboard_key_state state; + enum libinput_key_state state; }; struct libinput_event_pointer { @@ -92,8 +92,8 @@ struct libinput_event_tablet { }; static void -libinput_default_log_func(enum libinput_log_priority priority, - void *data, +libinput_default_log_func(struct libinput *libinput, + enum libinput_log_priority priority, const char *format, va_list args) { const char *prefix; @@ -109,55 +109,47 @@ libinput_default_log_func(enum libinput_log_priority priority, vfprintf(stderr, format, args); } -struct log_data { - enum libinput_log_priority priority; - libinput_log_handler handler; - void *user_data; -}; - -static struct log_data log_data = { - .priority = LIBINPUT_LOG_PRIORITY_ERROR, - .handler = libinput_default_log_func, - .user_data = NULL, -}; - void -log_msg_va(enum libinput_log_priority priority, +log_msg_va(struct libinput *libinput, + enum libinput_log_priority priority, const char *format, va_list args) { - if (log_data.handler && log_data.priority <= priority) - log_data.handler(priority, log_data.user_data, format, args); + if (libinput->log_handler && + libinput->log_priority <= priority) + libinput->log_handler(libinput, priority, format, args); } void -log_msg(enum libinput_log_priority priority, const char *format, ...) +log_msg(struct libinput *libinput, + enum libinput_log_priority priority, + const char *format, ...) { va_list args; va_start(args, format); - log_msg_va(priority, format, args); + log_msg_va(libinput, priority, format, args); va_end(args); } LIBINPUT_EXPORT void -libinput_log_set_priority(enum libinput_log_priority priority) +libinput_log_set_priority(struct libinput *libinput, + enum libinput_log_priority priority) { - log_data.priority = priority; + libinput->log_priority = priority; } LIBINPUT_EXPORT enum libinput_log_priority -libinput_log_get_priority(void) +libinput_log_get_priority(const struct libinput *libinput) { - return log_data.priority; + return libinput->log_priority; } LIBINPUT_EXPORT void -libinput_log_set_handler(libinput_log_handler log_handler, - void *user_data) +libinput_log_set_handler(struct libinput *libinput, + libinput_log_handler log_handler) { - log_data.handler = log_handler; - log_data.user_data = user_data; + libinput->log_handler = log_handler; } static void @@ -342,7 +334,7 @@ libinput_event_keyboard_get_key(struct libinput_event_keyboard *event) return event->key; } -LIBINPUT_EXPORT enum libinput_keyboard_key_state +LIBINPUT_EXPORT enum libinput_key_state libinput_event_keyboard_get_key_state(struct libinput_event_keyboard *event) { return event->state; @@ -655,9 +647,12 @@ libinput_init(struct libinput *libinput, return -1; } + libinput->log_handler = libinput_default_log_func; + libinput->log_priority = LIBINPUT_LOG_PRIORITY_ERROR; libinput->interface = interface; libinput->interface_backend = interface_backend; libinput->user_data = user_data; + libinput->refcount = 1; list_init(&libinput->source_destroy_list); list_init(&libinput->seat_list); list_init(&libinput->tool_list); @@ -687,8 +682,15 @@ libinput_drop_destroyed_sources(struct libinput *libinput) list_init(&libinput->source_destroy_list); } -LIBINPUT_EXPORT void -libinput_destroy(struct libinput *libinput) +LIBINPUT_EXPORT struct libinput * +libinput_ref(struct libinput *libinput) +{ + libinput->refcount++; + return libinput; +} + +LIBINPUT_EXPORT struct libinput * +libinput_unref(struct libinput *libinput) { struct libinput_event *event; struct libinput_device *device, *next_device; @@ -696,7 +698,12 @@ libinput_destroy(struct libinput *libinput) struct libinput_tool *tool, *next_tool; if (libinput == NULL) - return; + return NULL; + + assert(libinput->refcount > 0); + libinput->refcount--; + if (libinput->refcount > 0) + return libinput; libinput_suspend(libinput); @@ -724,6 +731,8 @@ libinput_destroy(struct libinput *libinput) libinput_drop_destroyed_sources(libinput); close(libinput->epoll_fd); free(libinput); + + return NULL; } LIBINPUT_EXPORT void @@ -769,10 +778,11 @@ libinput_seat_init(struct libinput_seat *seat, list_insert(&libinput->seat_list, &seat->link); } -LIBINPUT_EXPORT void +LIBINPUT_EXPORT struct libinput_seat * libinput_seat_ref(struct libinput_seat *seat) { seat->refcount++; + return seat; } static void @@ -784,13 +794,17 @@ libinput_seat_destroy(struct libinput_seat *seat) seat->destroy(seat); } -LIBINPUT_EXPORT void +LIBINPUT_EXPORT struct libinput_seat * libinput_seat_unref(struct libinput_seat *seat) { assert(seat->refcount > 0); seat->refcount--; - if (seat->refcount == 0) + if (seat->refcount == 0) { libinput_seat_destroy(seat); + return NULL; + } else { + return seat; + } } LIBINPUT_EXPORT void @@ -825,10 +839,11 @@ libinput_device_init(struct libinput_device *device, device->refcount = 1; } -LIBINPUT_EXPORT void +LIBINPUT_EXPORT struct libinput_device * libinput_device_ref(struct libinput_device *device) { device->refcount++; + return device; } static void @@ -837,13 +852,17 @@ libinput_device_destroy(struct libinput_device *device) evdev_device_destroy((struct evdev_device *) device); } -LIBINPUT_EXPORT void +LIBINPUT_EXPORT struct libinput_device * libinput_device_unref(struct libinput_device *device) { assert(device->refcount > 0); device->refcount--; - if (device->refcount == 0) + if (device->refcount == 0) { libinput_device_destroy(device); + return NULL; + } else { + return device; + } } LIBINPUT_EXPORT int @@ -879,14 +898,14 @@ libinput_dispatch(struct libinput *libinput) static uint32_t update_seat_key_count(struct libinput_seat *seat, int32_t key, - enum libinput_keyboard_key_state state) + enum libinput_key_state state) { assert(key >= 0 && key <= KEY_MAX); switch (state) { - case LIBINPUT_KEYBOARD_KEY_STATE_PRESSED: + case LIBINPUT_KEY_STATE_PRESSED: return ++seat->button_count[key]; - case LIBINPUT_KEYBOARD_KEY_STATE_RELEASED: + case LIBINPUT_KEY_STATE_RELEASED: /* We might not have received the first PRESSED event. */ if (seat->button_count[key] == 0) return 0; @@ -978,7 +997,7 @@ void keyboard_notify_key(struct libinput_device *device, uint32_t time, uint32_t key, - enum libinput_keyboard_key_state state) + enum libinput_key_state state) { struct libinput_event_keyboard *key_event; uint32_t seat_key_count; diff --git a/src/libinput.h b/src/libinput.h index 0a914569..3e0b8754 100644 --- a/src/libinput.h +++ b/src/libinput.h @@ -33,6 +33,7 @@ extern "C" { #define LIBINPUT_ATTRIBUTE_PRINTF(_format, _args) \ __attribute__ ((format (printf, _format, _args))) +#define LIBINPUT_ATTRIBUTE_DEPRECATED __attribute__ ((deprecated)) /** * @mainpage @@ -49,7 +50,7 @@ extern "C" { * * Software button areas * ===================== - * On most touchpads, the bottom area of the touchpad is split into a a left + * On most touchpads, the bottom area of the touchpad is split into a left * and a right-button area. Pressing the touchpad down with a finger in * those areas will generate clicks as shown in the diagram below: * @@ -131,9 +132,9 @@ enum libinput_device_capability { * Logical state of a key. Note that the logical state may not represent * the physical state of the key. */ -enum libinput_keyboard_key_state { - LIBINPUT_KEYBOARD_KEY_STATE_RELEASED = 0, - LIBINPUT_KEYBOARD_KEY_STATE_PRESSED = 1 +enum libinput_key_state { + LIBINPUT_KEY_STATE_RELEASED = 0, + LIBINPUT_KEY_STATE_PRESSED = 1 }; /** @@ -165,8 +166,8 @@ enum libinput_button_state { * Axes on a device that are not x or y coordinates. */ enum libinput_pointer_axis { - LIBINPUT_POINTER_AXIS_VERTICAL_SCROLL = 0, - LIBINPUT_POINTER_AXIS_HORIZONTAL_SCROLL = 1 + LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL = 0, + LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL = 1, }; /** @@ -462,7 +463,7 @@ libinput_event_keyboard_get_key(struct libinput_event_keyboard *event); * * @return The state change of the key */ -enum libinput_keyboard_key_state +enum libinput_key_state libinput_event_keyboard_get_key_state(struct libinput_event_keyboard *event); @@ -681,8 +682,8 @@ libinput_event_pointer_get_axis(struct libinput_event_pointer *event); * * Return the axis value of the given axis. The interpretation of the value * is dependent on the axis. For the two scrolling axes - * LIBINPUT_POINTER_AXIS_VERTICAL_SCROLL and - * LIBINPUT_POINTER_AXIS_HORIZONTAL_SCROLL, the value of the event is in + * LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL and + * LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL, the value of the event is in * relative scroll units, with the positive direction being down or right, * respectively. The dimension of a scroll unit is equal to one unit of * motion in the respective axis, where applicable (e.g. touchpad two-finger @@ -1051,7 +1052,7 @@ struct libinput_interface { * @param path The device path to open * @param flags Flags as defined by open(2) * @param user_data The user_data provided in - * libinput_udev_create_for_seat() + * libinput_udev_create_context() * * @return the file descriptor, or a negative errno on failure. */ @@ -1061,7 +1062,7 @@ struct libinput_interface { * * @param fd The file descriptor to close * @param user_data The user_data provided in - * libinput_udev_create_for_seat() + * libinput_udev_create_context() */ void (*close_restricted)(int fd, void *user_data); }; @@ -1069,31 +1070,45 @@ struct libinput_interface { /** * @ingroup base * - * Create a new libinput context from udev, for input devices matching - * the given seat ID. New devices or devices removed will appear as events - * during libinput_dispatch. - * - * libinput_udev_create_for_seat() succeeds even if no input device is - * available in this seat, or if devices are available but fail to open in - * @ref libinput_interface::open_restricted. Devices that do not have the - * minimum capabilities to be recognized as pointer, keyboard or touch - * device are ignored. Such devices and those that failed to open - * ignored until the next call to libinput_resume(). + * Create a new libinput context from udev. This context is inactive until + * assigned a seat ID with libinput_udev_assign_seat(). * * @param interface The callback interface * @param user_data Caller-specific data passed to the various callback * interfaces. * @param udev An already initialized udev context - * @param seat_id A seat identifier. This string must not be NULL. * - * @return An initialized libinput context, ready to handle events or NULL on - * error. + * @return An initialized, but inactive libinput context or NULL on error */ struct libinput * -libinput_udev_create_for_seat(const struct libinput_interface *interface, - void *user_data, - struct udev *udev, - const char *seat_id); +libinput_udev_create_context(const struct libinput_interface *interface, + void *user_data, + struct udev *udev); + +/** + * @ingroup base + * + * Assign a seat to this libinput context. New devices or the removal of + * existing devices will appear as events during libinput_dispatch(). + * + * libinput_udev_assign_seat() succeeds even if no input devices are currently + * available on this seat, or if devices are available but fail to open in + * @ref libinput_interface::open_restricted. Devices that do not have the + * minimum capabilities to be recognized as pointer, keyboard or touch + * device are ignored. Such devices and those that failed to open + * ignored until the next call to libinput_resume(). + * + * This function may only be called once per context. + * + * @param libinput A libinput context initialized with + * libinput_udev_create_context() + * @param seat_id A seat identifier. This string must not be NULL. + * + * @return 0 on success or -1 on failure. + */ +int +libinput_udev_assign_seat(struct libinput *libinput, + const char *seat_id); /** * @ingroup base @@ -1105,6 +1120,9 @@ libinput_udev_create_for_seat(const struct libinput_interface *interface, * The context is fully initialized but will not generate events until at * least one device has been added. * + * The reference count of the context is initialized to 1. See @ref + * libinput_unref. + * * @param interface The callback interface * @param user_data Caller-specific data passed to the various callback * interfaces. @@ -1133,7 +1151,7 @@ libinput_path_create_context(const struct libinput_interface *interface, * @return The newly initiated device on success, or NULL on failure. * * @note It is an application bug to call this function on a libinput - * context initialized with libinput_udev_create_for_seat(). + * context initialized with libinput_udev_create_context(). */ struct libinput_device * libinput_path_add_device(struct libinput *libinput, @@ -1155,7 +1173,7 @@ libinput_path_add_device(struct libinput *libinput, * @param device A libinput device * * @note It is an application bug to call this function on a libinput - * context initialized with libinput_udev_create_for_seat(). + * context initialized with libinput_udev_create_context(). */ void libinput_path_remove_device(struct libinput_device *device); @@ -1254,13 +1272,27 @@ libinput_suspend(struct libinput *libinput); /** * @ingroup base * - * Destroy the libinput context. After this, object references associated with - * the destroyed context are invalid and may not be interacted with. + * Add a reference to the context. A context is destroyed whenever the + * reference count reaches 0. See @ref libinput_unref. + * + * @param libinput A previously initialized valid libinput context + * @return The passed libinput context + */ +struct libinput * +libinput_ref(struct libinput *libinput); + +/** + * @ingroup base + * + * Dereference the libinput context. After this, the context may have been + * destroyed, if the last reference was dereferenced. If so, the context is + * invalid and may not be interacted with. * * @param libinput A previously initialized libinput context + * @return NULL if context was destroyed otherwise the passed context */ -void -libinput_destroy(struct libinput *libinput); +struct libinput * +libinput_unref(struct libinput *libinput); /** * @ingroup base @@ -1270,13 +1302,15 @@ libinput_destroy(struct libinput *libinput); * * The default log priority is LIBINPUT_LOG_PRIORITY_ERROR. * + * @param libinput A previously initialized libinput context * @param priority The minimum priority of log messages to print. * * @see libinput_log_set_handler * @see libinput_log_get_priority */ void -libinput_log_set_priority(enum libinput_log_priority priority); +libinput_log_set_priority(struct libinput *libinput, + enum libinput_log_priority priority); /** * @ingroup base @@ -1286,30 +1320,30 @@ libinput_log_set_priority(enum libinput_log_priority priority); * * The default log priority is LIBINPUT_LOG_PRIORITY_ERROR. * + * @param libinput A previously initialized libinput context * @return The minimum priority of log messages to print. * * @see libinput_log_set_handler * @see libinput_log_set_priority */ enum libinput_log_priority -libinput_log_get_priority(void); +libinput_log_get_priority(const struct libinput *libinput); /** * @ingroup base * * Log handler type for custom logging. * + * @param libinput The libinput context * @param priority The priority of the current message - * @param user_data Caller-specific data pointer as previously passed into - * libinput_log_set_handler() * @param format Message format in printf-style * @param args Message arguments * * @see libinput_set_log_priority * @see libinput_log_set_handler */ -typedef void (*libinput_log_handler)(enum libinput_log_priority priority, - void *user_data, +typedef void (*libinput_log_handler)(struct libinput *libinput, + enum libinput_log_priority priority, const char *format, va_list args) LIBINPUT_ATTRIBUTE_PRINTF(3, 0); @@ -1322,6 +1356,7 @@ typedef void (*libinput_log_handler)(enum libinput_log_priority priority, * * The default log handler prints to stderr. * + * @param libinput A previously initialized libinput context * @param log_handler The log handler for library messages. * @param user_data Caller-specific data pointer, passed into the log * handler. @@ -1329,8 +1364,8 @@ typedef void (*libinput_log_handler)(enum libinput_log_priority priority, * @see libinput_log_set_handler */ void -libinput_log_set_handler(libinput_log_handler log_handler, - void *user_data); +libinput_log_set_handler(struct libinput *libinput, + libinput_log_handler log_handler); /** * @defgroup seat Initialization and manipulation of seats @@ -1367,8 +1402,9 @@ libinput_log_set_handler(libinput_log_handler log_handler, * the seat correctly to avoid dangling pointers. * * @param seat A previously obtained seat + * @return The passed seat */ -void +struct libinput_seat * libinput_seat_ref(struct libinput_seat *seat); /** @@ -1380,8 +1416,9 @@ libinput_seat_ref(struct libinput_seat *seat); * the seat correctly to avoid dangling pointers. * * @param seat A previously obtained seat + * @return NULL if seat was destroyed, otherwise the passed seat */ -void +struct libinput_seat * libinput_seat_unref(struct libinput_seat *seat); /** @@ -1415,7 +1452,7 @@ libinput_seat_get_user_data(struct libinput_seat *seat); * * Return the physical name of the seat. For libinput contexts created from * udev, this is always the same value as passed into - * libinput_udev_create_for_seat() and all seats from that context will have + * libinput_udev_assign_seat() and all seats from that context will have * the same physical name. * * The physical name of the seat is one that is usually set by the system or @@ -1454,8 +1491,9 @@ libinput_seat_get_logical_name(struct libinput_seat *seat); * the device correctly to avoid dangling pointers. * * @param device A previously obtained device + * @return The passed device */ -void +struct libinput_device * libinput_device_ref(struct libinput_device *device); /** @@ -1467,8 +1505,9 @@ libinput_device_ref(struct libinput_device *device); * the device correctly to avoid dangling pointers. * * @param device A previously obtained device + * @return NULL if device was destroyed, otherwise the passed device */ -void +struct libinput_device * libinput_device_unref(struct libinput_device *device); /** diff --git a/src/path.c b/src/path.c index 27e5ad63..e9c0ee8d 100644 --- a/src/path.c +++ b/src/path.c @@ -160,7 +160,9 @@ path_device_enable(struct path_input *input, const char *devnode) if (path_get_udev_properties(devnode, &sysname, &seat_name, &seat_logical_name) == -1) { - log_info("failed to obtain sysname for device '%s'.\n", devnode); + log_info(&input->base, + "failed to obtain sysname for device '%s'.\n", + devnode); return NULL; } @@ -171,7 +173,9 @@ path_device_enable(struct path_input *input, const char *devnode) } else { seat = path_seat_create(input, seat_name, seat_logical_name); if (!seat) { - log_info("failed to create seat for device '%s'.\n", devnode); + log_info(&input->base, + "failed to create seat for device '%s'.\n", + devnode); goto out; } } @@ -181,10 +185,14 @@ path_device_enable(struct path_input *input, const char *devnode) if (device == EVDEV_UNHANDLED_DEVICE) { device = NULL; - log_info("not using input device '%s'.\n", devnode); + log_info(&input->base, + "not using input device '%s'.\n", + devnode); goto out; } else if (device == NULL) { - log_info("failed to create input device '%s'.\n", devnode); + log_info(&input->base, + "failed to create input device '%s'.\n", + devnode); goto out; } @@ -264,7 +272,7 @@ libinput_path_add_device(struct libinput *libinput, struct libinput_device *device; if (libinput->interface_backend != &interface_backend) { - log_bug_client("Mismatching backends.\n"); + log_bug_client(libinput, "Mismatching backends.\n"); return NULL; } @@ -301,7 +309,7 @@ libinput_path_remove_device(struct libinput_device *device) struct path_device *dev; if (libinput->interface_backend != &interface_backend) { - log_bug_client("Mismatching backends.\n"); + log_bug_client(libinput, "Mismatching backends.\n"); return; } diff --git a/src/timer.c b/src/timer.c index 65fdd17a..3076bb7a 100644 --- a/src/timer.c +++ b/src/timer.c @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -59,12 +60,28 @@ libinput_timer_arm_timer_fd(struct libinput *libinput) r = timerfd_settime(libinput->timer.fd, TFD_TIMER_ABSTIME, &its, NULL); if (r) - log_error("timerfd_settime error: %s\n", strerror(errno)); + log_error(libinput, "timerfd_settime error: %s\n", strerror(errno)); } void libinput_timer_set(struct libinput_timer *timer, uint64_t expire) { +#ifndef NDEBUG + struct timespec ts; + + if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) { + uint64_t now = ts.tv_sec * 1000ULL + ts.tv_nsec / 1000000; + if (abs(expire - now) > 5000) + log_bug_libinput(timer->libinput, + "timer offset more than 5s, now %" + PRIu64 " expire %" PRIu64 "\n", + now, expire); + } else { + log_error(timer->libinput, + "clock_gettime error: %s\n", strerror(errno)); + } +#endif + assert(expire); if (!timer->expire) @@ -96,7 +113,7 @@ libinput_timer_handler(void *data) r = clock_gettime(CLOCK_MONOTONIC, &ts); if (r) { - log_error("clock_gettime error: %s\n", strerror(errno)); + log_error(libinput, "clock_gettime error: %s\n", strerror(errno)); return; } diff --git a/src/udev-seat.c b/src/udev-seat.c index 38a13b72..635fabfd 100644 --- a/src/udev-seat.c +++ b/src/udev-seat.c @@ -80,10 +80,10 @@ device_added(struct udev_device *udev_device, struct udev_input *input) libinput_seat_unref(&seat->base); if (device == EVDEV_UNHANDLED_DEVICE) { - log_info("not using input device '%s'.\n", devnode); + log_info(&input->base, "not using input device '%s'.\n", devnode); return 0; } else if (device == NULL) { - log_info("failed to create input device '%s'.\n", devnode); + log_info(&input->base, "failed to create input device '%s'.\n", devnode); return 0; } @@ -100,7 +100,8 @@ device_added(struct udev_device *udev_device, struct udev_input *input) &device->abs.calibration[4], &device->abs.calibration[5]) == 6) { device->abs.apply_calibration = 1; - log_info("Applying calibration: %f %f %f %f %f %f\n", + log_info(&input->base, + "Applying calibration: %f %f %f %f %f %f\n", device->abs.calibration[0], device->abs.calibration[1], device->abs.calibration[2], @@ -128,7 +129,8 @@ device_removed(struct udev_device *udev_device, struct udev_input *input) list_for_each_safe(device, next, &seat->base.devices_list, base.link) { if (!strcmp(device->devnode, devnode)) { - log_info("input device %s, %s removed\n", + log_info(&input->base, + "input device %s, %s removed\n", device->devname, device->devnode); evdev_device_remove(device); break; @@ -243,7 +245,8 @@ udev_input_enable(struct libinput *libinput) input->udev_monitor = udev_monitor_new_from_netlink(udev, "udev"); if (!input->udev_monitor) { - log_info("udev: failed to create the udev monitor\n"); + log_info(libinput, + "udev: failed to create the udev monitor\n"); return -1; } @@ -251,7 +254,7 @@ udev_input_enable(struct libinput *libinput) "input", NULL); if (udev_monitor_enable_receiving(input->udev_monitor)) { - log_info("udev: failed to bind the udev monitor\n"); + log_info(libinput, "udev: failed to bind the udev monitor\n"); udev_monitor_unref(input->udev_monitor); input->udev_monitor = NULL; return -1; @@ -333,14 +336,13 @@ static const struct libinput_interface_backend interface_backend = { }; LIBINPUT_EXPORT struct libinput * -libinput_udev_create_for_seat(const struct libinput_interface *interface, - void *user_data, - struct udev *udev, - const char *seat_id) +libinput_udev_create_context(const struct libinput_interface *interface, + void *user_data, + struct udev *udev) { struct udev_input *input; - if (!interface || !udev || !seat_id) + if (!interface || !udev) return NULL; input = zalloc(sizeof *input); @@ -349,19 +351,36 @@ libinput_udev_create_for_seat(const struct libinput_interface *interface, if (libinput_init(&input->base, interface, &interface_backend, user_data) != 0) { + libinput_unref(&input->base); free(input); return NULL; } input->udev = udev_ref(udev); - input->seat_id = strdup(seat_id); - - if (udev_input_enable(&input->base) < 0) { - udev_unref(udev); - libinput_destroy(&input->base); - free(input); - return NULL; - } return &input->base; } + +LIBINPUT_EXPORT int +libinput_udev_assign_seat(struct libinput *libinput, + const char *seat_id) +{ + struct udev_input *input = (struct udev_input*)libinput; + + if (!seat_id) + return -1; + if (input->seat_id != NULL) + return -1; + + if (libinput->interface_backend != &interface_backend) { + log_bug_client(libinput, "Mismatching backends.\n"); + return -1; + } + + input->seat_id = strdup(seat_id); + + if (udev_input_enable(&input->base) < 0) + return -1; + + return 0; +} diff --git a/test/50-litest.conf b/test/50-litest.conf new file mode 100644 index 00000000..76579d77 --- /dev/null +++ b/test/50-litest.conf @@ -0,0 +1,6 @@ +# Ignore devices created by libinput's test suite (litest) +Section "InputClass" + Identifier "libinput test suite blacklist" + MatchProduct "litest" + Option "Ignore" "on" +EndSection diff --git a/test/keyboard.c b/test/keyboard.c index a518b66c..bf5d55af 100644 --- a/test/keyboard.c +++ b/test/keyboard.c @@ -64,7 +64,7 @@ START_TEST(keyboard_seat_key_count) ck_assert_notnull(kev); ck_assert_int_eq(libinput_event_keyboard_get_key(kev), KEY_A); ck_assert_int_eq(libinput_event_keyboard_get_key_state(kev), - LIBINPUT_KEYBOARD_KEY_STATE_PRESSED); + LIBINPUT_KEY_STATE_PRESSED); ++expected_key_button_count; seat_key_count = @@ -93,7 +93,7 @@ START_TEST(keyboard_seat_key_count) ck_assert_notnull(kev); ck_assert_int_eq(libinput_event_keyboard_get_key(kev), KEY_A); ck_assert_int_eq(libinput_event_keyboard_get_key_state(kev), - LIBINPUT_KEYBOARD_KEY_STATE_RELEASED); + LIBINPUT_KEY_STATE_RELEASED); --expected_key_button_count; seat_key_count = @@ -108,7 +108,7 @@ START_TEST(keyboard_seat_key_count) for (i = 0; i < num_devices; ++i) litest_delete_device(devices[i]); - libinput_destroy(libinput); + libinput_unref(libinput); } END_TEST diff --git a/test/litest.c b/test/litest.c index fae8b162..958d2cfe 100644 --- a/test/litest.c +++ b/test/litest.c @@ -44,6 +44,7 @@ #include "libinput-util.h" static int in_debugger = -1; +static int verbose = 0; struct test { struct list node; @@ -258,8 +259,8 @@ litest_list_tests(struct list *tests) } static void -litest_log_handler(enum libinput_log_priority pri, - void *user_data, +litest_log_handler(struct libinput *libinput, + enum libinput_log_priority pri, const char *format, va_list args) { @@ -275,6 +276,23 @@ litest_log_handler(enum libinput_log_priority pri, vfprintf(stderr, format, args); } +static int +open_restricted(const char *path, int flags, void *userdata) +{ + return open(path, flags); +} + +static void +close_restricted(int fd, void *userdata) +{ + close(fd); +} + +struct libinput_interface interface = { + .open_restricted = open_restricted, + .close_restricted = close_restricted, +}; + static const struct option opts[] = { { "list", 0, 0, 'l' }, { "verbose", 0, 0, 'v' }, @@ -312,8 +330,7 @@ litest_run(int argc, char **argv) { litest_list_tests(&all_tests); return 0; case 'v': - libinput_log_set_priority(LIBINPUT_LOG_PRIORITY_DEBUG); - libinput_log_set_handler(litest_log_handler, NULL); + verbose = 1; break; default: fprintf(stderr, "usage: %s [--list]\n", argv[0]); @@ -343,24 +360,6 @@ litest_run(int argc, char **argv) { return failed; } -static int -open_restricted(const char *path, int flags, void *userdata) -{ - return open(path, flags); -} - -static void -close_restricted(int fd, void *userdata) -{ - close(fd); -} - -const struct libinput_interface interface = { - .open_restricted = open_restricted, - .close_restricted = close_restricted, -}; - - static struct input_absinfo * merge_absinfo(const struct input_absinfo *orig, const struct input_absinfo *override) @@ -491,6 +490,11 @@ litest_create_context(void) struct libinput *libinput = libinput_path_create_context(&interface, NULL); ck_assert_notnull(libinput); + + libinput_log_set_handler(libinput, litest_log_handler); + if (verbose) + libinput_log_set_priority(libinput, LIBINPUT_LOG_PRIORITY_DEBUG); + return libinput; } @@ -581,7 +585,7 @@ litest_delete_device(struct litest_device *d) libinput_device_unref(d->libinput_device); if (d->owns_context) - libinput_destroy(d->libinput); + libinput_unref(d->libinput); libevdev_free(d->evdev); libevdev_uinput_destroy(d->uinput); memset(d,0, sizeof(*d)); @@ -915,11 +919,13 @@ litest_create_uinput_device_from_description(const char *name, .flat = 0, .resolution = 100 }; + char buf[512]; dev = libevdev_new(); ck_assert(dev != NULL); - libevdev_set_name(dev, name); + snprintf(buf, sizeof(buf), "litest %s", name); + libevdev_set_name(dev, buf); if (id) { libevdev_set_id_bustype(dev, id->bustype); libevdev_set_id_vendor(dev, id->vendor); diff --git a/test/log.c b/test/log.c index a2818207..6ce5e7f4 100644 --- a/test/log.c +++ b/test/log.c @@ -32,7 +32,7 @@ #include "litest.h" static int log_handler_called; -static void *log_handler_userdata; +static struct libinput *log_handler_context; static int open_restricted(const char *path, int flags, void *data) { @@ -51,130 +51,90 @@ const struct libinput_interface simple_interface = { }; static void -simple_log_handler(enum libinput_log_priority priority, - void *userdata, +simple_log_handler(struct libinput *libinput, + enum libinput_log_priority priority, const char *format, va_list args) { log_handler_called++; - ck_assert(userdata == log_handler_userdata); + if (log_handler_context) + ck_assert(libinput == log_handler_context); ck_assert(format != NULL); } START_TEST(log_default_priority) { enum libinput_log_priority pri; + struct libinput *li; - pri = libinput_log_get_priority(); + li = libinput_path_create_context(&simple_interface, NULL); + pri = libinput_log_get_priority(li); ck_assert_int_eq(pri, LIBINPUT_LOG_PRIORITY_ERROR); + + libinput_unref(li); } END_TEST START_TEST(log_handler_invoked) { struct libinput *li; - enum libinput_log_priority pri = libinput_log_get_priority(); - - libinput_log_set_priority(LIBINPUT_LOG_PRIORITY_DEBUG); - libinput_log_set_handler(simple_log_handler, NULL); - log_handler_userdata = NULL; li = libinput_path_create_context(&simple_interface, NULL); + + libinput_log_set_priority(li, LIBINPUT_LOG_PRIORITY_DEBUG); + libinput_log_set_handler(li, simple_log_handler); + log_handler_context = li; + libinput_path_add_device(li, "/tmp"); ck_assert_int_gt(log_handler_called, 0); log_handler_called = 0; - libinput_destroy(li); - libinput_log_set_priority(pri); -} -END_TEST + libinput_unref(li); -START_TEST(log_userdata_NULL) -{ - struct libinput *li; - enum libinput_log_priority pri = libinput_log_get_priority(); - - libinput_log_set_priority(LIBINPUT_LOG_PRIORITY_DEBUG); - libinput_log_set_handler(simple_log_handler, NULL); - log_handler_userdata = NULL; - - li = libinput_path_create_context(&simple_interface, NULL); - libinput_path_add_device(li, "/tmp"); - - ck_assert_int_gt(log_handler_called, 0); - log_handler_called = 0; - - libinput_destroy(li); - - libinput_log_set_priority(pri); -} -END_TEST - -START_TEST(log_userdata) -{ - struct libinput *li; - enum libinput_log_priority pri = libinput_log_get_priority(); - - libinput_log_set_priority(LIBINPUT_LOG_PRIORITY_DEBUG); - libinput_log_set_handler(simple_log_handler, &li); - log_handler_userdata = &li; - - li = libinput_path_create_context(&simple_interface, NULL); - libinput_path_add_device(li, "/tmp"); - - ck_assert_int_gt(log_handler_called, 0); - log_handler_called = 0; - - libinput_destroy(li); - libinput_log_set_priority(pri); + log_handler_context = NULL; } END_TEST START_TEST(log_handler_NULL) { struct libinput *li; - enum libinput_log_priority pri = libinput_log_get_priority(); - - libinput_log_set_priority(LIBINPUT_LOG_PRIORITY_DEBUG); - libinput_log_set_handler(NULL, NULL); - log_handler_userdata = NULL; li = libinput_path_create_context(&simple_interface, NULL); + libinput_log_set_priority(li, LIBINPUT_LOG_PRIORITY_DEBUG); + libinput_log_set_handler(li, NULL); + libinput_path_add_device(li, "/tmp"); ck_assert_int_eq(log_handler_called, 0); log_handler_called = 0; - libinput_log_set_handler(simple_log_handler, NULL); - libinput_destroy(li); - libinput_log_set_priority(pri); + libinput_unref(li); } END_TEST START_TEST(log_priority) { struct libinput *li; - enum libinput_log_priority pri = libinput_log_get_priority(); - - libinput_log_set_priority(LIBINPUT_LOG_PRIORITY_ERROR); - libinput_log_set_handler(simple_log_handler, NULL); - log_handler_userdata = NULL; li = libinput_path_create_context(&simple_interface, NULL); + libinput_log_set_priority(li, LIBINPUT_LOG_PRIORITY_ERROR); + libinput_log_set_handler(li, simple_log_handler); + log_handler_context = li; + libinput_path_add_device(li, "/tmp"); ck_assert_int_eq(log_handler_called, 0); - libinput_log_set_priority(LIBINPUT_LOG_PRIORITY_INFO); + libinput_log_set_priority(li, LIBINPUT_LOG_PRIORITY_INFO); libinput_path_add_device(li, "/tmp"); ck_assert_int_gt(log_handler_called, 0); log_handler_called = 0; - libinput_destroy(li); - libinput_log_set_priority(pri); + libinput_unref(li); + log_handler_context = NULL; } END_TEST @@ -182,8 +142,6 @@ int main (int argc, char **argv) { litest_add_no_device("log:defaults", log_default_priority); litest_add_no_device("log:logging", log_handler_invoked); litest_add_no_device("log:logging", log_handler_NULL); - litest_add_no_device("log:logging", log_userdata); - litest_add_no_device("log:logging", log_userdata_NULL); litest_add_no_device("log:logging", log_priority); return litest_run(argc, argv); diff --git a/test/misc.c b/test/misc.c index 9ff31753..c4eaf911 100644 --- a/test/misc.c +++ b/test/misc.c @@ -134,7 +134,7 @@ START_TEST(event_conversion_device_notify) libinput_event_destroy(event); } - libinput_destroy(li); + libinput_unref(li); libevdev_uinput_destroy(uinput); ck_assert_int_gt(device_added, 0); @@ -195,7 +195,7 @@ START_TEST(event_conversion_pointer) libinput_event_destroy(event); } - libinput_destroy(li); + libinput_unref(li); libevdev_uinput_destroy(uinput); ck_assert_int_gt(motion, 0); @@ -255,7 +255,7 @@ START_TEST(event_conversion_pointer_abs) libinput_event_destroy(event); } - libinput_destroy(li); + libinput_unref(li); libevdev_uinput_destroy(uinput); ck_assert_int_gt(motion, 0); @@ -305,7 +305,7 @@ START_TEST(event_conversion_key) libinput_event_destroy(event); } - libinput_destroy(li); + libinput_unref(li); libevdev_uinput_destroy(uinput); ck_assert_int_gt(key, 0); @@ -365,7 +365,7 @@ START_TEST(event_conversion_touch) libinput_event_destroy(event); } - libinput_destroy(li); + libinput_unref(li); libevdev_uinput_destroy(uinput); ck_assert_int_gt(touch, 0); @@ -409,6 +409,25 @@ START_TEST(bitfield_helpers) } END_TEST +START_TEST(context_ref_counting) +{ + struct libinput *li; + + /* These tests rely on valgrind to detect memory leak and use after + * free errors. */ + + li = libinput_path_create_context(&simple_interface, NULL); + ck_assert_notnull(li); + ck_assert_ptr_eq(libinput_unref(li), NULL); + + li = libinput_path_create_context(&simple_interface, NULL); + ck_assert_notnull(li); + ck_assert_ptr_eq(libinput_ref(li), li); + ck_assert_ptr_eq(libinput_unref(li), li); + ck_assert_ptr_eq(libinput_unref(li), NULL); +} +END_TEST + int main (int argc, char **argv) { litest_add_no_device("events:conversion", event_conversion_device_notify); litest_add_no_device("events:conversion", event_conversion_pointer); @@ -416,6 +435,7 @@ int main (int argc, char **argv) { litest_add_no_device("events:conversion", event_conversion_key); litest_add_no_device("events:conversion", event_conversion_touch); litest_add_no_device("bitfield_helpers", bitfield_helpers); + litest_add_no_device("context:refcount", context_ref_counting); return litest_run(argc, argv); } diff --git a/test/path.c b/test/path.c index 24f60e01..99b474eb 100644 --- a/test/path.c +++ b/test/path.c @@ -65,7 +65,7 @@ START_TEST(path_create_NULL) ck_assert(li == NULL); li = libinput_path_create_context(&simple_interface, NULL); ck_assert(li != NULL); - libinput_destroy(li); + libinput_unref(li); ck_assert_int_eq(open_func_count, 0); ck_assert_int_eq(close_func_count, 0); @@ -92,7 +92,7 @@ START_TEST(path_create_invalid) ck_assert_int_eq(open_func_count, 0); ck_assert_int_eq(close_func_count, 0); - libinput_destroy(li); + libinput_unref(li); ck_assert_int_eq(close_func_count, 0); open_func_count = 0; @@ -126,7 +126,7 @@ START_TEST(path_create_destroy) ck_assert_int_eq(open_func_count, 1); libevdev_uinput_destroy(uinput); - libinput_destroy(li); + libinput_unref(li); ck_assert_int_eq(close_func_count, 1); open_func_count = 0; @@ -372,7 +372,7 @@ START_TEST(path_suspend) libinput_resume(li); libevdev_uinput_destroy(uinput); - libinput_destroy(li); + libinput_unref(li); open_func_count = 0; close_func_count = 0; @@ -406,7 +406,7 @@ START_TEST(path_double_suspend) libinput_resume(li); libevdev_uinput_destroy(uinput); - libinput_destroy(li); + libinput_unref(li); open_func_count = 0; close_func_count = 0; @@ -440,7 +440,7 @@ START_TEST(path_double_resume) libinput_resume(li); libevdev_uinput_destroy(uinput); - libinput_destroy(li); + libinput_unref(li); open_func_count = 0; close_func_count = 0; @@ -523,7 +523,7 @@ START_TEST(path_add_device_suspend_resume) libevdev_uinput_destroy(uinput1); libevdev_uinput_destroy(uinput2); - libinput_destroy(li); + libinput_unref(li); open_func_count = 0; close_func_count = 0; @@ -614,7 +614,7 @@ START_TEST(path_add_device_suspend_resume_fail) ck_assert_int_eq(nevents, 2); libevdev_uinput_destroy(uinput2); - libinput_destroy(li); + libinput_unref(li); open_func_count = 0; close_func_count = 0; @@ -704,7 +704,7 @@ START_TEST(path_add_device_suspend_resume_remove_device) ck_assert_int_eq(nevents, 1); libevdev_uinput_destroy(uinput1); - libinput_destroy(li); + libinput_unref(li); open_func_count = 0; close_func_count = 0; @@ -790,7 +790,7 @@ START_TEST(path_seat_recycle) ck_assert(found == 1); - libinput_destroy(li); + libinput_unref(li); libevdev_uinput_destroy(uinput); } diff --git a/test/pointer.c b/test/pointer.c index fd76ffe7..7d5668f8 100644 --- a/test/pointer.c +++ b/test/pointer.c @@ -181,8 +181,8 @@ test_wheel_event(struct litest_device *dev, int which, int amount) ck_assert(ptrev != NULL); ck_assert_int_eq(libinput_event_pointer_get_axis(ptrev), which == REL_WHEEL ? - LIBINPUT_POINTER_AXIS_VERTICAL_SCROLL : - LIBINPUT_POINTER_AXIS_HORIZONTAL_SCROLL); + LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL : + LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL); ck_assert_int_eq(libinput_event_pointer_get_axis_value(ptrev), expected); libinput_event_destroy(event); } @@ -292,7 +292,7 @@ START_TEST(pointer_seat_button_count) for (i = 0; i < num_devices; ++i) litest_delete_device(devices[i]); - libinput_destroy(libinput); + libinput_unref(libinput); } END_TEST diff --git a/test/touchpad.c b/test/touchpad.c index 35658338..288805ef 100644 --- a/test/touchpad.c +++ b/test/touchpad.c @@ -125,7 +125,7 @@ START_TEST(touchpad_1fg_tap) assert_button_event(li, BTN_LEFT, LIBINPUT_BUTTON_STATE_PRESSED); - usleep(300000); /* tap-n-drag timeout */ + msleep(300); /* tap-n-drag timeout */ assert_button_event(li, BTN_LEFT, LIBINPUT_BUTTON_STATE_RELEASED); @@ -177,7 +177,7 @@ START_TEST(touchpad_1fg_tap_n_drag) ck_assert_int_eq(libinput_next_event_type(li), LIBINPUT_EVENT_NONE); - usleep(300000); /* tap-n-drag timeout */ + msleep(300); /* tap-n-drag timeout */ assert_button_event(li, BTN_LEFT, LIBINPUT_BUTTON_STATE_RELEASED); @@ -202,7 +202,31 @@ START_TEST(touchpad_2fg_tap) assert_button_event(li, BTN_RIGHT, LIBINPUT_BUTTON_STATE_PRESSED); - usleep(300000); /* tap-n-drag timeout */ + msleep(300); /* tap-n-drag timeout */ + assert_button_event(li, BTN_RIGHT, + LIBINPUT_BUTTON_STATE_RELEASED); + + litest_assert_empty_queue(li); +} +END_TEST + +START_TEST(touchpad_2fg_tap_inverted) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + + litest_drain_events(dev->libinput); + + litest_touch_down(dev, 0, 50, 50); + litest_touch_down(dev, 1, 70, 70); + litest_touch_up(dev, 1); + litest_touch_up(dev, 0); + + libinput_dispatch(li); + + assert_button_event(li, BTN_RIGHT, + LIBINPUT_BUTTON_STATE_PRESSED); + msleep(300); /* tap-n-drag timeout */ assert_button_event(li, BTN_RIGHT, LIBINPUT_BUTTON_STATE_RELEASED); @@ -681,7 +705,7 @@ START_TEST(clickpad_softbutton_left_1st_fg_move) /* move out of the area, then wait for softbutton timer */ litest_touch_move_to(dev, 0, 20, 90, 90, 20, 10); libinput_dispatch(li); - usleep(400000); + msleep(400); libinput_dispatch(li); litest_drain_events(li); @@ -982,13 +1006,13 @@ START_TEST(clickpad_topsoftbuttons_move_out_ignore) litest_touch_down(dev, 0, 50, 5); libinput_dispatch(li); - usleep(200000); + msleep(200); libinput_dispatch(li); litest_assert_empty_queue(li); litest_touch_move_to(dev, 0, 50, 5, 80, 90, 20); libinput_dispatch(li); - usleep(400000); + msleep(400); libinput_dispatch(li); litest_event(dev, EV_KEY, BTN_LEFT, 1); @@ -1002,6 +1026,95 @@ START_TEST(clickpad_topsoftbuttons_move_out_ignore) } END_TEST +static void +test_2fg_scroll(struct litest_device *dev, int dx, int dy, int sleep) +{ + struct libinput *li = dev->libinput; + + litest_touch_down(dev, 0, 47, 50); + litest_touch_down(dev, 1, 53, 50); + + litest_touch_move_to(dev, 0, 47, 50, 47 + dx, 50 + dy, 5); + litest_touch_move_to(dev, 1, 53, 50, 53 + dx, 50 + dy, 5); + + /* Avoid a small scroll being seen as a tap */ + if (sleep) { + libinput_dispatch(li); + msleep(sleep); + libinput_dispatch(li); + } + + litest_touch_up(dev, 1); + litest_touch_up(dev, 0); + + libinput_dispatch(li); +} + +static void +check_2fg_scroll(struct litest_device *dev, int axis, int dir) +{ + struct libinput *li = dev->libinput; + struct libinput_event *event, *next_event; + struct libinput_event_pointer *ptrev; + + event = libinput_get_event(li); + next_event = libinput_get_event(li); + ck_assert(next_event != NULL); /* At least 1 scroll + stop scroll */ + + while (event) { + ck_assert_int_eq(libinput_event_get_type(event), + LIBINPUT_EVENT_POINTER_AXIS); + ptrev = libinput_event_get_pointer_event(event); + ck_assert(ptrev != NULL); + ck_assert_int_eq(libinput_event_pointer_get_axis(ptrev), axis); + + if (next_event) { + /* Normal scroll event, check dir */ + if (dir > 0) { + ck_assert_int_ge( + libinput_event_pointer_get_axis_value(ptrev), + dir); + } else { + ck_assert_int_le( + libinput_event_pointer_get_axis_value(ptrev), + dir); + } + } else { + /* Last scroll event, must be 0 */ + ck_assert_int_eq( + libinput_event_pointer_get_axis_value(ptrev), + 0); + } + libinput_event_destroy(event); + event = next_event; + next_event = libinput_get_event(li); + } +} + +START_TEST(touchpad_2fg_scroll) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + + litest_drain_events(li); + + /* Note this mixes in a tiny amount of movement in the wrong direction, + which should be ignored */ + test_2fg_scroll(dev, 1, 40, 0); + check_2fg_scroll(dev, LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL, 10); + test_2fg_scroll(dev, 1, -40, 0); + check_2fg_scroll(dev, LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL, -10); + test_2fg_scroll(dev, 40, 1, 0); + check_2fg_scroll(dev, LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL, 10); + test_2fg_scroll(dev, -40, 1, 0); + check_2fg_scroll(dev, LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL, -10); + + /* 2fg scroll smaller than the threshold should not generate events */ + test_2fg_scroll(dev, 1, 1, 200); + litest_assert_empty_queue(li); +} +END_TEST + int main(int argc, char **argv) { litest_add("touchpad:motion", touchpad_1fg_motion, LITEST_TOUCHPAD, LITEST_ANY); @@ -1010,6 +1123,7 @@ int main(int argc, char **argv) { litest_add("touchpad:tap", touchpad_1fg_tap, LITEST_TOUCHPAD, LITEST_ANY); litest_add("touchpad:tap", touchpad_1fg_tap_n_drag, LITEST_TOUCHPAD, LITEST_ANY); litest_add("touchpad:tap", touchpad_2fg_tap, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH); + litest_add("touchpad:tap", touchpad_2fg_tap_inverted, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH); litest_add("touchpad:tap", touchpad_1fg_tap_click, LITEST_TOUCHPAD, LITEST_ANY); litest_add("touchpad:tap", touchpad_2fg_tap_click, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH|LITEST_APPLE_CLICKPAD); litest_add("touchpad:tap", touchpad_2fg_tap_click_apple, LITEST_APPLE_CLICKPAD, LITEST_ANY); @@ -1039,5 +1153,7 @@ int main(int argc, char **argv) { litest_add("touchpad:topsoftbuttons", clickpad_topsoftbuttons_middle, LITEST_TOPBUTTONPAD, LITEST_ANY); litest_add("touchpad:topsoftbuttons", clickpad_topsoftbuttons_move_out_ignore, LITEST_TOPBUTTONPAD, LITEST_ANY); + litest_add("touchpad:scroll", touchpad_2fg_scroll, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH); + return litest_run(argc, argv); } diff --git a/test/udev.c b/test/udev.c index 6af2cb08..f07decb6 100644 --- a/test/udev.c +++ b/test/udev.c @@ -52,26 +52,25 @@ START_TEST(udev_create_NULL) { struct libinput *li; const struct libinput_interface interface; - struct udev *udev = (struct udev*)0xdeadbeef; - const char *seat = (const char*)0xdeaddead; + struct udev *udev; - li = libinput_udev_create_for_seat(NULL, NULL, NULL, NULL); + udev = udev_new(); + + li = libinput_udev_create_context(NULL, NULL, NULL); ck_assert(li == NULL); - li = libinput_udev_create_for_seat(&interface, NULL, NULL, NULL); - ck_assert(li == NULL); - li = libinput_udev_create_for_seat(NULL, NULL, udev, NULL); - ck_assert(li == NULL); - li = libinput_udev_create_for_seat(NULL, NULL, NULL, seat); + li = libinput_udev_create_context(&interface, NULL, NULL); ck_assert(li == NULL); - li = libinput_udev_create_for_seat(&interface, NULL, udev, NULL); - ck_assert(li == NULL); - li = libinput_udev_create_for_seat(NULL, NULL, udev, seat); + li = libinput_udev_create_context(NULL, NULL, udev); ck_assert(li == NULL); - li = libinput_udev_create_for_seat(&interface, NULL, NULL, seat); - ck_assert(li == NULL); + li = libinput_udev_create_context(&interface, NULL, udev); + ck_assert(li != NULL); + ck_assert_int_eq(libinput_udev_assign_seat(li, NULL), -1); + + libinput_unref(li); + udev_unref(udev); } END_TEST @@ -85,8 +84,9 @@ START_TEST(udev_create_seat0) udev = udev_new(); ck_assert(udev != NULL); - li = libinput_udev_create_for_seat(&simple_interface, NULL, udev, "seat0"); + li = libinput_udev_create_context(&simple_interface, NULL, udev); ck_assert(li != NULL); + ck_assert_int_eq(libinput_udev_assign_seat(li, "seat0"), 0); fd = libinput_get_fd(li); ck_assert_int_ge(fd, 0); @@ -97,7 +97,7 @@ START_TEST(udev_create_seat0) ck_assert(event != NULL); libinput_event_destroy(event); - libinput_destroy(li); + libinput_unref(li); udev_unref(udev); } END_TEST @@ -113,8 +113,9 @@ START_TEST(udev_create_empty_seat) ck_assert(udev != NULL); /* expect a libinput reference, but no events */ - li = libinput_udev_create_for_seat(&simple_interface, NULL, udev, "seatdoesntexist"); + li = libinput_udev_create_context(&simple_interface, NULL, udev); ck_assert(li != NULL); + ck_assert_int_eq(libinput_udev_assign_seat(li, "seatdoesntexist"), 0); fd = libinput_get_fd(li); ck_assert_int_ge(fd, 0); @@ -124,7 +125,7 @@ START_TEST(udev_create_empty_seat) ck_assert(event == NULL); libinput_event_destroy(event); - libinput_destroy(li); + libinput_unref(li); udev_unref(udev); } END_TEST @@ -147,8 +148,9 @@ START_TEST(udev_added_seat_default) udev = udev_new(); ck_assert(udev != NULL); - li = libinput_udev_create_for_seat(&simple_interface, NULL, udev, "seat0"); + li = libinput_udev_create_context(&simple_interface, NULL, udev); ck_assert(li != NULL); + ck_assert_int_eq(libinput_udev_assign_seat(li, "seat0"), 0); libinput_dispatch(li); while (!default_seat_found && (event = libinput_get_event(li))) { @@ -169,7 +171,7 @@ START_TEST(udev_added_seat_default) ck_assert(default_seat_found); - libinput_destroy(li); + libinput_unref(li); udev_unref(udev); } END_TEST @@ -184,8 +186,9 @@ START_TEST(udev_double_suspend) udev = udev_new(); ck_assert(udev != NULL); - li = libinput_udev_create_for_seat(&simple_interface, NULL, udev, "seat0"); + li = libinput_udev_create_context(&simple_interface, NULL, udev); ck_assert(li != NULL); + ck_assert_int_eq(libinput_udev_assign_seat(li, "seat0"), 0); fd = libinput_get_fd(li); ck_assert_int_ge(fd, 0); @@ -200,7 +203,7 @@ START_TEST(udev_double_suspend) libinput_resume(li); libinput_event_destroy(event); - libinput_destroy(li); + libinput_unref(li); udev_unref(udev); } END_TEST @@ -215,8 +218,9 @@ START_TEST(udev_double_resume) udev = udev_new(); ck_assert(udev != NULL); - li = libinput_udev_create_for_seat(&simple_interface, NULL, udev, "seat0"); + li = libinput_udev_create_context(&simple_interface, NULL, udev); ck_assert(li != NULL); + ck_assert_int_eq(libinput_udev_assign_seat(li, "seat0"), 0); fd = libinput_get_fd(li); ck_assert_int_ge(fd, 0); @@ -231,7 +235,7 @@ START_TEST(udev_double_resume) libinput_resume(li); libinput_event_destroy(event); - libinput_destroy(li); + libinput_unref(li); udev_unref(udev); } END_TEST @@ -266,8 +270,9 @@ START_TEST(udev_suspend_resume) udev = udev_new(); ck_assert(udev != NULL); - li = libinput_udev_create_for_seat(&simple_interface, NULL, udev, "seat0"); + li = libinput_udev_create_context(&simple_interface, NULL, udev); ck_assert(li != NULL); + ck_assert_int_eq(libinput_udev_assign_seat(li, "seat0"), 0); fd = libinput_get_fd(li); ck_assert_int_ge(fd, 0); @@ -289,7 +294,7 @@ START_TEST(udev_suspend_resume) process_events_count_devices(li, &num_devices); ck_assert_int_gt(num_devices, 0); - libinput_destroy(li); + libinput_unref(li); udev_unref(udev); } END_TEST @@ -305,8 +310,9 @@ START_TEST(udev_device_sysname) udev = udev_new(); ck_assert(udev != NULL); - li = libinput_udev_create_for_seat(&simple_interface, NULL, udev, "seat0"); + li = libinput_udev_create_context(&simple_interface, NULL, udev); ck_assert(li != NULL); + ck_assert_int_eq(libinput_udev_assign_seat(li, "seat0"), 0); libinput_dispatch(li); @@ -322,7 +328,7 @@ START_TEST(udev_device_sysname) libinput_event_destroy(ev); } - libinput_destroy(li); + libinput_unref(li); udev_unref(udev); } END_TEST @@ -342,8 +348,9 @@ START_TEST(udev_seat_recycle) udev = udev_new(); ck_assert(udev != NULL); - li = libinput_udev_create_for_seat(&simple_interface, NULL, udev, "seat0"); + li = libinput_udev_create_context(&simple_interface, NULL, udev); ck_assert(li != NULL); + ck_assert_int_eq(libinput_udev_assign_seat(li, "seat0"), 0); libinput_dispatch(li); while ((ev = libinput_get_event(li))) { @@ -396,7 +403,7 @@ START_TEST(udev_seat_recycle) ck_assert(found == 1); - libinput_destroy(li); + libinput_unref(li); udev_unref(udev); } END_TEST diff --git a/tools/.gitignore b/tools/.gitignore index 2cdd654f..cf348a6f 100644 --- a/tools/.gitignore +++ b/tools/.gitignore @@ -1 +1,2 @@ event-debug +event-gui diff --git a/tools/Makefile.am b/tools/Makefile.am index 8b6e22be..f59068da 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -7,3 +7,12 @@ event_debug_SOURCES = event-debug.c event_debug_LDADD = ../src/libinput.la $(LIBUDEV_LIBS) event_debug_LDFLAGS = -static event_debug_CFLAGS = $(LIBUDEV_CFLAGS) + +if BUILD_EVENTGUI +noinst_PROGRAMS += event-gui + +event_gui_SOURCES = event-gui.c +event_gui_LDADD = ../src/libinput.la $(CAIRO_LIBS) $(GTK_LIBS) $(LIBUDEV_LIBS) +event_gui_CFLAGS = $(CAIRO_CFLAGS) $(GTK_CFLAGS) $(LIBUDEV_CFLAGS) +event_gui_LDFLAGS = -static +endif diff --git a/tools/event-debug.c b/tools/event-debug.c index a26500e4..299587bb 100644 --- a/tools/event-debug.c +++ b/tools/event-debug.c @@ -131,6 +131,15 @@ static const struct libinput_interface interface = { .close_restricted = close_restricted, }; +static void +log_handler(struct libinput *li, + enum libinput_log_priority priority, + const char *format, + va_list args) +{ + vprintf(format, args); +} + static int open_udev(struct libinput **li) { @@ -140,12 +149,23 @@ open_udev(struct libinput **li) return 1; } - *li = libinput_udev_create_for_seat(&interface, NULL, udev, seat); + *li = libinput_udev_create_context(&interface, NULL, udev); if (!*li) { fprintf(stderr, "Failed to initialize context from udev\n"); return 1; } + if (verbose) { + libinput_log_set_handler(*li, log_handler); + libinput_log_set_priority(*li, LIBINPUT_LOG_PRIORITY_DEBUG); + } + + if (libinput_udev_assign_seat(*li, seat)) { + fprintf(stderr, "Failed to set seat\n"); + libinput_unref(*li); + return 1; + } + return 0; } @@ -160,10 +180,15 @@ open_device(struct libinput **li, const char *path) return 1; } + if (verbose) { + libinput_log_set_handler(*li, log_handler); + libinput_log_set_priority(*li, LIBINPUT_LOG_PRIORITY_DEBUG); + } + device = libinput_path_add_device(*li, path); if (!device) { fprintf(stderr, "Failed to initialized device %s\n", path); - libinput_destroy(*li); + libinput_unref(*li); return 1; } @@ -259,13 +284,13 @@ static void print_key_event(struct libinput_event *ev) { struct libinput_event_keyboard *k = libinput_event_get_keyboard_event(ev); - enum libinput_keyboard_key_state state; + enum libinput_key_state state; print_event_time(libinput_event_keyboard_get_time(k)); state = libinput_event_keyboard_get_key_state(k); printf("%d %s\n", libinput_event_keyboard_get_key(k), - state == LIBINPUT_KEYBOARD_KEY_STATE_PRESSED ? "pressed" : "released"); + state == LIBINPUT_KEY_STATE_PRESSED ? "pressed" : "released"); } static void @@ -332,10 +357,10 @@ print_pointer_axis_event(struct libinput_event *ev) double val; switch (axis) { - case LIBINPUT_POINTER_AXIS_VERTICAL_SCROLL: + case LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL: ax = "vscroll"; break; - case LIBINPUT_POINTER_AXIS_HORIZONTAL_SCROLL: + case LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL: ax = "hscroll"; break; default: @@ -574,15 +599,6 @@ mainloop(struct libinput *li) close(fds[1].fd); } -static void -log_handler(enum libinput_log_priority priority, - void *user_data, - const char *format, - va_list args) -{ - vprintf(format, args); -} - int main(int argc, char **argv) { @@ -592,11 +608,6 @@ main(int argc, char **argv) if (parse_args(argc, argv)) return 1; - if (verbose) { - libinput_log_set_handler(log_handler, NULL); - libinput_log_set_priority(LIBINPUT_LOG_PRIORITY_DEBUG); - } - if (mode == MODE_UDEV) { if (open_udev(&li)) return 1; @@ -611,7 +622,7 @@ main(int argc, char **argv) mainloop(li); - libinput_destroy(li); + libinput_unref(li); if (udev) udev_unref(udev); diff --git a/tools/event-gui.c b/tools/event-gui.c new file mode 100644 index 00000000..d65a8d15 --- /dev/null +++ b/tools/event-gui.c @@ -0,0 +1,474 @@ +/* + * Copyright © 2014 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of the copyright holders not be used in + * advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. The copyright holders make + * no representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#define _GNU_SOURCE +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#define clip(val_, min_, max_) min((max_), max((min_), (val_))) + +struct touch { + int active; + int x, y; +}; + +struct window { + GtkWidget *win; + GtkWidget *area; + int width, height; /* of window */ + + /* sprite position */ + double x, y; + + /* abs position */ + int absx, absy; + + /* scroll bar positions */ + int vx, vy; + int hx, hy; + + /* touch positions */ + struct touch touches[32]; + + /* l/m/r mouse buttons */ + int l, m, r; +}; + +static int +error(const char *fmt, ...) +{ + va_list args; + fprintf(stderr, "error: "); + + va_start(args, fmt); + vfprintf(stderr, fmt, args); + va_end(args); + + return EXIT_FAILURE; +} + +static void +msg(const char *fmt, ...) +{ + va_list args; + printf("info: "); + + va_start(args, fmt); + vprintf(fmt, args); + va_end(args); +} + +static void +usage(void) +{ + printf("%s [path/to/device]\n", program_invocation_short_name); +} + +static gboolean +draw(GtkWidget *widget, cairo_t *cr, gpointer data) +{ + struct window *w = data; + struct touch *t; + + cairo_set_source_rgb(cr, 1, 1, 1); + cairo_rectangle(cr, 0, 0, w->width, w->height); + cairo_fill(cr); + + /* draw pointer sprite */ + cairo_set_source_rgb(cr, 0, 0, 0); + cairo_save(cr); + cairo_move_to(cr, w->x, w->y); + cairo_rel_line_to(cr, 10, 15); + cairo_rel_line_to(cr, -10, 0); + cairo_rel_line_to(cr, 0, -15); + cairo_fill(cr); + cairo_restore(cr); + + /* draw scroll bars */ + cairo_set_source_rgb(cr, .4, .8, 0); + + cairo_save(cr); + cairo_rectangle(cr, w->vx - 10, w->vy - 20, 20, 40); + cairo_rectangle(cr, w->hx - 20, w->hy - 10, 40, 20); + cairo_fill(cr); + cairo_restore(cr); + + /* touch points */ + cairo_set_source_rgb(cr, .8, .2, .2); + + ARRAY_FOR_EACH(w->touches, t) { + cairo_save(cr); + cairo_arc(cr, t->x, t->y, 10, 0, 2 * M_PI); + cairo_fill(cr); + cairo_restore(cr); + } + + /* abs position */ + cairo_set_source_rgb(cr, .2, .4, .8); + + cairo_save(cr); + cairo_move_to(cr, w->absx, w->absy); + cairo_arc(cr, 0, 0, 10, 0, 2 * M_PI); + cairo_fill(cr); + cairo_restore(cr); + + /* lmr buttons */ + cairo_save(cr); + if (w->l || w->m || w->r) { + cairo_set_source_rgb(cr, .2, .8, .8); + if (w->l) + cairo_rectangle(cr, w->width/2 - 100, w->height - 200, 70, 30); + if (w->m) + cairo_rectangle(cr, w->width/2 - 20, w->height - 200, 40, 30); + if (w->r) + cairo_rectangle(cr, w->width/2 + 30, w->height - 200, 70, 30); + cairo_fill(cr); + } + + cairo_set_source_rgb(cr, 0, 0, 0); + cairo_rectangle(cr, w->width/2 - 100, w->height - 200, 70, 30); + cairo_rectangle(cr, w->width/2 - 20, w->height - 200, 40, 30); + cairo_rectangle(cr, w->width/2 + 30, w->height - 200, 70, 30); + cairo_stroke(cr); + cairo_restore(cr); + + return TRUE; +} + +static void +map_event_cb(GtkWidget *widget, GdkEvent *event, gpointer data) +{ + struct window *w = data; + + gtk_window_get_size(GTK_WINDOW(widget), &w->width, &w->height); + + w->x = w->width/2; + w->y = w->height/2; + + w->vx = w->width/2; + w->vy = w->height/2; + w->hx = w->width/2; + w->hy = w->height/2; + + g_signal_connect(G_OBJECT(w->area), "draw", G_CALLBACK(draw), w); + + gdk_window_set_cursor(gtk_widget_get_window(w->win), + gdk_cursor_new(GDK_BLANK_CURSOR)); +} + +static void +window_init(struct window *w) +{ + memset(w, 0, sizeof(*w)); + + w->win = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_widget_set_events(w->win, 0); + gtk_window_set_title(GTK_WINDOW(w->win), "libinput debugging tool"); + gtk_window_set_default_size(GTK_WINDOW(w->win), 1024, 768); + gtk_window_maximize(GTK_WINDOW(w->win)); + gtk_window_set_resizable(GTK_WINDOW(w->win), TRUE); + gtk_widget_realize(w->win); + g_signal_connect(G_OBJECT(w->win), "map-event", G_CALLBACK(map_event_cb), w); + g_signal_connect(G_OBJECT(w->win), "delete-event", G_CALLBACK(gtk_main_quit), NULL); + + w->area = gtk_drawing_area_new(); + gtk_widget_set_events(w->area, 0); + gtk_container_add(GTK_CONTAINER(w->win), w->area); + gtk_widget_show_all(w->win); +} + +static void +handle_event_device_notify(struct libinput_event *ev) +{ + struct libinput_device *dev = libinput_event_get_device(ev); + const char *type; + + if (libinput_event_get_type(ev) == LIBINPUT_EVENT_DEVICE_ADDED) + type = "added"; + else + type = "removed"; + + msg("%s %s\n", libinput_device_get_sysname(dev), type); +} + +static void +handle_event_motion(struct libinput_event *ev, struct window *w) +{ + struct libinput_event_pointer *p = libinput_event_get_pointer_event(ev); + double dx = libinput_event_pointer_get_dx(p), + dy = libinput_event_pointer_get_dy(p); + + w->x += dx; + w->y += dy; + w->x = clip(w->x, 0.0, w->width); + w->y = clip(w->y, 0.0, w->height); +} + +static void +handle_event_absmotion(struct libinput_event *ev, struct window *w) +{ + struct libinput_event_pointer *p = libinput_event_get_pointer_event(ev); + double x = libinput_event_pointer_get_absolute_x(p), + y = libinput_event_pointer_get_absolute_y(p); + + w->absx = clip((int)x, 0, w->width); + w->absy = clip((int)y, 0, w->height); +} + +static void +handle_event_touch(struct libinput_event *ev, struct window *w) +{ + struct libinput_event_touch *t = libinput_event_get_touch_event(ev); + int slot = libinput_event_touch_get_seat_slot(t); + struct touch *touch; + double x, y; + + if (slot == -1 || slot >= ARRAY_LENGTH(w->touches)) + return; + + touch = &w->touches[slot]; + + if (libinput_event_get_type(ev) == LIBINPUT_EVENT_TOUCH_UP) { + touch->active = 0; + return; + } + + x = libinput_event_touch_get_x(t), + y = libinput_event_touch_get_y(t); + + touch->active = 1; + touch->x = (int)x; + touch->y = (int)y; +} + +static void +handle_event_axis(struct libinput_event *ev, struct window *w) +{ + struct libinput_event_pointer *p = libinput_event_get_pointer_event(ev); + enum libinput_pointer_axis axis = libinput_event_pointer_get_axis(p); + double v = libinput_event_pointer_get_axis_value(p); + + switch (axis) { + case LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL: + w->vy += (int)v; + w->vy = clip(w->vy, 0, w->height); + break; + case LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL: + w->hx += (int)v; + w->hx = clip(w->hx, 0, w->width); + break; + default: + abort(); + } +} + +static int +handle_event_keyboard(struct libinput_event *ev, struct window *w) +{ + struct libinput_event_keyboard *k = libinput_event_get_keyboard_event(ev); + + if (libinput_event_keyboard_get_key(k) == KEY_ESC) + return 1; + + return 0; +} + +static void +handle_event_button(struct libinput_event *ev, struct window *w) +{ + struct libinput_event_pointer *p = libinput_event_get_pointer_event(ev); + unsigned int button = libinput_event_pointer_get_button(p); + int is_press; + + is_press = libinput_event_pointer_get_button_state(p) == LIBINPUT_BUTTON_STATE_PRESSED; + + switch (button) { + case BTN_LEFT: + w->l = is_press; + break; + case BTN_RIGHT: + w->r = is_press; + break; + case BTN_MIDDLE: + w->m = is_press; + break; + } + +} + +static gboolean +handle_event_libinput(GIOChannel *source, GIOCondition condition, gpointer data) +{ + struct libinput *li = data; + struct window *w = libinput_get_user_data(li); + struct libinput_event *ev; + + libinput_dispatch(li); + + while ((ev = libinput_get_event(li))) { + switch (libinput_event_get_type(ev)) { + case LIBINPUT_EVENT_NONE: + abort(); + case LIBINPUT_EVENT_DEVICE_ADDED: + case LIBINPUT_EVENT_DEVICE_REMOVED: + handle_event_device_notify(ev); + break; + case LIBINPUT_EVENT_POINTER_MOTION: + handle_event_motion(ev, w); + break; + case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE: + handle_event_absmotion(ev, w); + break; + case LIBINPUT_EVENT_TOUCH_DOWN: + case LIBINPUT_EVENT_TOUCH_MOTION: + case LIBINPUT_EVENT_TOUCH_UP: + handle_event_touch(ev, w); + break; + case LIBINPUT_EVENT_POINTER_AXIS: + handle_event_axis(ev, w); + break; + case LIBINPUT_EVENT_TOUCH_CANCEL: + case LIBINPUT_EVENT_TOUCH_FRAME: + break; + case LIBINPUT_EVENT_POINTER_BUTTON: + handle_event_button(ev, w); + break; + case LIBINPUT_EVENT_KEYBOARD_KEY: + if (handle_event_keyboard(ev, w)) { + libinput_event_destroy(ev); + gtk_main_quit(); + return FALSE; + } + break; + } + + libinput_event_destroy(ev); + libinput_dispatch(li); + } + gtk_widget_queue_draw(w->area); + + return TRUE; +} + +static void +sockets_init(struct libinput *li) +{ + GIOChannel *c = g_io_channel_unix_new(libinput_get_fd(li)); + + g_io_channel_set_encoding(c, NULL, NULL); + g_io_add_watch(c, G_IO_IN, handle_event_libinput, li); +} + +static int +parse_opts(int argc, char *argv[]) +{ + while (1) { + static struct option long_options[] = { + { "help", no_argument, 0, 'h' }, + }; + + int option_index = 0; + int c; + + c = getopt_long(argc, argv, "h", long_options, + &option_index); + if (c == -1) + break; + + switch(c) { + case 'h': + usage(); + return 0; + default: + usage(); + return 1; + } + } + + return 0; +} + + +static int +open_restricted(const char *path, int flags, void *user_data) +{ + int fd = open(path, flags); + return fd < 0 ? -errno : fd; +} + +static void +close_restricted(int fd, void *user_data) +{ + close(fd); +} + +const static struct libinput_interface interface = { + .open_restricted = open_restricted, + .close_restricted = close_restricted, +}; + +int +main(int argc, char *argv[]) +{ + struct window w; + struct libinput *li; + struct udev *udev; + + gtk_init(&argc, &argv); + + if (parse_opts(argc, argv) != 0) + return 1; + + udev = udev_new(); + if (!udev) + error("Failed to initialize udev\n"); + + li = libinput_udev_create_context(&interface, &w, udev); + if (!li || libinput_udev_assign_seat(li, "seat0") != 0) + error("Failed to initialize context from udev\n"); + + window_init(&w); + sockets_init(li); + + gtk_main(); + + libinput_unref(li); + udev_unref(udev); + + return 0; +}