[PATCH weston] evdev: Handle SYN_DROPPED, query the state of buttons

Martin Minarik minarik11 at student.fiit.stuba.sk
Mon Mar 18 02:35:20 PDT 2013


When the kernel event queue overruns, the evdev.c will:
1. Skip events until and up to the next SYN_REPORT
2. Notify the compositor of the lag, the compositor can specify
   a key range of a key buttons to query the state of. The compositor
   will also invalidate the button event counters, if any.
3. Replay the button states and key states to the compositor via
   the usual api with a custom ACTUAL_STATE flag set.
4. Notify the compositor that the lag is over. The compositor
   will check, in case no button is held on the lagged device
   it will prematurely terminate the grab. This can be maybe
   coded even more clever to query all the seat devices, in that case,
   compositor button counter would be restored completely, and grabs
   terminated.

This introduces a new field, enum weston_button_state_update:
 STATE_CHANGE_EVENT	The state has changed, can count these events
 STATE_ACTUAL_UPDATE	The actual state, it might not have changed

This fixes:
   https://bugs.freedesktop.org/show_bug.cgi?id=62368
---
 src/compositor-wayland.c |    2 +-
 src/compositor-x11.c     |    3 +-
 src/compositor.c         |   60 ++++++++++++++++++++++++++----
 src/compositor.h         |   16 +++++++-
 src/evdev-touchpad.c     |    9 +++--
 src/evdev.c              |   91 ++++++++++++++++++++++++++++++++++++++++++++--
 tests/weston-test.c      |    2 +-
 7 files changed, 165 insertions(+), 18 deletions(-)

diff --git a/src/compositor-wayland.c b/src/compositor-wayland.c
index ceb912a..6a105b3 100644
--- a/src/compositor-wayland.c
+++ b/src/compositor-wayland.c
@@ -375,7 +375,7 @@ input_handle_button(void *data, struct wl_pointer *pointer,
 	struct wayland_input *input = data;
 	enum wl_pointer_button_state state = state_w;
 
-	notify_button(&input->base, time, button, state);
+	notify_button(&input->base, time, button, state, STATE_CHANGE_EVENT);
 }
 
 static void
diff --git a/src/compositor-x11.c b/src/compositor-x11.c
index 8e052dd..346e1ec 100644
--- a/src/compositor-x11.c
+++ b/src/compositor-x11.c
@@ -943,7 +943,8 @@ x11_compositor_deliver_button_event(struct x11_compositor *c,
 	notify_button(&c->core_seat,
 		      weston_compositor_get_time(), button,
 		      state ? WL_POINTER_BUTTON_STATE_PRESSED :
-			      WL_POINTER_BUTTON_STATE_RELEASED);
+			      WL_POINTER_BUTTON_STATE_RELEASED,
+		      STATE_CHANGE_EVENT);
 }
 
 static void
diff --git a/src/compositor.c b/src/compositor.c
index 248d3b4..cbfb8cc 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -1635,7 +1635,15 @@ weston_compositor_idle_inhibit(struct weston_compositor *compositor)
 static void
 weston_compositor_idle_release(struct weston_compositor *compositor)
 {
-	compositor->idle_inhibit--;
+	if (compositor->idle_inhibit)
+		compositor->idle_inhibit--;
+	weston_compositor_wake(compositor);
+}
+
+static void
+weston_compositor_idle_reset(struct weston_compositor *compositor)
+{
+	compositor->idle_inhibit = 0;
 	weston_compositor_wake(compositor);
 }
 
@@ -1776,8 +1784,35 @@ weston_surface_activate(struct weston_surface *surface,
 }
 
 WL_EXPORT void
