[PATCH] input: Send leave and enter pair when the surface moves under the cursor

Kristian Høgsberg krh at bitplanet.net
Wed Feb 5 17:14:42 PST 2014


The client needs to know that the pointer is at a different position in
its surface.  We can't send motion as that corresponds to the pointer
actually moving.  Leaving the surface and entering at the new position
is a better semantic match and doesn't correspond to pointer motion
or user input.

https://bugs.freedesktop.org/show_bug.cgi?id=71927
---
 src/compositor.h |  1 +
 src/input.c      | 28 ++++++++++++++++------------
 2 files changed, 17 insertions(+), 12 deletions(-)

We've discussed this in the past and I finally wrote the code.  It works as
expected and fixes the bug linked above where the cursor becomes stale when
we maximize a surface and the pointer ends up at a different position.

The one things missing from this patch is handling the implicit grab.  If
there's an implicit grab (a button pressed and held in the surface) we can
leave, but we always have to enter with 0 buttons pressed.  This means that
we have to wait for the buttons to be released before we send the enter.

Should be simple enough to do, but I wanted to send this out as an RFC to
see if we have consensus on the expected behavior.

Kristian

diff --git a/src/compositor.h b/src/compositor.h
index ced792f..b9fca91 100644
--- a/src/compositor.h
+++ b/src/compositor.h
@@ -328,6 +328,7 @@ struct weston_pointer {
 	uint32_t grab_time;
 
 	wl_fixed_t x, y;
+	wl_fixed_t sx, sy;
 	uint32_t button_count;
 
 	struct wl_listener output_destroy_listener;
diff --git a/src/input.c b/src/input.c
index e20c870..26afd65 100644
--- a/src/input.c
+++ b/src/input.c
@@ -157,7 +157,7 @@ default_grab_pointer_focus(struct weston_pointer_grab *grab)
 					   pointer->x, pointer->y,
 					   &sx, &sy);
 
-	if (pointer->focus != view)
+	if (pointer->focus != view || pointer->sx != sx || pointer->sy != sy)
 		weston_pointer_set_focus(pointer, view, sx, sy);
 }
 
@@ -166,18 +166,19 @@ default_grab_pointer_motion(struct weston_pointer_grab *grab, uint32_t time,
 			    wl_fixed_t x, wl_fixed_t y)
 {
 	struct weston_pointer *pointer = grab->pointer;
-	wl_fixed_t sx, sy;
 	struct wl_list *resource_list;
 	struct wl_resource *resource;
 
+	if (pointer->focus)
+		weston_view_from_global_fixed(pointer->focus, x, y,
+					      &pointer->sx, &pointer->sy);
+
 	weston_pointer_move(pointer, x, y);
 
-	if (pointer->focus)
-		weston_view_from_global_fixed(pointer->focus,
-					      pointer->x, pointer->y, &sx, &sy);
 	resource_list = &pointer->focus_resource_list;
 	wl_resource_for_each(resource, resource_list) {
-		wl_pointer_send_motion(resource, time, sx, sy);
+		wl_pointer_send_motion(resource, time,
+				       pointer->sx, pointer->sy);
 	}
 }
 
@@ -614,16 +615,17 @@ weston_pointer_set_focus(struct weston_pointer *pointer,
 	struct wl_display *display = pointer->seat->compositor->wl_display;
 	uint32_t serial;
 	struct wl_list *focus_resource_list;
-	int different_surface = 0;
+	int refocus = 0;
 
 	if ((!pointer->focus && view) ||
 	    (pointer->focus && !view) ||
-	    (pointer->focus && pointer->focus->surface != view->surface))
-		different_surface = 1;
+	    (pointer->focus && pointer->focus->surface != view->surface) ||
+	    pointer->sx != sx || pointer->sy != sy)
+		refocus = 1;
 
 	focus_resource_list = &pointer->focus_resource_list;
 
-	if (!wl_list_empty(focus_resource_list) && different_surface) {
+	if (!wl_list_empty(focus_resource_list) && refocus) {
 		serial = wl_display_next_serial(display);
 		wl_resource_for_each(resource, focus_resource_list) {
 			wl_pointer_send_leave(resource, serial,
@@ -633,8 +635,7 @@ weston_pointer_set_focus(struct weston_pointer *pointer,
 		move_resources(&pointer->resource_list, focus_resource_list);
 	}
 
-	if (find_resource_for_view(&pointer->resource_list, view) &&
-	    different_surface) {
+	if (find_resource_for_view(&pointer->resource_list, view) && refocus) {
 		struct wl_client *surface_client =
 			wl_resource_get_client(view->surface->resource);
 
@@ -672,6 +673,9 @@ weston_pointer_set_focus(struct weston_pointer *pointer,
 
 	pointer->focus = view;
 	pointer->focus_view_listener.notify = pointer_focus_view_destroyed;
+	pointer->sx = sx;
+	pointer->sy = sy;
+
 	wl_signal_emit(&pointer->focus_signal, pointer);
 }
 
-- 
1.8.4.2



More information about the wayland-devel mailing list