input: Send leave and enter pair when the surface moves under the cursor
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
diff --git a/src/compositor.h b/src/compositor.h
index 8778aff..8fb8afb 100644
--- a/src/compositor.h
+++ b/src/compositor.h
@@ -328,6 +328,7 @@
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 b5efe73..c8c798e 100644
--- a/src/input.c
+++ b/src/input.c
@@ -157,7 +157,7 @@
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 @@
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 @@
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 @@
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 @@
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);
}