-notify_button(struct weston_seat *seat, uint32_t time, int32_t button,
-	      enum wl_pointer_button_state state)
+notify_lag(struct weston_seat *seat, uint32_t time,
+	   int32_t *query_key_min, int32_t *query_key_max)
+{
+	struct wl_pointer *pointer = seat->seat.pointer;
+	struct weston_compositor *compositor = seat->compositor;
+
+	weston_compositor_idle_reset(compositor);
+
+	if (pointer->button_count) {
+		pointer->button_count = 0;
+		*query_key_min = pointer->grab_button;
+		*query_key_max = pointer->grab_button + 1;
+	}
+}
+
+WL_EXPORT void
+notify_lag_end(struct weston_seat *seat, uint32_t time)
+{
+	struct wl_pointer *pointer = seat->seat.pointer;
+
+	if (pointer->button_count == 0)
+		pointer->grab->interface->button(pointer->grab, time,
+			pointer->grab_button, WL_POINTER_BUTTON_STATE_RELEASED);
+}
+
+WL_EXPORT void
+notify_button(struct weston_seat *seat, uint32_t time, uint32_t button,
+	      enum wl_pointer_button_state state,
+	      enum weston_button_state_update update_state)
 {
 	struct weston_compositor *compositor = seat->compositor;
 	struct wl_pointer *pointer = seat->seat.pointer;
@@ -1789,16 +1824,25 @@ notify_button(struct weston_seat *seat, uint32_t time, int32_t button,
 		if (compositor->ping_handler && focus)
 			compositor->ping_handler(focus, serial);
 		weston_compositor_idle_inhibit(compositor);
-		if (pointer->button_count == 0) {
+
+		if ((pointer->button_count == 0) &&
+		    (update_state == STATE_CHANGE_EVENT)) {
 			pointer->grab_button = button;
 			pointer->grab_time = time;
 			pointer->grab_x = pointer->x;
 			pointer->grab_y = pointer->y;
 		}
-		pointer->button_count++;
+		if (button == pointer->grab_button)
+			pointer->button_count++;
 	} else {
 		weston_compositor_idle_release(compositor);
-		pointer->button_count--;
+
+		if (pointer->button_count == 0)
+			return;
+
+		if ((button == pointer->grab_button) &&
+		    (update_state == STATE_CHANGE_EVENT))
+			pointer->button_count--;
 	}
 
 	weston_compositor_run_button_binding(compositor, seat, time, button,
@@ -1806,7 +1850,9 @@ notify_button(struct weston_seat *seat, uint32_t time, int32_t button,
 
 	pointer->grab->interface->button(pointer->grab, time, button, state);
 
-	if (pointer->button_count == 1)
+	if ((state == WL_POINTER_BUTTON_STATE_PRESSED) &&
+	    (pointer->button_count == 1) &&
+	    (update_state == STATE_CHANGE_EVENT))
 		pointer->grab_serial =
 			wl_display_get_serial(compositor->wl_display);
 }
diff --git a/src/compositor.h b/src/compositor.h
index 4a0c1e3..a614ee9 100644
--- a/src/compositor.h
+++ b/src/compositor.h
@@ -491,6 +491,11 @@ enum weston_key_state_update {
 	STATE_UPDATE_NONE,
 };
 
+enum weston_button_state_update {
+	STATE_CHANGE_EVENT,
+	STATE_ACTUAL_UPDATE,
+};
+
 void
 weston_version(int *major, int *minor, int *micro);
 
@@ -542,8 +547,15 @@ void
 notify_motion(struct weston_seat *seat, uint32_t time,
 	      wl_fixed_t x, wl_fixed_t y);
 void
-notify_button(struct weston_seat *seat, uint32_t time, int32_t button,
-	      enum wl_pointer_button_state state);
+notify_lag(struct weston_seat *seat, uint32_t time,
+	   int32_t *query_key_min, int32_t *query_key_max);
+void
+notify_lag_end(struct weston_seat *seat, uint32_t time);
+
+void
+notify_button(struct weston_seat *seat, uint32_t time, uint32_t button,
+	      enum wl_pointer_button_state state,
+	      enum weston_button_state_update update_state);
 void
 notify_axis(struct weston_seat *seat, uint32_t time, uint32_t axis,
 	    wl_fixed_t value);
diff --git a/src/evdev-touchpad.c b/src/evdev-touchpad.c
index c25a199..aad5dfc 100644
--- a/src/evdev-touchpad.c
+++ b/src/evdev-touchpad.c
@@ -275,7 +275,8 @@ notify_button_pressed(struct touchpad_dispatch *touchpad, uint32_t time)
 {
 	notify_button(touchpad->device->seat, time,
 		      DEFAULT_TOUCHPAD_SINGLE_TAP_BUTTON,
-		      WL_POINTER_BUTTON_STATE_PRESSED);
+		      WL_POINTER_BUTTON_STATE_PRESSED,
+		      STATE_CHANGE_EVENT);
 }
 
 static void
@@ -283,7 +284,8 @@ notify_button_released(struct touchpad_dispatch *touchpad, uint32_t time)
 {
 	notify_button(touchpad->device->seat, time,
 		      DEFAULT_TOUCHPAD_SINGLE_TAP_BUTTON,
-		      WL_POINTER_BUTTON_STATE_RELEASED);
+		      WL_POINTER_BUTTON_STATE_RELEASED,
+		      STATE_CHANGE_EVENT);
 }
 
 static void
@@ -581,7 +583,8 @@ process_key(struct touchpad_dispatch *touchpad,
 		notify_button(device->seat,
 			      time, e->code,
 			      e->value ? WL_POINTER_BUTTON_STATE_PRESSED :
-			                 WL_POINTER_BUTTON_STATE_RELEASED);
+			                 WL_POINTER_BUTTON_STATE_RELEASED,
+					 STATE_CHANGE_EVENT);
 		break;
 	case BTN_TOOL_PEN:
 	case BTN_TOOL_RUBBER:
diff --git a/src/evdev.c b/src/evdev.c
index d2954b5..6d140ce 100644
--- a/src/evdev.c
+++ b/src/evdev.c
@@ -60,6 +60,34 @@ evdev_led_update(struct evdev_device *device, enum weston_led leds)
 	(void)i; /* no, we really don't care about the return value */
 }
 
