[PATCH] xwayland: Only request cursor frame events if the surface is visible

Rui Matos tiagomatos at gmail.com
Tue Feb 2 21:06:33 CET 2016


If the wayland compositor hides our cursor surface (e.g. because the
pointer moved over a different wayland client) before our last
submitted buffer gets a chance to be displayed, no frame event will be
sent and thus we end up in a state where we'll never do any more
cursor updates since we never clear cursor_frame_cb.

Signed-off-by: Rui Matos <tiagomatos at gmail.com>
---

If you have seen stuck cursors with xwayland windows lately this is
probably why.

 hw/xwayland/xwayland-cursor.c |  6 ++++--
 hw/xwayland/xwayland-input.c  | 30 ++++++++++++++++++++++++++++++
 hw/xwayland/xwayland.h        |  1 +
 3 files changed, 35 insertions(+), 2 deletions(-)

diff --git a/hw/xwayland/xwayland-cursor.c b/hw/xwayland/xwayland-cursor.c
index 76729db..a6ee78f 100644
--- a/hw/xwayland/xwayland-cursor.c
+++ b/hw/xwayland/xwayland-cursor.c
@@ -140,8 +140,10 @@ xwl_seat_set_cursor(struct xwl_seat *xwl_seat)
                       xwl_seat->x_cursor->bits->width,
                       xwl_seat->x_cursor->bits->height);
 
-    xwl_seat->cursor_frame_cb = wl_surface_frame(xwl_seat->cursor);
-    wl_callback_add_listener(xwl_seat->cursor_frame_cb, &frame_listener, xwl_seat);
+    if (xwl_seat->cursor_visible) {
+        xwl_seat->cursor_frame_cb = wl_surface_frame(xwl_seat->cursor);
+        wl_callback_add_listener(xwl_seat->cursor_frame_cb, &frame_listener, xwl_seat);
+    }
 
     wl_surface_commit(xwl_seat->cursor);
 }
diff --git a/hw/xwayland/xwayland-input.c b/hw/xwayland/xwayland-input.c
index 61ca70b..bdf1fbc 100644
--- a/hw/xwayland/xwayland-input.c
+++ b/hw/xwayland/xwayland-input.c
@@ -781,6 +781,34 @@ static const struct wl_seat_listener seat_listener = {
 };
 
 static void
+cursor_surface_handle_enter(void *data, struct wl_surface *surface,
+                            struct wl_output *output)
+{
+    struct xwl_seat *xwl_seat = data;
+    xwl_seat->cursor_visible = TRUE;
+    if (xwl_seat->cursor_needs_update) {
+        xwl_seat->cursor_needs_update = FALSE;
+        xwl_seat_set_cursor(xwl_seat);
+    }
+}
+
+static void
+cursor_surface_handle_leave(void *data, struct wl_surface *surface,
+                            struct wl_output *output)
+{
+    struct xwl_seat *xwl_seat = data;
+    xwl_seat->cursor_visible = FALSE;
+    if (xwl_seat->cursor_frame_cb)
+        wl_callback_destroy(xwl_seat->cursor_frame_cb);
+    xwl_seat->cursor_frame_cb = NULL;
+}
+
+static const struct wl_surface_listener cursor_surface_listener = {
+    cursor_surface_handle_enter,
+    cursor_surface_handle_leave
+};
+
+static void
 create_input_device(struct xwl_screen *xwl_screen, uint32_t id, uint32_t version)
 {
     struct xwl_seat *xwl_seat;
@@ -800,6 +828,8 @@ create_input_device(struct xwl_screen *xwl_screen, uint32_t id, uint32_t version
     xwl_seat->id = id;
 
     xwl_seat->cursor = wl_compositor_create_surface(xwl_screen->compositor);
+    wl_surface_add_listener(xwl_seat->cursor, &cursor_surface_listener, xwl_seat);
+
     wl_seat_add_listener(xwl_seat->seat, &seat_listener, xwl_seat);
     wl_array_init(&xwl_seat->keys);
 
diff --git a/hw/xwayland/xwayland.h b/hw/xwayland/xwayland.h
index a7d7119..a0af07a 100644
--- a/hw/xwayland/xwayland.h
+++ b/hw/xwayland/xwayland.h
@@ -131,6 +131,7 @@ struct xwl_seat {
     struct wl_surface *cursor;
     struct wl_callback *cursor_frame_cb;
     Bool cursor_needs_update;
+    Bool cursor_visible;
 
     struct xorg_list touches;
 
-- 
2.5.0



More information about the xorg-devel mailing list