+struct evdev_dispatch_interface fallback_interface;
+struct evdev_dispatch_interface syn_drop_interface;
+
+static inline void
+evdev_process_syn(struct evdev_device *device, struct input_event *e, int time)
+{
+	switch (e->code) {
+	case SYN_DROPPED:
+		if (device->dispatch->interface == &fallback_interface)
+			device->dispatch->interface = &syn_drop_interface;
+		break;
+	case SYN_REPORT:
+	default:
+		device->pending_events |= EVDEV_SYN;
+		break;
+	}
+}
+
+static int
+evdev_query_eviocg_button_range(struct evdev_device *device, int time,
+				int32_t key_min, int32_t key_max);
+
+static inline void
+evdev_process_syn_skip(struct evdev_device *d, struct input_event *e, int time)
+{
+
+}
+
 static inline void
 evdev_process_key(struct evdev_device *device, struct input_event *e, int time)
 {
@@ -78,9 +106,9 @@ evdev_process_key(struct evdev_device *device, struct input_event *e, int time)
 		notify_button(device->seat,
 			      time, e->code,
 			      e->value ? WL_POINTER_BUTTON_STATE_PRESSED :
-					 WL_POINTER_BUTTON_STATE_RELEASED);
+					 WL_POINTER_BUTTON_STATE_RELEASED,
+			      STATE_CHANGE_EVENT);
 		break;
-
 	default:
 		notify_key(device->seat,
 			   time, e->code,
@@ -308,7 +336,7 @@ fallback_process(struct evdev_dispatch *dispatch,
 		evdev_process_key(device, event, time);
 		break;
 	case EV_SYN:
-		device->pending_events |= EVDEV_SYN;
+		evdev_process_syn(device, event, time);
 		break;
 	}
 }
@@ -324,6 +352,39 @@ struct evdev_dispatch_interface fallback_interface = {
 	fallback_destroy
 };
 
+static void
+syn_drop_process(struct evdev_dispatch *dispatch,
+		 struct evdev_device *device,
+		 struct input_event *event,
+		 uint32_t time)
+{
+	int32_t key_min = KEY_MAX, key_max = 0;
+
+	if ((event->code != EV_SYN) || (event->code != SYN_REPORT))
+		return;
+
+	if (device->dispatch->interface == &syn_drop_interface)
+		device->dispatch->interface = &fallback_interface;
+
+	notify_lag(device->seat, time, &key_min, &key_max);
+
+	if (key_min < key_max)
+		evdev_query_eviocg_button_range(device, time, key_min, key_max);
+
+	notify_lag_end(device->seat, time);
+}
+
+static void
+syn_drop_destroy(struct evdev_dispatch *dispatch)
+{
+	free(dispatch);
+}
+
+struct evdev_dispatch_interface syn_drop_interface = {
+	syn_drop_process,
+	syn_drop_destroy
+};
+
 static struct evdev_dispatch *
 fallback_dispatch_create(void)
 {
@@ -399,6 +460,30 @@ evdev_device_data(int fd, uint32_t mask, void *data)
 }
 
 static int
+evdev_query_eviocg_button_range(struct evdev_device *device, int time,
+				int32_t key_min, int32_t key_max)
+{
+	unsigned long key_bits[NBITS(KEY_MAX)];
+	int key;
+
+	memset(key_bits, 0, sizeof(key_bits));
+
+	if (ioctl(device->fd, EVIOCGKEY(KEY_MAX), key_bits) < 0)
+		return -1;
+
+	for (key = key_min; key < key_max; key++) {
+		int value = TEST_BIT(key_bits, key);
+		notify_button(device->seat,
+		      time, key,
+		      value ?	WL_POINTER_BUTTON_STATE_PRESSED :
+				WL_POINTER_BUTTON_STATE_RELEASED,
+		      STATE_ACTUAL_UPDATE);
+	}
+
+	return 0;
+}
+
+static int
 evdev_handle_device(struct evdev_device *device)
 {
 	struct input_absinfo absinfo;
diff --git a/tests/weston-test.c b/tests/weston-test.c
index b29b64f..6782205 100644
--- a/tests/weston-test.c
+++ b/tests/weston-test.c
@@ -142,7 +142,7 @@ send_button(struct wl_client *client, struct wl_resource *resource,
 
 	test->compositor->focus = 1;
 
-	notify_button(seat, 100, button, state);
+	notify_button(seat, 100, button, state, STATE_CHANGE_EVENT);
 }
 
 static void
-- 
1.7.10.4



More information about the wayland-devel mailing list